diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2b5b285 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +name: Site acceptance + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + acceptance: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.13 + - name: Install workspace + run: bun install --frozen-lockfile + - name: Content, types, generation, and static contracts + run: | + bun run check + bun run test + - name: Install browser + run: | + bunx playwright install --with-deps chromium + echo "CHROME_PATH=$(bun -e 'import { chromium } from "playwright"; console.log(chromium.executablePath())')" >> "$GITHUB_ENV" + - name: Browser, accessibility, and visual acceptance + run: bun run test:e2e + - name: Lighthouse budgets + run: bun run test:lighthouse + - name: Diff hygiene + run: git diff --check + - name: Upload browser diagnostics + if: failure() + uses: actions/upload-artifact@v4 + with: + name: playwright-diagnostics + path: | + playwright-report + test-results + if-no-files-found: ignore diff --git a/.github/workflows/release-sync.yml b/.github/workflows/release-sync.yml new file mode 100644 index 0000000..ef0b328 --- /dev/null +++ b/.github/workflows/release-sync.yml @@ -0,0 +1,108 @@ +name: Mobench release sync + +on: + schedule: + - cron: '23 7 * * *' + workflow_dispatch: + inputs: + tag: + description: Optional explicit stable tag; defaults to the latest release + required: false + type: string + +permissions: + contents: write + pull-requests: write + +concurrency: + group: mobench-release-sync + cancel-in-progress: false + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.13 + + - name: Resolve stable release and checksum + id: release + env: + GH_TOKEN: ${{ github.token }} + REQUESTED_TAG: ${{ inputs.tag }} + run: | + tag="$REQUESTED_TAG" + if [ -z "$tag" ]; then + tag="$(gh api repos/worldcoin/mobile-bench-rs/releases/latest --jq '.tag_name')" + fi + current="$(bun -e 'console.log((await Bun.file("packages/truth/pin.json").json()).release)')" + if [ "$tag" = "$current" ]; then + echo "update=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + checksum_dir="$(mktemp -d)" + gh release download "$tag" \ + --repo worldcoin/mobile-bench-rs \ + --pattern 'mobench-site-manifest-v1.json.sha256' \ + --dir "$checksum_dir" + expected="$(awk '{print $1}' "$checksum_dir/mobench-site-manifest-v1.json.sha256")" + if ! printf '%s' "$expected" | grep -Eq '^[0-9a-f]{64}$'; then + echo "Release checksum asset is invalid" >&2 + exit 1 + fi + echo "update=true" >> "$GITHUB_OUTPUT" + echo "tag=$tag" >> "$GITHUB_OUTPUT" + echo "version=${tag#v}" >> "$GITHUB_OUTPUT" + echo "checksum=$expected" >> "$GITHUB_OUTPUT" + + - name: Install workspace + if: steps.release.outputs.update == 'true' + run: bun install --frozen-lockfile + + - name: Sync pinned release + if: steps.release.outputs.update == 'true' + env: + GH_TOKEN: ${{ github.token }} + run: | + bun run sync:release -- \ + --tag "${{ steps.release.outputs.tag }}" \ + --expected-manifest-sha256 "${{ steps.release.outputs.checksum }}" + bun install + bun run generate + + - name: Validate update + if: steps.release.outputs.update == 'true' + run: | + bun run check + bun run test + git diff --check + + - name: Open update pull request + if: steps.release.outputs.update == 'true' + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.release.outputs.tag }} + VERSION: ${{ steps.release.outputs.version }} + run: | + if git diff --quiet; then + exit 0 + fi + branch="automation/mobench-release-$VERSION" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git switch -c "$branch" + git add .github apps docs packages scripts tests README.md bun.lock package.json + git commit -m "chore: sync mobench $TAG truth contract" + git push --force-with-lease origin "$branch" + existing="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url // empty')" + if [ -z "$existing" ]; then + gh pr create \ + --head "$branch" \ + --title "chore: sync mobench $TAG truth contract" \ + --body "Pins the tested $TAG release manifest, schemas, fixtures, generated references, and route-independent release copy. Preview deployment and E2E checks remain required before merge." + fi diff --git a/.gitignore b/.gitignore index 139c0f7..6e5816e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules dist +.astro .DS_Store *.local .vercel @@ -7,3 +8,7 @@ dist .env.* !.env.example .design-src +playwright-report +test-results +.lighthouseci +*.tsbuildinfo diff --git a/README.md b/README.md index 8838034..ae8233d 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,61 @@ # mobench.org -Marketing site and documentation for **mobench** (`mobile-bench-rs`) — an open-source Rust -benchmarking harness that runs your benchmarks on real iOS and Android phones and reports -wall-clock time, peak memory, and energy. Built by [World](https://world.org). +The public website for [mobench](https://github.com/worldcoin/mobile-bench-rs), a Rust toolkit for building mobile benchmark runners, executing ordinary benchmark suites on BrowserStack devices, and producing stable CI reports. The repository publishes two static Astro sites: -## Stack +- `mobench.org` — product education and task entry points. +- `docs.mobench.org` — Starlight documentation, search, references, and examples. -- [TanStack Router](https://tanstack.com/router) (file-based routing, SPA) -- [Vite](https://vite.dev) + React + TypeScript -- [Tailwind CSS v4](https://tailwindcss.com) -- [shadcn/ui](https://ui.shadcn.com) primitives (Button, Accordion) +The current stable documentation targets `mobench 0.1.43`. Use the `mobench` executable in published commands. The `cargo mobench` wrapper is not a supported documentation entry point until its upstream argument-forwarding fix is released and smoke-tested. -## Routes +## Workspace -| Path | Source | Description | -| ------- | ----------------------- | ------------------------------------------------------- | -| `/` | `src/routes/index.tsx` | Landing page — hero, features, benchmarks, FAQ, CTA. | -| `/docs` | `src/routes/docs.tsx` | Documentation app — sidebar nav, 8 pages, right-rail TOC. | +```text +apps/ + marketing/ Astro marketing site + docs/ Astro Starlight documentation site +packages/ + truth/ Pinned upstream manifest, schema snapshots, and checksums +scripts/ Content, command, routing, and release-sync validation +docs/ Authoring, architecture, release, and deployment runbooks +``` -Both pages were imported from the Claude Design project *Mobile Bench landing page design* -(`Mobench Landing.dc.html`, `Mobench Docs.dc.html`) and reimplemented as React. +Both applications render complete HTML at build time. JavaScript is reserved for progressive enhancements such as theme selection, mobile navigation, search, and copy controls. ## Develop +Install [Bun](https://bun.sh/) and Rust only if you are validating upstream examples. + ```bash -npm install -npm run dev # http://localhost:3000 +bun install --frozen-lockfile +bun run dev:marketing # http://localhost:3000 +bun run dev:docs # http://localhost:3001 ``` -## Build +Do not use npm, pnpm, or Yarn in this repository. + +## Validate ```bash -npm run build # outputs to dist/ -npm run serve # preview the production build +bun run check +bun run test +bun run build +bun run test:e2e ``` +The checks validate MDX frontmatter, aliases, CLI and configuration snippets, upstream version alignment, internal links, generated `llms` files, redirect contracts, static routes, accessibility, and performance budgets. See [Authoring](docs/AUTHORING.md) and [Release sync](docs/RELEASE_SYNC.md) before changing product claims or reference material. + ## Deploy -Configured for [Vercel](https://vercel.com) (`vercel.json`): framework preset `vite`, SPA -rewrites so client-side routes resolve to `index.html`. +Create two Vercel projects from this repository, with root directories `apps/marketing` and `apps/docs`. The marketing project owns only marketing routes; the docs project owns only canonical documentation routes. Cross-host duplicates and legacy aliases must return redirects, not duplicate pages. + +Preview both projects before production and follow [Deployment and smoke checks](docs/DEPLOYMENT.md). Keep the preceding production deployments available for rollback. + +## Source of truth + +CLI flags, configuration keys, artifact names, schemas, and capability statements originate in the versioned `mobench-site-manifest-v1.json` release asset generated by `mobile-bench-rs`. This repository pins a release tag, commit SHA, manifest checksum, and schema snapshot. Upstream changes arrive through reviewed update pull requests; production builds never fetch `main`. + +To prepare a release update manually, use `bun run sync:release -- --help`. The command requires an explicit tag and trusted manifest checksum; the scheduled watcher uses the same path and opens a review branch rather than updating production directly. + +## License + +[MIT](LICENSE) diff --git a/apps/docs/astro.config.mjs b/apps/docs/astro.config.mjs new file mode 100644 index 0000000..44abf4a --- /dev/null +++ b/apps/docs/astro.config.mjs @@ -0,0 +1,86 @@ +import { defineConfig } from 'astro/config' +import sitemap from '@astrojs/sitemap' +import starlight from '@astrojs/starlight' + +const repository = 'https://github.com/worldcoin/mobile-bench-rs' + +export default defineConfig({ + site: 'https://docs.mobench.org', + output: 'static', + integrations: [ + starlight({ + title: 'mobench docs', + disable404Route: true, + description: 'Build, run, and analyze Rust benchmarks on mobile targets.', + favicon: '/favicon.svg', + logo: { + src: './src/assets/logo.svg', + alt: 'mobench', + }, + social: [ + { icon: 'github', label: 'GitHub', href: repository }, + ], + editLink: { + baseUrl: 'https://github.com/worldfnd/mobench.org/edit/main/apps/docs/', + }, + lastUpdated: true, + customCss: ['./src/styles/mobench.css'], + components: { + Head: './src/components/Head.astro', + PageTitle: './src/components/PageTitle.astro', + }, + sidebar: [ + { label: 'Get started', items: [ + { label: 'Installation', slug: 'installation' }, + { label: 'Quickstart', slug: 'quickstart' }, + ] }, + { label: 'Write benchmarks', items: [ + { label: 'Benchmark functions', slug: 'benchmark-functions' }, + { label: 'Setup and teardown', slug: 'setup-teardown' }, + { label: 'Benchmark quality', slug: 'benchmark-quality' }, + ] }, + { label: 'Run benchmarks', items: [ + { label: 'Host-side preflight', slug: 'host-preflight' }, + { label: 'BrowserStack devices', slug: 'browserstack' }, + { label: 'CI runs', slug: 'ci' }, + ] }, + { label: 'Analyze results', items: [ + { label: 'Outputs and metrics', slug: 'outputs' }, + { label: 'Regression comparison', slug: 'regressions' }, + { label: 'Local native profiling', slug: 'profiling' }, + ] }, + { label: 'Reference', items: [ + { label: 'CLI', slug: 'cli' }, + { label: 'Configuration', slug: 'configuration' }, + { label: 'Device matrices', slug: 'device-matrices' }, + { label: 'Output schemas', slug: 'schemas' }, + { label: 'Compatibility', slug: 'compatibility' }, + ] }, + { label: 'Examples', items: [ + { label: 'Basic benchmark', slug: 'basic-example' }, + { label: 'FFI benchmark', slug: 'ffi-example' }, + ] }, + { label: 'Help', items: [ + { label: 'Troubleshooting', slug: 'troubleshooting' }, + ] }, + ], + head: [ + { + tag: 'script', + attrs: { type: 'application/ld+json' }, + content: JSON.stringify({ + '@context': 'https://schema.org', + '@type': 'SoftwareSourceCode', + name: 'mobench', + codeRepository: repository, + programmingLanguage: 'Rust', + runtimePlatform: ['Android', 'iOS'], + }), + }, + ], + }), + sitemap(), + ], + build: { format: 'directory' }, + compressHTML: true, +}) diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 0000000..423c168 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,24 @@ +{ + "name": "@mobench/docs", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "astro dev --port 3001", + "build": "astro build", + "check": "astro check", + "preview": "astro preview --port 3001" + }, + "dependencies": { + "@astrojs/sitemap": "^3.7.3", + "@astrojs/starlight": "^0.41.3", + "@mobench/site-config": "workspace:*", + "@vercel/analytics": "2.0.1", + "astro": "7.0.6", + "sharp": "0.35.3" + }, + "devDependencies": { + "@astrojs/check": "^0.9.6", + "typescript": "^6.0.3" + } +} diff --git a/apps/docs/public/favicon.svg b/apps/docs/public/favicon.svg new file mode 100644 index 0000000..9248cc3 --- /dev/null +++ b/apps/docs/public/favicon.svg @@ -0,0 +1 @@ + diff --git a/apps/docs/public/fixtures/summary-basic.json b/apps/docs/public/fixtures/summary-basic.json new file mode 100644 index 0000000..ff47d09 --- /dev/null +++ b/apps/docs/public/fixtures/summary-basic.json @@ -0,0 +1,84 @@ +{ + "summary": { + "generated_at": "2026-03-26T00:00:00Z", + "generated_at_unix": 1774483200, + "target": "android", + "function": "multiple", + "iterations": 5, + "warmup": 1, + "devices": [ + "Google Pixel 8-14.0", + "Samsung Galaxy S23-14.0" + ], + "device_summaries": [ + { + "device": "Google Pixel 8-14.0", + "benchmarks": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 100000000, + "median_ns": 100000000, + "p95_ns": 105000000, + "min_ns": 95000000, + "max_ns": 105000000 + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 145000000, + "median_ns": 145000000, + "p95_ns": 151000000, + "min_ns": 140000000, + "max_ns": 151000000 + } + ] + }, + { + "device": "Samsung Galaxy S23-14.0", + "benchmarks": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 94000000, + "median_ns": 94000000, + "p95_ns": 98000000, + "min_ns": 90000000, + "max_ns": 98000000 + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 136000000, + "median_ns": 136000000, + "p95_ns": 140000000, + "min_ns": 132000000, + "max_ns": 140000000 + } + ] + } + ] + }, + "benchmark_results": { + "Google Pixel 8-14.0": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": [95000000, 98000000, 100000000, 102000000, 105000000] + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": [140000000, 142000000, 145000000, 147000000, 151000000] + } + ], + "Samsung Galaxy S23-14.0": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": [90000000, 92000000, 94000000, 96000000, 98000000] + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": [132000000, 134000000, 136000000, 138000000, 140000000] + } + ] + } +} diff --git a/apps/docs/public/fixtures/summary-ffi.json b/apps/docs/public/fixtures/summary-ffi.json new file mode 100644 index 0000000..be49897 --- /dev/null +++ b/apps/docs/public/fixtures/summary-ffi.json @@ -0,0 +1,84 @@ +{ + "summary": { + "generated_at": "2026-03-26T00:00:00Z", + "generated_at_unix": 1774483200, + "target": "android", + "function": "multiple", + "iterations": 5, + "warmup": 1, + "devices": [ + "Google Pixel 8 Pro-14.0", + "OnePlus 12-14.0" + ], + "device_summaries": [ + { + "device": "Google Pixel 8 Pro-14.0", + "benchmarks": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 112000000, + "median_ns": 112000000, + "p95_ns": 118000000, + "min_ns": 108000000, + "max_ns": 118000000 + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 159000000, + "median_ns": 159000000, + "p95_ns": 165000000, + "min_ns": 154000000, + "max_ns": 165000000 + } + ] + }, + { + "device": "OnePlus 12-14.0", + "benchmarks": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 103000000, + "median_ns": 103000000, + "p95_ns": 107000000, + "min_ns": 99000000, + "max_ns": 107000000 + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 149000000, + "median_ns": 149000000, + "p95_ns": 153000000, + "min_ns": 145000000, + "max_ns": 153000000 + } + ] + } + ] + }, + "benchmark_results": { + "Google Pixel 8 Pro-14.0": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": [108000000, 110000000, 112000000, 114000000, 118000000] + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": [154000000, 156000000, 159000000, 161000000, 165000000] + } + ], + "OnePlus 12-14.0": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": [99000000, 101000000, 103000000, 105000000, 107000000] + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": [145000000, 147000000, 149000000, 151000000, 153000000] + } + ] + } +} diff --git a/apps/docs/public/fonts/geist-latin-wght-normal.woff2 b/apps/docs/public/fonts/geist-latin-wght-normal.woff2 new file mode 100644 index 0000000..991445d Binary files /dev/null and b/apps/docs/public/fonts/geist-latin-wght-normal.woff2 differ diff --git a/apps/docs/public/fonts/geist-mono-latin-wght-normal.woff2 b/apps/docs/public/fonts/geist-mono-latin-wght-normal.woff2 new file mode 100644 index 0000000..ab3d5ee Binary files /dev/null and b/apps/docs/public/fonts/geist-mono-latin-wght-normal.woff2 differ diff --git a/apps/docs/public/llms-full.txt b/apps/docs/public/llms-full.txt new file mode 100644 index 0000000..9478acf --- /dev/null +++ b/apps/docs/public/llms-full.txt @@ -0,0 +1,1928 @@ +# mobench documentation — full authored text + +Release: 0.1.43 +Canonical origin: https://docs.mobench.org/ + +# Outputs and metrics + +Canonical URL: https://docs.mobench.org/outputs/ +Description: Understand mobench JSON, Markdown, CSV, plots, and optional resource values. +Source: BrowserStack metrics guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-metrics.md — Timing fields, resource columns, sources, and missing-value semantics. + +Normal runs can write a JSON report with `--output`. CI runs always normalize results into a three-file contract, with plots when available. + +## CI contract + +| Path | Intended use | +| --- | --- | +| `summary.json` | Machine-readable results, metadata, baselines, and integrations | +| `summary.md` | Human review and CI job summaries | +| `results.csv` | Tables, notebooks, and external analysis | +| `plots/*.svg` | Optional visual summaries when plot rendering is available | + +Generate the contract with an explicit directory: + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --local-only \ + --plots auto \ + --output-dir target/mobench/ci +``` + +The example uses the host harness to demonstrate files; it does not produce mobile measurements. + +## Timing fields + +Results include a sample count and timing statistics such as: + +- `mean_ns` +- `median_ns` +- `p95_ns` +- `min_ns` +- `max_ns` + +Raw sample durations live in JSON where the report contract provides them. Compare nanosecond values as numbers; format units only at the presentation layer. + +## Optional resource fields + +CSV and summary data can include: + +- `cpu_total_ms` +- `cpu_median_ms` +- `peak_memory_kb` +- `peak_memory_growth_kb` +- `process_peak_memory_kb` + +These values depend on the runner, platform, device, and provider data. A blank CSV cell or absent JSON field means **unavailable**, not zero. Keep missing values out of averages and regression gates that assume measured data. + +## Inspect and render + +```bash +mobench summary target/mobench/results.json +mobench summary --format json target/mobench/results.json +mobench summary --format csv target/mobench/results.json +``` + +Render Markdown from a CI summary: + +```bash +mobench report summarize \ + --summary target/mobench/ci/summary.json \ + --plots auto +``` + +## Next step + +Store a representative `summary.json`, then configure [regression comparison](/regressions/). + +# Regression comparison + +Canonical URL: https://docs.mobench.org/regressions/ +Description: Compare compatible mobench summaries and gate meaningful slowdowns. +Source: BrowserStack CI guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md — Baseline sources, thresholds, JUnit output, and compare behavior. + +Regression checks compare candidate timing summaries with a stored baseline. They are meaningful only when the benchmark, device, OS, build mode, and run counts are compatible. + +## Compare existing files + +```bash +mobench compare \ + --baseline baselines/android-summary.json \ + --candidate target/mobench/ci/summary.json \ + --output target/mobench/ci/comparison.md +``` + +Review the Markdown report before turning a threshold into a required check. + +## Compare during CI + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --baseline artifact:baselines/android-summary.json \ + --regression-threshold-pct 5 \ + --junit target/mobench/ci/junit.xml \ + --release \ + --output-dir target/mobench/ci +``` + +Baseline sources accept a local path, URL, or `artifact:` form. If a baseline resolves to the same path as the candidate output, mobench snapshots the previous file before writing the new result. + +## Choose a threshold + +Start with observed device-to-device and run-to-run variation rather than an arbitrary percentage. A good gate: + +- compares the same device and OS +- uses the same release profile and runner backend +- keeps iteration and warmup counts stable +- ignores unavailable resource values +- is rerun when a candidate sits near the threshold + +A single noisy result is a prompt to investigate, not proof of a code regression. + +## Publish results + +Render or publish a sticky pull-request comment from the standard summary: + +```bash +mobench report github \ + --pr 123 \ + --summary target/mobench/ci/summary.json \ + --publish +``` + +The default marker is ``, allowing later runs to update the same comment. + +## Next step + +When timing shows a repeatable slowdown, use [local profiling](/profiling/) to locate the hot path. + +# Local native profiling + +Canonical URL: https://docs.mobench.org/profiling/ +Description: Capture Android and iOS native stacks and compare profile manifests locally. +Source: Profiling guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/profiling.md — Capability matrix, commands, requirements, and artifact layout. + +Profiling is separate from repeated benchmark timing. Use it after a slowdown is reproducible and you need native stacks, flamegraphs, or semantic phase detail. + +## Supported combinations + +| Provider | Backend | Behavior in 0.1.43 | +| --- | --- | --- | +| `local` | `android-native` | Attempts `simpleperf` capture, symbolization, folded stacks, reports, and flamegraphs | +| `local` | `ios-instruments` | Attempts simulator-host `sample` capture, folded stacks, reports, and flamegraphs | +| `local` | `rust-tracing` | Writes a planned manifest/trace contract; native capture is not implemented | +| `browserstack` | Any native backend | Unsupported | + +BrowserStack benchmark runs may still contain timing and resource metrics. They do not provide retrievable native stack artifacts in this release. + +## Profile Android locally + +Requirements include `adb`, an Android NDK, `simpleperf`, NDK `llvm-addr2line`, and a local device or emulator. + +```bash +mobench profile run \ + --target android \ + --provider local \ + --backend android-native \ + --function bench_mobile::checksum \ + --output-dir target/mobench/profile \ + --trace-events-output target/mobench/profile/trace-events.json +``` + +## Profile iOS locally + +The current backend uses macOS `sample` against an iOS simulator-host process. It requires macOS, Xcode command-line tools, `xcrun`, `simctl`, and an installed simulator runtime. + +```bash +mobench profile run \ + --target ios \ + --provider local \ + --backend ios-instruments \ + --function bench_mobile::checksum \ + --output-dir target/mobench/profile +``` + +Use Xcode Instruments directly for deeper real-device investigations. + +## Read the bundle + +Common outputs include: + +- `profile.json` +- `summary.md` +- `artifacts/raw/…` +- `artifacts/processed/stacks.folded` +- `artifacts/processed/native-report.txt` +- `artifacts/processed/flamegraph.full.svg` +- `artifacts/processed/flamegraph.focused.svg` +- `artifacts/processed/flamegraph.html` +- `artifacts/semantic/phases.json` when phase data exists + +Render a manifest: + +```bash +mobench profile summarize \ + --profile target/mobench/profile/profile.json +``` + +## Compare two profiles + +```bash +mobench profile diff \ + --baseline target/mobench/profile/baseline/profile.json \ + --candidate target/mobench/profile/candidate/profile.json \ + --normalize +``` + +In differential Inferno flamegraphs, red is hotter in the candidate and blue is hotter in the baseline. + +## Next step + +Open `flamegraph.html`, confirm the capture status in `profile.json`, and correlate hot frames with the timing regression. + +# Basic benchmark crate + +Canonical URL: https://docs.mobench.org/basic-example/ +Description: Follow the minimal SDK example from registration to host and mobile execution. +Source: Basic benchmark example — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/basic-benchmark/README.md — Minimal crate setup, registered functions, tests, and run commands. + +The upstream `examples/basic-benchmark` crate is the smallest complete integration. It registers two realistic workloads, exposes mobile entrypoints, and keeps deterministic fixture output for tests. + +## Cargo setup + +```toml +[lib] +name = "basic_benchmark" +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +mobench-sdk = { version = "0.1.43", default-features = false, features = ["registry"] } +inventory = "0.3" +serde = { version = "1", features = ["derive"] } +thiserror = "1" +uniffi = { version = "0.28", features = ["cli"] } +``` + +Use dependency versions compatible with your lockfile; the key mobench requirement is matching the `0.1.43` SDK line. + +## Benchmark functions + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn bench_checksum() { + let bytes = std::hint::black_box(&INPUT); + let result = checksum_sweep(bytes, 8 * 1024, 2_048); + std::hint::black_box(result); +} +``` + +The upstream example uses deterministic, nontrivial input and enough repeated work to avoid a benchmark dominated by timer noise. + +## Test and discover + +From a checkout of `mobile-bench-rs`: + +```bash +cargo test -p basic-benchmark +mobench list --crate-path examples/basic-benchmark +``` + +Host-side preflight: + +```bash +mobench run \ + --crate-path examples/basic-benchmark \ + --target android \ + --function basic_benchmark::bench_fibonacci \ + --local-only +``` + +This validates the host harness only. For a mobile result, add an exact BrowserStack device and `--release`: + +```bash +mobench run \ + --crate-path examples/basic-benchmark \ + --target android \ + --function basic_benchmark::bench_fibonacci \ + --devices "Google Pixel 7-13.0" \ + --release \ + --output target/mobench/results.json +``` + +## Next step + +Copy the crate structure, replace one benchmark at a time, and confirm each new name with `mobench list`. + +# FFI benchmark crate + +Canonical URL: https://docs.mobench.org/ffi-example/ +Description: Expose mobench benchmarks through UniFFI, the native C ABI, or BoltFFI. +Source: FFI benchmark example — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/ffi-benchmark/README.md — UniFFI types, native C ABI export, BoltFFI bridge, tests, and run flow. + +The upstream `examples/ffi-benchmark` crate shows the full boundary between Rust benchmark registration and generated Kotlin or Swift runners. Start with the basic example unless your project needs custom cross-language types. + +## Default UniFFI path + +The compatibility backend serializes benchmark request and report types through generated UniFFI bindings. A crate can expose an entrypoint like: + +```rust +#[derive(uniffi::Record)] +pub struct BenchSpec { + pub name: String, + pub iterations: u32, + pub warmup: u32, +} + +uniffi::setup_scaffolding!(); + +#[uniffi::export] +pub fn run_benchmark(spec: BenchSpec) -> Result { + let sdk_spec = mobench_sdk::BenchSpec { + name: spec.name, + iterations: spec.iterations, + warmup: spec.warmup, + }; + Ok(mobench_sdk::run_benchmark(sdk_spec)?.into()) +} +``` + +The SDK also provides FFI-oriented types that can replace custom records for simpler projects. + +## Native C ABI path + +Configure `ffi_backend = "native-c-abi"` when generated runners should call the SDK's JSON C ABI directly: + +```rust +mobench_sdk::export_native_c_abi!(); +``` + +The generated runner calls `mobench_run_benchmark_json` and returns Rust-owned buffers through `mobench_free_buf`. Never free or reuse those buffers through another allocator. + +## BoltFFI path + +Projects using BoltFFI can expose the same JSON bridge: + +```rust +#[boltffi::export] +pub fn run_benchmark_json(spec_json: &str) -> Result { + let spec = serde_json::from_str(spec_json).map_err(|error| error.to_string())?; + let report = run_benchmark(spec).map_err(|error| error.to_string())?; + serde_json::to_string(&report).map_err(|error| error.to_string()) +} +``` + +Set `ffi_backend = "boltffi"` and ensure the BoltFFI generator is available to the build. + +## Exercise the example + +```bash +cargo test -p ffi-benchmark +mobench list --crate-path examples/ffi-benchmark +mobench run \ + --crate-path examples/ffi-benchmark \ + --target android \ + --function ffi_benchmark::bench_fibonacci \ + --local-only +``` + +The last command is a host preflight, not a mobile measurement. + +## Next step + +Select one backend, build both target platforms, and keep that backend fixed across your baseline and candidate runs. + +# Installation + +Canonical URL: https://docs.mobench.org/installation/ +Description: Install mobench 0.1.43 and prepare a Rust benchmark crate. +Source: Upstream README quick start — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/README.md — CLI and SDK installation commands. + +Install the `mobench` executable once, then add `mobench-sdk` to each crate that owns benchmark functions. + +## Requirements + +- Rust 1.85 or newer +- Cargo +- Android or iOS build tools only when you build for that platform +- BrowserStack App Automate credentials only when you run on remote devices + +Check your toolchain: + +```bash +rustc --version +cargo --version +``` + +## Install the CLI + +If you use `cargo-binstall`: + +```bash +cargo binstall mobench --version 0.1.43 +``` + +Or compile the release from crates.io: + +```bash +cargo install mobench --version 0.1.43 --locked +``` + +Confirm that the canonical executable is available: + +```bash +mobench --version +mobench --help +``` + +## Add the SDK + +From the benchmark crate: + +```bash +cargo add mobench-sdk@0.1.43 inventory +``` + +Mobile runners load your crate as a native library. Include the required crate types in `Cargo.toml`: + +```toml +[lib] +crate-type = ["lib", "cdylib", "staticlib"] +``` + +The default `mobench-sdk` features include registration, builders, and code generation. For a deliberately smaller integration, see the [compatibility reference](/compatibility/). + +## Install platform prerequisites + +Ask mobench for a platform-specific check before installing tools blindly: + +```bash +mobench check --target android +mobench check --target ios +``` + +Android builds use the Android SDK, Android NDK, `cargo-ndk`, and Rust Android targets. iOS builds require macOS, Xcode command-line tools, XcodeGen, and Rust iOS targets. + +## Next step + +Continue to the [quickstart](/quickstart/) and register your first benchmark function. + +# Quickstart + +Canonical URL: https://docs.mobench.org/quickstart/ +Description: Register a Rust benchmark, validate it on the host, and run it on a mobile device. +Source: Basic benchmark example — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/basic-benchmark/README.md — Minimal SDK registration and CLI flow. + +This path first proves that mobench can discover and report your function on the host. It then moves the same function to a BrowserStack device for the actual mobile measurement. + +## 1. Register a benchmark + +Add a public function to your library crate: + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn checksum() { + let bytes = std::hint::black_box(vec![42_u8; 64 * 1024]); + let sum: u64 = bytes.iter().map(|byte| u64::from(*byte)).sum(); + std::hint::black_box(sum); +} +``` + +Use enough work to rise above timer noise, and pass results through `black_box` so the optimizer cannot erase the operation. + +## 2. Confirm discovery + +From the project root, replace `bench-mobile` if your benchmark crate lives elsewhere: + +```bash +mobench list --crate-path bench-mobile +``` + +The output should include the fully qualified function name, such as `bench_mobile::checksum`. + +## 3. Run the host preflight + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --local-only \ + --iterations 20 \ + --warmup 5 \ + --output target/mobench/preflight.json +``` + +`--local-only` checks the host harness, discovery, and report path. It does not run Android code and must not be treated as a mobile result. + +Inspect the report: + +```bash +mobench summary target/mobench/preflight.json +``` + +## 4. Run on a mobile device + +Set your BrowserStack App Automate credentials: + +```bash +export BROWSERSTACK_USERNAME="your_username" +export BROWSERSTACK_ACCESS_KEY="your_access_key" +``` + +Choose a device that appears in `mobench devices --platform android`, then run: + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 20 \ + --warmup 5 \ + --release \ + --fetch \ + --output target/mobench/results.json +``` + +Using `--release` keeps the measured code optimized and reduces Android upload size. + +## Next step + +Read [benchmark quality](/benchmark-quality/) before using the result as a baseline. + +# Troubleshooting + +Canonical URL: https://docs.mobench.org/troubleshooting/ +Description: Diagnose discovery, toolchain, BrowserStack, result, and profiling failures. +Source: Upstream testing guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/testing.md — Supported validation paths and platform smoke checks. + +Start with the narrowest command that can reproduce the failure, add `--verbose`, and keep the generated output directory until you understand the error. + +## Benchmark does not appear in `list` + +1. Confirm the function has `#[benchmark]` and a supported signature. +2. Confirm the benchmark crate depends on `mobench-sdk` with the registry feature and on `inventory`. +3. Pass an explicit `--crate-path` when the workspace contains several libraries. +4. Run `cargo check` for compile-time macro errors. + +```bash +mobench --verbose list --crate-path crates/bench-mobile +``` + +## `--local-only` succeeds but the device run fails + +That result is expected when the failure is in mobile compilation, packaging, signing, upload, or the generated runner. `--local-only` skips all of those layers. + +Run the platform checks and build separately: + +```bash +mobench check --target android +mobench build --target android --release --progress +mobench verify --target android --check-artifacts +``` + +For iOS, also verify Xcode, XcodeGen, signing, deployment target, and runner compatibility. + +## BrowserStack credentials or device fail + +```bash +mobench doctor --target both --browserstack true +mobench devices --validate "Google Pixel 7-13.0" +``` + +Check that the credentials are App Automate credentials, the device identifier still exists, and the app deployment target does not exceed the selected iOS version. + +## Upload times out + +Build and run with `--release`. Debug Android artifacts can be much larger. If the build was accepted but result polling expired, fetch it later with the BrowserStack build ID. + +## Result has no CPU or memory value + +Resource metrics are optional and vary by runner and provider availability. Missing means unavailable, not zero. Keep the timing result and resource availability as separate facts. + +## CI output is in the wrong place + +`ci run` and `profile run` use `--output-dir`. A normal `run` uses `--output` for its JSON report. + +```bash +mobench ci run --help +mobench profile run --help +mobench run --help +``` + +## Profiling writes no native capture + +Check the provider/backend combination first. BrowserStack native profiling is unsupported, and `rust-tracing` is only a planned manifest/trace contract in 0.1.43. + +For Android, confirm `adb`, `simpleperf`, the NDK, and `llvm-addr2line`. For iOS, confirm a simulator runtime, `xcrun`, `simctl`, and macOS `sample`. Read the capture status and warnings in `profile.json`; do not treat a planned or partial capture as complete. + +## Still stuck + +Capture these facts before opening an upstream issue: + +- `mobench --version` and `rustc --version` +- the smallest failing command with secrets removed +- platform and device identifier +- relevant `mobench.toml` and `bench-config.toml` sections +- verbose output and generated artifact paths +- whether host preflight, build, upload, execution, or fetch failed + +Contributor architecture and release-maintenance documentation belongs in the [upstream repository](https://github.com/worldcoin/mobile-bench-rs), not in the product guide. + +## Next step + +Re-run the narrow failing command with `--verbose`, then attach the sanitized evidence to an upstream issue. + +# mobench documentation + +Canonical URL: https://docs.mobench.org/ +Description: Build, run, and analyze Rust benchmarks on Android and iOS. +Source: Upstream README — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/README.md — Product scope, workflow, release, and supported backends. + +mobench takes a Rust benchmark from a function in your crate to repeatable results on Android and iOS. It builds native libraries, generates mobile runners, executes them on selected BrowserStack devices, and writes artifacts that people and CI can compare. + +The current documentation describes mobench **0.1.43** and requires Rust **1.85 or newer**. + +## Choose a starting point + +| Goal | Start here | +| --- | --- | +| Install the CLI and SDK | [Installation](/installation/) | +| Get one benchmark running | [Quickstart](/quickstart/) | +| Write trustworthy benchmark functions | [Benchmark functions](/benchmark-functions/) | +| Validate a project without using a device farm | [Host-side preflight](/host-preflight/) | +| Run on Android or iOS devices | [BrowserStack](/browserstack/) | +| Add a stable CI contract | [CI runs](/ci/) | +| Interpret artifacts and compare revisions | [Outputs](/outputs/) | +| Capture native stacks locally | [Profiling](/profiling/) | + +## What mobench measures + +Normal benchmark runs record measured iteration durations. CPU time and memory fields may also be present when the runner or provider can collect them. Missing resource values mean **unavailable**, not zero. + +Native stack profiling is a separate, local-first workflow. Android uses `simpleperf`; iOS uses simulator-host `sample`. BrowserStack native profiling is not supported in 0.1.43. + +## The execution boundary + +Selecting devices makes `mobench run` build and schedule a real mobile benchmark through BrowserStack. `--local-only` skips mobile builds and writes host-side preflight/spec output without executing the requested benchmark. Use it to validate discovery, configuration, and report shape—not as evidence of mobile performance. + +## Stable outputs + +`mobench ci run` writes a reusable contract: + +- `summary.json` for machines and comparisons +- `summary.md` for people and CI job summaries +- `results.csv` for analysis tools +- `plots/*.svg` when plotting is available + +## Next step + +[Install mobench](/installation/), then complete the quickstart before adding a device matrix or CI workflow. + +# CLI reference + +Canonical URL: https://docs.mobench.org/cli/ +Description: Find mobench commands and the flags that connect authoring, execution, CI, and profiling. +Source: CLI definitions — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/crates/mobench/src/cli.rs — Clap command, subcommand, argument, default, and enum definitions. + +The canonical executable is `mobench`. Run `mobench --help` against your installed version for the complete generated argument reference. + +{/* BEGIN GENERATED CLI REFERENCE */} +{/* Generated from @mobench/truth. Do not edit this section by hand. */} + +## Global flags + +| Flag | Value | Default | Purpose | +| --- | --- | --- | --- | +| `--dry-run` | boolean | false | Print what would be done without actually doing it | +| `--non-interactive` | boolean | false | Disable interactive prompts (fail instead) | +| `-v`, `--verbose` | boolean | false | Print verbose output including all commands | +| `--yes` | boolean | false | Assume yes to prompts and allow overwriting files | + +The generated CLI also provides `--help`, `-h`, `--version`, and `-V` where Clap exposes them. + +## Command index + +| Command | Purpose | +| --- | --- | +| `mobench build` | Build mobile artifacts from the resolved benchmark crate | +| `mobench check` | Check prerequisites for building mobile artifacts | +| `mobench ci` | CI helpers (workflow and action scaffolding) | +| `mobench ci check-run` | Create a GitHub Check Run with benchmark results | +| `mobench ci init` | Generate GitHub Actions workflow + local action wrapper | +| `mobench ci merge-split-runs` | Merge one-sample CI summaries into a normal CI output set | +| `mobench ci run` | Run a full CI benchmark flow with stable output contract | +| `mobench ci summarize` | Summarize benchmark results with device metrics | +| `mobench compare` | Compare two run summaries for regressions | +| `mobench config` | Validate run configuration and associated files | +| `mobench config validate` | Validate bench-config.toml and referenced matrix/settings | +| `mobench devices` | List available BrowserStack devices for testing | +| `mobench devices resolve` | Resolve devices from a matrix deterministically for CI usage | +| `mobench doctor` | Validate local + CI prerequisites and configuration | +| `mobench fetch` | Fetch BrowserStack build artifacts (logs, session JSON) for CI | +| `mobench fixture` | Fixture lifecycle helpers for reproducible CI setup | +| `mobench fixture build` | Build fixture artifacts using existing build commands | +| `mobench fixture cache-key` | Compute deterministic fixture cache key from config/toolchain inputs | +| `mobench fixture init` | Create starter fixture files for CI runs | +| `mobench fixture verify` | Verify fixture files and optional profile filtering | +| `mobench fixture verify-plots` | Render and verify checked-in plot fixtures | +| `mobench init` | Scaffold a base config file for the CLI | +| `mobench init-sdk` | Initialize a new benchmark project with the SDK templates | +| `mobench list` | List all discovered benchmark functions | +| `mobench package-ipa` | Package iOS app as IPA for distribution or testing | +| `mobench package-xcuitest` | Package XCUITest runner for BrowserStack testing | +| `mobench plan` | Generate a sample device matrix file | +| `mobench profile` | Profiling helpers for native profile capture and summary rendering | +| `mobench profile diff` | Generate a differential flamegraph bundle from two normalized profile manifests | +| `mobench profile run` | Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture | +| `mobench profile summarize` | Render markdown or JSON from a normalized profile manifest | +| `mobench report` | Reporting helpers for CI summaries and PR comments | +| `mobench report github` | Generate/publish sticky GitHub PR comment from summary output | +| `mobench report summarize` | Generate markdown summary from standardized output JSON | +| `mobench run` | Build mobile artifacts, write host preflight output, or run on BrowserStack devices | +| `mobench summary` | Display summary statistics from a benchmark report JSON file | +| `mobench verify` | Verify benchmark setup: registry, spec, artifacts, and optional smoke test | + +## Complete command flag index + +Global flags above are omitted from each command row. Positional arguments use angle brackets. + +### `mobench build` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate (default: auto-detect bench-mobile/ or crates/{crate}) | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--release` | boolean | default: false | Build in release mode | +| `--target` | `android \| both \| ios` | required | — | + +### `mobench check` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--format` | `json \| text` | default: text | Output format (text or json) | +| `-t`, `--target` | `android \| both \| ios` | required | Target platform (android or ios) | + +### `mobench ci check-run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--annotation-path` | `ANNOTATION_PATH` | default: src/lib.rs | File path used in Check Run annotations (relative to repo root) | +| `--baseline` | `BASELINE` | optional | Optional baseline JSON for regression detection | +| `--name` | `NAME` | default: Mobench | Check Run name displayed in the PR | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage | +| `--repo` | `REPO` | required | GitHub repository (owner/repo format) | +| `--results` | `RESULTS` | optional | Path to summary JSON with benchmark results | +| `--results-dir` | `RESULTS_DIR` | optional | Directory containing summary JSON files (processes all) | +| `--sha` | `SHA` | required | Git commit SHA to annotate | + +### `mobench ci init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--action-dir` | `ACTION_DIR` | default: .github/actions/mobench | Directory to write the local GitHub Action | +| `--workflow` | `WORKFLOW` | default: .github/workflows/mobile-bench.yml | Path to write the workflow file | + +### `mobench ci merge-split-runs` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--device` | `DEVICE` | required | Device label all samples must match | +| `--function` | `FUNCTION` | required | Fully-qualified benchmark function all samples must contain | +| `--iterations` | `ITERATIONS` | required | Expected measured sample count | +| `--output-dir` | `OUTPUT_DIR` | required | Directory to write merged summary.json, summary.md, and results.csv | +| `--samples-dir` | `SAMPLES_DIR` | required | Directory containing sample-*/summary.json one-sample CI outputs | +| `--warmup` | `WARMUP` | default: 0 | Warmup count reported in merged CI summaries | + +### `mobench ci run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--android-benchmark-timeout-secs` | `ANDROID_BENCHMARK_TIMEOUT_SECS` | optional | Android benchmark watchdog timeout in seconds for the generated harness | +| `--android-heartbeat-interval-secs` | `ANDROID_HEARTBEAT_INTERVAL_SECS` | optional | Android benchmark heartbeat interval in seconds for the generated harness | +| `--baseline` | `BASELINE` | optional | Baseline summary source (path\|url\|artifact:<path>) | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Device matrix YAML file to load device names from | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--devices` | `DEVICES` | optional | Device identifiers or labels (BrowserStack devices) | +| `--fetch` | boolean | default: false | Fetch BrowserStack artifacts after the run completes | +| `--fetch-output-dir` | `FETCH_OUTPUT_DIR` | default: target/browserstack | — | +| `--fetch-poll-interval-secs` | `FETCH_POLL_INTERVAL_SECS` | default: 5 | — | +| `--fetch-timeout-secs` | `FETCH_TIMEOUT_SECS` | default: 300 | — | +| `--function` | `FUNCTION` | optional | Fully-qualified Rust function to benchmark (single function) | +| `--functions` | `FUNCTIONS` | optional | Multiple benchmark functions (comma-separated or JSON array). Runs each in sequence. | +| `--ios-app` | `IOS_APP` | optional | Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--ios-test-suite` | `IOS_TEST_SUITE` | optional | Path to iOS XCUITest test suite package (.zip or .ipa) | +| `--iterations` | `ITERATIONS` | default: 100 | — | +| `--junit` | `JUNIT` | optional | Write JUnit XML report to the given path | +| `--local-only` | boolean | default: false | Skip mobile builds and write host-side preflight/spec output without mobile execution | +| `--mobench-ref` | `MOBENCH_REF` | optional | Metadata: git ref/sha for this mobench invocation | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/ci | Output directory for CI contract files | +| `--plots` | `auto \| off \| require` | default: auto | — | +| `--pr-number` | `PR_NUMBER` | optional | Metadata: pull request number | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage when comparing to baseline | +| `--release` | boolean | default: false | Build in release mode (recommended for BrowserStack to reduce APK size and upload time) | +| `--request-command` | `REQUEST_COMMAND` | optional | Metadata: original command requested by the caller | +| `--requested-by` | `REQUESTED_BY` | optional | Metadata: user or actor that requested the run | +| `--target` | `android \| both \| ios` | required | — | +| `--warmup` | `WARMUP` | default: 10 | — | + +### `mobench ci summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--build-id` | `BUILD_ID` | optional | BrowserStack build ID to enrich results with device metrics (requires --results-dir) | +| `--output-file` | `OUTPUT_FILE` | optional | Write output to file in addition to stdout | +| `--output-format` | `json \| markdown \| table` | default: table | Output format: table (terminal), markdown, or json | +| `--platform` | `android \| ios` | optional | Platform filter (show only one platform) | +| `--results-dir` | `RESULTS_DIR` | optional | Directory containing summary.json/CSV results (offline mode) | + +### `mobench compare` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--baseline` | `BASELINE` | required | Baseline JSON summary to compare against | +| `--candidate` | `CANDIDATE` | required | Candidate JSON summary to compare | +| `--output` | `OUTPUT` | optional | Optional output path for markdown report | + +### `mobench config validate` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--format` | `json \| text` | default: text | — | + +### `mobench devices` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--json` | boolean | default: false | Output as JSON | +| `--platform` | `android \| ios` | optional | Filter by platform (android or ios) | +| `--validate` | `VALIDATE` | optional | Validate device specs against available devices | + +### `mobench devices resolve` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | optional | Path to run config file (optional source for matrix/tags) | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Path to device matrix YAML file | +| `--format` | `json \| text` | default: text | — | +| `--platform` | `android \| ios` | required | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to resolve (defaults to `default`) | + +### `mobench doctor` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--browserstack` | `false \| true` | default: true | Validate BrowserStack credentials | +| `--config` | `CONFIG` | optional | Optional path to run config file to validate | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Optional path to device matrix YAML file to validate | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--format` | `json \| text` | default: text | — | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fetch` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--build-id` | `BUILD_ID` | required | — | +| `--output-dir` | `OUTPUT_DIR` | default: target/browserstack | — | +| `--poll-interval-secs` | `POLL_INTERVAL_SECS` | default: 10 | — | +| `--target` | `android \| ios` | required | — | +| `--timeout-secs` | `TIMEOUT_SECS` | default: 1800 | — | +| `--wait` | boolean | default: true | — | + +### `mobench fixture build` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to benchmark crate | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--release` | boolean | default: false | Build in release mode | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture cache-key` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | optional | — | +| `--format` | `json \| text` | default: text | — | +| `--profile` | `PROFILE` | optional | Device profile/tag for keying | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | default: device-matrix.yaml | — | +| `--force` | boolean | default: false | Overwrite existing fixture files | + +### `mobench fixture verify` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | optional | — | +| `--format` | `json \| text` | default: text | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to verify | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture verify-plots` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `` | `basic \| ffi` | required | — | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for rendered fixture artifacts (defaults under target/mobench/plot-fixtures) | + +### `mobench init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | default: bench-config.toml | — | +| `--target` | `android \| ios` | default: android | — | + +### `mobench init-sdk` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--examples` | boolean | default: false | Generate example benchmarks | +| `--output-dir` | `OUTPUT_DIR` | default: . | — | +| `--project-name` | `PROJECT_NAME` | default: bench-project | — | +| `--target` | `android \| both \| ios` | required | — | + +### `mobench list` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | + +### `mobench package-ipa` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--method` | `adhoc \| development` | default: adhoc | Signing method | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--scheme` | `SCHEME` | default: BenchRunner | Xcode scheme to build | + +### `mobench package-xcuitest` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--scheme` | `SCHEME` | default: BenchRunner | Xcode scheme to build | + +### `mobench plan` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | default: device-matrix.yaml | — | + +### `mobench profile diff` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--baseline` | `BASELINE` | required | Path to the baseline profile.json manifest | +| `--candidate` | `CANDIDATE` | required | Path to the candidate profile.json manifest | +| `--normalize` | boolean | default: false | Normalize baseline sample counts to candidate totals before diffing | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/profile/diff | Output directory for differential profile artifacts | + +### `mobench profile run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--backend` | `android-native \| auto \| ios-instruments \| rust-tracing` | default: auto | — | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device` | `DEVICE` | optional | Explicit BrowserStack device name to resolve for this profiling request | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Path to device matrix YAML file used with --profile or config-based device tags | +| `--format` | `both \| native \| processed` | default: both | — | +| `--function` | `FUNCTION` | required | Fully-qualified Rust function to profile | +| `--os-version` | `OS_VERSION` | optional | OS version for --device (for example `16` or `14.0`) | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/profile | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to resolve (for example `high-spec`) | +| `--provider` | `browserstack \| local` | default: local | — | +| `--target` | `android \| ios` | required | — | +| `--trace-events-output` | `TRACE_EVENTS_OUTPUT` | optional | Write machine-readable trace/event JSON to this path for downstream consumers | +| `--warmup-mode` | `cold \| warm` | optional | Warm or cold capture mode for local native profiling (defaults to warm for local Android/iOS native backends) | + +### `mobench profile summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | optional | — | +| `--output-format` | `json \| markdown` | default: markdown | — | +| `--profile` | `PROFILE` | default: target/mobench/profile/profile.json | — | + +### `mobench report github` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--marker` | `MARKER` | default: <!-- mobench-report --> | — | +| `--output` | `OUTPUT` | optional | Write generated comment body to file | +| `--pr` | `PR` | optional | Pull request number (auto-detected from GITHUB_REF if omitted) | +| `--publish` | boolean | default: false | Publish via GitHub API using GITHUB_TOKEN | +| `--summary` | `SUMMARY` | default: target/mobench/ci/summary.json | — | + +### `mobench report summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | optional | Write markdown output to file | +| `--plots` | `auto \| off \| require` | default: auto | — | +| `--summary` | `SUMMARY` | default: target/mobench/ci/summary.json | — | + +### `mobench run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--android-benchmark-timeout-secs` | `ANDROID_BENCHMARK_TIMEOUT_SECS` | optional | Android benchmark watchdog timeout in seconds for the generated harness | +| `--android-heartbeat-interval-secs` | `ANDROID_HEARTBEAT_INTERVAL_SECS` | optional | Android benchmark heartbeat interval in seconds for the generated harness | +| `--baseline` | `BASELINE` | optional | Baseline summary source (path\|url\|artifact:<path>) | +| `--ci` | boolean | default: false | Enable CI mode (job summary, optional JUnit, regression exit codes) | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Device matrix YAML file to load device names from | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--devices` | `DEVICES` | optional | Device identifiers or labels (BrowserStack devices) | +| `--fetch` | boolean | default: false | Fetch BrowserStack artifacts after the run completes | +| `--fetch-output-dir` | `FETCH_OUTPUT_DIR` | default: target/browserstack | — | +| `--fetch-poll-interval-secs` | `FETCH_POLL_INTERVAL_SECS` | default: 5 | — | +| `--fetch-timeout-secs` | `FETCH_TIMEOUT_SECS` | default: 300 | — | +| `--function` | `FUNCTION` | optional | Fully-qualified Rust function to benchmark | +| `--ios-app` | `IOS_APP` | optional | Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--ios-test-suite` | `IOS_TEST_SUITE` | optional | Path to iOS XCUITest test suite package (.zip or .ipa) | +| `--iterations` | `ITERATIONS` | optional | — | +| `--junit` | `JUNIT` | optional | Write JUnit XML report to the given path | +| `--local-only` | boolean | default: false | Skip mobile builds and write host-side preflight/spec output without mobile execution | +| `--output` | `OUTPUT` | optional | Optional output path for JSON report | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage when comparing to baseline | +| `--release` | boolean | default: false | Build in release mode (recommended for BrowserStack to reduce APK size and upload time) | +| `--summary-csv` | boolean | default: false | Write CSV summary alongside JSON | +| `--target` | `android \| ios` | optional | — | +| `--warmup` | `WARMUP` | optional | — | + +### `mobench summary` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--format` | `csv \| json \| text` | optional | Output format: text (default), json, or csv | +| `` | `REPORT` | required | Path to the benchmark report JSON file | + +### `mobench verify` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--check-artifacts` | boolean | default: false | Check that build artifacts exist | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--function` | `FUNCTION` | optional | Function name to verify/smoke test | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--smoke-test` | boolean | default: false | Run a local smoke test with minimal iterations | +| `--spec-path` | `SPEC_PATH` | optional | Path to bench_spec.json to validate | +| `--target` | `android \| both \| ios` | optional | Target platform to verify artifacts for | + + +{/* END GENERATED CLI REFERENCE */} + +`ci run` uses `--output-dir`, which defaults to `target/mobench/ci`. Its core outputs are `summary.json`, `summary.md`, and `results.csv`. `profile run` also uses `--output-dir`, defaulting to `target/mobench/profile`. BrowserStack native profiling is unsupported in 0.1.43. + +## Next step + +Run `mobench run --help` and save a minimal invocation in your repository's benchmark README. + +# Configuration + +Canonical URL: https://docs.mobench.org/configuration/ +Description: Configure project builds separately from benchmark run and provider settings. +Source: Current configuration specification — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md — Project config, run config, resolution order, and examples. + +mobench uses two TOML files for different concerns: + +- `mobench.toml` describes the benchmark crate and generated mobile projects. +- `bench-config.toml` describes a run, device selection, and BrowserStack settings. + +Keeping them separate lets one project support several CI matrices without duplicating build identity. + +{/* BEGIN GENERATED CONFIG REFERENCE */} +{/* Generated from @mobench/truth. Do not edit this section by hand. */} + +## Published configuration keys + +These are the complete configuration keys in the pinned release contract. Example files below may use only a task-specific subset. + +### `mobench.toml` + +| Key | Value | Required | Default | Evidence | +| --- | --- | --- | --- | --- | +| `project.crate` | `string|null` | no | — | `source-mobench-config` | +| `project.library_name` | `string|null` | no | — | `source-mobench-config` | +| `project.output_dir` | `path|null` | no | — | `source-mobench-config` | +| `android.package` | `string` | no | dev.world.bench | `source-mobench-config` | +| `android.min_sdk` | `integer` | no | 24 | `source-mobench-config` | +| `android.target_sdk` | `integer` | no | 34 | `source-mobench-config` | +| `android.abis` | `string[]|null` | no | — | `source-mobench-config` | +| `ios.bundle_id` | `string` | no | dev.world.bench | `source-mobench-config` | +| `ios.deployment_target` | `string` | no | 15.0 | `source-mobench-config` | +| `ios.team_id` | `string|null` | no | — | `source-mobench-config` | +| `benchmarks.default_function` | `string|null` | no | — | `source-mobench-config` | +| `benchmarks.default_iterations` | `integer` | no | 100 | `source-mobench-config` | +| `benchmarks.default_warmup` | `integer` | no | 10 | `source-mobench-config` | +| `browserstack.ios_completion_timeout_secs` | `integer|null` | no | — | `source-mobench-config` | + +### `bench-config.toml` + +| Key | Value | Required | Default | Evidence | +| --- | --- | --- | --- | --- | +| `target` | `android|ios` | yes | — | `source-bench-config` | +| `function` | `string` | yes | — | `source-bench-config` | +| `iterations` | `integer` | yes | — | `source-bench-config` | +| `warmup` | `integer` | yes | — | `source-bench-config` | +| `device_matrix` | `path` | yes | — | `source-bench-config` | +| `device_tags` | `string[]|null` | no | — | `source-bench-config` | +| `browserstack.app_automate_username` | `string` | yes | — | `source-bench-config` | +| `browserstack.app_automate_access_key` | `string` | yes | — | `source-bench-config` | +| `browserstack.project` | `string|null` | no | — | `source-bench-config` | +| `browserstack.ios_completion_timeout_secs` | `integer|null` | no | — | `source-bench-config` | +| `browserstack.android_benchmark_timeout_secs` | `integer|null` | no | — | `source-bench-config` | +| `browserstack.android_heartbeat_interval_secs` | `integer|null` | no | — | `source-bench-config` | +| `ios_xcuitest.app` | `path` | no | — | `source-bench-config` | +| `ios_xcuitest.test_suite` | `path` | no | — | `source-bench-config` | + +{/* END GENERATED CONFIG REFERENCE */} + +## Project configuration + +Place `mobench.toml` at the project or workspace root: + +```toml test=config:mobench.toml +[project] +crate = "bench-mobile" +library_name = "bench_mobile" +output_dir = "target/mobench" + +[android] +package = "com.example.bench" +min_sdk = 24 +target_sdk = 34 +abis = ["arm64-v8a"] + +[ios] +bundle_id = "com.example.bench" +deployment_target = "15.0" +team_id = "ABCDE12345" + +[benchmarks] +default_function = "bench_mobile::checksum" +default_iterations = 100 +default_warmup = 10 +``` + +The pinned release contract defines only the keys shown above for generated project identity and build defaults. Runner-backend selection is not a published `mobench.toml` key in 0.1.43. + +## Run configuration + +Use `bench-config.toml` for a repeatable run: + +```toml test=config:bench-config.toml +target = "android" +function = "bench_mobile::checksum" +iterations = 100 +warmup = 10 +device_matrix = "device-matrix.yaml" +device_tags = ["default"] + +[browserstack] +app_automate_username = "${BROWSERSTACK_USERNAME}" +app_automate_access_key = "${BROWSERSTACK_ACCESS_KEY}" +project = "mobile-benchmarks" + +[ios_xcuitest] +app = "target/mobench/ios/BenchRunner.ipa" +test_suite = "target/mobench/ios/BenchRunnerUITests.zip" +``` + +Validate it before a run: + +```bash +mobench config validate --config bench-config.toml +``` + +## Resolution and overrides + +Explicit CLI values take precedence over config values. Project discovery considers explicit `--project-root` and `--crate-path`, explicit config, a discovered `mobench.toml`, Cargo workspace metadata, the Git root, and the legacy `bench-mobile/` layout. + +Use explicit paths in CI when a workspace contains several plausible benchmark crates: + +```bash +mobench build \ + --target android \ + --project-root . \ + --crate-path crates/bench-mobile +``` + +`--device-matrix` overrides the matrix path from `--config`. Do not combine `--devices` and `--device-matrix`; choose one source of device selection. + +## Next step + +Generate a [device matrix](/device-matrices/) and validate the combined setup with `mobench doctor`. + +# Device matrices + +Canonical URL: https://docs.mobench.org/device-matrices/ +Description: Select BrowserStack Android and iOS devices deterministically with tags. +Source: BrowserStack CI guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md — Device inventory, validation, matrix syntax, profiles, and legacy iOS constraints. + +A device matrix keeps exact BrowserStack identifiers and grouping decisions in version control. Tags let CI select a stable lane such as `default`, `pixel`, or `legacy-ios`. + +## Create a matrix + +Generate a starter file: + +```bash +mobench plan --output device-matrix.yaml +``` + +Example: + +```yaml +devices: + - name: "Google Pixel 7-13.0" + os: "android" + os_version: "13.0" + tags: ["default", "pixel"] + - name: "iPhone 14-16" + os: "ios" + os_version: "16" + tags: ["default", "iphone"] +``` + +Use identifiers from the live BrowserStack inventory: + +```bash +mobench devices --platform android +mobench devices --platform ios +mobench devices --json +``` + +## Validate identifiers + +```bash +mobench devices --validate "Google Pixel 7-13.0" +``` + +Invalid labels return nearby suggestions. Update the matrix deliberately when BrowserStack changes its inventory; do not silently fall back to another device. + +## Resolve a tagged profile + +```bash +mobench devices resolve \ + --platform android \ + --profile default \ + --device-matrix device-matrix.yaml +``` + +Run the selected group: + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --device-matrix device-matrix.yaml \ + --device-tags default \ + --release \ + --output-dir target/mobench/ci +``` + +`--device-tags` accepts comma-separated or repeated values. Explicit `--devices` and a matrix cannot be combined. + +## Legacy iOS lane + +An older BrowserStack device requires all three parts to agree: + +- the matrix's device OS +- the `mobench.toml` iOS deployment target +- the Xcode version on the build runner + +For a device below iOS 15, select `uikit-legacy`. mobench fails early when the app deployment target is newer than the chosen device OS. + +## Next step + +Run `mobench doctor --device-matrix device-matrix.yaml --browserstack true` before committing a CI lane. + +# Output schemas + +Canonical URL: https://docs.mobench.org/schemas/ +Description: Use the versioned mobench JSON contracts without depending on private implementation details. +Source: Upstream schemas — https://github.com/worldcoin/mobile-bench-rs/tree/d1a3176f9144f35e777e83fd07045116144da257/docs/schemas — Versioned CI, summary, and trace-event JSON Schema files. + +mobench publishes JSON Schemas for the contracts intended for downstream validation. Pin a schema revision alongside the mobench release used to create the artifact. + +## Published schemas + +| File | Contract | +| --- | --- | +| `ci-contract-v1.schema.json` | The top-level `ci` metadata and status contract | +| `summary-v1.schema.json` | The top-level normalized `summary` result contract | +| `trace-events-v1.schema.json` | Profiling trace source, total duration, lanes, and events | + +The CI and summary schemas are focused wrappers around the stable output sections. A complete `summary.json` can include additional forward-compatible fields. + +## Validate in CI + +Use any JSON Schema 2020-12 validator and point it at the pinned upstream file. Treat validation as a contract check, not as a semantic comparison of devices or benchmarks. + +Example with a generic validator: + +```bash +check-jsonschema \ + --schemafile vendor/mobench/summary-v1.schema.json \ + target/mobench/ci/summary.json +``` + +Vendor the schema or pin its commit URL so a remote branch update cannot change a historical validation job. + +## Trace-event semantics + +The trace-event schema requires: + +- `source` +- `total_duration_ns` +- `lanes` + +Trace events describe profiling lanes and phases. They are not interchangeable with sampled benchmark durations in the normal summary contract. + +## Missing values + +Optional CPU and memory fields may be absent. Preserve absence through parsing and serialization; do not substitute numeric zero. + +## Next step + +Pin the schema files at release commit `d1a3176f9144f35e777e83fd07045116144da257` next to the workflow that consumes `summary.json`. + +# Compatibility + +Canonical URL: https://docs.mobench.org/compatibility/ +Description: Match Rust, platform tools, devices, and generated runner backends to mobench 0.1.43. +Source: Build guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/build.md — Rust and platform prerequisites, targets, outputs, and generated backends. + +mobench 0.1.43 has a Rust MSRV of **1.85**. Mobile compatibility also depends on the platform toolchain, target architecture, runner backend, and selected device OS. + +## Android + +Typical requirements: + +- Android SDK and NDK +- `cargo-ndk` +- `ANDROID_NDK_HOME` or discoverable SDK installation +- Rust targets such as `aarch64-linux-android`, `armv7-linux-androideabi`, and `x86_64-linux-android` + +The generated project defaults to Android min SDK 24, target SDK 34, and `arm64-v8a` unless configured otherwise. Set `UNIFFI_ANDROID_ABI=x86_64` when exercising the UniFFI path on a default x86_64 emulator. + +## iOS + +Typical requirements: + +- macOS +- Xcode command-line tools +- XcodeGen +- Rust targets `aarch64-apple-ios`, `aarch64-apple-ios-sim`, and `x86_64-apple-ios` + +The default deployment target is iOS 15.0 with the SwiftUI runner. Lower targets use `uikit-legacy` and need an Xcode release capable of building for that OS. BrowserStack device OS must be at least the app deployment target. + +## Generated runner backends + +| Backend | Use when | Integration requirement | +| --- | --- | --- | +| `uniffi` | You want the default compatibility path | UniFFI types and generated Kotlin/Swift bindings | +| `native-c-abi` | Binding overhead must stay out of measured work | Export `mobench_sdk::export_native_c_abi!()` | +| `boltffi` | The project already uses BoltFFI generation | Export the JSON bridge with `#[boltffi::export]` and provide BoltFFI tooling | + +Keep the backend constant across a baseline and candidate; changing it changes the execution path. + +## Profiling compatibility + +- Android native profiling is local and uses `simpleperf`. +- iOS profiling is local, simulator-host oriented, and uses macOS `sample`. +- `rust-tracing` is a planned manifest/trace contract only. +- BrowserStack native profiling is unsupported in 0.1.43. + +## Check the current machine + +```bash +mobench check --target android +mobench check --target ios +mobench doctor --target both +``` + +## Next step + +Run the platform check on the same machine image used by CI, then save its toolchain versions with your first baseline. + +# Host-side preflight + +Canonical URL: https://docs.mobench.org/host-preflight/ +Description: Validate configuration, discovery, builds, and reports before using mobile devices. +Source: Testing guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/testing.md — Prerequisite, discovery, verification, and host-side preflight commands. + +Preflight catches inexpensive failures before a mobile build or BrowserStack session. It validates your local tools and config, proves that the benchmark is discoverable, and checks the requested report shape. + +## Check prerequisites + +Use `doctor` for the combined project, config, and credential view: + +```bash +mobench doctor \ + --target both \ + --config bench-config.toml \ + --device-matrix device-matrix.yaml \ + --browserstack true +``` + +Use `check` for a focused platform toolchain check: + +```bash +mobench check --target android +mobench check --target ios +mobench check --target android --format json +``` + +Validate a run configuration independently: + +```bash +mobench config validate --config bench-config.toml +``` + +## Prove discovery + +```bash +mobench list --crate-path bench-mobile +``` + +If the function is missing, fix the registry or crate selection before building a mobile runner. + +## Verify generated artifacts + +After a build, verify registry and platform files: + +```bash +mobench verify \ + --target android \ + --crate-path bench-mobile \ + --check-artifacts \ + --output-dir target/mobench +``` + +`verify --smoke-test` only works when the benchmark crate is linked into the `mobench` CLI binary. External crates selected through `mobench.toml`, `--project-root`, or `--crate-path` should use `list`, `verify --check-artifacts`, and a normal host preflight. + +## Write host-side preflight output + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --local-only \ + --iterations 5 \ + --warmup 1 \ + --output target/mobench/preflight.json +``` + +This command skips mobile builds and writes preflight/spec output without executing the requested benchmark. It is useful for discovery and report-shape debugging, but it is not an Android, iOS, or host performance measurement. + +Inspect the result shape: + +```bash +mobench summary target/mobench/preflight.json +``` + +## Next step + +Resolve a real device and continue with the [BrowserStack run guide](/browserstack/). + +# BrowserStack device runs + +Canonical URL: https://docs.mobench.org/browserstack/ +Description: Build, upload, run, and fetch Rust benchmarks with BrowserStack App Automate. +Source: BrowserStack CI guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md — Credentials, device resolution, execution, fetching, and iOS compatibility. + +When a `run` or `ci run` command selects devices, mobench builds mobile artifacts, uploads them to BrowserStack App Automate, schedules the sessions, and collects available results. This is the normal path for real Android and iOS measurements in 0.1.43. + +## Configure credentials + +Environment variables are the simplest option: + +```bash +export BROWSERSTACK_USERNAME="your_username" +export BROWSERSTACK_ACCESS_KEY="your_access_key" +export BROWSERSTACK_PROJECT="mobile-benchmarks" +``` + +You can also reference them from `bench-config.toml`: + +```toml test=config:bench-config.toml +[browserstack] +app_automate_username = "${BROWSERSTACK_USERNAME}" +app_automate_access_key = "${BROWSERSTACK_ACCESS_KEY}" +project = "mobile-benchmarks" +``` + +Validate the credentials before starting a build: + +```bash +mobench doctor --target both --browserstack true +``` + +## Choose a device + +List the current BrowserStack inventory and validate an exact identifier: + +```bash +mobench devices --platform android +mobench devices --platform ios +mobench devices --validate "Google Pixel 7-13.0" +``` + +For repeatable suites, use a [device matrix](/device-matrices/) rather than copying labels across workflows. + +## Run Android + +```bash +mobench run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 30 \ + --warmup 5 \ + --release \ + --fetch \ + --output target/mobench/android-results.json +``` + +Use `--release` for optimized code and smaller APK uploads. + +## Run iOS + +```bash +mobench run \ + --target ios \ + --function bench_mobile::checksum \ + --devices "iPhone 14-16" \ + --iterations 20 \ + --warmup 3 \ + --release \ + --fetch \ + --output target/mobench/ios-results.json +``` + +mobench generates and packages the app and XCUITest suite unless `--ios-app` and `--ios-test-suite` point to existing artifacts. + +For older devices, the app deployment target must not exceed the device OS. Use the `uikit-legacy` runner and an appropriately old Xcode lane when SwiftUI is unavailable. + +## Fetch artifacts later + +```bash +mobench fetch \ + --target android \ + --build-id \ + --output-dir target/browserstack \ + --wait \ + --poll-interval-secs 10 \ + --timeout-secs 1800 +``` + +Fetched data can include session JSON, device logs, instrumentation logs, and available video links. BrowserStack does not expose native stack or flamegraph artifacts through this flow. + +## Next step + +Move a stable command into [CI](/ci/) and save its standard output contract. + +# CI runs + +Canonical URL: https://docs.mobench.org/ci/ +Description: Run repeatable mobile benchmarks and produce stable CI artifacts. +Source: BrowserStack CI guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md — CI run, split-sample merge, PR reporting, and regression commands. + +`mobench ci run` wraps execution in a stable file contract for artifact upload, job summaries, comparisons, plots, and downstream reporting. + +## Run one benchmark + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 20 \ + --warmup 5 \ + --release \ + --fetch \ + --plots auto \ + --output-dir target/mobench/ci +``` + +The output directory contains `summary.json`, `summary.md`, `results.csv`, and optional `plots/*.svg`. + +Use `--functions` for several benchmarks in one invocation: + +```bash +mobench ci run \ + --target android \ + --functions '["bench_mobile::checksum","bench_mobile::verify"]' \ + --devices "Google Pixel 7-13.0" \ + --release \ + --output-dir target/mobench/ci +``` + +## Minimal GitHub Actions shape + +```yaml +name: Mobile benchmarks + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-linux-android + - name: Run mobench + env: + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + run: | + mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --device-matrix device-matrix.yaml \ + --device-tags default \ + --release \ + --output-dir target/mobench/ci + - uses: actions/upload-artifact@v4 + with: + name: mobench-android + path: target/mobench/ci +``` + +Install the pinned mobench release in an earlier step or use your repository's pinned local action wrapper. + +## Merge split samples + +Fragile or long BrowserStack lanes can run each measured sample separately. Place the one-sample `summary.json` files below `sample-*` directories, then merge them: + +```bash +mobench ci merge-split-runs \ + --samples-dir target/mobench/split \ + --output-dir target/mobench/ci \ + --function bench_mobile::checksum \ + --device "Google Pixel 7-13.0" \ + --iterations 5 \ + --warmup 1 +``` + +The merge validates function, device, and sample counts, then writes the same three standard files as a normal CI run. + +## Add a regression gate + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --baseline artifact:baselines/android-summary.json \ + --regression-threshold-pct 5 \ + --junit target/mobench/ci/junit.xml \ + --release \ + --output-dir target/mobench/ci +``` + +## Next step + +Read [outputs](/outputs/) before wiring fields into dashboards or PR comments. + +# Benchmark functions + +Canonical URL: https://docs.mobench.org/benchmark-functions/ +Description: Register discoverable benchmark functions with the mobench SDK. +Source: Current API specification — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md — Benchmark macro rules, runtime API, and SDK feature flags. + +`#[benchmark]` registers a Rust function at compile time through `inventory`. The SDK runner and CLI use that registry to discover the function by its fully qualified name. + +## Minimal function + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn parse_fixture() { + let input = std::hint::black_box(include_bytes!("fixture.bin")); + let parsed = parse(input); + std::hint::black_box(parsed); +} +``` + +A simple benchmark: + +- takes no parameters +- returns `()` +- is public when generated mobile runners need to link it +- keeps the measured work and result observable to the optimizer + +Async functions, parameters on a simple benchmark, and non-unit return types are rejected at compile time. Use [setup and teardown](/setup-teardown/) when the measured function needs an input. + +## Discover registered functions + +```bash +mobench list --crate-path bench-mobile +``` + +Pass the exact discovered name to `--function`: + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::parse_fixture \ + --local-only +``` + +The host-only command is a discovery and reporting preflight. Select a device for a mobile measurement. + +## Programmatic execution + +Applications that need the SDK directly can build a validated `BenchSpec` and use the registry runner: + +```rust +use mobench_sdk::{run_benchmark, BenchSpec}; + +let spec = BenchSpec::new("bench_mobile::parse_fixture", 100, 10)?; +let report = run_benchmark(spec)?; +println!("median: {} ns", report.median_ns()); +``` + +For CI integrations, prefer the CLI's stable files over private implementation modules. + +## Named semantic phases + +When a benchmark contains meaningful sub-operations, `profile_phase` can record phase metadata separately from sampled native stacks: + +```rust +use mobench_sdk::{benchmark, profile_phase}; + +#[benchmark] +pub fn prove_and_verify() { + let proof = profile_phase("prove", || prove()); + profile_phase("verify", || verify(&proof)); +} +``` + +## Next step + +Choose a fixture lifecycle in [setup and teardown](/setup-teardown/), then apply the quality checklist. + +# Setup and teardown + +Canonical URL: https://docs.mobench.org/setup-teardown/ +Description: Keep fixture creation, mutation, and cleanup outside measured samples. +Source: Current API specification — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md — Implemented setup, per-iteration setup, and teardown semantics. + +Use the macro's fixture attributes when input creation or cleanup is not part of the operation you want to measure. + +## Reuse one fixture + +Setup runs once before warmup and measured iterations. The benchmark receives a shared reference. + +```rust +use mobench_sdk::benchmark; + +fn create_input() -> Vec { + vec![42; 1024 * 1024] +} + +#[benchmark(setup = create_input)] +pub fn checksum(input: &Vec) { + let sum: u64 = input.iter().map(|byte| u64::from(*byte)).sum(); + std::hint::black_box(sum); +} +``` + +Choose this mode when repeated work does not mutate the fixture in a way that changes later samples. + +## Create a fresh fixture per iteration + +`per_iteration` runs setup before each warmup or measured iteration and passes the value by ownership. Setup remains outside the sample timer. + +```rust +use mobench_sdk::benchmark; + +fn unsorted_values() -> Vec { + (0..10_000).rev().collect() +} + +#[benchmark(setup = unsorted_values, per_iteration)] +pub fn sort_values(mut values: Vec) { + values.sort_unstable(); + std::hint::black_box(values); +} +``` + +Use this mode when the operation consumes or irreversibly mutates its input. + +## Clean up after the run + +Teardown receives the setup value after warmup and measurement. It runs outside measured timing, including when measured execution returns an error. + +```rust +fn open_store() -> Store { + Store::temporary() +} + +fn remove_store(store: Store) { + store.remove(); +} + +#[benchmark(setup = open_store, teardown = remove_store)] +pub fn query_store(store: &Store) { + std::hint::black_box(store.query("key")); +} +``` + +Teardown is not combined with `per_iteration`; make a consumed fixture clean itself up through ownership when each iteration needs independent cleanup. + +## Next step + +Run the benchmark with multiple warmups and inspect it against the [quality checklist](/benchmark-quality/). + +# Benchmark quality + +Canonical URL: https://docs.mobench.org/benchmark-quality/ +Description: Design mobile benchmarks that produce comparable, defensible results. +Source: BrowserStack metrics guide — https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-metrics.md — Result interpretation, optional resource data, and comparison guidance. + +A mobile number is useful only when the work, build, device, and run conditions are clear enough to reproduce. + +## Keep the optimizer honest + +- Pass variable inputs and final outputs through `std::hint::black_box` or `mobench_sdk::black_box`. +- Make the workload long enough to rise above timer resolution and harness overhead. +- Keep setup, cloning, and cleanup outside the measured closure unless they are the subject of the benchmark. +- Prefer deterministic fixture data over network or wall-clock dependencies. + +## Separate warmup from measurement + +Warmups execute the benchmark without adding samples. They can stabilize code paths and caches, but they do not guarantee a thermally stable device. + +Use the same warmup and iteration counts when comparing revisions. Record changes to either value as a new experiment. + +## Compare like with like + +Keep these dimensions stable: + +- device model and OS version +- release versus debug build +- benchmark function and fixture +- runner backend +- iteration and warmup counts +- relevant dependency and toolchain versions + +Prefer medians and percentiles when isolated scheduling noise affects the mean. Repeat the full run when a result is close to your regression threshold. + +## Treat resource values as optional + +CPU and memory measurements depend on runner and provider availability. A blank or absent value means **unavailable**. Do not coerce it to zero, carry it into arithmetic, or claim that it was measured. + +mobench 0.1.43 does not define a power-consumption metric. + +## Use the right execution mode + +`--local-only` validates the host harness and output pipeline. It does not measure Android or iOS execution. For mobile results, choose a BrowserStack device and use `--release`. + +Native profiling is a separate local workflow and should answer *where time is spent*, not replace repeated timing samples. + +## Pre-baseline checklist + +- The function appears in `mobench list`. +- A host preflight completes without warnings you do not understand. +- The release mobile build succeeds. +- The exact device identifier resolves. +- The output contains the expected number of measured samples. +- Missing resource values remain missing. +- The baseline file is stored with its environment metadata. + +## Next step + +Complete the [host-side preflight](/host-preflight/) before spending BrowserStack time. diff --git a/apps/docs/public/llms.txt b/apps/docs/public/llms.txt new file mode 100644 index 0000000..699a900 --- /dev/null +++ b/apps/docs/public/llms.txt @@ -0,0 +1,51 @@ +# mobench + +> Source-backed documentation for mobench 0.1.43: build Android and iOS runners, execute ordinary benchmarks on BrowserStack devices, and analyze stable reports or supported local native profiles. + +Canonical documentation: https://docs.mobench.org/ +Source: https://github.com/worldcoin/mobile-bench-rs/tree/v0.1.43 +Pinned release SHA: d1a3176f9144f35e777e83fd07045116144da257 + +## Capability boundary + +- Use the `mobench` executable for release 0.1.43. The published `cargo mobench` wrapper is unsupported. +- Ordinary mobile benchmarks execute through BrowserStack when devices are selected. +- `--local-only` is host preflight and does not measure Android or iOS execution. +- Local native profiling has a separate Android simpleperf and iOS simulator-host capability matrix. +- The release does not define an energy or battery measurement contract. + +## Documentation + +- [Outputs and metrics](https://docs.mobench.org/outputs/): Understand mobench JSON, Markdown, CSV, plots, and optional resource values. +- [Regression comparison](https://docs.mobench.org/regressions/): Compare compatible mobench summaries and gate meaningful slowdowns. +- [Local native profiling](https://docs.mobench.org/profiling/): Capture Android and iOS native stacks and compare profile manifests locally. +- [Basic benchmark crate](https://docs.mobench.org/basic-example/): Follow the minimal SDK example from registration to host and mobile execution. +- [FFI benchmark crate](https://docs.mobench.org/ffi-example/): Expose mobench benchmarks through UniFFI, the native C ABI, or BoltFFI. +- [Installation](https://docs.mobench.org/installation/): Install mobench 0.1.43 and prepare a Rust benchmark crate. +- [Quickstart](https://docs.mobench.org/quickstart/): Register a Rust benchmark, validate it on the host, and run it on a mobile device. +- [Troubleshooting](https://docs.mobench.org/troubleshooting/): Diagnose discovery, toolchain, BrowserStack, result, and profiling failures. +- [mobench documentation](https://docs.mobench.org/): Build, run, and analyze Rust benchmarks on Android and iOS. +- [CLI reference](https://docs.mobench.org/cli/): Find mobench commands and the flags that connect authoring, execution, CI, and profiling. +- [Configuration](https://docs.mobench.org/configuration/): Configure project builds separately from benchmark run and provider settings. +- [Device matrices](https://docs.mobench.org/device-matrices/): Select BrowserStack Android and iOS devices deterministically with tags. +- [Output schemas](https://docs.mobench.org/schemas/): Use the versioned mobench JSON contracts without depending on private implementation details. +- [Compatibility](https://docs.mobench.org/compatibility/): Match Rust, platform tools, devices, and generated runner backends to mobench 0.1.43. +- [Host-side preflight](https://docs.mobench.org/host-preflight/): Validate configuration, discovery, builds, and reports before using mobile devices. +- [BrowserStack device runs](https://docs.mobench.org/browserstack/): Build, upload, run, and fetch Rust benchmarks with BrowserStack App Automate. +- [CI runs](https://docs.mobench.org/ci/): Run repeatable mobile benchmarks and produce stable CI artifacts. +- [Benchmark functions](https://docs.mobench.org/benchmark-functions/): Register discoverable benchmark functions with the mobench SDK. +- [Setup and teardown](https://docs.mobench.org/setup-teardown/): Keep fixture creation, mutation, and cleanup outside measured samples. +- [Benchmark quality](https://docs.mobench.org/benchmark-quality/): Design mobile benchmarks that produce comparable, defensible results. + +## Stable command entry points + +```bash +cargo install mobench --version 0.1.43 +mobench list --crate-path bench-mobile +mobench run --target android --function bench_mobile::checksum --local-only --output target/mobench/preflight.json +mobench run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output target/mobench/results.json +mobench ci run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output-dir target/mobench/ci +mobench profile run --target android --provider local --backend android-native --function bench_mobile::checksum --output-dir target/mobench/profile +``` + +Full authored documentation: https://docs.mobench.org/llms-full.txt diff --git a/apps/docs/public/manifests/mobench-site-manifest-v1.json b/apps/docs/public/manifests/mobench-site-manifest-v1.json new file mode 100644 index 0000000..9333624 --- /dev/null +++ b/apps/docs/public/manifests/mobench-site-manifest-v1.json @@ -0,0 +1,9063 @@ +{ + "schema_version": 1, + "release": { + "version": "0.1.43", + "tag": "v0.1.43", + "sha": "d1a3176f9144f35e777e83fd07045116144da257", + "repository": "https://github.com/worldcoin/mobile-bench-rs" + }, + "msrv": "1.85", + "binaries": [ + { + "name": "mobench", + "invocation": "mobench ", + "canonical_for_release": true, + "status": "supported", + "note": "Canonical executable for the pinned v0.1.43 release." + }, + { + "name": "cargo-mobench", + "invocation": "cargo mobench ", + "canonical_for_release": false, + "status": "unsupported", + "note": "The published v0.1.43 wrapper forwards Cargo's injected `mobench` token. A source fix is integration-tested but requires a later release." + } + ], + "command_tree": { + "name": "mobench", + "path": "mobench", + "about": "Mobile Rust benchmarking orchestrator", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "version", + "long": "version", + "short": "V", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Version", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print version" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "build", + "path": "mobench build", + "about": "Build mobile artifacts from the resolved benchmark crate", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate (default: auto-detect bench-mobile/ or crates/{crate})" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "check", + "path": "mobench check", + "about": "Check prerequisites for building mobile artifacts", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": "Output format (text or json)" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "target", + "long": "target", + "short": "t", + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Target platform (android or ios)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "ci", + "path": "mobench ci", + "about": "CI helpers (workflow and action scaffolding)", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "check-run", + "path": "mobench ci check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [ + { + "id": "annotation_path", + "long": "annotation-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANNOTATION_PATH" + ], + "possible_values": [], + "defaults": [ + "src/lib.rs" + ], + "environment": null, + "help": "File path used in Check Run annotations (relative to repo root)" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional baseline JSON for regression detection" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "name", + "long": "name", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "NAME" + ], + "possible_values": [], + "defaults": [ + "Mobench" + ], + "environment": null, + "help": "Check Run name displayed in the PR" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage" + }, + { + "id": "repo", + "long": "repo", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REPO" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "GitHub repository (owner/repo format)" + }, + { + "id": "results", + "long": "results", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to summary JSON with benchmark results" + }, + { + "id": "results_dir", + "long": "results-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing summary JSON files (processes all)" + }, + { + "id": "sha", + "long": "sha", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SHA" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Git commit SHA to annotate" + }, + { + "id": "token", + "long": "token", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "TOKEN" + ], + "possible_values": [], + "defaults": [], + "environment": "GITHUB_TOKEN", + "help": "GitHub App token (from GITHUB_TOKEN env var or actions/create-github-app-token)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench ci help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "check-run", + "path": "mobench ci help check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench ci help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench ci help init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench ci help merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench ci help run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench ci help summarize", + "about": "Summarize benchmark results with device metrics", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench ci init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [ + { + "id": "action_dir", + "long": "action-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ACTION_DIR" + ], + "possible_values": [], + "defaults": [ + ".github/actions/mobench" + ], + "environment": null, + "help": "Directory to write the local GitHub Action" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "workflow", + "long": "workflow", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WORKFLOW" + ], + "possible_values": [], + "defaults": [ + ".github/workflows/mobile-bench.yml" + ], + "environment": null, + "help": "Path to write the workflow file" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench ci merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [ + { + "id": "device", + "long": "device", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device label all samples must match" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified benchmark function all samples must contain" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Expected measured sample count" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory to write merged summary.json, summary.md, and results.csv" + }, + { + "id": "samples_dir", + "long": "samples-dir", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SAMPLES_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing sample-*/summary.json one-sample CI outputs" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [ + "0" + ], + "environment": null, + "help": "Warmup count reported in merged CI summaries" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench ci run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [ + { + "id": "android_benchmark_timeout_secs", + "long": "android-benchmark-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_BENCHMARK_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark watchdog timeout in seconds for the generated harness" + }, + { + "id": "android_heartbeat_interval_secs", + "long": "android-heartbeat-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_HEARTBEAT_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark heartbeat interval in seconds for the generated harness" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline summary source (path|url|artifact:)" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device matrix YAML file to load device names from" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "devices", + "long": "devices", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICES" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device identifiers or labels (BrowserStack devices)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fetch", + "long": "fetch", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FETCH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Fetch BrowserStack artifacts after the run completes" + }, + { + "id": "fetch_output_dir", + "long": "fetch-output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_poll_interval_secs", + "long": "fetch-poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_timeout_secs", + "long": "fetch-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "300" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to benchmark (single function)" + }, + { + "id": "functions", + "long": "functions", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "FUNCTIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Multiple benchmark functions (comma-separated or JSON array). Runs each in sequence." + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "ios_app", + "long": "ios-app", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_APP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "ios_test_suite", + "long": "ios-test-suite", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_TEST_SUITE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS XCUITest test suite package (.zip or .ipa)" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [ + "100" + ], + "environment": null, + "help": null + }, + { + "id": "junit", + "long": "junit", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "JUNIT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write JUnit XML report to the given path" + }, + { + "id": "local_only", + "long": "local-only", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "LOCAL_ONLY" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Skip mobile builds and write host-side preflight/spec output without mobile execution" + }, + { + "id": "mobench_ref", + "long": "mobench-ref", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "MOBENCH_REF" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: git ref/sha for this mobench invocation" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci" + ], + "environment": null, + "help": "Output directory for CI contract files" + }, + { + "id": "plots", + "long": "plots", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLOTS" + ], + "possible_values": [ + "auto", + "off", + "require" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "pr_number", + "long": "pr-number", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PR_NUMBER" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: pull request number" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage when comparing to baseline" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode (recommended for BrowserStack to reduce APK size and upload time)" + }, + { + "id": "request_command", + "long": "request-command", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REQUEST_COMMAND" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: original command requested by the caller" + }, + { + "id": "requested_by", + "long": "requested-by", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REQUESTED_BY" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: user or actor that requested the run" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [ + "10" + ], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench ci summarize", + "about": "Summarize benchmark results with device metrics", + "options": [ + { + "id": "build_id", + "long": "build-id", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BUILD_ID" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "BrowserStack build ID to enrich results with device metrics (requires --results-dir)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_file", + "long": "output-file", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write output to file in addition to stdout" + }, + { + "id": "output_format", + "long": "output-format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FORMAT" + ], + "possible_values": [ + "json", + "markdown", + "table" + ], + "defaults": [ + "table" + ], + "environment": null, + "help": "Output format: table (terminal), markdown, or json" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Platform filter (show only one platform)" + }, + { + "id": "results_dir", + "long": "results-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing summary.json/CSV results (offline mode)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "compare", + "path": "mobench compare", + "about": "Compare two run summaries for regressions", + "options": [ + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline JSON summary to compare against" + }, + { + "id": "candidate", + "long": "candidate", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CANDIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Candidate JSON summary to compare" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional output path for markdown report" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "config", + "path": "mobench config", + "about": "Validate run configuration and associated files", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "help", + "path": "mobench config help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "help", + "path": "mobench config help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "validate", + "path": "mobench config help validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "validate", + "path": "mobench config validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "devices", + "path": "mobench devices", + "about": "List available BrowserStack devices for testing", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "json", + "long": "json", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "JSON" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Output as JSON" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Filter by platform (android or ios)" + }, + { + "id": "validate", + "long": "validate", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "VALIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Validate device specs against available devices" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "help", + "path": "mobench devices help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "help", + "path": "mobench devices help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "resolve", + "path": "mobench devices help resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "resolve", + "path": "mobench devices resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to run config file (optional source for matrix/tags)" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to device matrix YAML file" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to resolve (defaults to `default`)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "doctor", + "path": "mobench doctor", + "about": "Validate local + CI prerequisites and configuration", + "options": [ + { + "id": "browserstack", + "long": "browserstack", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BROWSERSTACK" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "true" + ], + "environment": null, + "help": "Validate BrowserStack credentials" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to run config file to validate" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to device matrix YAML file to validate" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "fetch", + "path": "mobench fetch", + "about": "Fetch BrowserStack build artifacts (logs, session JSON) for CI", + "options": [ + { + "id": "build_id", + "long": "build-id", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BUILD_ID" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "poll_interval_secs", + "long": "poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "10" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "timeout_secs", + "long": "timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "1800" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "wait", + "long": "wait", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "WAIT" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "true" + ], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "fixture", + "path": "mobench fixture", + "about": "Fixture lifecycle helpers for reproducible CI setup", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "build", + "path": "mobench fixture build", + "about": "Build fixture artifacts using existing build commands", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to benchmark crate" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench fixture cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag for keying" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench fixture help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench fixture help build", + "about": "Build fixture artifacts using existing build commands", + "options": [], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench fixture help cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench fixture help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench fixture help init", + "about": "Create starter fixture files for CI runs", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench fixture help verify", + "about": "Verify fixture files and optional profile filtering", + "options": [], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench fixture help verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench fixture init", + "about": "Create starter fixture files for CI runs", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [ + "device-matrix.yaml" + ], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "force", + "long": "force", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FORCE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Overwrite existing fixture files" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench fixture verify", + "about": "Verify fixture files and optional profile filtering", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to verify" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench fixture verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fixture", + "long": null, + "short": null, + "positional_index": 1, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FIXTURE" + ], + "possible_values": [ + "basic", + "ffi" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for rendered fixture artifacts (defaults under target/mobench/plot-fixtures)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "help", + "path": "mobench help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench help build", + "about": "Build mobile artifacts from the resolved benchmark crate", + "options": [], + "subcommands": [] + }, + { + "name": "check", + "path": "mobench help check", + "about": "Check prerequisites for building mobile artifacts", + "options": [], + "subcommands": [] + }, + { + "name": "ci", + "path": "mobench help ci", + "about": "CI helpers (workflow and action scaffolding)", + "options": [], + "subcommands": [ + { + "name": "check-run", + "path": "mobench help ci check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help ci init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench help ci merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench help ci run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help ci summarize", + "about": "Summarize benchmark results with device metrics", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "compare", + "path": "mobench help compare", + "about": "Compare two run summaries for regressions", + "options": [], + "subcommands": [] + }, + { + "name": "config", + "path": "mobench help config", + "about": "Validate run configuration and associated files", + "options": [], + "subcommands": [ + { + "name": "validate", + "path": "mobench help config validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "devices", + "path": "mobench help devices", + "about": "List available BrowserStack devices for testing", + "options": [], + "subcommands": [ + { + "name": "resolve", + "path": "mobench help devices resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "doctor", + "path": "mobench help doctor", + "about": "Validate local + CI prerequisites and configuration", + "options": [], + "subcommands": [] + }, + { + "name": "fetch", + "path": "mobench help fetch", + "about": "Fetch BrowserStack build artifacts (logs, session JSON) for CI", + "options": [], + "subcommands": [] + }, + { + "name": "fixture", + "path": "mobench help fixture", + "about": "Fixture lifecycle helpers for reproducible CI setup", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench help fixture build", + "about": "Build fixture artifacts using existing build commands", + "options": [], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench help fixture cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help fixture init", + "about": "Create starter fixture files for CI runs", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench help fixture verify", + "about": "Verify fixture files and optional profile filtering", + "options": [], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench help fixture verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "help", + "path": "mobench help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help init", + "about": "Scaffold a base config file for the CLI", + "options": [], + "subcommands": [] + }, + { + "name": "init-sdk", + "path": "mobench help init-sdk", + "about": "Initialize a new benchmark project with the SDK templates", + "options": [], + "subcommands": [] + }, + { + "name": "list", + "path": "mobench help list", + "about": "List all discovered benchmark functions", + "options": [], + "subcommands": [] + }, + { + "name": "package-ipa", + "path": "mobench help package-ipa", + "about": "Package iOS app as IPA for distribution or testing", + "options": [], + "subcommands": [] + }, + { + "name": "package-xcuitest", + "path": "mobench help package-xcuitest", + "about": "Package XCUITest runner for BrowserStack testing", + "options": [], + "subcommands": [] + }, + { + "name": "plan", + "path": "mobench help plan", + "about": "Generate a sample device matrix file", + "options": [], + "subcommands": [] + }, + { + "name": "profile", + "path": "mobench help profile", + "about": "Profiling helpers for native profile capture and summary rendering", + "options": [], + "subcommands": [ + { + "name": "diff", + "path": "mobench help profile diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench help profile run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help profile summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "report", + "path": "mobench help report", + "about": "Reporting helpers for CI summaries and PR comments", + "options": [], + "subcommands": [ + { + "name": "github", + "path": "mobench help report github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help report summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench help run", + "about": "Build mobile artifacts, write host preflight output, or run on BrowserStack devices", + "options": [], + "subcommands": [] + }, + { + "name": "summary", + "path": "mobench help summary", + "about": "Display summary statistics from a benchmark report JSON file", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench help verify", + "about": "Verify benchmark setup: registry, spec, artifacts, and optional smoke test", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench init", + "about": "Scaffold a base config file for the CLI", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [ + "android" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "init-sdk", + "path": "mobench init-sdk", + "about": "Initialize a new benchmark project with the SDK templates", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "examples", + "long": "examples", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "EXAMPLES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Generate example benchmarks" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "." + ], + "environment": null, + "help": null + }, + { + "id": "project_name", + "long": "project-name", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_NAME" + ], + "possible_values": [], + "defaults": [ + "bench-project" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "list", + "path": "mobench list", + "about": "List all discovered benchmark functions", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "package-ipa", + "path": "mobench package-ipa", + "about": "Package iOS app as IPA for distribution or testing", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "method", + "long": "method", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "METHOD" + ], + "possible_values": [ + "adhoc", + "development" + ], + "defaults": [ + "adhoc" + ], + "environment": null, + "help": "Signing method" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "scheme", + "long": "scheme", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SCHEME" + ], + "possible_values": [], + "defaults": [ + "BenchRunner" + ], + "environment": null, + "help": "Xcode scheme to build" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "package-xcuitest", + "path": "mobench package-xcuitest", + "about": "Package XCUITest runner for BrowserStack testing", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "scheme", + "long": "scheme", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SCHEME" + ], + "possible_values": [], + "defaults": [ + "BenchRunner" + ], + "environment": null, + "help": "Xcode scheme to build" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "plan", + "path": "mobench plan", + "about": "Generate a sample device matrix file", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [ + "device-matrix.yaml" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "profile", + "path": "mobench profile", + "about": "Profiling helpers for native profile capture and summary rendering", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "diff", + "path": "mobench profile diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [ + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the baseline profile.json manifest" + }, + { + "id": "candidate", + "long": "candidate", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CANDIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the candidate profile.json manifest" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "normalize", + "long": "normalize", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NORMALIZE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Normalize baseline sample counts to candidate totals before diffing" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile/diff" + ], + "environment": null, + "help": "Output directory for differential profile artifacts" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench profile help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "diff", + "path": "mobench profile help diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench profile help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench profile help run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench profile help summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench profile run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [ + { + "id": "backend", + "long": "backend", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BACKEND" + ], + "possible_values": [ + "android-native", + "auto", + "ios-instruments", + "rust-tracing" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device", + "long": "device", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Explicit BrowserStack device name to resolve for this profiling request" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to device matrix YAML file used with --profile or config-based device tags" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "both", + "native", + "processed" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to profile" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "os_version", + "long": "os-version", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OS_VERSION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "OS version for --device (for example `16` or `14.0`)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile" + ], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to resolve (for example `high-spec`)" + }, + { + "id": "provider", + "long": "provider", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROVIDER" + ], + "possible_values": [ + "browserstack", + "local" + ], + "defaults": [ + "local" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "trace_events_output", + "long": "trace-events-output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TRACE_EVENTS_OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write machine-readable trace/event JSON to this path for downstream consumers" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup_mode", + "long": "warmup-mode", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP_MODE" + ], + "possible_values": [ + "cold", + "warm" + ], + "defaults": [], + "environment": null, + "help": "Warm or cold capture mode for local native profiling (defaults to warm for local Android/iOS native backends)" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench profile summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "output_format", + "long": "output-format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FORMAT" + ], + "possible_values": [ + "json", + "markdown" + ], + "defaults": [ + "markdown" + ], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile/profile.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "report", + "path": "mobench report", + "about": "Reporting helpers for CI summaries and PR comments", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "github", + "path": "mobench report github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "marker", + "long": "marker", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "MARKER" + ], + "possible_values": [], + "defaults": [ + "" + ], + "environment": null, + "help": null + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write generated comment body to file" + }, + { + "id": "pr", + "long": "pr", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Pull request number (auto-detected from GITHUB_REF if omitted)" + }, + { + "id": "publish", + "long": "publish", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PUBLISH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Publish via GitHub API using GITHUB_TOKEN" + }, + { + "id": "summary", + "long": "summary", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SUMMARY" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci/summary.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench report help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "github", + "path": "mobench report help github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench report help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench report help summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "summarize", + "path": "mobench report summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write markdown output to file" + }, + { + "id": "plots", + "long": "plots", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLOTS" + ], + "possible_values": [ + "auto", + "off", + "require" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "summary", + "long": "summary", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SUMMARY" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci/summary.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench run", + "about": "Build mobile artifacts, write host preflight output, or run on BrowserStack devices", + "options": [ + { + "id": "android_benchmark_timeout_secs", + "long": "android-benchmark-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_BENCHMARK_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark watchdog timeout in seconds for the generated harness" + }, + { + "id": "android_heartbeat_interval_secs", + "long": "android-heartbeat-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_HEARTBEAT_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark heartbeat interval in seconds for the generated harness" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline summary source (path|url|artifact:)" + }, + { + "id": "ci", + "long": "ci", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "CI" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Enable CI mode (job summary, optional JUnit, regression exit codes)" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device matrix YAML file to load device names from" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "devices", + "long": "devices", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICES" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device identifiers or labels (BrowserStack devices)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fetch", + "long": "fetch", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FETCH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Fetch BrowserStack artifacts after the run completes" + }, + { + "id": "fetch_output_dir", + "long": "fetch-output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_poll_interval_secs", + "long": "fetch-poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_timeout_secs", + "long": "fetch-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "300" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to benchmark" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "ios_app", + "long": "ios-app", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_APP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "ios_test_suite", + "long": "ios-test-suite", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_TEST_SUITE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS XCUITest test suite package (.zip or .ipa)" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "junit", + "long": "junit", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "JUNIT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write JUnit XML report to the given path" + }, + { + "id": "local_only", + "long": "local-only", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "LOCAL_ONLY" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Skip mobile builds and write host-side preflight/spec output without mobile execution" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional output path for JSON report" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage when comparing to baseline" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode (recommended for BrowserStack to reduce APK size and upload time)" + }, + { + "id": "summary_csv", + "long": "summary-csv", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "SUMMARY_CSV" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Write CSV summary alongside JSON" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summary", + "path": "mobench summary", + "about": "Display summary statistics from a benchmark report JSON file", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "csv", + "json", + "text" + ], + "defaults": [], + "environment": null, + "help": "Output format: text (default), json, or csv" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "report", + "long": null, + "short": null, + "positional_index": 1, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REPORT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark report JSON file" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench verify", + "about": "Verify benchmark setup: registry, spec, artifacts, and optional smoke test", + "options": [ + { + "id": "check_artifacts", + "long": "check-artifacts", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "CHECK_ARTIFACTS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Check that build artifacts exist" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Function name to verify/smoke test" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "smoke_test", + "long": "smoke-test", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "SMOKE_TEST" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Run a local smoke test with minimal iterations" + }, + { + "id": "spec_path", + "long": "spec-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SPEC_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to bench_spec.json to validate" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Target platform to verify artifacts for" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + "config": [ + { + "file": "mobench.toml", + "keys": [ + { + "path": "project.crate", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "project.library_name", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "project.output_dir", + "value_type": "path|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.package", + "value_type": "string", + "required": false, + "default": "dev.world.bench", + "evidence_id": "source-mobench-config" + }, + { + "path": "android.min_sdk", + "value_type": "integer", + "required": false, + "default": 24, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.target_sdk", + "value_type": "integer", + "required": false, + "default": 34, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.abis", + "value_type": "string[]|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.bundle_id", + "value_type": "string", + "required": false, + "default": "dev.world.bench", + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.deployment_target", + "value_type": "string", + "required": false, + "default": "15.0", + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.team_id", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_function", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_iterations", + "value_type": "integer", + "required": false, + "default": 100, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_warmup", + "value_type": "integer", + "required": false, + "default": 10, + "evidence_id": "source-mobench-config" + }, + { + "path": "browserstack.ios_completion_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + } + ] + }, + { + "file": "bench-config.toml", + "keys": [ + { + "path": "target", + "value_type": "android|ios", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "function", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "iterations", + "value_type": "integer", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "warmup", + "value_type": "integer", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "device_matrix", + "value_type": "path", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "device_tags", + "value_type": "string[]|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.app_automate_username", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.app_automate_access_key", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.project", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.ios_completion_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.android_benchmark_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.android_heartbeat_interval_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "ios_xcuitest.app", + "value_type": "path", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "ios_xcuitest.test_suite", + "value_type": "path", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + } + ] + } + ], + "artifacts": [ + { + "id": "benchmark-spec", + "path_pattern": "target/mobench/{android|ios}/**/bench_spec.json", + "produced_by": [ + "mobench run", + "mobench build" + ], + "description": "Resolved benchmark request embedded in generated runners.", + "evidence_id": "source-run-artifacts" + }, + { + "id": "benchmark-metadata", + "path_pattern": "target/mobench/{android|ios}/**/bench_meta.json", + "produced_by": [ + "mobench run", + "mobench build" + ], + "description": "Build metadata embedded beside the benchmark spec.", + "evidence_id": "source-run-artifacts" + }, + { + "id": "android-app", + "path_pattern": "target/mobench/android/app/build/outputs/apk/{debug|release}/*.apk", + "produced_by": [ + "mobench build", + "mobench run" + ], + "description": "Generated Android app and instrumentation packages.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-framework", + "path_pattern": "target/mobench/ios/.xcframework", + "produced_by": [ + "mobench build", + "mobench run" + ], + "description": "Generated iOS xcframework.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-app", + "path_pattern": "target/mobench/ios/BenchRunner.ipa", + "produced_by": [ + "mobench package-ipa", + "mobench run" + ], + "description": "Packaged iOS benchmark application.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-test-suite", + "path_pattern": "target/mobench/ios/BenchRunnerUITests.zip", + "produced_by": [ + "mobench package-xcuitest", + "mobench run" + ], + "description": "Packaged XCUITest suite for BrowserStack.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ci-summary-json", + "path_pattern": "/summary.json", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Machine-readable benchmark summary.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "ci-summary-markdown", + "path_pattern": "/summary.md", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Human-readable benchmark summary.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "ci-results-csv", + "path_pattern": "/results.csv", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Tabular benchmark results.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "profile-manifest", + "path_pattern": "//profile.json", + "produced_by": [ + "mobench profile run" + ], + "description": "Normalized profile manifest, plus a latest convenience copy.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-summary", + "path_pattern": "//summary.md", + "produced_by": [ + "mobench profile run" + ], + "description": "Profile summary, plus a latest convenience copy.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-folded-stacks", + "path_pattern": "//artifacts/processed/stacks.folded", + "produced_by": [ + "mobench profile run" + ], + "description": "Processed native stack samples when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-native-report", + "path_pattern": "//artifacts/processed/native-report.txt", + "produced_by": [ + "mobench profile run" + ], + "description": "Symbolized native profiler report when available.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-flamegraphs", + "path_pattern": "//artifacts/processed/flamegraph.{full|focused}.svg", + "produced_by": [ + "mobench profile run" + ], + "description": "Full and benchmark-focused flamegraph SVGs when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-viewer", + "path_pattern": "//artifacts/processed/flamegraph.html", + "produced_by": [ + "mobench profile run" + ], + "description": "Standalone profile viewer when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "trace-events", + "path_pattern": "", + "produced_by": [ + "mobench profile run" + ], + "description": "Machine-readable structured trace-event contract.", + "evidence_id": "test-trace-events" + } + ], + "schemas": [ + { + "id": "summary-v1", + "path": "docs/schemas/summary-v1.schema.json", + "checksum_sha256": "dd67ff6dbf57e06acd3516b1f41f1b76654baf351a2a2fbc9ade2db1406a70fc" + }, + { + "id": "ci-contract-v1", + "path": "docs/schemas/ci-contract-v1.schema.json", + "checksum_sha256": "eff1ddfc6800a6a990cd85a3bf02feb03e0c71aac9ea64cd499e41790703e962" + }, + { + "id": "trace-events-v1", + "path": "docs/schemas/trace-events-v1.schema.json", + "checksum_sha256": "da8309604422fa31f653be40c0fafdcbc5dfbc8c001da78fc5f7e185f7c861ac" + }, + { + "id": "mobench-site-manifest-v1", + "path": "docs/schemas/mobench-site-manifest-v1.schema.json", + "checksum_sha256": "84bd1985e3a0025d56df39392a08f8f52631676b6ecc0173990d12be8828bb27" + } + ], + "capabilities": [ + { + "id": "benchmark.build.android", + "status": "supported", + "summary": "Build generated Android benchmark artifacts.", + "evidence_ids": [ + "source-build-artifacts" + ] + }, + { + "id": "benchmark.build.ios", + "status": "supported", + "summary": "Build generated iOS benchmark artifacts.", + "evidence_ids": [ + "source-build-artifacts" + ] + }, + { + "id": "benchmark.execute.browserstack.android", + "status": "supported", + "summary": "Execute Android benchmarks through BrowserStack App Automate when devices and credentials are provided.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.browserstack.ios", + "status": "supported", + "summary": "Execute iOS benchmarks through BrowserStack XCUITest when devices, credentials, and packages are provided.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.local-only", + "status": "unsupported", + "summary": "`--local-only` writes preflight/spec outputs but skips the mobile build and does not execute the requested benchmark in v0.1.43.", + "evidence_ids": [ + "source-local-only" + ] + }, + { + "id": "benchmark.execute.attached-device", + "status": "unsupported", + "summary": "Ordinary `mobench run` does not execute on an attached phone in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.android-emulator", + "status": "unsupported", + "summary": "Ordinary `mobench run` has no Android emulator execution provider in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.ios-simulator", + "status": "unsupported", + "summary": "Ordinary `mobench run` has no iOS simulator execution provider in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.build-without-devices", + "status": "supported", + "summary": "With no BrowserStack devices, `mobench run` builds artifacts and skips upload/execution.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "profile.local.android-native", + "status": "supported", + "summary": "Attempt local Android simpleperf capture, symbolization, and flamegraph generation when required tools and a device are available.", + "evidence_ids": [ + "source-android-profile", + "test-android-profile" + ] + }, + { + "id": "profile.local.ios-instruments", + "status": "supported", + "summary": "Attempt local iOS simulator-host sample capture and flamegraph generation when required tools are available.", + "evidence_ids": [ + "source-ios-profile", + "test-ios-profile" + ] + }, + { + "id": "profile.local.rust-tracing", + "status": "planned", + "summary": "The manifest/trace contract exists, but local rust-tracing capture is not implemented.", + "evidence_ids": [ + "source-rust-tracing" + ] + }, + { + "id": "profile.browserstack.android-native", + "status": "unsupported", + "summary": "BrowserStack native Android stack capture is not implemented.", + "evidence_ids": [ + "test-browserstack-profile" + ] + }, + { + "id": "profile.browserstack.ios-instruments", + "status": "unsupported", + "summary": "BrowserStack native iOS Instruments capture is not implemented.", + "evidence_ids": [ + "test-browserstack-profile" + ] + }, + { + "id": "profile.browserstack.rust-tracing", + "status": "unsupported", + "summary": "BrowserStack rust-tracing capture is not implemented.", + "evidence_ids": [ + "source-rust-tracing" + ] + } + ], + "evidence": [ + { + "id": "source-mobench-config", + "kind": "source", + "reference": "crates/mobench/src/config.rs#MobenchConfig" + }, + { + "id": "source-bench-config", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#BenchConfig" + }, + { + "id": "source-run-artifacts", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#persist_mobile_spec" + }, + { + "id": "source-build-artifacts", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#cmd_build" + }, + { + "id": "source-browserstack-run", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#run_from" + }, + { + "id": "source-local-only", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#run_from:local_only" + }, + { + "id": "source-android-profile", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_local_android_capture" + }, + { + "id": "source-ios-profile", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_local_ios_capture" + }, + { + "id": "source-rust-tracing", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_capture" + }, + { + "id": "test-ci-artifacts", + "kind": "test", + "reference": "crates/mobench/src/split_runs.rs#merge_split_run_summaries" + }, + { + "id": "test-profile-artifacts", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#profile_run_writes_run_scoped_and_latest_manifest_files" + }, + { + "id": "test-trace-events", + "kind": "test", + "reference": "crates/mobench/tests/profile_cli.rs#profile_run_dry_run_writes_trace_events_output_for_downstream_consumers" + }, + { + "id": "test-android-profile", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#android_backend_builds_capture_plan_with_flamegraph_artifacts" + }, + { + "id": "test-ios-profile", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#ios_backend_allocates_sample_and_flamegraph_artifacts" + }, + { + "id": "test-browserstack-profile", + "kind": "test", + "reference": "crates/mobench/tests/profile_cli.rs#browserstack_profile_run_reports_unsupported_native_capture" + }, + { + "id": "test-cargo-wrapper", + "kind": "test", + "reference": "crates/mobench/tests/invocation_cli.rs#cargo_mobench_invocation_works_through_cargo" + } + ] +} diff --git a/apps/docs/public/og/basic-example.png b/apps/docs/public/og/basic-example.png new file mode 100644 index 0000000..965f852 Binary files /dev/null and b/apps/docs/public/og/basic-example.png differ diff --git a/apps/docs/public/og/benchmark-functions.png b/apps/docs/public/og/benchmark-functions.png new file mode 100644 index 0000000..f3f08dc Binary files /dev/null and b/apps/docs/public/og/benchmark-functions.png differ diff --git a/apps/docs/public/og/benchmark-quality.png b/apps/docs/public/og/benchmark-quality.png new file mode 100644 index 0000000..ee68288 Binary files /dev/null and b/apps/docs/public/og/benchmark-quality.png differ diff --git a/apps/docs/public/og/browserstack.png b/apps/docs/public/og/browserstack.png new file mode 100644 index 0000000..d75485e Binary files /dev/null and b/apps/docs/public/og/browserstack.png differ diff --git a/apps/docs/public/og/ci.png b/apps/docs/public/og/ci.png new file mode 100644 index 0000000..1dbd86d Binary files /dev/null and b/apps/docs/public/og/ci.png differ diff --git a/apps/docs/public/og/cli.png b/apps/docs/public/og/cli.png new file mode 100644 index 0000000..7ce0b71 Binary files /dev/null and b/apps/docs/public/og/cli.png differ diff --git a/apps/docs/public/og/compatibility.png b/apps/docs/public/og/compatibility.png new file mode 100644 index 0000000..1894dfe Binary files /dev/null and b/apps/docs/public/og/compatibility.png differ diff --git a/apps/docs/public/og/configuration.png b/apps/docs/public/og/configuration.png new file mode 100644 index 0000000..613f361 Binary files /dev/null and b/apps/docs/public/og/configuration.png differ diff --git a/apps/docs/public/og/device-matrices.png b/apps/docs/public/og/device-matrices.png new file mode 100644 index 0000000..287bb20 Binary files /dev/null and b/apps/docs/public/og/device-matrices.png differ diff --git a/apps/docs/public/og/ffi-example.png b/apps/docs/public/og/ffi-example.png new file mode 100644 index 0000000..a457118 Binary files /dev/null and b/apps/docs/public/og/ffi-example.png differ diff --git a/apps/docs/public/og/host-preflight.png b/apps/docs/public/og/host-preflight.png new file mode 100644 index 0000000..70a4bad Binary files /dev/null and b/apps/docs/public/og/host-preflight.png differ diff --git a/apps/docs/public/og/index.png b/apps/docs/public/og/index.png new file mode 100644 index 0000000..ec01d38 Binary files /dev/null and b/apps/docs/public/og/index.png differ diff --git a/apps/docs/public/og/installation.png b/apps/docs/public/og/installation.png new file mode 100644 index 0000000..5e60394 Binary files /dev/null and b/apps/docs/public/og/installation.png differ diff --git a/apps/docs/public/og/outputs.png b/apps/docs/public/og/outputs.png new file mode 100644 index 0000000..a7d36f0 Binary files /dev/null and b/apps/docs/public/og/outputs.png differ diff --git a/apps/docs/public/og/profiling.png b/apps/docs/public/og/profiling.png new file mode 100644 index 0000000..bf0e27b Binary files /dev/null and b/apps/docs/public/og/profiling.png differ diff --git a/apps/docs/public/og/quickstart.png b/apps/docs/public/og/quickstart.png new file mode 100644 index 0000000..4c1a68c Binary files /dev/null and b/apps/docs/public/og/quickstart.png differ diff --git a/apps/docs/public/og/regressions.png b/apps/docs/public/og/regressions.png new file mode 100644 index 0000000..46f5a01 Binary files /dev/null and b/apps/docs/public/og/regressions.png differ diff --git a/apps/docs/public/og/schemas.png b/apps/docs/public/og/schemas.png new file mode 100644 index 0000000..12e2c58 Binary files /dev/null and b/apps/docs/public/og/schemas.png differ diff --git a/apps/docs/public/og/setup-teardown.png b/apps/docs/public/og/setup-teardown.png new file mode 100644 index 0000000..68613cd Binary files /dev/null and b/apps/docs/public/og/setup-teardown.png differ diff --git a/apps/docs/public/og/sources.json b/apps/docs/public/og/sources.json new file mode 100644 index 0000000..a472deb --- /dev/null +++ b/apps/docs/public/og/sources.json @@ -0,0 +1,22 @@ +{ + "outputs.png": "73b81c839510f0431e5af2ae8909e71911d75c6122b3ebddcec598f4f178677a", + "profiling.png": "e74c3260aaca4326841f3bd991c8e9e480f8bf12429498fd9549549230eae59e", + "regressions.png": "965b5321e6b7c533ec5db5286602f2fba9a071de42eb2a23feff42f29481e39e", + "basic-example.png": "35f993c9163d6ea78d329bb9fed28f15bd930e9026d670cfc5a0238178ad51a1", + "ffi-example.png": "623605bae13c8a15c12770405205aa0a4bb289c5405f81f0a76459f7e80f1ee4", + "installation.png": "cb3666f44b7bfec5c68d066395dbabce575b7c07491bbabe5ab0ab468a2ccaa4", + "quickstart.png": "5db0d4816a68b79621a86cdd2b3bce84d973bac1cfb392152629eb5b390fdfd4", + "troubleshooting.png": "e71cc7ee9a207cc81ff4fecf4285f468faee5d217961420602b32ae029b065ae", + "index.png": "ad18990ca3ca52108cf766b65900cf05a9a2266acd8b207f007923f0a192cb63", + "cli.png": "024145b6b257f65425d4f01e02b4e6ac5e8d68e541ea3f92f5f549d803c36e2d", + "compatibility.png": "9851565dc082b36bb607903b21ac733a7e2a6ff769be2a5b2602d6cb739f21c3", + "configuration.png": "92e642d19cb8bbadaccd4d5c7f60d673d3717a5379fdb4b4985b5fd74adac094", + "device-matrices.png": "742e681a7b826deb6087413706b42b1d32c5ca42f060830d68ec96ed24e30f13", + "schemas.png": "e41a1020e0218ee161d85d850382bdef5b606caeda8d80f904f84259fa786486", + "browserstack.png": "c4002efad904f6efba71d83520f30d267ae3b11e81f889743c6892761a34646a", + "ci.png": "a93c3bc4fac01dc8949d026a1967e75fc8a5445177d038036de7fd3382afe932", + "host-preflight.png": "f5709a7b8078a0c8d801e15a71cf101ac397fcb121c823267fa57db7ea9c04a9", + "benchmark-functions.png": "f5855a3134d1d065bc7cf0277a32b82576060852054180ec769c395e81bf4e3f", + "benchmark-quality.png": "4a129d7bdd4656f3b359dd5766642d26d993e0c44c3d3ed8bbab8a52f8dbee6a", + "setup-teardown.png": "ba8e17c52b8f4ddeacdc7d277a093513bd36bd320a0dd8fe9afc3a1028a7d0ca" +} diff --git a/apps/docs/public/og/troubleshooting.png b/apps/docs/public/og/troubleshooting.png new file mode 100644 index 0000000..ad6c732 Binary files /dev/null and b/apps/docs/public/og/troubleshooting.png differ diff --git a/apps/docs/public/robots.txt b/apps/docs/public/robots.txt new file mode 100644 index 0000000..b33a489 --- /dev/null +++ b/apps/docs/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://docs.mobench.org/sitemap-index.xml diff --git a/apps/docs/public/schemas/ci-contract-v1.schema.json b/apps/docs/public/schemas/ci-contract-v1.schema.json new file mode 100644 index 0000000..6d1d5a4 --- /dev/null +++ b/apps/docs/public/schemas/ci-contract-v1.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/ci-contract-v1.schema.json", + "title": "Mobench CI Contract v1", + "type": "object", + "required": ["ci"], + "properties": { + "ci": { + "type": "object", + "required": ["metadata", "outputs"], + "properties": { + "metadata": { + "type": "object", + "required": ["requested_by", "request_command", "mobench_version"], + "properties": { + "requested_by": { "type": "string" }, + "pr_number": { "type": ["string", "null"] }, + "request_command": { "type": "string" }, + "mobench_ref": { "type": ["string", "null"] }, + "mobench_version": { "type": "string" } + } + }, + "outputs": { + "type": "object", + "required": ["summary_json", "summary_md", "results_csv"], + "properties": { + "summary_json": { "type": "string" }, + "summary_md": { "type": "string" }, + "results_csv": { "type": "string" } + } + } + } + } + }, + "additionalProperties": true +} diff --git a/apps/docs/public/schemas/mobench-site-manifest-v1.schema.json b/apps/docs/public/schemas/mobench-site-manifest-v1.schema.json new file mode 100644 index 0000000..74adf44 --- /dev/null +++ b/apps/docs/public/schemas/mobench-site-manifest-v1.schema.json @@ -0,0 +1,152 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://mobench.org/schemas/mobench-site-manifest-v1.schema.json", + "title": "Mobench website release manifest v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "release", + "msrv", + "binaries", + "command_tree", + "config", + "artifacts", + "schemas", + "capabilities", + "evidence" + ], + "properties": { + "schema_version": { "const": 1 }, + "release": { + "type": "object", + "additionalProperties": false, + "required": ["version", "tag", "sha", "repository"], + "properties": { + "version": { "type": "string", "minLength": 1 }, + "tag": { "type": "string", "pattern": "^v" }, + "sha": { "type": "string", "pattern": "^[0-9a-fA-F]{40}$" }, + "repository": { "type": "string", "format": "uri" } + } + }, + "msrv": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+" }, + "binaries": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/binary" } }, + "command_tree": { "$ref": "#/$defs/command" }, + "config": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/config" } }, + "artifacts": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/artifact" } }, + "schemas": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/schema" } }, + "capabilities": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/capability" } }, + "evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/evidence" } } + }, + "$defs": { + "status": { "enum": ["supported", "preview", "planned", "unsupported"] }, + "binary": { + "type": "object", + "additionalProperties": false, + "required": ["name", "invocation", "canonical_for_release", "status", "note"], + "properties": { + "name": { "type": "string" }, + "invocation": { "type": "string" }, + "canonical_for_release": { "type": "boolean" }, + "status": { "$ref": "#/$defs/status" }, + "note": { "type": "string" } + } + }, + "command": { + "type": "object", + "additionalProperties": false, + "required": ["name", "path", "about", "options", "subcommands"], + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "about": { "type": ["string", "null"] }, + "options": { "type": "array", "items": { "$ref": "#/$defs/option" } }, + "subcommands": { "type": "array", "items": { "$ref": "#/$defs/command" } } + } + }, + "option": { + "type": "object", + "additionalProperties": false, + "required": ["id", "long", "short", "positional_index", "required", "global", "hidden", "action", "value_names", "possible_values", "defaults", "environment", "help"], + "properties": { + "id": { "type": "string" }, + "long": { "type": ["string", "null"] }, + "short": { "type": ["string", "null"], "maxLength": 1 }, + "positional_index": { "type": ["integer", "null"], "minimum": 1 }, + "required": { "type": "boolean" }, + "global": { "type": "boolean" }, + "hidden": { "type": "boolean" }, + "action": { "type": "string" }, + "value_names": { "type": "array", "items": { "type": "string" } }, + "possible_values": { "type": "array", "items": { "type": "string" } }, + "defaults": { "type": "array", "items": { "type": "string" } }, + "environment": { "type": ["string", "null"] }, + "help": { "type": ["string", "null"] } + } + }, + "config": { + "type": "object", + "additionalProperties": false, + "required": ["file", "keys"], + "properties": { + "file": { "type": "string" }, + "keys": { "type": "array", "items": { "$ref": "#/$defs/configKey" } } + } + }, + "configKey": { + "type": "object", + "additionalProperties": false, + "required": ["path", "value_type", "required", "default", "evidence_id"], + "properties": { + "path": { "type": "string" }, + "value_type": { "type": "string" }, + "required": { "type": "boolean" }, + "default": {}, + "evidence_id": { "type": "string" } + } + }, + "artifact": { + "type": "object", + "additionalProperties": false, + "required": ["id", "path_pattern", "produced_by", "description", "evidence_id"], + "properties": { + "id": { "type": "string" }, + "path_pattern": { "type": "string" }, + "produced_by": { "type": "array", "items": { "type": "string" } }, + "description": { "type": "string" }, + "evidence_id": { "type": "string" } + } + }, + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["id", "path", "checksum_sha256"], + "properties": { + "id": { "type": "string" }, + "path": { "type": "string" }, + "checksum_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" } + } + }, + "capability": { + "type": "object", + "additionalProperties": false, + "required": ["id", "status", "summary", "evidence_ids"], + "properties": { + "id": { "type": "string" }, + "status": { "$ref": "#/$defs/status" }, + "summary": { "type": "string" }, + "evidence_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } } + } + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": ["id", "kind", "reference"], + "properties": { + "id": { "type": "string" }, + "kind": { "enum": ["source", "test"] }, + "reference": { "type": "string" } + } + } + } +} diff --git a/apps/docs/public/schemas/summary-v1.schema.json b/apps/docs/public/schemas/summary-v1.schema.json new file mode 100644 index 0000000..9f452ae --- /dev/null +++ b/apps/docs/public/schemas/summary-v1.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/summary-v1.schema.json", + "title": "Mobench Summary v1", + "type": "object", + "required": ["summary"], + "properties": { + "summary": { + "type": "object", + "required": [ + "generated_at", + "generated_at_unix", + "target", + "function", + "iterations", + "warmup", + "devices", + "device_summaries" + ], + "properties": { + "generated_at": { "type": "string" }, + "generated_at_unix": { "type": "integer" }, + "target": { "type": "string", "enum": ["android", "ios"] }, + "function": { "type": "string" }, + "iterations": { "type": "integer" }, + "warmup": { "type": "integer" }, + "devices": { + "type": "array", + "items": { "type": "string" } + }, + "device_summaries": { + "type": "array", + "items": { + "type": "object", + "required": ["device", "benchmarks"], + "properties": { + "device": { "type": "string" }, + "benchmarks": { + "type": "array", + "items": { + "type": "object", + "required": ["function", "samples"], + "properties": { + "function": { "type": "string" }, + "samples": { "type": "integer" }, + "mean_ns": { "type": ["integer", "null"] }, + "median_ns": { "type": ["integer", "null"] }, + "p95_ns": { "type": ["integer", "null"] }, + "min_ns": { "type": ["integer", "null"] }, + "max_ns": { "type": ["integer", "null"] }, + "resource_usage": { + "type": ["object", "null"], + "properties": { + "cpu_total_ms": { "type": ["integer", "null"] }, + "cpu_median_ms": { "type": ["integer", "null"] }, + "peak_memory_kb": { "type": ["integer", "null"] }, + "peak_memory_growth_kb": { "type": ["integer", "null"] }, + "process_peak_memory_kb": { "type": ["integer", "null"] }, + "total_pss_kb": { "type": ["integer", "null"] }, + "private_dirty_kb": { "type": ["integer", "null"] }, + "native_heap_kb": { "type": ["integer", "null"] }, + "java_heap_kb": { "type": ["integer", "null"] } + } + } + } + } + } + } + } + } + } + } + }, + "additionalProperties": true +} diff --git a/apps/docs/public/schemas/trace-events-v1.schema.json b/apps/docs/public/schemas/trace-events-v1.schema.json new file mode 100644 index 0000000..73e866e --- /dev/null +++ b/apps/docs/public/schemas/trace-events-v1.schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/trace-events-v1.schema.json", + "title": "Mobench Trace Events v1", + "type": "object", + "required": ["source", "total_duration_ns", "lanes"], + "properties": { + "source": { + "type": "object", + "required": ["kind", "profiler", "origin"], + "properties": { + "kind": { "type": "string" }, + "profiler": { "type": "string" }, + "origin": { "type": "string", "enum": ["local", "browserstack"] } + }, + "additionalProperties": false + }, + "total_duration_ns": { "type": "integer", "minimum": 0 }, + "lanes": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "label", "events"], + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "events": { + "type": "array", + "items": { + "type": "object", + "required": [ + "event_kind", + "start_offset_ns", + "end_offset_ns", + "frames", + "phase", + "iteration" + ], + "properties": { + "event_kind": { "type": "string" }, + "start_offset_ns": { "type": "integer", "minimum": 0 }, + "end_offset_ns": { "type": ["integer", "null"], "minimum": 0 }, + "frames": { + "type": "array", + "items": { "type": "string" } + }, + "phase": { "type": ["string", "null"] }, + "iteration": { "type": ["integer", "null"], "minimum": 0 } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false +} diff --git a/apps/docs/src/assets/logo.svg b/apps/docs/src/assets/logo.svg new file mode 100644 index 0000000..61f3089 --- /dev/null +++ b/apps/docs/src/assets/logo.svg @@ -0,0 +1,7 @@ + + mobench + + + + mobench + diff --git a/apps/docs/src/components/Head.astro b/apps/docs/src/components/Head.astro new file mode 100644 index 0000000..232b13c --- /dev/null +++ b/apps/docs/src/components/Head.astro @@ -0,0 +1,43 @@ +--- +import Default from '@astrojs/starlight/components/Head.astro' + +const route = Astro.locals.starlightRoute +const data = route.entry.data +const slug = route.entry.id === 'index' ? 'index' : route.entry.id +const canonical = Astro.url.href +const image = new URL(`/og/${slug}.png`, 'https://docs.mobench.org').href +const imageAlt = `${data.title} — mobench ${data.release ?? 'documentation'}` +const breadcrumbs = route.entry.id === 'index' + ? [{ '@type': 'ListItem', position: 1, name: 'mobench documentation', item: 'https://docs.mobench.org/' }] + : [ + { '@type': 'ListItem', position: 1, name: 'mobench documentation', item: 'https://docs.mobench.org/' }, + { '@type': 'ListItem', position: 2, name: data.title, item: canonical }, + ] +const structuredData = [ + { + '@context': 'https://schema.org', + '@type': 'TechArticle', + headline: data.title, + description: data.description, + url: canonical, + image, + dateModified: data.lastVerified instanceof Date ? data.lastVerified.toISOString().slice(0, 10) : undefined, + isPartOf: { '@type': 'WebSite', name: 'mobench docs', url: 'https://docs.mobench.org/' }, + about: { '@type': 'SoftwareApplication', name: 'mobench', softwareVersion: data.release }, + }, + { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: breadcrumbs, + }, +] +--- + + + + + + + + diff --git a/apps/docs/src/components/PageTitle.astro b/apps/docs/src/components/PageTitle.astro new file mode 100644 index 0000000..c26501f --- /dev/null +++ b/apps/docs/src/components/PageTitle.astro @@ -0,0 +1,53 @@ +--- +import Default from '@astrojs/starlight/components/PageTitle.astro' + +const route = Astro.locals.starlightRoute +const cleanPath = Astro.url.pathname.replace(/\/$/, '') +const markdownPath = cleanPath ? `${cleanPath}.md` : '/index.md' +const sourcePath = route.entry.filePath?.replace(/^.*?src\/content\/docs\//, '') ?? `${route.entry.id}.mdx` +const sourceUrl = `https://github.com/worldfnd/mobench.org/blob/main/apps/docs/src/content/docs/${sourcePath}` +--- + +
+ +
+ + + View source + + +

+
+
+ + + + diff --git a/apps/docs/src/content.config.ts b/apps/docs/src/content.config.ts new file mode 100644 index 0000000..cb83588 --- /dev/null +++ b/apps/docs/src/content.config.ts @@ -0,0 +1,36 @@ +import { defineCollection } from 'astro:content' +import { z } from 'astro/zod' +import { docsLoader } from '@astrojs/starlight/loaders' +import { docsSchema } from '@astrojs/starlight/schema' + +const sourceReference = z.object({ + label: z.string().min(1), + url: z.url(), + evidence: z.string().min(1).optional(), +}) + +const docs = defineCollection({ + loader: docsLoader(), + schema: docsSchema({ + extend: z.object({ + slug: z.string().regex(/^(?:index|[a-z0-9]+(?:-[a-z0-9]+)*)$/), + audience: z + .array(z.enum(['new-user', 'benchmark-author', 'ci-engineer', 'contributor'])) + .optional(), + release: z.string().optional(), + lastVerified: z.coerce.date().optional(), + sourceRefs: z.array(sourceReference).optional(), + aliases: z.array(z.string().startsWith('/')).default([]), + section: z.string().optional(), + order: z.number().int().nonnegative().optional(), + og: z + .object({ + image: z.string().startsWith('/'), + alt: z.string().min(1), + }) + .optional(), + }), + }), +}) + +export const collections = { docs } diff --git a/apps/docs/src/content/docs/analyze-results/outputs.mdx b/apps/docs/src/content/docs/analyze-results/outputs.mdx new file mode 100644 index 0000000..1eb1383 --- /dev/null +++ b/apps/docs/src/content/docs/analyze-results/outputs.mdx @@ -0,0 +1,85 @@ +--- +title: Outputs and metrics +slug: outputs +aliases: [/reports, /outputs-and-reports] +description: Understand mobench JSON, Markdown, CSV, plots, and optional resource values. +sidebar: + order: 1 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Analyze results +order: 1 +sourceRefs: + - label: BrowserStack metrics guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-metrics.md + evidence: Timing fields, resource columns, sources, and missing-value semantics. +--- + +Normal runs can write a JSON report with `--output`. CI runs always normalize results into a three-file contract, with plots when available. + +## CI contract + +| Path | Intended use | +| --- | --- | +| `summary.json` | Machine-readable results, metadata, baselines, and integrations | +| `summary.md` | Human review and CI job summaries | +| `results.csv` | Tables, notebooks, and external analysis | +| `plots/*.svg` | Optional visual summaries when plot rendering is available | + +Generate the contract with an explicit directory: + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --local-only \ + --plots auto \ + --output-dir target/mobench/ci +``` + +The example uses the host harness to demonstrate files; it does not produce mobile measurements. + +## Timing fields + +Results include a sample count and timing statistics such as: + +- `mean_ns` +- `median_ns` +- `p95_ns` +- `min_ns` +- `max_ns` + +Raw sample durations live in JSON where the report contract provides them. Compare nanosecond values as numbers; format units only at the presentation layer. + +## Optional resource fields + +CSV and summary data can include: + +- `cpu_total_ms` +- `cpu_median_ms` +- `peak_memory_kb` +- `peak_memory_growth_kb` +- `process_peak_memory_kb` + +These values depend on the runner, platform, device, and provider data. A blank CSV cell or absent JSON field means **unavailable**, not zero. Keep missing values out of averages and regression gates that assume measured data. + +## Inspect and render + +```bash +mobench summary target/mobench/results.json +mobench summary --format json target/mobench/results.json +mobench summary --format csv target/mobench/results.json +``` + +Render Markdown from a CI summary: + +```bash +mobench report summarize \ + --summary target/mobench/ci/summary.json \ + --plots auto +``` + +## Next step + +Store a representative `summary.json`, then configure [regression comparison](/regressions/). diff --git a/apps/docs/src/content/docs/analyze-results/profiling.mdx b/apps/docs/src/content/docs/analyze-results/profiling.mdx new file mode 100644 index 0000000..a9ee9d3 --- /dev/null +++ b/apps/docs/src/content/docs/analyze-results/profiling.mdx @@ -0,0 +1,94 @@ +--- +title: Local native profiling +slug: profiling +description: Capture Android and iOS native stacks and compare profile manifests locally. +sidebar: + order: 3 +audience: [benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Analyze results +order: 3 +sourceRefs: + - label: Profiling guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/profiling.md + evidence: Capability matrix, commands, requirements, and artifact layout. +--- + +Profiling is separate from repeated benchmark timing. Use it after a slowdown is reproducible and you need native stacks, flamegraphs, or semantic phase detail. + +## Supported combinations + +| Provider | Backend | Behavior in 0.1.43 | +| --- | --- | --- | +| `local` | `android-native` | Attempts `simpleperf` capture, symbolization, folded stacks, reports, and flamegraphs | +| `local` | `ios-instruments` | Attempts simulator-host `sample` capture, folded stacks, reports, and flamegraphs | +| `local` | `rust-tracing` | Writes a planned manifest/trace contract; native capture is not implemented | +| `browserstack` | Any native backend | Unsupported | + +BrowserStack benchmark runs may still contain timing and resource metrics. They do not provide retrievable native stack artifacts in this release. + +## Profile Android locally + +Requirements include `adb`, an Android NDK, `simpleperf`, NDK `llvm-addr2line`, and a local device or emulator. + +```bash +mobench profile run \ + --target android \ + --provider local \ + --backend android-native \ + --function bench_mobile::checksum \ + --output-dir target/mobench/profile \ + --trace-events-output target/mobench/profile/trace-events.json +``` + +## Profile iOS locally + +The current backend uses macOS `sample` against an iOS simulator-host process. It requires macOS, Xcode command-line tools, `xcrun`, `simctl`, and an installed simulator runtime. + +```bash +mobench profile run \ + --target ios \ + --provider local \ + --backend ios-instruments \ + --function bench_mobile::checksum \ + --output-dir target/mobench/profile +``` + +Use Xcode Instruments directly for deeper real-device investigations. + +## Read the bundle + +Common outputs include: + +- `profile.json` +- `summary.md` +- `artifacts/raw/…` +- `artifacts/processed/stacks.folded` +- `artifacts/processed/native-report.txt` +- `artifacts/processed/flamegraph.full.svg` +- `artifacts/processed/flamegraph.focused.svg` +- `artifacts/processed/flamegraph.html` +- `artifacts/semantic/phases.json` when phase data exists + +Render a manifest: + +```bash +mobench profile summarize \ + --profile target/mobench/profile/profile.json +``` + +## Compare two profiles + +```bash +mobench profile diff \ + --baseline target/mobench/profile/baseline/profile.json \ + --candidate target/mobench/profile/candidate/profile.json \ + --normalize +``` + +In differential Inferno flamegraphs, red is hotter in the candidate and blue is hotter in the baseline. + +## Next step + +Open `flamegraph.html`, confirm the capture status in `profile.json`, and correlate hot frames with the timing regression. diff --git a/apps/docs/src/content/docs/analyze-results/regressions.mdx b/apps/docs/src/content/docs/analyze-results/regressions.mdx new file mode 100644 index 0000000..31686b1 --- /dev/null +++ b/apps/docs/src/content/docs/analyze-results/regressions.mdx @@ -0,0 +1,74 @@ +--- +title: Regression comparison +slug: regressions +description: Compare compatible mobench summaries and gate meaningful slowdowns. +sidebar: + order: 2 +audience: [ci-engineer, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Analyze results +order: 2 +sourceRefs: + - label: BrowserStack CI guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md + evidence: Baseline sources, thresholds, JUnit output, and compare behavior. +--- + +Regression checks compare candidate timing summaries with a stored baseline. They are meaningful only when the benchmark, device, OS, build mode, and run counts are compatible. + +## Compare existing files + +```bash +mobench compare \ + --baseline baselines/android-summary.json \ + --candidate target/mobench/ci/summary.json \ + --output target/mobench/ci/comparison.md +``` + +Review the Markdown report before turning a threshold into a required check. + +## Compare during CI + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --baseline artifact:baselines/android-summary.json \ + --regression-threshold-pct 5 \ + --junit target/mobench/ci/junit.xml \ + --release \ + --output-dir target/mobench/ci +``` + +Baseline sources accept a local path, URL, or `artifact:` form. If a baseline resolves to the same path as the candidate output, mobench snapshots the previous file before writing the new result. + +## Choose a threshold + +Start with observed device-to-device and run-to-run variation rather than an arbitrary percentage. A good gate: + +- compares the same device and OS +- uses the same release profile and runner backend +- keeps iteration and warmup counts stable +- ignores unavailable resource values +- is rerun when a candidate sits near the threshold + +A single noisy result is a prompt to investigate, not proof of a code regression. + +## Publish results + +Render or publish a sticky pull-request comment from the standard summary: + +```bash +mobench report github \ + --pr 123 \ + --summary target/mobench/ci/summary.json \ + --publish +``` + +The default marker is ``, allowing later runs to update the same comment. + +## Next step + +When timing shows a repeatable slowdown, use [local profiling](/profiling/) to locate the hot path. diff --git a/apps/docs/src/content/docs/examples/basic.mdx b/apps/docs/src/content/docs/examples/basic.mdx new file mode 100644 index 0000000..a0007e3 --- /dev/null +++ b/apps/docs/src/content/docs/examples/basic.mdx @@ -0,0 +1,86 @@ +--- +title: Basic benchmark crate +slug: basic-example +aliases: [/examples] +description: Follow the minimal SDK example from registration to host and mobile execution. +sidebar: + order: 1 +audience: [new-user, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Examples +order: 1 +sourceRefs: + - label: Basic benchmark example + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/basic-benchmark/README.md + evidence: Minimal crate setup, registered functions, tests, and run commands. +--- + +The upstream `examples/basic-benchmark` crate is the smallest complete integration. It registers two realistic workloads, exposes mobile entrypoints, and keeps deterministic fixture output for tests. + +## Cargo setup + +```toml +[lib] +name = "basic_benchmark" +crate-type = ["lib", "cdylib", "staticlib"] + +[dependencies] +mobench-sdk = { version = "0.1.43", default-features = false, features = ["registry"] } +inventory = "0.3" +serde = { version = "1", features = ["derive"] } +thiserror = "1" +uniffi = { version = "0.28", features = ["cli"] } +``` + +Use dependency versions compatible with your lockfile; the key mobench requirement is matching the `0.1.43` SDK line. + +## Benchmark functions + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn bench_checksum() { + let bytes = std::hint::black_box(&INPUT); + let result = checksum_sweep(bytes, 8 * 1024, 2_048); + std::hint::black_box(result); +} +``` + +The upstream example uses deterministic, nontrivial input and enough repeated work to avoid a benchmark dominated by timer noise. + +## Test and discover + +From a checkout of `mobile-bench-rs`: + +```bash +cargo test -p basic-benchmark +mobench list --crate-path examples/basic-benchmark +``` + +Host-side preflight: + +```bash +mobench run \ + --crate-path examples/basic-benchmark \ + --target android \ + --function basic_benchmark::bench_fibonacci \ + --local-only +``` + +This validates the host harness only. For a mobile result, add an exact BrowserStack device and `--release`: + +```bash +mobench run \ + --crate-path examples/basic-benchmark \ + --target android \ + --function basic_benchmark::bench_fibonacci \ + --devices "Google Pixel 7-13.0" \ + --release \ + --output target/mobench/results.json +``` + +## Next step + +Copy the crate structure, replace one benchmark at a time, and confirm each new name with `mobench list`. diff --git a/apps/docs/src/content/docs/examples/ffi.mdx b/apps/docs/src/content/docs/examples/ffi.mdx new file mode 100644 index 0000000..4c6d2f6 --- /dev/null +++ b/apps/docs/src/content/docs/examples/ffi.mdx @@ -0,0 +1,88 @@ +--- +title: FFI benchmark crate +slug: ffi-example +description: Expose mobench benchmarks through UniFFI, the native C ABI, or BoltFFI. +sidebar: + order: 2 +audience: [benchmark-author, contributor] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Examples +order: 2 +sourceRefs: + - label: FFI benchmark example + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/ffi-benchmark/README.md + evidence: UniFFI types, native C ABI export, BoltFFI bridge, tests, and run flow. +--- + +The upstream `examples/ffi-benchmark` crate shows the full boundary between Rust benchmark registration and generated Kotlin or Swift runners. Start with the basic example unless your project needs custom cross-language types. + +## Default UniFFI path + +The compatibility backend serializes benchmark request and report types through generated UniFFI bindings. A crate can expose an entrypoint like: + +```rust +#[derive(uniffi::Record)] +pub struct BenchSpec { + pub name: String, + pub iterations: u32, + pub warmup: u32, +} + +uniffi::setup_scaffolding!(); + +#[uniffi::export] +pub fn run_benchmark(spec: BenchSpec) -> Result { + let sdk_spec = mobench_sdk::BenchSpec { + name: spec.name, + iterations: spec.iterations, + warmup: spec.warmup, + }; + Ok(mobench_sdk::run_benchmark(sdk_spec)?.into()) +} +``` + +The SDK also provides FFI-oriented types that can replace custom records for simpler projects. + +## Native C ABI path + +Configure `ffi_backend = "native-c-abi"` when generated runners should call the SDK's JSON C ABI directly: + +```rust +mobench_sdk::export_native_c_abi!(); +``` + +The generated runner calls `mobench_run_benchmark_json` and returns Rust-owned buffers through `mobench_free_buf`. Never free or reuse those buffers through another allocator. + +## BoltFFI path + +Projects using BoltFFI can expose the same JSON bridge: + +```rust +#[boltffi::export] +pub fn run_benchmark_json(spec_json: &str) -> Result { + let spec = serde_json::from_str(spec_json).map_err(|error| error.to_string())?; + let report = run_benchmark(spec).map_err(|error| error.to_string())?; + serde_json::to_string(&report).map_err(|error| error.to_string()) +} +``` + +Set `ffi_backend = "boltffi"` and ensure the BoltFFI generator is available to the build. + +## Exercise the example + +```bash +cargo test -p ffi-benchmark +mobench list --crate-path examples/ffi-benchmark +mobench run \ + --crate-path examples/ffi-benchmark \ + --target android \ + --function ffi_benchmark::bench_fibonacci \ + --local-only +``` + +The last command is a host preflight, not a mobile measurement. + +## Next step + +Select one backend, build both target platforms, and keep that backend fixed across your baseline and candidate runs. diff --git a/apps/docs/src/content/docs/get-started/installation.mdx b/apps/docs/src/content/docs/get-started/installation.mdx new file mode 100644 index 0000000..1689721 --- /dev/null +++ b/apps/docs/src/content/docs/get-started/installation.mdx @@ -0,0 +1,86 @@ +--- +title: Installation +slug: installation +aliases: [/install] +description: Install mobench 0.1.43 and prepare a Rust benchmark crate. +sidebar: + order: 1 +audience: [new-user, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Get started +order: 1 +sourceRefs: + - label: Upstream README quick start + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/README.md + evidence: CLI and SDK installation commands. +--- + +Install the `mobench` executable once, then add `mobench-sdk` to each crate that owns benchmark functions. + +## Requirements + +- Rust 1.85 or newer +- Cargo +- Android or iOS build tools only when you build for that platform +- BrowserStack App Automate credentials only when you run on remote devices + +Check your toolchain: + +```bash +rustc --version +cargo --version +``` + +## Install the CLI + +If you use `cargo-binstall`: + +```bash +cargo binstall mobench --version 0.1.43 +``` + +Or compile the release from crates.io: + +```bash +cargo install mobench --version 0.1.43 --locked +``` + +Confirm that the canonical executable is available: + +```bash +mobench --version +mobench --help +``` + +## Add the SDK + +From the benchmark crate: + +```bash +cargo add mobench-sdk@0.1.43 inventory +``` + +Mobile runners load your crate as a native library. Include the required crate types in `Cargo.toml`: + +```toml +[lib] +crate-type = ["lib", "cdylib", "staticlib"] +``` + +The default `mobench-sdk` features include registration, builders, and code generation. For a deliberately smaller integration, see the [compatibility reference](/compatibility/). + +## Install platform prerequisites + +Ask mobench for a platform-specific check before installing tools blindly: + +```bash +mobench check --target android +mobench check --target ios +``` + +Android builds use the Android SDK, Android NDK, `cargo-ndk`, and Rust Android targets. iOS builds require macOS, Xcode command-line tools, XcodeGen, and Rust iOS targets. + +## Next step + +Continue to the [quickstart](/quickstart/) and register your first benchmark function. diff --git a/apps/docs/src/content/docs/get-started/quickstart.mdx b/apps/docs/src/content/docs/get-started/quickstart.mdx new file mode 100644 index 0000000..75f62a5 --- /dev/null +++ b/apps/docs/src/content/docs/get-started/quickstart.mdx @@ -0,0 +1,96 @@ +--- +title: Quickstart +slug: quickstart +description: Register a Rust benchmark, validate it on the host, and run it on a mobile device. +sidebar: + order: 2 +audience: [new-user, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Get started +order: 2 +sourceRefs: + - label: Basic benchmark example + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/examples/basic-benchmark/README.md + evidence: Minimal SDK registration and CLI flow. +--- + +This path first proves that mobench can discover and report your function on the host. It then moves the same function to a BrowserStack device for the actual mobile measurement. + +## 1. Register a benchmark + +Add a public function to your library crate: + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn checksum() { + let bytes = std::hint::black_box(vec![42_u8; 64 * 1024]); + let sum: u64 = bytes.iter().map(|byte| u64::from(*byte)).sum(); + std::hint::black_box(sum); +} +``` + +Use enough work to rise above timer noise, and pass results through `black_box` so the optimizer cannot erase the operation. + +## 2. Confirm discovery + +From the project root, replace `bench-mobile` if your benchmark crate lives elsewhere: + +```bash +mobench list --crate-path bench-mobile +``` + +The output should include the fully qualified function name, such as `bench_mobile::checksum`. + +## 3. Run the host preflight + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --local-only \ + --iterations 20 \ + --warmup 5 \ + --output target/mobench/preflight.json +``` + +`--local-only` checks the host harness, discovery, and report path. It does not run Android code and must not be treated as a mobile result. + +Inspect the report: + +```bash +mobench summary target/mobench/preflight.json +``` + +## 4. Run on a mobile device + +Set your BrowserStack App Automate credentials: + +```bash +export BROWSERSTACK_USERNAME="your_username" +export BROWSERSTACK_ACCESS_KEY="your_access_key" +``` + +Choose a device that appears in `mobench devices --platform android`, then run: + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 20 \ + --warmup 5 \ + --release \ + --fetch \ + --output target/mobench/results.json +``` + +Using `--release` keeps the measured code optimized and reduces Android upload size. + +## Next step + +Read [benchmark quality](/benchmark-quality/) before using the result as a baseline. diff --git a/apps/docs/src/content/docs/help/troubleshooting.mdx b/apps/docs/src/content/docs/help/troubleshooting.mdx new file mode 100644 index 0000000..01b0ccf --- /dev/null +++ b/apps/docs/src/content/docs/help/troubleshooting.mdx @@ -0,0 +1,94 @@ +--- +title: Troubleshooting +slug: troubleshooting +aliases: [/testing, /codebase] +description: Diagnose discovery, toolchain, BrowserStack, result, and profiling failures. +sidebar: + order: 1 +audience: [new-user, benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Help +order: 1 +sourceRefs: + - label: Upstream testing guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/testing.md + evidence: Supported validation paths and platform smoke checks. +--- + +Start with the narrowest command that can reproduce the failure, add `--verbose`, and keep the generated output directory until you understand the error. + +## Benchmark does not appear in `list` + +1. Confirm the function has `#[benchmark]` and a supported signature. +2. Confirm the benchmark crate depends on `mobench-sdk` with the registry feature and on `inventory`. +3. Pass an explicit `--crate-path` when the workspace contains several libraries. +4. Run `cargo check` for compile-time macro errors. + +```bash +mobench --verbose list --crate-path crates/bench-mobile +``` + +## `--local-only` succeeds but the device run fails + +That result is expected when the failure is in mobile compilation, packaging, signing, upload, or the generated runner. `--local-only` skips all of those layers. + +Run the platform checks and build separately: + +```bash +mobench check --target android +mobench build --target android --release --progress +mobench verify --target android --check-artifacts +``` + +For iOS, also verify Xcode, XcodeGen, signing, deployment target, and runner compatibility. + +## BrowserStack credentials or device fail + +```bash +mobench doctor --target both --browserstack true +mobench devices --validate "Google Pixel 7-13.0" +``` + +Check that the credentials are App Automate credentials, the device identifier still exists, and the app deployment target does not exceed the selected iOS version. + +## Upload times out + +Build and run with `--release`. Debug Android artifacts can be much larger. If the build was accepted but result polling expired, fetch it later with the BrowserStack build ID. + +## Result has no CPU or memory value + +Resource metrics are optional and vary by runner and provider availability. Missing means unavailable, not zero. Keep the timing result and resource availability as separate facts. + +## CI output is in the wrong place + +`ci run` and `profile run` use `--output-dir`. A normal `run` uses `--output` for its JSON report. + +```bash +mobench ci run --help +mobench profile run --help +mobench run --help +``` + +## Profiling writes no native capture + +Check the provider/backend combination first. BrowserStack native profiling is unsupported, and `rust-tracing` is only a planned manifest/trace contract in 0.1.43. + +For Android, confirm `adb`, `simpleperf`, the NDK, and `llvm-addr2line`. For iOS, confirm a simulator runtime, `xcrun`, `simctl`, and macOS `sample`. Read the capture status and warnings in `profile.json`; do not treat a planned or partial capture as complete. + +## Still stuck + +Capture these facts before opening an upstream issue: + +- `mobench --version` and `rustc --version` +- the smallest failing command with secrets removed +- platform and device identifier +- relevant `mobench.toml` and `bench-config.toml` sections +- verbose output and generated artifact paths +- whether host preflight, build, upload, execution, or fetch failed + +Contributor architecture and release-maintenance documentation belongs in the [upstream repository](https://github.com/worldcoin/mobile-bench-rs), not in the product guide. + +## Next step + +Re-run the narrow failing command with `--verbose`, then attach the sanitized evidence to an upstream issue. diff --git a/apps/docs/src/content/docs/index.mdx b/apps/docs/src/content/docs/index.mdx new file mode 100644 index 0000000..963f9a2 --- /dev/null +++ b/apps/docs/src/content/docs/index.mdx @@ -0,0 +1,55 @@ +--- +title: mobench documentation +slug: index +aliases: [/docs, /overview] +description: Build, run, and analyze Rust benchmarks on Android and iOS. +audience: [new-user, benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Overview +order: 0 +sourceRefs: + - label: Upstream README + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/README.md + evidence: Product scope, workflow, release, and supported backends. +--- + +mobench takes a Rust benchmark from a function in your crate to repeatable results on Android and iOS. It builds native libraries, generates mobile runners, executes them on selected BrowserStack devices, and writes artifacts that people and CI can compare. + +The current documentation describes mobench **0.1.43** and requires Rust **1.85 or newer**. + +## Choose a starting point + +| Goal | Start here | +| --- | --- | +| Install the CLI and SDK | [Installation](/installation/) | +| Get one benchmark running | [Quickstart](/quickstart/) | +| Write trustworthy benchmark functions | [Benchmark functions](/benchmark-functions/) | +| Validate a project without using a device farm | [Host-side preflight](/host-preflight/) | +| Run on Android or iOS devices | [BrowserStack](/browserstack/) | +| Add a stable CI contract | [CI runs](/ci/) | +| Interpret artifacts and compare revisions | [Outputs](/outputs/) | +| Capture native stacks locally | [Profiling](/profiling/) | + +## What mobench measures + +Normal benchmark runs record measured iteration durations. CPU time and memory fields may also be present when the runner or provider can collect them. Missing resource values mean **unavailable**, not zero. + +Native stack profiling is a separate, local-first workflow. Android uses `simpleperf`; iOS uses simulator-host `sample`. BrowserStack native profiling is not supported in 0.1.43. + +## The execution boundary + +Selecting devices makes `mobench run` build and schedule a real mobile benchmark through BrowserStack. `--local-only` skips mobile builds and writes host-side preflight/spec output without executing the requested benchmark. Use it to validate discovery, configuration, and report shape—not as evidence of mobile performance. + +## Stable outputs + +`mobench ci run` writes a reusable contract: + +- `summary.json` for machines and comparisons +- `summary.md` for people and CI job summaries +- `results.csv` for analysis tools +- `plots/*.svg` when plotting is available + +## Next step + +[Install mobench](/installation/), then complete the quickstart before adding a device matrix or CI workflow. diff --git a/apps/docs/src/content/docs/reference/cli.mdx b/apps/docs/src/content/docs/reference/cli.mdx new file mode 100644 index 0000000..af6a294 --- /dev/null +++ b/apps/docs/src/content/docs/reference/cli.mdx @@ -0,0 +1,445 @@ +--- +title: CLI reference +slug: cli +aliases: [/cli-reference, /cli-man-pages] +description: Find mobench commands and the flags that connect authoring, execution, CI, and profiling. +sidebar: + order: 1 +tableOfContents: + minHeadingLevel: 2 + maxHeadingLevel: 2 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Reference +order: 1 +sourceRefs: + - label: CLI definitions + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/crates/mobench/src/cli.rs + evidence: Clap command, subcommand, argument, default, and enum definitions. +--- + +The canonical executable is `mobench`. Run `mobench --help` against your installed version for the complete generated argument reference. + +{/* BEGIN GENERATED CLI REFERENCE */} +{/* Generated from @mobench/truth. Do not edit this section by hand. */} + +## Global flags + +| Flag | Value | Default | Purpose | +| --- | --- | --- | --- | +| `--dry-run` | boolean | false | Print what would be done without actually doing it | +| `--non-interactive` | boolean | false | Disable interactive prompts (fail instead) | +| `-v`, `--verbose` | boolean | false | Print verbose output including all commands | +| `--yes` | boolean | false | Assume yes to prompts and allow overwriting files | + +The generated CLI also provides `--help`, `-h`, `--version`, and `-V` where Clap exposes them. + +## Command index + +| Command | Purpose | +| --- | --- | +| `mobench build` | Build mobile artifacts from the resolved benchmark crate | +| `mobench check` | Check prerequisites for building mobile artifacts | +| `mobench ci` | CI helpers (workflow and action scaffolding) | +| `mobench ci check-run` | Create a GitHub Check Run with benchmark results | +| `mobench ci init` | Generate GitHub Actions workflow + local action wrapper | +| `mobench ci merge-split-runs` | Merge one-sample CI summaries into a normal CI output set | +| `mobench ci run` | Run a full CI benchmark flow with stable output contract | +| `mobench ci summarize` | Summarize benchmark results with device metrics | +| `mobench compare` | Compare two run summaries for regressions | +| `mobench config` | Validate run configuration and associated files | +| `mobench config validate` | Validate bench-config.toml and referenced matrix/settings | +| `mobench devices` | List available BrowserStack devices for testing | +| `mobench devices resolve` | Resolve devices from a matrix deterministically for CI usage | +| `mobench doctor` | Validate local + CI prerequisites and configuration | +| `mobench fetch` | Fetch BrowserStack build artifacts (logs, session JSON) for CI | +| `mobench fixture` | Fixture lifecycle helpers for reproducible CI setup | +| `mobench fixture build` | Build fixture artifacts using existing build commands | +| `mobench fixture cache-key` | Compute deterministic fixture cache key from config/toolchain inputs | +| `mobench fixture init` | Create starter fixture files for CI runs | +| `mobench fixture verify` | Verify fixture files and optional profile filtering | +| `mobench fixture verify-plots` | Render and verify checked-in plot fixtures | +| `mobench init` | Scaffold a base config file for the CLI | +| `mobench init-sdk` | Initialize a new benchmark project with the SDK templates | +| `mobench list` | List all discovered benchmark functions | +| `mobench package-ipa` | Package iOS app as IPA for distribution or testing | +| `mobench package-xcuitest` | Package XCUITest runner for BrowserStack testing | +| `mobench plan` | Generate a sample device matrix file | +| `mobench profile` | Profiling helpers for native profile capture and summary rendering | +| `mobench profile diff` | Generate a differential flamegraph bundle from two normalized profile manifests | +| `mobench profile run` | Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture | +| `mobench profile summarize` | Render markdown or JSON from a normalized profile manifest | +| `mobench report` | Reporting helpers for CI summaries and PR comments | +| `mobench report github` | Generate/publish sticky GitHub PR comment from summary output | +| `mobench report summarize` | Generate markdown summary from standardized output JSON | +| `mobench run` | Build mobile artifacts, write host preflight output, or run on BrowserStack devices | +| `mobench summary` | Display summary statistics from a benchmark report JSON file | +| `mobench verify` | Verify benchmark setup: registry, spec, artifacts, and optional smoke test | + +## Complete command flag index + +Global flags above are omitted from each command row. Positional arguments use angle brackets. + +### `mobench build` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate (default: auto-detect bench-mobile/ or crates/{crate}) | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--release` | boolean | default: false | Build in release mode | +| `--target` | `android \| both \| ios` | required | — | + +### `mobench check` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--format` | `json \| text` | default: text | Output format (text or json) | +| `-t`, `--target` | `android \| both \| ios` | required | Target platform (android or ios) | + +### `mobench ci check-run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--annotation-path` | `ANNOTATION_PATH` | default: src/lib.rs | File path used in Check Run annotations (relative to repo root) | +| `--baseline` | `BASELINE` | optional | Optional baseline JSON for regression detection | +| `--name` | `NAME` | default: Mobench | Check Run name displayed in the PR | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage | +| `--repo` | `REPO` | required | GitHub repository (owner/repo format) | +| `--results` | `RESULTS` | optional | Path to summary JSON with benchmark results | +| `--results-dir` | `RESULTS_DIR` | optional | Directory containing summary JSON files (processes all) | +| `--sha` | `SHA` | required | Git commit SHA to annotate | + +### `mobench ci init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--action-dir` | `ACTION_DIR` | default: .github/actions/mobench | Directory to write the local GitHub Action | +| `--workflow` | `WORKFLOW` | default: .github/workflows/mobile-bench.yml | Path to write the workflow file | + +### `mobench ci merge-split-runs` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--device` | `DEVICE` | required | Device label all samples must match | +| `--function` | `FUNCTION` | required | Fully-qualified benchmark function all samples must contain | +| `--iterations` | `ITERATIONS` | required | Expected measured sample count | +| `--output-dir` | `OUTPUT_DIR` | required | Directory to write merged summary.json, summary.md, and results.csv | +| `--samples-dir` | `SAMPLES_DIR` | required | Directory containing sample-*/summary.json one-sample CI outputs | +| `--warmup` | `WARMUP` | default: 0 | Warmup count reported in merged CI summaries | + +### `mobench ci run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--android-benchmark-timeout-secs` | `ANDROID_BENCHMARK_TIMEOUT_SECS` | optional | Android benchmark watchdog timeout in seconds for the generated harness | +| `--android-heartbeat-interval-secs` | `ANDROID_HEARTBEAT_INTERVAL_SECS` | optional | Android benchmark heartbeat interval in seconds for the generated harness | +| `--baseline` | `BASELINE` | optional | Baseline summary source (path\|url\|artifact:<path>) | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Device matrix YAML file to load device names from | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--devices` | `DEVICES` | optional | Device identifiers or labels (BrowserStack devices) | +| `--fetch` | boolean | default: false | Fetch BrowserStack artifacts after the run completes | +| `--fetch-output-dir` | `FETCH_OUTPUT_DIR` | default: target/browserstack | — | +| `--fetch-poll-interval-secs` | `FETCH_POLL_INTERVAL_SECS` | default: 5 | — | +| `--fetch-timeout-secs` | `FETCH_TIMEOUT_SECS` | default: 300 | — | +| `--function` | `FUNCTION` | optional | Fully-qualified Rust function to benchmark (single function) | +| `--functions` | `FUNCTIONS` | optional | Multiple benchmark functions (comma-separated or JSON array). Runs each in sequence. | +| `--ios-app` | `IOS_APP` | optional | Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--ios-test-suite` | `IOS_TEST_SUITE` | optional | Path to iOS XCUITest test suite package (.zip or .ipa) | +| `--iterations` | `ITERATIONS` | default: 100 | — | +| `--junit` | `JUNIT` | optional | Write JUnit XML report to the given path | +| `--local-only` | boolean | default: false | Skip mobile builds and write host-side preflight/spec output without mobile execution | +| `--mobench-ref` | `MOBENCH_REF` | optional | Metadata: git ref/sha for this mobench invocation | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/ci | Output directory for CI contract files | +| `--plots` | `auto \| off \| require` | default: auto | — | +| `--pr-number` | `PR_NUMBER` | optional | Metadata: pull request number | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage when comparing to baseline | +| `--release` | boolean | default: false | Build in release mode (recommended for BrowserStack to reduce APK size and upload time) | +| `--request-command` | `REQUEST_COMMAND` | optional | Metadata: original command requested by the caller | +| `--requested-by` | `REQUESTED_BY` | optional | Metadata: user or actor that requested the run | +| `--target` | `android \| both \| ios` | required | — | +| `--warmup` | `WARMUP` | default: 10 | — | + +### `mobench ci summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--build-id` | `BUILD_ID` | optional | BrowserStack build ID to enrich results with device metrics (requires --results-dir) | +| `--output-file` | `OUTPUT_FILE` | optional | Write output to file in addition to stdout | +| `--output-format` | `json \| markdown \| table` | default: table | Output format: table (terminal), markdown, or json | +| `--platform` | `android \| ios` | optional | Platform filter (show only one platform) | +| `--results-dir` | `RESULTS_DIR` | optional | Directory containing summary.json/CSV results (offline mode) | + +### `mobench compare` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--baseline` | `BASELINE` | required | Baseline JSON summary to compare against | +| `--candidate` | `CANDIDATE` | required | Candidate JSON summary to compare | +| `--output` | `OUTPUT` | optional | Optional output path for markdown report | + +### `mobench config validate` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--format` | `json \| text` | default: text | — | + +### `mobench devices` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--json` | boolean | default: false | Output as JSON | +| `--platform` | `android \| ios` | optional | Filter by platform (android or ios) | +| `--validate` | `VALIDATE` | optional | Validate device specs against available devices | + +### `mobench devices resolve` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | optional | Path to run config file (optional source for matrix/tags) | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Path to device matrix YAML file | +| `--format` | `json \| text` | default: text | — | +| `--platform` | `android \| ios` | required | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to resolve (defaults to `default`) | + +### `mobench doctor` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--browserstack` | `false \| true` | default: true | Validate BrowserStack credentials | +| `--config` | `CONFIG` | optional | Optional path to run config file to validate | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Optional path to device matrix YAML file to validate | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--format` | `json \| text` | default: text | — | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fetch` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--build-id` | `BUILD_ID` | required | — | +| `--output-dir` | `OUTPUT_DIR` | default: target/browserstack | — | +| `--poll-interval-secs` | `POLL_INTERVAL_SECS` | default: 10 | — | +| `--target` | `android \| ios` | required | — | +| `--timeout-secs` | `TIMEOUT_SECS` | default: 1800 | — | +| `--wait` | boolean | default: true | — | + +### `mobench fixture build` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to benchmark crate | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--release` | boolean | default: false | Build in release mode | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture cache-key` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | optional | — | +| `--format` | `json \| text` | default: text | — | +| `--profile` | `PROFILE` | optional | Device profile/tag for keying | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | default: device-matrix.yaml | — | +| `--force` | boolean | default: false | Overwrite existing fixture files | + +### `mobench fixture verify` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--config` | `CONFIG` | default: bench-config.toml | — | +| `--device-matrix` | `DEVICE_MATRIX` | optional | — | +| `--format` | `json \| text` | default: text | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to verify | +| `--target` | `android \| both \| ios` | default: both | — | + +### `mobench fixture verify-plots` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `` | `basic \| ffi` | required | — | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for rendered fixture artifacts (defaults under target/mobench/plot-fixtures) | + +### `mobench init` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | default: bench-config.toml | — | +| `--target` | `android \| ios` | default: android | — | + +### `mobench init-sdk` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--examples` | boolean | default: false | Generate example benchmarks | +| `--output-dir` | `OUTPUT_DIR` | default: . | — | +| `--project-name` | `PROJECT_NAME` | default: bench-project | — | +| `--target` | `android \| both \| ios` | required | — | + +### `mobench list` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | + +### `mobench package-ipa` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--method` | `adhoc \| development` | default: adhoc | Signing method | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--scheme` | `SCHEME` | default: BenchRunner | Xcode scheme to build | + +### `mobench package-xcuitest` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--scheme` | `SCHEME` | default: BenchRunner | Xcode scheme to build | + +### `mobench plan` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | default: device-matrix.yaml | — | + +### `mobench profile diff` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--baseline` | `BASELINE` | required | Path to the baseline profile.json manifest | +| `--candidate` | `CANDIDATE` | required | Path to the candidate profile.json manifest | +| `--normalize` | boolean | default: false | Normalize baseline sample counts to candidate totals before diffing | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/profile/diff | Output directory for differential profile artifacts | + +### `mobench profile run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--backend` | `android-native \| auto \| ios-instruments \| rust-tracing` | default: auto | — | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device` | `DEVICE` | optional | Explicit BrowserStack device name to resolve for this profiling request | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Path to device matrix YAML file used with --profile or config-based device tags | +| `--format` | `both \| native \| processed` | default: both | — | +| `--function` | `FUNCTION` | required | Fully-qualified Rust function to profile | +| `--os-version` | `OS_VERSION` | optional | OS version for --device (for example `16` or `14.0`) | +| `--output-dir` | `OUTPUT_DIR` | default: target/mobench/profile | — | +| `--profile` | `PROFILE` | optional | Device profile/tag to resolve (for example `high-spec`) | +| `--provider` | `browserstack \| local` | default: local | — | +| `--target` | `android \| ios` | required | — | +| `--trace-events-output` | `TRACE_EVENTS_OUTPUT` | optional | Write machine-readable trace/event JSON to this path for downstream consumers | +| `--warmup-mode` | `cold \| warm` | optional | Warm or cold capture mode for local native profiling (defaults to warm for local Android/iOS native backends) | + +### `mobench profile summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | optional | — | +| `--output-format` | `json \| markdown` | default: markdown | — | +| `--profile` | `PROFILE` | default: target/mobench/profile/profile.json | — | + +### `mobench report github` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--marker` | `MARKER` | default: <!-- mobench-report --> | — | +| `--output` | `OUTPUT` | optional | Write generated comment body to file | +| `--pr` | `PR` | optional | Pull request number (auto-detected from GITHUB_REF if omitted) | +| `--publish` | boolean | default: false | Publish via GitHub API using GITHUB_TOKEN | +| `--summary` | `SUMMARY` | default: target/mobench/ci/summary.json | — | + +### `mobench report summarize` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--output` | `OUTPUT` | optional | Write markdown output to file | +| `--plots` | `auto \| off \| require` | default: auto | — | +| `--summary` | `SUMMARY` | default: target/mobench/ci/summary.json | — | + +### `mobench run` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--android-benchmark-timeout-secs` | `ANDROID_BENCHMARK_TIMEOUT_SECS` | optional | Android benchmark watchdog timeout in seconds for the generated harness | +| `--android-heartbeat-interval-secs` | `ANDROID_HEARTBEAT_INTERVAL_SECS` | optional | Android benchmark heartbeat interval in seconds for the generated harness | +| `--baseline` | `BASELINE` | optional | Baseline summary source (path\|url\|artifact:<path>) | +| `--ci` | boolean | default: false | Enable CI mode (job summary, optional JUnit, regression exit codes) | +| `--config` | `CONFIG` | optional | Optional path to config file | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--device-matrix` | `DEVICE_MATRIX` | optional | Device matrix YAML file to load device names from | +| `--device-tags` | `DEVICE_TAGS` | optional | Device tags to select from the device matrix (comma-separated or repeatable) | +| `--devices` | `DEVICES` | optional | Device identifiers or labels (BrowserStack devices) | +| `--fetch` | boolean | default: false | Fetch BrowserStack artifacts after the run completes | +| `--fetch-output-dir` | `FETCH_OUTPUT_DIR` | default: target/browserstack | — | +| `--fetch-poll-interval-secs` | `FETCH_POLL_INTERVAL_SECS` | default: 5 | — | +| `--fetch-timeout-secs` | `FETCH_TIMEOUT_SECS` | default: 300 | — | +| `--function` | `FUNCTION` | optional | Fully-qualified Rust function to benchmark | +| `--ios-app` | `IOS_APP` | optional | Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest | +| `--ios-deployment-target` | `IOS_DEPLOYMENT_TARGET` | optional | iOS deployment target for generated app and XCUITest targets | +| `--ios-runner` | `swiftui \| uikit-legacy` | optional | iOS runner template (swiftui or uikit-legacy) | +| `--ios-test-suite` | `IOS_TEST_SUITE` | optional | Path to iOS XCUITest test suite package (.zip or .ipa) | +| `--iterations` | `ITERATIONS` | optional | — | +| `--junit` | `JUNIT` | optional | Write JUnit XML report to the given path | +| `--local-only` | boolean | default: false | Skip mobile builds and write host-side preflight/spec output without mobile execution | +| `--output` | `OUTPUT` | optional | Optional output path for JSON report | +| `--progress` | boolean | default: false | Show simplified step-by-step progress output | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--regression-threshold-pct` | `REGRESSION_THRESHOLD_PCT` | default: 5 | Regression threshold percentage when comparing to baseline | +| `--release` | boolean | default: false | Build in release mode (recommended for BrowserStack to reduce APK size and upload time) | +| `--summary-csv` | boolean | default: false | Write CSV summary alongside JSON | +| `--target` | `android \| ios` | optional | — | +| `--warmup` | `WARMUP` | optional | — | + +### `mobench summary` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--format` | `csv \| json \| text` | optional | Output format: text (default), json, or csv | +| `` | `REPORT` | required | Path to the benchmark report JSON file | + +### `mobench verify` + +| Flag or argument | Value | Requirement | Purpose | +| --- | --- | --- | --- | +| `--check-artifacts` | boolean | default: false | Check that build artifacts exist | +| `--crate-path` | `CRATE_PATH` | optional | Path to the benchmark crate directory containing Cargo.toml | +| `--function` | `FUNCTION` | optional | Function name to verify/smoke test | +| `--output-dir` | `OUTPUT_DIR` | optional | Output directory for mobile artifacts (default: target/mobench) | +| `--project-root` | `PROJECT_ROOT` | optional | Project root containing mobench.toml or the Cargo workspace | +| `--smoke-test` | boolean | default: false | Run a local smoke test with minimal iterations | +| `--spec-path` | `SPEC_PATH` | optional | Path to bench_spec.json to validate | +| `--target` | `android \| both \| ios` | optional | Target platform to verify artifacts for | + + +{/* END GENERATED CLI REFERENCE */} + +`ci run` uses `--output-dir`, which defaults to `target/mobench/ci`. Its core outputs are `summary.json`, `summary.md`, and `results.csv`. `profile run` also uses `--output-dir`, defaulting to `target/mobench/profile`. BrowserStack native profiling is unsupported in 0.1.43. + +## Next step + +Run `mobench run --help` and save a minimal invocation in your repository's benchmark README. diff --git a/apps/docs/src/content/docs/reference/compatibility.mdx b/apps/docs/src/content/docs/reference/compatibility.mdx new file mode 100644 index 0000000..a488106 --- /dev/null +++ b/apps/docs/src/content/docs/reference/compatibility.mdx @@ -0,0 +1,70 @@ +--- +title: Compatibility +slug: compatibility +aliases: [/build, /build-artifacts, /sdk, /sdk-integration, /public-api] +description: Match Rust, platform tools, devices, and generated runner backends to mobench 0.1.43. +sidebar: + order: 5 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Reference +order: 5 +sourceRefs: + - label: Build guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/build.md + evidence: Rust and platform prerequisites, targets, outputs, and generated backends. +--- + +mobench 0.1.43 has a Rust MSRV of **1.85**. Mobile compatibility also depends on the platform toolchain, target architecture, runner backend, and selected device OS. + +## Android + +Typical requirements: + +- Android SDK and NDK +- `cargo-ndk` +- `ANDROID_NDK_HOME` or discoverable SDK installation +- Rust targets such as `aarch64-linux-android`, `armv7-linux-androideabi`, and `x86_64-linux-android` + +The generated project defaults to Android min SDK 24, target SDK 34, and `arm64-v8a` unless configured otherwise. Set `UNIFFI_ANDROID_ABI=x86_64` when exercising the UniFFI path on a default x86_64 emulator. + +## iOS + +Typical requirements: + +- macOS +- Xcode command-line tools +- XcodeGen +- Rust targets `aarch64-apple-ios`, `aarch64-apple-ios-sim`, and `x86_64-apple-ios` + +The default deployment target is iOS 15.0 with the SwiftUI runner. Lower targets use `uikit-legacy` and need an Xcode release capable of building for that OS. BrowserStack device OS must be at least the app deployment target. + +## Generated runner backends + +| Backend | Use when | Integration requirement | +| --- | --- | --- | +| `uniffi` | You want the default compatibility path | UniFFI types and generated Kotlin/Swift bindings | +| `native-c-abi` | Binding overhead must stay out of measured work | Export `mobench_sdk::export_native_c_abi!()` | +| `boltffi` | The project already uses BoltFFI generation | Export the JSON bridge with `#[boltffi::export]` and provide BoltFFI tooling | + +Keep the backend constant across a baseline and candidate; changing it changes the execution path. + +## Profiling compatibility + +- Android native profiling is local and uses `simpleperf`. +- iOS profiling is local, simulator-host oriented, and uses macOS `sample`. +- `rust-tracing` is a planned manifest/trace contract only. +- BrowserStack native profiling is unsupported in 0.1.43. + +## Check the current machine + +```bash +mobench check --target android +mobench check --target ios +mobench doctor --target both +``` + +## Next step + +Run the platform check on the same machine image used by CI, then save its toolchain versions with your first baseline. diff --git a/apps/docs/src/content/docs/reference/configuration.mdx b/apps/docs/src/content/docs/reference/configuration.mdx new file mode 100644 index 0000000..36a42ec --- /dev/null +++ b/apps/docs/src/content/docs/reference/configuration.mdx @@ -0,0 +1,147 @@ +--- +title: Configuration +slug: configuration +aliases: [/concepts] +description: Configure project builds separately from benchmark run and provider settings. +sidebar: + order: 2 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Reference +order: 2 +sourceRefs: + - label: Current configuration specification + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md + evidence: Project config, run config, resolution order, and examples. +--- + +mobench uses two TOML files for different concerns: + +- `mobench.toml` describes the benchmark crate and generated mobile projects. +- `bench-config.toml` describes a run, device selection, and BrowserStack settings. + +Keeping them separate lets one project support several CI matrices without duplicating build identity. + +{/* BEGIN GENERATED CONFIG REFERENCE */} +{/* Generated from @mobench/truth. Do not edit this section by hand. */} + +## Published configuration keys + +These are the complete configuration keys in the pinned release contract. Example files below may use only a task-specific subset. + +### `mobench.toml` + +| Key | Value | Required | Default | Evidence | +| --- | --- | --- | --- | --- | +| `project.crate` | `string|null` | no | — | `source-mobench-config` | +| `project.library_name` | `string|null` | no | — | `source-mobench-config` | +| `project.output_dir` | `path|null` | no | — | `source-mobench-config` | +| `android.package` | `string` | no | dev.world.bench | `source-mobench-config` | +| `android.min_sdk` | `integer` | no | 24 | `source-mobench-config` | +| `android.target_sdk` | `integer` | no | 34 | `source-mobench-config` | +| `android.abis` | `string[]|null` | no | — | `source-mobench-config` | +| `ios.bundle_id` | `string` | no | dev.world.bench | `source-mobench-config` | +| `ios.deployment_target` | `string` | no | 15.0 | `source-mobench-config` | +| `ios.team_id` | `string|null` | no | — | `source-mobench-config` | +| `benchmarks.default_function` | `string|null` | no | — | `source-mobench-config` | +| `benchmarks.default_iterations` | `integer` | no | 100 | `source-mobench-config` | +| `benchmarks.default_warmup` | `integer` | no | 10 | `source-mobench-config` | +| `browserstack.ios_completion_timeout_secs` | `integer|null` | no | — | `source-mobench-config` | + +### `bench-config.toml` + +| Key | Value | Required | Default | Evidence | +| --- | --- | --- | --- | --- | +| `target` | `android|ios` | yes | — | `source-bench-config` | +| `function` | `string` | yes | — | `source-bench-config` | +| `iterations` | `integer` | yes | — | `source-bench-config` | +| `warmup` | `integer` | yes | — | `source-bench-config` | +| `device_matrix` | `path` | yes | — | `source-bench-config` | +| `device_tags` | `string[]|null` | no | — | `source-bench-config` | +| `browserstack.app_automate_username` | `string` | yes | — | `source-bench-config` | +| `browserstack.app_automate_access_key` | `string` | yes | — | `source-bench-config` | +| `browserstack.project` | `string|null` | no | — | `source-bench-config` | +| `browserstack.ios_completion_timeout_secs` | `integer|null` | no | — | `source-bench-config` | +| `browserstack.android_benchmark_timeout_secs` | `integer|null` | no | — | `source-bench-config` | +| `browserstack.android_heartbeat_interval_secs` | `integer|null` | no | — | `source-bench-config` | +| `ios_xcuitest.app` | `path` | no | — | `source-bench-config` | +| `ios_xcuitest.test_suite` | `path` | no | — | `source-bench-config` | + +{/* END GENERATED CONFIG REFERENCE */} + +## Project configuration + +Place `mobench.toml` at the project or workspace root: + +```toml test=config:mobench.toml +[project] +crate = "bench-mobile" +library_name = "bench_mobile" +output_dir = "target/mobench" + +[android] +package = "com.example.bench" +min_sdk = 24 +target_sdk = 34 +abis = ["arm64-v8a"] + +[ios] +bundle_id = "com.example.bench" +deployment_target = "15.0" +team_id = "ABCDE12345" + +[benchmarks] +default_function = "bench_mobile::checksum" +default_iterations = 100 +default_warmup = 10 +``` + +The pinned release contract defines only the keys shown above for generated project identity and build defaults. Runner-backend selection is not a published `mobench.toml` key in 0.1.43. + +## Run configuration + +Use `bench-config.toml` for a repeatable run: + +```toml test=config:bench-config.toml +target = "android" +function = "bench_mobile::checksum" +iterations = 100 +warmup = 10 +device_matrix = "device-matrix.yaml" +device_tags = ["default"] + +[browserstack] +app_automate_username = "${BROWSERSTACK_USERNAME}" +app_automate_access_key = "${BROWSERSTACK_ACCESS_KEY}" +project = "mobile-benchmarks" + +[ios_xcuitest] +app = "target/mobench/ios/BenchRunner.ipa" +test_suite = "target/mobench/ios/BenchRunnerUITests.zip" +``` + +Validate it before a run: + +```bash +mobench config validate --config bench-config.toml +``` + +## Resolution and overrides + +Explicit CLI values take precedence over config values. Project discovery considers explicit `--project-root` and `--crate-path`, explicit config, a discovered `mobench.toml`, Cargo workspace metadata, the Git root, and the legacy `bench-mobile/` layout. + +Use explicit paths in CI when a workspace contains several plausible benchmark crates: + +```bash +mobench build \ + --target android \ + --project-root . \ + --crate-path crates/bench-mobile +``` + +`--device-matrix` overrides the matrix path from `--config`. Do not combine `--devices` and `--device-matrix`; choose one source of device selection. + +## Next step + +Generate a [device matrix](/device-matrices/) and validate the combined setup with `mobench doctor`. diff --git a/apps/docs/src/content/docs/reference/device-matrices.mdx b/apps/docs/src/content/docs/reference/device-matrices.mdx new file mode 100644 index 0000000..5993be6 --- /dev/null +++ b/apps/docs/src/content/docs/reference/device-matrices.mdx @@ -0,0 +1,93 @@ +--- +title: Device matrices +slug: device-matrices +description: Select BrowserStack Android and iOS devices deterministically with tags. +sidebar: + order: 3 +audience: [ci-engineer, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Reference +order: 3 +sourceRefs: + - label: BrowserStack CI guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md + evidence: Device inventory, validation, matrix syntax, profiles, and legacy iOS constraints. +--- + +A device matrix keeps exact BrowserStack identifiers and grouping decisions in version control. Tags let CI select a stable lane such as `default`, `pixel`, or `legacy-ios`. + +## Create a matrix + +Generate a starter file: + +```bash +mobench plan --output device-matrix.yaml +``` + +Example: + +```yaml +devices: + - name: "Google Pixel 7-13.0" + os: "android" + os_version: "13.0" + tags: ["default", "pixel"] + - name: "iPhone 14-16" + os: "ios" + os_version: "16" + tags: ["default", "iphone"] +``` + +Use identifiers from the live BrowserStack inventory: + +```bash +mobench devices --platform android +mobench devices --platform ios +mobench devices --json +``` + +## Validate identifiers + +```bash +mobench devices --validate "Google Pixel 7-13.0" +``` + +Invalid labels return nearby suggestions. Update the matrix deliberately when BrowserStack changes its inventory; do not silently fall back to another device. + +## Resolve a tagged profile + +```bash +mobench devices resolve \ + --platform android \ + --profile default \ + --device-matrix device-matrix.yaml +``` + +Run the selected group: + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --device-matrix device-matrix.yaml \ + --device-tags default \ + --release \ + --output-dir target/mobench/ci +``` + +`--device-tags` accepts comma-separated or repeated values. Explicit `--devices` and a matrix cannot be combined. + +## Legacy iOS lane + +An older BrowserStack device requires all three parts to agree: + +- the matrix's device OS +- the `mobench.toml` iOS deployment target +- the Xcode version on the build runner + +For a device below iOS 15, select `uikit-legacy`. mobench fails early when the app deployment target is newer than the chosen device OS. + +## Next step + +Run `mobench doctor --device-matrix device-matrix.yaml --browserstack true` before committing a CI lane. diff --git a/apps/docs/src/content/docs/reference/schemas.mdx b/apps/docs/src/content/docs/reference/schemas.mdx new file mode 100644 index 0000000..951943a --- /dev/null +++ b/apps/docs/src/content/docs/reference/schemas.mdx @@ -0,0 +1,61 @@ +--- +title: Output schemas +slug: schemas +aliases: [/current-spec, /reference] +description: Use the versioned mobench JSON contracts without depending on private implementation details. +sidebar: + order: 4 +audience: [ci-engineer, contributor] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Reference +order: 4 +sourceRefs: + - label: Upstream schemas + url: https://github.com/worldcoin/mobile-bench-rs/tree/d1a3176f9144f35e777e83fd07045116144da257/docs/schemas + evidence: Versioned CI, summary, and trace-event JSON Schema files. +--- + +mobench publishes JSON Schemas for the contracts intended for downstream validation. Pin a schema revision alongside the mobench release used to create the artifact. + +## Published schemas + +| File | Contract | +| --- | --- | +| `ci-contract-v1.schema.json` | The top-level `ci` metadata and status contract | +| `summary-v1.schema.json` | The top-level normalized `summary` result contract | +| `trace-events-v1.schema.json` | Profiling trace source, total duration, lanes, and events | + +The CI and summary schemas are focused wrappers around the stable output sections. A complete `summary.json` can include additional forward-compatible fields. + +## Validate in CI + +Use any JSON Schema 2020-12 validator and point it at the pinned upstream file. Treat validation as a contract check, not as a semantic comparison of devices or benchmarks. + +Example with a generic validator: + +```bash +check-jsonschema \ + --schemafile vendor/mobench/summary-v1.schema.json \ + target/mobench/ci/summary.json +``` + +Vendor the schema or pin its commit URL so a remote branch update cannot change a historical validation job. + +## Trace-event semantics + +The trace-event schema requires: + +- `source` +- `total_duration_ns` +- `lanes` + +Trace events describe profiling lanes and phases. They are not interchangeable with sampled benchmark durations in the normal summary contract. + +## Missing values + +Optional CPU and memory fields may be absent. Preserve absence through parsing and serialization; do not substitute numeric zero. + +## Next step + +Pin the schema files at release commit `d1a3176f9144f35e777e83fd07045116144da257` next to the workflow that consumes `summary.json`. diff --git a/apps/docs/src/content/docs/run-benchmarks/browserstack.mdx b/apps/docs/src/content/docs/run-benchmarks/browserstack.mdx new file mode 100644 index 0000000..1ab74c4 --- /dev/null +++ b/apps/docs/src/content/docs/run-benchmarks/browserstack.mdx @@ -0,0 +1,108 @@ +--- +title: BrowserStack device runs +slug: browserstack +aliases: [/app-automate] +description: Build, upload, run, and fetch Rust benchmarks with BrowserStack App Automate. +sidebar: + order: 2 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Run benchmarks +order: 2 +sourceRefs: + - label: BrowserStack CI guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md + evidence: Credentials, device resolution, execution, fetching, and iOS compatibility. +--- + +When a `run` or `ci run` command selects devices, mobench builds mobile artifacts, uploads them to BrowserStack App Automate, schedules the sessions, and collects available results. This is the normal path for real Android and iOS measurements in 0.1.43. + +## Configure credentials + +Environment variables are the simplest option: + +```bash +export BROWSERSTACK_USERNAME="your_username" +export BROWSERSTACK_ACCESS_KEY="your_access_key" +export BROWSERSTACK_PROJECT="mobile-benchmarks" +``` + +You can also reference them from `bench-config.toml`: + +```toml test=config:bench-config.toml +[browserstack] +app_automate_username = "${BROWSERSTACK_USERNAME}" +app_automate_access_key = "${BROWSERSTACK_ACCESS_KEY}" +project = "mobile-benchmarks" +``` + +Validate the credentials before starting a build: + +```bash +mobench doctor --target both --browserstack true +``` + +## Choose a device + +List the current BrowserStack inventory and validate an exact identifier: + +```bash +mobench devices --platform android +mobench devices --platform ios +mobench devices --validate "Google Pixel 7-13.0" +``` + +For repeatable suites, use a [device matrix](/device-matrices/) rather than copying labels across workflows. + +## Run Android + +```bash +mobench run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 30 \ + --warmup 5 \ + --release \ + --fetch \ + --output target/mobench/android-results.json +``` + +Use `--release` for optimized code and smaller APK uploads. + +## Run iOS + +```bash +mobench run \ + --target ios \ + --function bench_mobile::checksum \ + --devices "iPhone 14-16" \ + --iterations 20 \ + --warmup 3 \ + --release \ + --fetch \ + --output target/mobench/ios-results.json +``` + +mobench generates and packages the app and XCUITest suite unless `--ios-app` and `--ios-test-suite` point to existing artifacts. + +For older devices, the app deployment target must not exceed the device OS. Use the `uikit-legacy` runner and an appropriately old Xcode lane when SwiftUI is unavailable. + +## Fetch artifacts later + +```bash +mobench fetch \ + --target android \ + --build-id \ + --output-dir target/browserstack \ + --wait \ + --poll-interval-secs 10 \ + --timeout-secs 1800 +``` + +Fetched data can include session JSON, device logs, instrumentation logs, and available video links. BrowserStack does not expose native stack or flamegraph artifacts through this flow. + +## Next step + +Move a stable command into [CI](/ci/) and save its standard output contract. diff --git a/apps/docs/src/content/docs/run-benchmarks/ci.mdx b/apps/docs/src/content/docs/run-benchmarks/ci.mdx new file mode 100644 index 0000000..ff1bf82 --- /dev/null +++ b/apps/docs/src/content/docs/run-benchmarks/ci.mdx @@ -0,0 +1,119 @@ +--- +title: CI runs +slug: ci +description: Run repeatable mobile benchmarks and produce stable CI artifacts. +sidebar: + order: 3 +audience: [ci-engineer, benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Run benchmarks +order: 3 +sourceRefs: + - label: BrowserStack CI guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-ci.md + evidence: CI run, split-sample merge, PR reporting, and regression commands. +--- + +`mobench ci run` wraps execution in a stable file contract for artifact upload, job summaries, comparisons, plots, and downstream reporting. + +## Run one benchmark + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --iterations 20 \ + --warmup 5 \ + --release \ + --fetch \ + --plots auto \ + --output-dir target/mobench/ci +``` + +The output directory contains `summary.json`, `summary.md`, `results.csv`, and optional `plots/*.svg`. + +Use `--functions` for several benchmarks in one invocation: + +```bash +mobench ci run \ + --target android \ + --functions '["bench_mobile::checksum","bench_mobile::verify"]' \ + --devices "Google Pixel 7-13.0" \ + --release \ + --output-dir target/mobench/ci +``` + +## Minimal GitHub Actions shape + +```yaml +name: Mobile benchmarks + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-linux-android + - name: Run mobench + env: + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + run: | + mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --device-matrix device-matrix.yaml \ + --device-tags default \ + --release \ + --output-dir target/mobench/ci + - uses: actions/upload-artifact@v4 + with: + name: mobench-android + path: target/mobench/ci +``` + +Install the pinned mobench release in an earlier step or use your repository's pinned local action wrapper. + +## Merge split samples + +Fragile or long BrowserStack lanes can run each measured sample separately. Place the one-sample `summary.json` files below `sample-*` directories, then merge them: + +```bash +mobench ci merge-split-runs \ + --samples-dir target/mobench/split \ + --output-dir target/mobench/ci \ + --function bench_mobile::checksum \ + --device "Google Pixel 7-13.0" \ + --iterations 5 \ + --warmup 1 +``` + +The merge validates function, device, and sample counts, then writes the same three standard files as a normal CI run. + +## Add a regression gate + +```bash +mobench ci run \ + --target android \ + --function bench_mobile::checksum \ + --devices "Google Pixel 7-13.0" \ + --baseline artifact:baselines/android-summary.json \ + --regression-threshold-pct 5 \ + --junit target/mobench/ci/junit.xml \ + --release \ + --output-dir target/mobench/ci +``` + +## Next step + +Read [outputs](/outputs/) before wiring fields into dashboards or PR comments. diff --git a/apps/docs/src/content/docs/run-benchmarks/preflight.mdx b/apps/docs/src/content/docs/run-benchmarks/preflight.mdx new file mode 100644 index 0000000..aae1b33 --- /dev/null +++ b/apps/docs/src/content/docs/run-benchmarks/preflight.mdx @@ -0,0 +1,92 @@ +--- +title: Host-side preflight +slug: host-preflight +aliases: [/local-devices] +description: Validate configuration, discovery, builds, and reports before using mobile devices. +sidebar: + order: 1 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Run benchmarks +order: 1 +sourceRefs: + - label: Testing guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/testing.md + evidence: Prerequisite, discovery, verification, and host-side preflight commands. +--- + +Preflight catches inexpensive failures before a mobile build or BrowserStack session. It validates your local tools and config, proves that the benchmark is discoverable, and checks the requested report shape. + +## Check prerequisites + +Use `doctor` for the combined project, config, and credential view: + +```bash +mobench doctor \ + --target both \ + --config bench-config.toml \ + --device-matrix device-matrix.yaml \ + --browserstack true +``` + +Use `check` for a focused platform toolchain check: + +```bash +mobench check --target android +mobench check --target ios +mobench check --target android --format json +``` + +Validate a run configuration independently: + +```bash +mobench config validate --config bench-config.toml +``` + +## Prove discovery + +```bash +mobench list --crate-path bench-mobile +``` + +If the function is missing, fix the registry or crate selection before building a mobile runner. + +## Verify generated artifacts + +After a build, verify registry and platform files: + +```bash +mobench verify \ + --target android \ + --crate-path bench-mobile \ + --check-artifacts \ + --output-dir target/mobench +``` + +`verify --smoke-test` only works when the benchmark crate is linked into the `mobench` CLI binary. External crates selected through `mobench.toml`, `--project-root`, or `--crate-path` should use `list`, `verify --check-artifacts`, and a normal host preflight. + +## Write host-side preflight output + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::checksum \ + --local-only \ + --iterations 5 \ + --warmup 1 \ + --output target/mobench/preflight.json +``` + +This command skips mobile builds and writes preflight/spec output without executing the requested benchmark. It is useful for discovery and report-shape debugging, but it is not an Android, iOS, or host performance measurement. + +Inspect the result shape: + +```bash +mobench summary target/mobench/preflight.json +``` + +## Next step + +Resolve a real device and continue with the [BrowserStack run guide](/browserstack/). diff --git a/apps/docs/src/content/docs/write-benchmarks/benchmark-functions.mdx b/apps/docs/src/content/docs/write-benchmarks/benchmark-functions.mdx new file mode 100644 index 0000000..67afec2 --- /dev/null +++ b/apps/docs/src/content/docs/write-benchmarks/benchmark-functions.mdx @@ -0,0 +1,91 @@ +--- +title: Benchmark functions +slug: benchmark-functions +aliases: [/authoring, /writing-benchmarks, /writing] +description: Register discoverable benchmark functions with the mobench SDK. +sidebar: + order: 1 +audience: [benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Write benchmarks +order: 1 +sourceRefs: + - label: Current API specification + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md + evidence: Benchmark macro rules, runtime API, and SDK feature flags. +--- + +`#[benchmark]` registers a Rust function at compile time through `inventory`. The SDK runner and CLI use that registry to discover the function by its fully qualified name. + +## Minimal function + +```rust +use mobench_sdk::benchmark; + +#[benchmark] +pub fn parse_fixture() { + let input = std::hint::black_box(include_bytes!("fixture.bin")); + let parsed = parse(input); + std::hint::black_box(parsed); +} +``` + +A simple benchmark: + +- takes no parameters +- returns `()` +- is public when generated mobile runners need to link it +- keeps the measured work and result observable to the optimizer + +Async functions, parameters on a simple benchmark, and non-unit return types are rejected at compile time. Use [setup and teardown](/setup-teardown/) when the measured function needs an input. + +## Discover registered functions + +```bash +mobench list --crate-path bench-mobile +``` + +Pass the exact discovered name to `--function`: + +```bash +mobench run \ + --target android \ + --crate-path bench-mobile \ + --function bench_mobile::parse_fixture \ + --local-only +``` + +The host-only command is a discovery and reporting preflight. Select a device for a mobile measurement. + +## Programmatic execution + +Applications that need the SDK directly can build a validated `BenchSpec` and use the registry runner: + +```rust +use mobench_sdk::{run_benchmark, BenchSpec}; + +let spec = BenchSpec::new("bench_mobile::parse_fixture", 100, 10)?; +let report = run_benchmark(spec)?; +println!("median: {} ns", report.median_ns()); +``` + +For CI integrations, prefer the CLI's stable files over private implementation modules. + +## Named semantic phases + +When a benchmark contains meaningful sub-operations, `profile_phase` can record phase metadata separately from sampled native stacks: + +```rust +use mobench_sdk::{benchmark, profile_phase}; + +#[benchmark] +pub fn prove_and_verify() { + let proof = profile_phase("prove", || prove()); + profile_phase("verify", || verify(&proof)); +} +``` + +## Next step + +Choose a fixture lifecycle in [setup and teardown](/setup-teardown/), then apply the quality checklist. diff --git a/apps/docs/src/content/docs/write-benchmarks/quality.mdx b/apps/docs/src/content/docs/write-benchmarks/quality.mdx new file mode 100644 index 0000000..5ddd527 --- /dev/null +++ b/apps/docs/src/content/docs/write-benchmarks/quality.mdx @@ -0,0 +1,70 @@ +--- +title: Benchmark quality +slug: benchmark-quality +description: Design mobile benchmarks that produce comparable, defensible results. +sidebar: + order: 3 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Write benchmarks +order: 3 +sourceRefs: + - label: BrowserStack metrics guide + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/guides/browserstack-metrics.md + evidence: Result interpretation, optional resource data, and comparison guidance. +--- + +A mobile number is useful only when the work, build, device, and run conditions are clear enough to reproduce. + +## Keep the optimizer honest + +- Pass variable inputs and final outputs through `std::hint::black_box` or `mobench_sdk::black_box`. +- Make the workload long enough to rise above timer resolution and harness overhead. +- Keep setup, cloning, and cleanup outside the measured closure unless they are the subject of the benchmark. +- Prefer deterministic fixture data over network or wall-clock dependencies. + +## Separate warmup from measurement + +Warmups execute the benchmark without adding samples. They can stabilize code paths and caches, but they do not guarantee a thermally stable device. + +Use the same warmup and iteration counts when comparing revisions. Record changes to either value as a new experiment. + +## Compare like with like + +Keep these dimensions stable: + +- device model and OS version +- release versus debug build +- benchmark function and fixture +- runner backend +- iteration and warmup counts +- relevant dependency and toolchain versions + +Prefer medians and percentiles when isolated scheduling noise affects the mean. Repeat the full run when a result is close to your regression threshold. + +## Treat resource values as optional + +CPU and memory measurements depend on runner and provider availability. A blank or absent value means **unavailable**. Do not coerce it to zero, carry it into arithmetic, or claim that it was measured. + +mobench 0.1.43 does not define a power-consumption metric. + +## Use the right execution mode + +`--local-only` validates the host harness and output pipeline. It does not measure Android or iOS execution. For mobile results, choose a BrowserStack device and use `--release`. + +Native profiling is a separate local workflow and should answer *where time is spent*, not replace repeated timing samples. + +## Pre-baseline checklist + +- The function appears in `mobench list`. +- A host preflight completes without warnings you do not understand. +- The release mobile build succeeds. +- The exact device identifier resolves. +- The output contains the expected number of measured samples. +- Missing resource values remain missing. +- The baseline file is stored with its environment metadata. + +## Next step + +Complete the [host-side preflight](/host-preflight/) before spending BrowserStack time. diff --git a/apps/docs/src/content/docs/write-benchmarks/setup-teardown.mdx b/apps/docs/src/content/docs/write-benchmarks/setup-teardown.mdx new file mode 100644 index 0000000..2647aa1 --- /dev/null +++ b/apps/docs/src/content/docs/write-benchmarks/setup-teardown.mdx @@ -0,0 +1,84 @@ +--- +title: Setup and teardown +slug: setup-teardown +aliases: [/setup-and-teardown] +description: Keep fixture creation, mutation, and cleanup outside measured samples. +sidebar: + order: 2 +audience: [benchmark-author] +release: 0.1.43 +lastVerified: 2026-07-15 +section: Write benchmarks +order: 2 +sourceRefs: + - label: Current API specification + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/docs/specs/mobench-current-spec.md + evidence: Implemented setup, per-iteration setup, and teardown semantics. +--- + +Use the macro's fixture attributes when input creation or cleanup is not part of the operation you want to measure. + +## Reuse one fixture + +Setup runs once before warmup and measured iterations. The benchmark receives a shared reference. + +```rust +use mobench_sdk::benchmark; + +fn create_input() -> Vec { + vec![42; 1024 * 1024] +} + +#[benchmark(setup = create_input)] +pub fn checksum(input: &Vec) { + let sum: u64 = input.iter().map(|byte| u64::from(*byte)).sum(); + std::hint::black_box(sum); +} +``` + +Choose this mode when repeated work does not mutate the fixture in a way that changes later samples. + +## Create a fresh fixture per iteration + +`per_iteration` runs setup before each warmup or measured iteration and passes the value by ownership. Setup remains outside the sample timer. + +```rust +use mobench_sdk::benchmark; + +fn unsorted_values() -> Vec { + (0..10_000).rev().collect() +} + +#[benchmark(setup = unsorted_values, per_iteration)] +pub fn sort_values(mut values: Vec) { + values.sort_unstable(); + std::hint::black_box(values); +} +``` + +Use this mode when the operation consumes or irreversibly mutates its input. + +## Clean up after the run + +Teardown receives the setup value after warmup and measurement. It runs outside measured timing, including when measured execution returns an error. + +```rust +fn open_store() -> Store { + Store::temporary() +} + +fn remove_store(store: Store) { + store.remove(); +} + +#[benchmark(setup = open_store, teardown = remove_store)] +pub fn query_store(store: &Store) { + std::hint::black_box(store.query("key")); +} +``` + +Teardown is not combined with `per_iteration`; make a consumed fixture clean itself up through ownership when each iteration needs independent cleanup. + +## Next step + +Run the benchmark with multiple warmups and inspect it against the [quality checklist](/benchmark-quality/). diff --git a/apps/docs/src/pages/404.astro b/apps/docs/src/pages/404.astro new file mode 100644 index 0000000..6c8ac2b --- /dev/null +++ b/apps/docs/src/pages/404.astro @@ -0,0 +1,12 @@ +--- +import '../styles/mobench.css' +--- + + + + Page not found — mobench docs +
mmobench docs

404 / DOCS ROUTE MISSING

This page is outside the current manifest.

The guide may have moved. Start at the documentation index or use search from any documentation page.

+ + diff --git a/apps/docs/src/pages/[...slug].md.ts b/apps/docs/src/pages/[...slug].md.ts new file mode 100644 index 0000000..3963127 --- /dev/null +++ b/apps/docs/src/pages/[...slug].md.ts @@ -0,0 +1,32 @@ +const sources = import.meta.glob('../content/docs/**/*.{md,mdx}', { + eager: true, + query: '?raw', + import: 'default', +}) + +function sourceSlug(path: string, source: string) { + const frontmatter = source.match(/^---\r?\n([\s\S]*?)\r?\n---/) + const configuredSlug = frontmatter?.[1]?.match(/^slug:\s*["']?([^"'\r\n]+)["']?\s*$/m)?.[1]?.trim() + return configuredSlug || path.replace('../content/docs/', '').replace(/\.(md|mdx)$/, '') +} + +function markdownBody(source: string) { + return source.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, '').trimStart() +} + +export function getStaticPaths() { + return Object.entries(sources).map(([path, source]) => ({ + params: { slug: sourceSlug(path, source) }, + props: { source: markdownBody(source) }, + })) +} + +export function GET({ props }: { props: { source: string } }) { + return new Response(props.source, { + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Cache-Control': 'public, max-age=0, must-revalidate', + 'X-Content-Type-Options': 'nosniff', + }, + }) +} diff --git a/apps/docs/src/scripts/analytics.ts b/apps/docs/src/scripts/analytics.ts new file mode 100644 index 0000000..c74b329 --- /dev/null +++ b/apps/docs/src/scripts/analytics.ts @@ -0,0 +1,39 @@ +import { inject, track } from '@vercel/analytics' +import { analyticsEvents, type AnalyticsEvent } from '@mobench/site-config' + +const analyticsEnabled = window.location.hostname === 'docs.mobench.org' +const allowedEvents = new Set(analyticsEvents) + +function emit(name: AnalyticsEvent) { + if (!analyticsEnabled || !allowedEvents.has(name)) return + track(name) +} + +if (analyticsEnabled) inject() + +document.addEventListener('click', (event) => { + const result = event.target instanceof Element + ? event.target.closest('.pagefind-ui__result-link') + : null + if (result) emit('search_result_opened') +}) + +const searchRoot = document.querySelector('#starlight__search') +let zeroResultTracked = false + +searchRoot?.addEventListener('input', () => { + zeroResultTracked = false +}) + +if (searchRoot) { + const observer = new MutationObserver(() => { + const input = searchRoot.querySelector('input') + const message = searchRoot.querySelector('.pagefind-ui__message') + const hasNoResults = message?.textContent?.trim().startsWith('No results') ?? false + if (!zeroResultTracked && input?.value.trim() && hasNoResults) { + emit('search_zero_results') + zeroResultTracked = true + } + }) + observer.observe(searchRoot, { childList: true, subtree: true, characterData: true }) +} diff --git a/apps/docs/src/scripts/search-accessibility.ts b/apps/docs/src/scripts/search-accessibility.ts new file mode 100644 index 0000000..73fcc6e --- /dev/null +++ b/apps/docs/src/scripts/search-accessibility.ts @@ -0,0 +1,38 @@ +const siteSearch = document.querySelector('site-search') +const searchRoot = document.querySelector('#starlight__search') +const searchTrigger = siteSearch?.querySelector('[data-open-modal]') + +if (searchTrigger) { + const visibleLabel = searchTrigger.textContent?.replace(/\s+/g, ' ').trim() + if (visibleLabel) searchTrigger.setAttribute('aria-label', visibleLabel) +} + +siteSearch?.addEventListener('keydown', (event) => { + if (!(event instanceof KeyboardEvent) || !['ArrowDown', 'ArrowUp'].includes(event.key)) return + const input = searchRoot?.querySelector('.pagefind-ui__search-input') + const links = [...(searchRoot?.querySelectorAll('.pagefind-ui__result-link') ?? [])] + if (!input || !links.length) return + + const activeIndex = links.indexOf(document.activeElement as HTMLElement) + if (event.key === 'ArrowDown') { + links[Math.min(activeIndex + 1, links.length - 1)]?.focus() + } else if (activeIndex <= 0) { + input.focus() + } else { + links[activeIndex - 1]?.focus() + } + event.preventDefault() +}) + +if (searchRoot) { + const announceResults = () => { + const message = searchRoot.querySelector('.pagefind-ui__message') + message?.setAttribute('role', 'status') + message?.setAttribute('aria-live', 'polite') + } + new MutationObserver(announceResults).observe(searchRoot, { + childList: true, + subtree: true, + characterData: true, + }) +} diff --git a/apps/docs/src/styles/mobench.css b/apps/docs/src/styles/mobench.css new file mode 100644 index 0000000..7b0f2af --- /dev/null +++ b/apps/docs/src/styles/mobench.css @@ -0,0 +1,112 @@ +@font-face { + font-family: 'Geist Variable'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url('/fonts/geist-latin-wght-normal.woff2') format('woff2-variations'); +} + +@font-face { + font-family: 'Geist Mono Variable'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url('/fonts/geist-mono-latin-wght-normal.woff2') format('woff2-variations'); +} + +:root { + --sl-font: 'Geist Variable', 'Geist', sans-serif; + --sl-font-mono: 'Geist Mono Variable', 'Geist Mono', monospace; + --sl-color-accent-low: #24391e; + --sl-color-accent: #9bd17e; + --sl-color-accent-high: #d9f2c9; + --sl-color-white: #f5efdd; + --sl-color-gray-1: #e1dac7; + --sl-color-gray-2: #c7bfae; + --sl-color-gray-3: #a79e8b; + --sl-color-gray-4: #706b5e; + --sl-color-gray-5: #393d34; + --sl-color-gray-6: #1b2118; + --sl-color-black: #11160f; + --sl-color-bg: #11160f; + --sl-color-bg-nav: rgba(17, 22, 15, .92); + --sl-color-bg-sidebar: #151a13; + --sl-color-bg-inline-code: #20291c; + --sl-color-hairline-light: rgba(245, 239, 221, .17); + --sl-color-hairline: rgba(245, 239, 221, .13); + --sl-content-width: 48rem; + --sl-sidebar-width: 18rem; + --sl-nav-height: 4.6rem; +} + +:root[data-theme='light'] { + --sl-color-accent-low: #e0ecd4; + --sl-color-accent: #356c28; + --sl-color-accent-high: #254d1c; + --sl-color-white: #271f16; + --sl-color-gray-1: #443c31; + --sl-color-gray-2: #5f574a; + --sl-color-gray-3: #6c6252; + --sl-color-gray-4: #b4aa95; + --sl-color-gray-5: #d4cbb6; + --sl-color-gray-6: #ebe4d1; + --sl-color-gray-7: #f4efdd; + --sl-color-black: #fffdf5; + --sl-color-bg: #f4efdd; + --sl-color-bg-nav: rgba(244, 239, 221, .92); + --sl-color-bg-sidebar: #eee7d5; + --sl-color-bg-inline-code: #e2ecd7; + --sl-color-hairline-light: rgba(39, 31, 22, .17); + --sl-color-hairline: rgba(39, 31, 22, .13); +} + +html { scroll-behavior: smooth; } +body { letter-spacing: -.006em; -webkit-font-smoothing: antialiased; } +body::before { position: fixed; z-index: -1; inset: 0; pointer-events: none; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.45'/%3E%3C/svg%3E"); opacity: .022; content: ''; } + +header.header { border-bottom: 1px solid var(--sl-color-hairline); backdrop-filter: blur(18px); } +.site-title { letter-spacing: -.04em; } +.site-title img { max-height: 2.35rem; } + +/* Keep task search obvious at every viewport instead of collapsing it away. */ +site-search { min-width: min(24rem, 38vw); } +site-search > button { min-width: 2.75rem; min-height: 2.75rem; border-radius: .55rem !important; background: color-mix(in srgb, var(--sl-color-black) 76%, transparent) !important; } +starlight-menu-button button { min-width: 2.75rem; min-height: 2.75rem; } +@media (max-width: 50rem) { + site-search { display: block !important; min-width: 2.75rem; } + site-search > button { min-width: 2.75rem; } + site-search > button > span:not(.sl-hidden) { display: none; } +} + +.sidebar-pane { border-inline-end-color: var(--sl-color-hairline) !important; } +nav.sidebar a { border-radius: .4rem; } +nav.sidebar a[aria-current='page'] { background: var(--sl-color-accent-low); color: var(--sl-color-accent-high); font-weight: 620; } +.sidebar-content summary { color: var(--sl-color-white); font-family: var(--sl-font-mono); font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; } + +.main-pane { background-image: linear-gradient(90deg, transparent 0, transparent calc(100% - 1px), var(--sl-color-hairline) calc(100% - 1px)); } +.content-panel { padding-block: clamp(2rem, 6vw, 4rem); } +.sl-markdown-content h2 { margin-top: 3.25rem; padding-top: 1rem; border-top: 1px solid var(--sl-color-hairline); letter-spacing: -.045em; } +.sl-markdown-content h3 { letter-spacing: -.03em; } +.sl-markdown-content p, .sl-markdown-content li { line-height: 1.72; } +.sl-markdown-content a:not([class]) { text-decoration-color: color-mix(in srgb, var(--sl-color-accent) 38%, transparent); text-underline-offset: .2em; } +.sl-markdown-content table { display: block; width: 100%; max-width: 100%; overflow-x: auto; font-size: .86rem; } +.sl-markdown-content th { background: var(--sl-color-bg-sidebar); } +.sl-markdown-content :not(pre) > code { border: 1px solid var(--sl-color-hairline); border-radius: .25rem; color: var(--sl-color-accent-high); } +.expressive-code { margin-block: 1.6rem; } +.expressive-code figure { box-shadow: none !important; } + +.pagination-links a { border-color: var(--sl-color-hairline); border-radius: .65rem; background: color-mix(in srgb, var(--sl-color-black) 58%, transparent); } +.pagination-links a:hover { border-color: var(--sl-color-accent); } + +mobile-starlight-toc nav { backdrop-filter: blur(18px); } +mobile-starlight-toc summary { min-height: 2.9rem; } + +@media (max-width: 50rem) { + :root { --sl-nav-height: 4.2rem; } + .content-panel { padding-inline: 1rem; } +} + +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; transition-duration: .01ms !important; } +} diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json new file mode 100644 index 0000000..8bf91d3 --- /dev/null +++ b/apps/docs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} diff --git a/apps/docs/vercel.json b/apps/docs/vercel.json new file mode 100644 index 0000000..5cbf517 --- /dev/null +++ b/apps/docs/vercel.json @@ -0,0 +1,253 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": "astro", + "installCommand": "cd ../.. && bun install --frozen-lockfile", + "buildCommand": "cd ../.. && bun run generate && bun run build:docs", + "outputDirectory": "dist", + "redirects": [ + { + "source": "/analyze-results/outputs", + "destination": "/outputs/", + "permanent": true + }, + { + "source": "/analyze-results/profiling", + "destination": "/profiling/", + "permanent": true + }, + { + "source": "/analyze-results/regressions", + "destination": "/regressions/", + "permanent": true + }, + { + "source": "/app-automate", + "destination": "/browserstack/", + "permanent": true + }, + { + "source": "/authoring", + "destination": "/benchmark-functions/", + "permanent": true + }, + { + "source": "/build-artifacts", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/build", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/cli-man-pages", + "destination": "/cli/", + "permanent": true + }, + { + "source": "/cli-reference", + "destination": "/cli/", + "permanent": true + }, + { + "source": "/codebase", + "destination": "/troubleshooting/", + "permanent": true + }, + { + "source": "/concepts", + "destination": "/configuration/", + "permanent": true + }, + { + "source": "/current-spec", + "destination": "/schemas/", + "permanent": true + }, + { + "source": "/diagrams", + "destination": "/device-matrices/", + "permanent": true + }, + { + "source": "/docs", + "destination": "/", + "permanent": true + }, + { + "source": "/examples", + "destination": "/basic-example/", + "permanent": true + }, + { + "source": "/examples/basic", + "destination": "/basic-example/", + "permanent": true + }, + { + "source": "/examples/ffi", + "destination": "/ffi-example/", + "permanent": true + }, + { + "source": "/get-started/installation", + "destination": "/installation/", + "permanent": true + }, + { + "source": "/get-started/quickstart", + "destination": "/quickstart/", + "permanent": true + }, + { + "source": "/help/troubleshooting", + "destination": "/troubleshooting/", + "permanent": true + }, + { + "source": "/home", + "destination": "/", + "permanent": true + }, + { + "source": "/install", + "destination": "/installation/", + "permanent": true + }, + { + "source": "/local-devices", + "destination": "/host-preflight/", + "permanent": true + }, + { + "source": "/outputs-and-reports", + "destination": "/outputs/", + "permanent": true + }, + { + "source": "/overview", + "destination": "/", + "permanent": true + }, + { + "source": "/public-api", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/reference", + "destination": "/schemas/", + "permanent": true + }, + { + "source": "/reference/cli", + "destination": "/cli/", + "permanent": true + }, + { + "source": "/reference/compatibility", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/reference/configuration", + "destination": "/configuration/", + "permanent": true + }, + { + "source": "/reference/device-matrices", + "destination": "/device-matrices/", + "permanent": true + }, + { + "source": "/reference/schemas", + "destination": "/schemas/", + "permanent": true + }, + { + "source": "/reports", + "destination": "/outputs/", + "permanent": true + }, + { + "source": "/run-benchmarks/browserstack", + "destination": "/browserstack/", + "permanent": true + }, + { + "source": "/run-benchmarks/ci", + "destination": "/ci/", + "permanent": true + }, + { + "source": "/run-benchmarks/preflight", + "destination": "/host-preflight/", + "permanent": true + }, + { + "source": "/sdk-integration", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/sdk", + "destination": "/compatibility/", + "permanent": true + }, + { + "source": "/setup-and-teardown", + "destination": "/setup-teardown/", + "permanent": true + }, + { + "source": "/testing", + "destination": "/troubleshooting/", + "permanent": true + }, + { + "source": "/write-benchmarks/benchmark-functions", + "destination": "/benchmark-functions/", + "permanent": true + }, + { + "source": "/write-benchmarks/quality", + "destination": "/benchmark-quality/", + "permanent": true + }, + { + "source": "/write-benchmarks/setup-teardown", + "destination": "/setup-teardown/", + "permanent": true + }, + { + "source": "/writing-benchmarks", + "destination": "/benchmark-functions/", + "permanent": true + }, + { + "source": "/writing", + "destination": "/benchmark-functions/", + "permanent": true + } + ], + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "Referrer-Policy", + "value": "strict-origin-when-cross-origin" + }, + { + "key": "Permissions-Policy", + "value": "camera=(), microphone=(), geolocation=()" + } + ] + } + ] +} diff --git a/apps/marketing/astro.config.mjs b/apps/marketing/astro.config.mjs new file mode 100644 index 0000000..fa1374e --- /dev/null +++ b/apps/marketing/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config' +import sitemap from '@astrojs/sitemap' + +export default defineConfig({ + site: 'https://mobench.org', + output: 'static', + integrations: [sitemap()], + build: { format: 'directory' }, + compressHTML: true, +}) diff --git a/apps/marketing/package.json b/apps/marketing/package.json new file mode 100644 index 0000000..dff5fb8 --- /dev/null +++ b/apps/marketing/package.json @@ -0,0 +1,24 @@ +{ + "name": "@mobench/marketing", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "astro dev --port 3000", + "build": "astro build", + "check": "astro check", + "preview": "astro preview --port 3000" + }, + "dependencies": { + "@astrojs/sitemap": "^3.7.3", + "@mobench/site-config": "workspace:*", + "@mobench/truth": "workspace:*", + "@vercel/analytics": "2.0.1", + "astro": "7.0.6", + "sharp": "0.35.3" + }, + "devDependencies": { + "@astrojs/check": "^0.9.6", + "typescript": "^6.0.3" + } +} diff --git a/apps/marketing/public/favicon.svg b/apps/marketing/public/favicon.svg new file mode 100644 index 0000000..9248cc3 --- /dev/null +++ b/apps/marketing/public/favicon.svg @@ -0,0 +1 @@ + diff --git a/apps/marketing/public/fonts/geist-latin-wght-normal.woff2 b/apps/marketing/public/fonts/geist-latin-wght-normal.woff2 new file mode 100644 index 0000000..991445d Binary files /dev/null and b/apps/marketing/public/fonts/geist-latin-wght-normal.woff2 differ diff --git a/apps/marketing/public/fonts/geist-mono-latin-wght-normal.woff2 b/apps/marketing/public/fonts/geist-mono-latin-wght-normal.woff2 new file mode 100644 index 0000000..ab3d5ee Binary files /dev/null and b/apps/marketing/public/fonts/geist-mono-latin-wght-normal.woff2 differ diff --git a/apps/marketing/public/hero/mobench-bench-320.png b/apps/marketing/public/hero/mobench-bench-320.png new file mode 100644 index 0000000..8273c21 Binary files /dev/null and b/apps/marketing/public/hero/mobench-bench-320.png differ diff --git a/apps/marketing/public/hero/mobench-bench-480.avif b/apps/marketing/public/hero/mobench-bench-480.avif new file mode 100644 index 0000000..9bcc606 Binary files /dev/null and b/apps/marketing/public/hero/mobench-bench-480.avif differ diff --git a/apps/marketing/public/hero/mobench-bench-480.webp b/apps/marketing/public/hero/mobench-bench-480.webp new file mode 100644 index 0000000..6ba5f00 Binary files /dev/null and b/apps/marketing/public/hero/mobench-bench-480.webp differ diff --git a/apps/marketing/public/hero/mobench-bench-768.avif b/apps/marketing/public/hero/mobench-bench-768.avif new file mode 100644 index 0000000..d549204 Binary files /dev/null and b/apps/marketing/public/hero/mobench-bench-768.avif differ diff --git a/apps/marketing/public/hero/mobench-bench-768.webp b/apps/marketing/public/hero/mobench-bench-768.webp new file mode 100644 index 0000000..4d6bc57 Binary files /dev/null and b/apps/marketing/public/hero/mobench-bench-768.webp differ diff --git a/apps/marketing/public/llms.txt b/apps/marketing/public/llms.txt new file mode 100644 index 0000000..699a900 --- /dev/null +++ b/apps/marketing/public/llms.txt @@ -0,0 +1,51 @@ +# mobench + +> Source-backed documentation for mobench 0.1.43: build Android and iOS runners, execute ordinary benchmarks on BrowserStack devices, and analyze stable reports or supported local native profiles. + +Canonical documentation: https://docs.mobench.org/ +Source: https://github.com/worldcoin/mobile-bench-rs/tree/v0.1.43 +Pinned release SHA: d1a3176f9144f35e777e83fd07045116144da257 + +## Capability boundary + +- Use the `mobench` executable for release 0.1.43. The published `cargo mobench` wrapper is unsupported. +- Ordinary mobile benchmarks execute through BrowserStack when devices are selected. +- `--local-only` is host preflight and does not measure Android or iOS execution. +- Local native profiling has a separate Android simpleperf and iOS simulator-host capability matrix. +- The release does not define an energy or battery measurement contract. + +## Documentation + +- [Outputs and metrics](https://docs.mobench.org/outputs/): Understand mobench JSON, Markdown, CSV, plots, and optional resource values. +- [Regression comparison](https://docs.mobench.org/regressions/): Compare compatible mobench summaries and gate meaningful slowdowns. +- [Local native profiling](https://docs.mobench.org/profiling/): Capture Android and iOS native stacks and compare profile manifests locally. +- [Basic benchmark crate](https://docs.mobench.org/basic-example/): Follow the minimal SDK example from registration to host and mobile execution. +- [FFI benchmark crate](https://docs.mobench.org/ffi-example/): Expose mobench benchmarks through UniFFI, the native C ABI, or BoltFFI. +- [Installation](https://docs.mobench.org/installation/): Install mobench 0.1.43 and prepare a Rust benchmark crate. +- [Quickstart](https://docs.mobench.org/quickstart/): Register a Rust benchmark, validate it on the host, and run it on a mobile device. +- [Troubleshooting](https://docs.mobench.org/troubleshooting/): Diagnose discovery, toolchain, BrowserStack, result, and profiling failures. +- [mobench documentation](https://docs.mobench.org/): Build, run, and analyze Rust benchmarks on Android and iOS. +- [CLI reference](https://docs.mobench.org/cli/): Find mobench commands and the flags that connect authoring, execution, CI, and profiling. +- [Configuration](https://docs.mobench.org/configuration/): Configure project builds separately from benchmark run and provider settings. +- [Device matrices](https://docs.mobench.org/device-matrices/): Select BrowserStack Android and iOS devices deterministically with tags. +- [Output schemas](https://docs.mobench.org/schemas/): Use the versioned mobench JSON contracts without depending on private implementation details. +- [Compatibility](https://docs.mobench.org/compatibility/): Match Rust, platform tools, devices, and generated runner backends to mobench 0.1.43. +- [Host-side preflight](https://docs.mobench.org/host-preflight/): Validate configuration, discovery, builds, and reports before using mobile devices. +- [BrowserStack device runs](https://docs.mobench.org/browserstack/): Build, upload, run, and fetch Rust benchmarks with BrowserStack App Automate. +- [CI runs](https://docs.mobench.org/ci/): Run repeatable mobile benchmarks and produce stable CI artifacts. +- [Benchmark functions](https://docs.mobench.org/benchmark-functions/): Register discoverable benchmark functions with the mobench SDK. +- [Setup and teardown](https://docs.mobench.org/setup-teardown/): Keep fixture creation, mutation, and cleanup outside measured samples. +- [Benchmark quality](https://docs.mobench.org/benchmark-quality/): Design mobile benchmarks that produce comparable, defensible results. + +## Stable command entry points + +```bash +cargo install mobench --version 0.1.43 +mobench list --crate-path bench-mobile +mobench run --target android --function bench_mobile::checksum --local-only --output target/mobench/preflight.json +mobench run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output target/mobench/results.json +mobench ci run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output-dir target/mobench/ci +mobench profile run --target android --provider local --backend android-native --function bench_mobile::checksum --output-dir target/mobench/profile +``` + +Full authored documentation: https://docs.mobench.org/llms-full.txt diff --git a/apps/marketing/public/og/landing.png b/apps/marketing/public/og/landing.png new file mode 100644 index 0000000..97f1141 Binary files /dev/null and b/apps/marketing/public/og/landing.png differ diff --git a/apps/marketing/public/og/landing.svg b/apps/marketing/public/og/landing.svg new file mode 100644 index 0000000..c22f271 --- /dev/null +++ b/apps/marketing/public/og/landing.svg @@ -0,0 +1 @@ +mmobenchRust benchmarks,measured on mobile.BUILD → BROWSERSTACK → COMPAREMOBILE RUNNER112 ms diff --git a/apps/marketing/public/og/sources.json b/apps/marketing/public/og/sources.json new file mode 100644 index 0000000..46cbabb --- /dev/null +++ b/apps/marketing/public/og/sources.json @@ -0,0 +1,3 @@ +{ + "landing.png": "4e95e24bcb1ff9dccdea7c42ec7580c8c11eee346e3ed81040618264d601b66b" +} diff --git a/apps/marketing/public/robots.txt b/apps/marketing/public/robots.txt new file mode 100644 index 0000000..97b7ea2 --- /dev/null +++ b/apps/marketing/public/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://mobench.org/sitemap-index.xml diff --git a/apps/marketing/src/layouts/BaseLayout.astro b/apps/marketing/src/layouts/BaseLayout.astro new file mode 100644 index 0000000..45522cd --- /dev/null +++ b/apps/marketing/src/layouts/BaseLayout.astro @@ -0,0 +1,115 @@ +--- +import '../styles/global.css' + +interface Props { + title: string + description: string + canonicalPath?: string + image?: string + imageAlt?: string + noindex?: boolean +} + +const { + title, + description, + canonicalPath = Astro.url.pathname, + image = '/og/landing.png', + imageAlt = 'mobench — Rust benchmarks built for mobile', + noindex = false, +} = Astro.props +const canonical = new URL(canonicalPath, 'https://mobench.org') +const socialImage = new URL(image, 'https://mobench.org') +const structuredData = { + '@context': 'https://schema.org', + '@type': 'SoftwareSourceCode', + name: 'mobench', + description, + url: canonical.href, + codeRepository: 'https://github.com/worldcoin/mobile-bench-rs', + programmingLanguage: 'Rust', + runtimePlatform: ['Android', 'iOS'], + license: 'https://opensource.org/license/mit', +} +--- + + + + + + + + + + {noindex && } + + + + + + + + + + + + + + {title} + + + + + diff --git a/apps/marketing/src/pages/404.astro b/apps/marketing/src/pages/404.astro new file mode 100644 index 0000000..da558d8 --- /dev/null +++ b/apps/marketing/src/pages/404.astro @@ -0,0 +1,13 @@ +--- +import BaseLayout from '../layouts/BaseLayout.astro' +--- + + +
+ mmobench +

404 / route missing

This path did not finish the run.

The page may have moved to the canonical documentation host.

+
+ +
diff --git a/apps/marketing/src/pages/index.astro b/apps/marketing/src/pages/index.astro new file mode 100644 index 0000000..b552a26 --- /dev/null +++ b/apps/marketing/src/pages/index.astro @@ -0,0 +1,301 @@ +--- +import BaseLayout from '../layouts/BaseLayout.astro' +import { site } from '@mobench/site-config' +import manifest from '@mobench/truth/manifest' + +const docs = { + quickstart: `${site.docsUrl}/quickstart/`, + browserstack: `${site.docsUrl}/browserstack/`, + profiling: `${site.docsUrl}/profiling/`, + authoring: `${site.docsUrl}/benchmark-functions/`, +} + +type CapabilityStatus = 'supported' | 'preview' | 'planned' | 'unsupported' + +const capabilityContracts = new Map(manifest.capabilities.map((capability) => [capability.id, capability])) +const capabilityRows = [ + { capability: 'Build an Android benchmark runner', mode: 'Local toolchain', ids: ['benchmark.build.android'] }, + { capability: 'Build an iOS benchmark runner', mode: 'macOS + Xcode', ids: ['benchmark.build.ios'] }, + { capability: 'Run ordinary mobile benchmarks', mode: 'BrowserStack App Automate', ids: ['benchmark.execute.browserstack.android', 'benchmark.execute.browserstack.ios'] }, + { capability: 'Capture native profiles', mode: 'Local Android or iOS tooling', ids: ['profile.local.android-native', 'profile.local.ios-instruments'] }, + { capability: 'Run ordinary benchmarks on a local device', mode: 'Attached device / emulator / simulator', ids: ['benchmark.execute.attached-device', 'benchmark.execute.android-emulator', 'benchmark.execute.ios-simulator'] }, + { capability: 'Use --local-only for mobile timing', mode: 'Host preflight only', ids: ['benchmark.execute.local-only'] }, +] as const + +const capabilities = capabilityRows.map((row) => { + const contracts = row.ids.map((id) => { + const contract = capabilityContracts.get(id) + if (!contract) throw new Error(`Pinned manifest is missing capability ${id}`) + return contract + }) + const statuses = new Set(contracts.map((contract) => contract.status)) + if (statuses.size !== 1) throw new Error(`Capability row has mixed statuses: ${row.ids.join(', ')}`) + const tone = contracts[0].status as CapabilityStatus + return { + ...row, + status: tone[0].toUpperCase() + tone.slice(1), + tone, + evidenceIds: [...new Set(contracts.flatMap((contract) => contract.evidence_ids))], + } +}) + +const fixtureRows = [ + { device: 'Google Pixel 8 · Android 14', benchmark: 'bench_fibonacci', median: 100, p95: 105, width: 71 }, + { device: 'Google Pixel 8 · Android 14', benchmark: 'bench_checksum', median: 145, p95: 151, width: 100 }, + { device: 'Galaxy S23 · Android 14', benchmark: 'bench_fibonacci', median: 94, p95: 98, width: 66 }, + { device: 'Galaxy S23 · Android 14', benchmark: 'bench_checksum', median: 136, p95: 140, width: 93 }, +] + +const faq = [ + ['Does mobench run benchmarks on my attached phone?', `Not for ordinary benchmark runs in v${site.crateVersion}. A normal run either builds artifacts or executes through BrowserStack when devices are selected. Local native profiling is a separate, narrower path.`], + ['What does --local-only do?', 'It skips mobile builds and writes host-side preflight/spec output without executing the requested benchmark. It is useful for checking discovery and report shape, but it is not a mobile performance measurement.'], + ['Why do the examples use mobench instead of cargo mobench?', `The v${site.crateVersion} Cargo wrapper forwards an injected argument and can fail. Use the mobench executable until a tested upstream release fixes the wrapper.`], + ['Do I have to write a mobile application?', 'No. You annotate Rust functions and mobench generates runner projects. Android and iOS still require their platform toolchains and targets.'], + ['What gets written after a CI run?', 'The stable CI output directory contains summary.json, summary.md, and results.csv. Optional fetched BrowserStack artifacts and profiling outputs live in their own directories.'], +] +--- + + + + +
+
+
+

Stable release {site.release}

+

Rust benchmarks, measured on mobile.

+

mobench turns annotated Rust functions into Android and iOS runners, executes ordinary benchmarks on BrowserStack devices, and writes reviewable CI results.

+

Current stable: local ordinary runs are build and host-preflight only. Local native profiling is supported separately.

+ +
+ cargo install mobench --version {site.crateVersion} + +
+
+ +
+ + + + + + +

Fixture-shaped output · remote Android execution

+
+
+ +
+
+

Designed around the tools mobile Rust teams already ship with

+
    +
  • Rust 1.85+
  • Android NDK
  • Xcode
  • BrowserStack
  • JSON · CSV · Markdown
  • +
+
+
+ +
+
+

Capability truth

Know exactly where the work runs.

+

mobench has three distinct paths today: mobile artifact builds, hosted ordinary benchmark execution, and local native profiling. Treating those as one “local run” hides important differences.

+
+
+ + + + + {capabilities.map((row) => )} + +
Capabilities in mobench {site.release}
CapabilityExecution mode{site.release}
{row.capability}{row.mode}{row.status}
+
+

Why this is explicit: --local-only skips the mobile build and writes host-side preflight/spec output. It does not execute or measure a benchmark.

+
+ +
+
+

The working loop

From one Rust function to a result you can review.

+
    +
  1. +
    01 Annotate
    +

    Mark the path that matters.

    +

    Keep the benchmark beside the Rust code. The macro registers it; the SDK owns timing and result types.

    +
    #[benchmark]
    +pub fn verify_proof() {
    +  black_box(run());
    +}
    + Benchmark authoring +
  2. +
  3. +
    02 Build
    +

    Generate the mobile runner.

    +

    Build Android APK/test APK outputs or iOS runner artifacts with the platform toolchain.

    +
    $ mobench build \
    +  --target android \
    +  --release
    + Build requirements +
  4. +
  5. +
    03 Run
    +

    Choose a hosted device.

    +

    Supplying a device selects the BrowserStack ordinary execution path in the current stable release.

    +
    $ mobench run \
    +  --target android \
    +  --function crate::verify_proof \
    +  --devices "Google Pixel 8-14.0"
    + BrowserStack setup +
  6. +
  7. +
    04 Compare
    +

    Commit to a stable contract.

    +

    CI mode writes machine-readable data and a Markdown summary into a predictable output directory.

    +
    $ mobench ci run \
    +  --target android \
    +  --function crate::verify_proof \
    +  --devices "Google Pixel 8-14.0" \
    +  --output-dir target/mobench/ci
    + Report artifacts +
  8. +
+
+
+ +
+
+
+

Evidence, not decoration

+

The output is made to be inspected.

+

This example is rendered from the checked-in examples/fixtures/basic/summary.json fixture in {site.release}. It demonstrates report shape and is not a product performance claim.

+
  • summary.jsonautomation and downstream tooling
  • summary.mdpull requests and human review
  • results.csvanalysis and dashboards
+ Inspect the source fixture +
+
+
Checked-in fixturebasic_benchmark
5 samplesAndroid 14
+ +
+ + + + {fixtureRows.map((row) => )} +
Exact values in the basic summary fixture
DeviceBenchmarkMedianp95
{row.device}{row.benchmark}{row.median} ms{row.p95} ms
+
+

Fixture data · values are intentionally deterministic for contract testing.

+
+
+
+ +
+
+ +
+

A concrete workload shape

+

Performance questions do not stop at the host boundary.

+

ProveKit is an open-source Rust proving system with Swift, Kotlin, and C-compatible FFI surfaces. World ID documents the product context where proof technology reaches mobile users. Together they illustrate why a host-only timing number is incomplete: compilation target, FFI, mobile scheduling, and device constraints all sit on the real execution path.

+

Source-backed context only. Mobench makes no device-coverage or performance claim from these links.

+
+ +
+
+ +
+

Pick the task

Start where your performance question starts.

+
+
01 / GET STARTED

Build the first runner

Install the CLI, register one benchmark, and verify the generated Android artifacts.

Open the quickstart
+
02 / HOSTED DEVICES

Run on BrowserStack

Configure credentials and move from generated artifacts to an ordinary benchmark on remote hardware.

Set up the first run
+
03 / NATIVE CAPTURE

Profile a local build

Use the narrower Android native or iOS Instruments path to generate capture and flamegraph artifacts.

Read profiling scope
+
+
+ +
+
+

Before you build

Platform tools stay platform tools.

mobench orchestrates the work; it does not replace the Android or Apple toolchains. Install only the path you need.

+
+
CORE

Rust project

  • Rust 1.85 or newer
  • mobench {site.crateVersion}
  • mobench-sdk and benchmark macro
  • A library crate suitable for mobile output
+
ANDROID

Android build

  • Android SDK and NDK
  • ANDROID_NDK_HOME
  • cargo-ndk
  • Required Rust Android targets
+
APPLE

iOS build

  • macOS and Xcode
  • Xcode command-line tools
  • Required Rust iOS targets
  • Signing when packaging for devices
+
EXECUTION

Hosted run

  • BrowserStack App Automate account
  • Username and access key in secrets
  • A valid device label or matrix
  • Generated application and test artifacts
+
+
+
+ +
+

One ecosystem, clear boundaries

Use the level of control the job needs.

+
+
$

mobench CLI

Build orchestration, hosted runs, CI contracts, reports, and profiling commands.

CLI API
+
{ }

mobench-sdk

Timing harness, registry, builders, runner APIs, shared types, and code generation.

SDK API
+
#

mobench-macros

The #[benchmark] attribute and registration layer used by normal benchmark crates.

Macro API
+
+
+ +
+
+

Focused answers

Before the first run.

Need command-level detail? The documentation is generated as static HTML and stays usable without client JavaScript.

Browse all documentation
+
{faq.map(([question, answer], index) =>
{question}

{answer}

)}
+
+
+ +
+

Ready when the toolchain is

Build the runner. Then choose where it runs.

+ +
+
+ + +
diff --git a/apps/marketing/src/pages/privacy.astro b/apps/marketing/src/pages/privacy.astro new file mode 100644 index 0000000..5c964da --- /dev/null +++ b/apps/marketing/src/pages/privacy.astro @@ -0,0 +1,13 @@ +--- +import BaseLayout from '../layouts/BaseLayout.astro' +--- + + +
+ mmobench +

Privacy

Minimal measurement, no search text.

Mobench may collect aggregate page and interaction counts to understand whether documentation paths work. Analytics events use fixed names and non-identifying properties.

What is never sent

  • Documentation search queries
  • Copied commands or page content
  • Benchmark data, credentials, or source code

External services

Links to GitHub, docs.rs, BrowserStack, and World Foundation leave this site and follow those services’ privacy terms.

← Return to mobench.org

+
+ +
diff --git a/apps/marketing/src/scripts/analytics.ts b/apps/marketing/src/scripts/analytics.ts new file mode 100644 index 0000000..7ee5e22 --- /dev/null +++ b/apps/marketing/src/scripts/analytics.ts @@ -0,0 +1,24 @@ +import { inject, track } from '@vercel/analytics' +import { analyticsEvents, type AnalyticsEvent } from '@mobench/site-config' + +const analyticsEnabled = window.location.hostname === 'mobench.org' +const allowedEvents = new Set(analyticsEvents) + +function emit(name?: string) { + if (!analyticsEnabled || !name || !allowedEvents.has(name)) return + track(name as AnalyticsEvent) +} + +if (analyticsEnabled) inject() + +document.addEventListener('click', (event) => { + const target = event.target instanceof Element + ? event.target.closest('[data-event]') + : null + const name = target?.dataset.event + if (name !== 'install_copied') emit(name) +}) + +document.addEventListener('mobench:analytics', (event) => { + emit((event as CustomEvent<{ name?: string }>).detail?.name) +}) diff --git a/apps/marketing/src/styles/global.css b/apps/marketing/src/styles/global.css new file mode 100644 index 0000000..7ca4038 --- /dev/null +++ b/apps/marketing/src/styles/global.css @@ -0,0 +1,294 @@ +:root { + --font-sans: 'Geist Variable', 'Geist', ui-sans-serif, system-ui, sans-serif; + --font-mono: 'Geist Mono Variable', 'Geist Mono', ui-monospace, monospace; +} + +@font-face { + font-family: 'Geist Variable'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url('/fonts/geist-latin-wght-normal.woff2') format('woff2-variations'); +} + +@font-face { + font-family: 'Geist Mono Variable'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url('/fonts/geist-mono-latin-wght-normal.woff2') format('woff2-variations'); +} + +:root { + color-scheme: light; + --cream: #f4efdd; + --cream-deep: #e9e1c9; + --paper: #fffdf5; + --paper-green: #e6efd8; + --ink: #271f16; + --ink-soft: #443c31; + --muted: #625a4c; + --faint: #6c6252; + --green: #356c28; + --green-bright: #4e8b37; + --green-deep: #263e20; + --line: rgba(39, 31, 22, 0.15); + --line-strong: rgba(39, 31, 22, 0.27); + --header: rgba(244, 239, 221, 0.88); + --shadow: rgba(55, 46, 30, 0.2); + --focus: #bd571d; + --max: 82rem; +} + +:root[data-theme='dark'] { + color-scheme: dark; + --cream: #11160f; + --cream-deep: #181e15; + --paper: #181f16; + --paper-green: #1c2918; + --ink: #f5efdd; + --ink-soft: #d8d0bc; + --muted: #b9b09c; + --faint: #a19783; + --green: #9bd17e; + --green-bright: #b4e298; + --green-deep: #ccedb8; + --line: rgba(245, 239, 221, 0.15); + --line-strong: rgba(245, 239, 221, 0.27); + --header: rgba(17, 22, 15, 0.9); + --shadow: rgba(0, 0, 0, 0.44); + --focus: #f3a064; +} + +* { box-sizing: border-box; } +html { scroll-behavior: smooth; scroll-padding-top: 6rem; } +body { margin: 0; background: var(--cream); color: var(--ink); font-family: var(--font-sans); font-size: 1rem; line-height: 1.55; -webkit-font-smoothing: antialiased; } +body::before { position: fixed; z-index: -1; inset: 0; pointer-events: none; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.45'/%3E%3C/svg%3E"); opacity: .025; content: ''; } +a { color: inherit; text-decoration-thickness: .08em; text-underline-offset: .2em; } +button, summary, a { -webkit-tap-highlight-color: transparent; } +button, summary { font: inherit; } +button:focus-visible, a:focus-visible, summary:focus-visible { outline: 3px solid var(--focus); outline-offset: 4px; } +code, pre { font-family: var(--font-mono); } +h1, h2, h3, p { margin-top: 0; } +h1, h2, h3 { text-wrap: balance; } +p { text-wrap: pretty; } +.shell { width: min(100% - 2.5rem, var(--max)); margin-inline: auto; } +.section { padding-block: clamp(5.5rem, 10vw, 9.5rem); } +.sr-only { position: absolute; overflow: hidden; width: 1px; height: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; clip-path: inset(50%); } +.skip-link { position: fixed; z-index: 100; top: .75rem; left: .75rem; padding: .7rem 1rem; background: var(--ink); color: var(--cream); transform: translateY(-180%); transition: transform .15s ease; } +.skip-link:focus { transform: translateY(0); } + +.site-header { position: sticky; z-index: 20; top: 0; border-bottom: 1px solid var(--line); background: var(--header); backdrop-filter: blur(18px); } +.header-inner { display: flex; min-height: 4.7rem; align-items: center; justify-content: space-between; gap: 2rem; } +.brand { display: inline-flex; align-items: center; gap: .65rem; color: var(--ink); font-size: 1.12rem; font-weight: 650; letter-spacing: -.035em; text-decoration: none; } +.brand-mark { display: grid; width: 2rem; height: 2rem; place-items: center; border-radius: .55rem; background: var(--green); color: var(--cream); font-family: var(--font-mono); font-size: 1.05rem; font-weight: 750; } +.version { padding: .16rem .38rem; border: 1px solid var(--line-strong); color: var(--muted); font-family: var(--font-mono); font-size: .64rem; font-weight: 500; letter-spacing: .02em; } +.desktop-nav { display: flex; margin-left: auto; align-items: center; gap: clamp(1.15rem, 2vw, 2rem); } +.desktop-nav a, .github-link { color: var(--muted); font-size: .86rem; font-weight: 540; text-decoration: none; } +.desktop-nav a:hover, .github-link:hover { color: var(--ink); } +.header-actions { display: flex; align-items: center; gap: .65rem; } +.icon-button { display: grid; width: 2.75rem; height: 2.75rem; place-items: center; border: 1px solid var(--line); border-radius: .65rem; background: transparent; color: var(--ink); cursor: pointer; transition: background .18s ease, transform .18s ease; } +.icon-button:hover { background: var(--paper); transform: translateY(-1px); } +.icon-button svg { width: 1.05rem; fill: none; stroke: currentColor; stroke-linecap: round; stroke-width: 1.7; } +.moon, [data-theme='dark'] .sun { display: none; } +[data-theme='dark'] .moon { display: block; } +.button { display: inline-flex; min-height: 3.15rem; align-items: center; justify-content: center; gap: .7rem; padding: .75rem 1.25rem; border: 1px solid var(--ink); border-radius: .7rem; background: var(--ink); color: var(--cream); font-size: .91rem; font-weight: 640; text-decoration: none; box-shadow: 0 .5rem 1.2rem -.9rem var(--shadow); transition: transform .18s ease, background .18s ease, box-shadow .18s ease; } +.button:hover { background: var(--green); border-color: var(--green); transform: translateY(-2px); box-shadow: 0 .8rem 1.5rem -1rem var(--shadow); } +.button:active { transform: translateY(0) scale(.985); } +.button-small { min-height: 2.65rem; padding: .5rem .9rem; font-size: .8rem; } +.text-link { color: var(--green); font-weight: 630; text-decoration: none; } +.text-link:hover { text-decoration: underline; } +.mobile-menu { display: none; position: relative; } +.mobile-menu summary { display: grid; width: 2.75rem; height: 2.75rem; padding: .7rem; align-content: center; gap: .25rem; border: 1px solid var(--line); border-radius: .65rem; cursor: pointer; list-style: none; } +.mobile-menu summary::-webkit-details-marker { display: none; } +.mobile-menu summary span { width: 100%; height: 1px; background: currentColor; } +.mobile-menu nav { position: absolute; top: calc(100% + .75rem); right: 0; display: grid; width: min(19rem, calc(100vw - 2.5rem)); padding: .7rem; border: 1px solid var(--line); border-radius: .8rem; background: var(--paper); box-shadow: 0 1.25rem 3rem -1.5rem var(--shadow); } +.mobile-menu nav a { padding: .8rem .7rem; border-bottom: 1px solid var(--line); color: var(--ink); text-decoration: none; } +.mobile-menu nav a:last-child { border-bottom: 0; } + +.hero { display: grid; min-height: calc(100svh - 4.7rem); padding-block: clamp(4rem, 7vw, 7rem); align-items: center; grid-template-columns: minmax(0, .95fr) minmax(24rem, .83fr); gap: clamp(3rem, 8vw, 8rem); } +.hero-copy { min-width: 0; padding-bottom: 1rem; } +.eyebrow { margin-bottom: 1.15rem; color: var(--green); font-family: var(--font-mono); font-size: .72rem; font-weight: 620; letter-spacing: .12em; text-transform: uppercase; } +.live-dot { display: inline-block; width: .48rem; height: .48rem; margin-right: .45rem; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--green) 16%, transparent); } +.hero h1 { max-width: 13ch; margin-bottom: 1.8rem; font-size: clamp(3.25rem, 6.5vw, 6.8rem); font-weight: 640; letter-spacing: -.072em; line-height: .9; } +.hero h1 em { color: var(--green); font-family: Georgia, 'Times New Roman', serif; font-weight: 400; letter-spacing: -.055em; } +.hero-lede { max-width: 39rem; margin-bottom: 1.15rem; color: var(--ink-soft); font-size: clamp(1.08rem, 1.65vw, 1.35rem); line-height: 1.48; } +.truth-note { max-width: 40rem; padding: .75rem 1rem; border-left: 3px solid var(--green); background: var(--paper-green); color: var(--muted); font-size: .88rem; } +.truth-note strong { color: var(--ink); } +.hero-actions { display: flex; margin-top: 2rem; align-items: center; flex-wrap: wrap; gap: 1.3rem; } +.install-row { display: flex; overflow: hidden; width: fit-content; max-width: 100%; margin-top: 1.2rem; align-items: stretch; border: 1px solid var(--line); border-radius: .65rem; background: color-mix(in srgb, var(--paper) 64%, transparent); } +.install-row code { overflow-x: auto; min-width: 0; max-width: calc(100% - 4.5rem); flex: 1 1 auto; padding: .78rem 1rem; color: var(--ink-soft); font-size: .76rem; white-space: nowrap; } +.install-row code:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; } +.install-row code span { color: var(--green); } +.install-row button { min-width: 4.5rem; flex: 0 0 4.5rem; border: 0; border-left: 1px solid var(--line); background: transparent; color: var(--green); font-size: .72rem; font-weight: 650; cursor: pointer; } +.install-row button:hover { background: var(--paper-green); } + +.hero-art { position: relative; min-height: 35rem; overflow: hidden; border: 1px solid var(--line); border-radius: 1.6rem; background: var(--paper-green); box-shadow: 0 3rem 6rem -4rem var(--shadow); isolation: isolate; } +.hero-legacy { position: absolute; z-index: 0; inset: 0; display: block; opacity: .17; } +.hero-legacy::after { position: absolute; inset: 0; background: linear-gradient(135deg, transparent, var(--paper-green) 72%); content: ''; } +.hero-legacy img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.7) contrast(.9); } +.art-grid { position: absolute; inset: 0; background-image: linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px); background-size: 2.3rem 2.3rem; opacity: .36; mask-image: linear-gradient(to bottom, #000, transparent 88%); } +.code-ticket { position: absolute; z-index: 2; top: 12%; left: 7%; width: 52%; padding: 1rem; border: 1px solid var(--line-strong); border-radius: .75rem; background: color-mix(in srgb, var(--paper) 94%, transparent); box-shadow: 0 1.5rem 3rem -2rem var(--shadow); transform: rotate(-3deg); } +.ticket-label { margin-bottom: 1rem; padding-bottom: .55rem; border-bottom: 1px solid var(--line); color: var(--faint); font-family: var(--font-mono); font-size: .64rem; } +.code-ticket code { color: var(--ink-soft); font-size: clamp(.7rem, 1.1vw, .88rem); line-height: 1.75; } +.code-ticket code span { color: var(--green); } +.route-line { position: absolute; z-index: 1; top: 43%; left: 17%; width: 54%; color: var(--green); font-family: var(--font-mono); font-size: .6rem; letter-spacing: .07em; text-align: center; text-transform: uppercase; transform: rotate(7deg); } +.route-line span { display: block; height: 1px; margin-bottom: .4rem; background: repeating-linear-gradient(90deg, var(--green) 0 7px, transparent 7px 12px); } +.phone { position: absolute; z-index: 3; top: 19%; right: 7%; width: 41%; min-width: 11rem; padding: .55rem; border: .22rem solid var(--ink); border-radius: 2.1rem; background: var(--ink); box-shadow: 0 2.5rem 4rem -2rem var(--shadow); transform: rotate(5deg); } +.phone-sensor { position: absolute; z-index: 2; top: .9rem; left: 50%; width: 34%; height: .28rem; border-radius: 1rem; background: color-mix(in srgb, var(--cream) 18%, var(--ink)); transform: translateX(-50%); } +.phone-screen { min-height: 22rem; padding: 3rem 1.1rem 1.2rem; border-radius: 1.55rem; background: #182414; color: #f4efdd; } +.screen-kicker { color: #a8d88f; font-family: var(--font-mono); font-size: .58rem; letter-spacing: .13em; } +.screen-value { margin-block: 1.4rem 1rem; font-family: var(--font-mono); font-size: clamp(2rem, 5vw, 3.35rem); font-weight: 650; letter-spacing: -.08em; } +.screen-value span { font-size: .8rem; font-weight: 450; letter-spacing: 0; } +.screen-rule { height: 2.6rem; margin-bottom: 1.5rem; border-bottom: 1px solid rgba(244, 239, 221, .17); } +.screen-rule i { display: block; width: 73%; height: .42rem; border-radius: 1rem; background: #9bd17e; box-shadow: 0 .8rem 0 rgba(155, 209, 126, .35), 0 1.6rem 0 rgba(155, 209, 126, .18); } +.screen-meta { display: flex; padding-block: .55rem; justify-content: space-between; border-bottom: 1px solid rgba(244, 239, 221, .13); font-family: var(--font-mono); font-size: .65rem; } +.screen-meta span { color: #a9af9f; } +.bench { position: absolute; z-index: 2; right: 3%; bottom: 7%; left: 3%; transform: perspective(20rem) rotateX(13deg); } +.bench span { display: block; height: .8rem; margin-top: .42rem; border: 1px solid rgba(39, 31, 22, .25); border-radius: .2rem; background: #788f5c; box-shadow: 0 .3rem .5rem -.35rem var(--shadow); } +.bench::before, .bench::after { position: absolute; top: 100%; width: .7rem; height: 2.2rem; background: var(--ink); content: ''; } +.bench::before { left: 12%; }.bench::after { right: 12%; } +.art-caption { position: absolute; z-index: 4; bottom: .7rem; left: 1rem; color: var(--muted); font-family: var(--font-mono); font-size: .58rem; letter-spacing: .04em; } + +.signal-strip { border-block: 1px solid var(--line); background: var(--paper); } +.signal-inner { display: flex; min-height: 5rem; align-items: center; justify-content: space-between; gap: 2rem; } +.signal-inner p { margin: 0; color: var(--faint); font-family: var(--font-mono); font-size: .67rem; letter-spacing: .08em; text-transform: uppercase; } +.signal-inner ul { display: flex; margin: 0; padding: 0; align-items: center; flex-wrap: wrap; gap: 1.8rem; color: var(--ink-soft); font-family: var(--font-mono); font-size: .69rem; list-style: none; } +.signal-inner li + li::before { margin-right: 1.8rem; color: var(--line-strong); content: '/'; } + +.section-intro { max-width: 53rem; margin-bottom: 3.8rem; } +.section-intro h2, .results-copy h2, .faq-grid h2, .final-cta h2 { margin-bottom: 1.2rem; font-size: clamp(2.4rem, 4.7vw, 4.8rem); font-weight: 610; letter-spacing: -.06em; line-height: .98; } +.split-intro { display: grid; max-width: none; grid-template-columns: 1.05fr .75fr; gap: clamp(2rem, 8vw, 8rem); } +.split-intro > p { max-width: 35rem; margin: 1.9rem 0 0; color: var(--muted); font-size: 1.07rem; } +.table-wrap { overflow-x: auto; } +table { width: 100%; border-collapse: collapse; } +.capability-table { min-width: 44rem; border-top: 1px solid var(--line-strong); } +.capability-table th, .capability-table td { padding: 1.15rem .9rem; border-bottom: 1px solid var(--line); text-align: left; } +.capability-table thead th { color: var(--faint); font-family: var(--font-mono); font-size: .66rem; font-weight: 550; letter-spacing: .1em; text-transform: uppercase; } +.capability-table tbody th { width: 41%; font-size: .93rem; font-weight: 600; } +.capability-table tbody td { color: var(--muted); font-size: .9rem; } +.status { display: inline-flex; align-items: center; gap: .5rem; color: var(--ink); font-family: var(--font-mono); font-size: .69rem; font-weight: 600; text-transform: uppercase; white-space: nowrap; } +.status i { width: .52rem; height: .52rem; border-radius: 50%; background: var(--green); } +.status.unsupported i { border: 1px solid var(--faint); background: transparent; } +.table-note { margin: 1.5rem 0 0; padding: 1rem 1.2rem; border: 1px solid var(--line); background: var(--paper); color: var(--muted); font-size: .85rem; } +.table-note strong { color: var(--ink); } + +.workflow-section { border-block: 1px solid var(--line); background: var(--paper); } +.workflow { display: grid; margin: 0; padding: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); border-top: 1px solid var(--line-strong); list-style: none; } +.workflow li { display: flex; min-height: 32rem; padding: 2rem; flex-direction: column; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); } +.workflow li:nth-child(2n) { border-right: 0; } +.step-index { display: flex; margin-bottom: 4rem; justify-content: space-between; color: var(--green); font-family: var(--font-mono); font-size: .68rem; letter-spacing: .09em; } +.step-index span { color: var(--faint); } +.workflow h3 { margin-bottom: .75rem; font-size: clamp(1.55rem, 2.6vw, 2.25rem); font-weight: 610; letter-spacing: -.045em; } +.workflow p { max-width: 32rem; color: var(--muted); font-size: .92rem; } +.workflow pre { overflow-x: auto; margin: auto 0 1.5rem; padding: 1.15rem; border: 1px solid var(--line); border-radius: .55rem; background: var(--cream); color: var(--ink-soft); font-size: .72rem; line-height: 1.7; } +.workflow a { color: var(--green); font-size: .82rem; font-weight: 640; text-decoration: none; } +.workflow a:hover { text-decoration: underline; } +.code-attr, .code-prompt { color: var(--green); } + +.results-section { padding-block: clamp(6rem, 11vw, 10rem); background: var(--green-deep); color: var(--cream); } +[data-theme='dark'] .results-section { background: #080c07; color: var(--ink); } +.results-grid { display: grid; grid-template-columns: .75fr 1.15fr; gap: clamp(3rem, 8vw, 8rem); align-items: center; } +.results-copy .eyebrow { color: #bce8a5; } +.results-copy > p:not(.eyebrow) { max-width: 33rem; color: color-mix(in srgb, var(--cream) 72%, transparent); } +[data-theme='dark'] .results-copy > p:not(.eyebrow) { color: var(--muted); } +.artifact-list { margin: 2rem 0; padding: 0; border-top: 1px solid color-mix(in srgb, var(--cream) 20%, transparent); list-style: none; } +.artifact-list li { display: grid; padding-block: .85rem; grid-template-columns: 9rem 1fr; gap: 1rem; border-bottom: 1px solid color-mix(in srgb, var(--cream) 20%, transparent); font-size: .79rem; } +.artifact-list span { color: color-mix(in srgb, var(--cream) 64%, transparent); } +[data-theme='dark'] .artifact-list span { color: var(--muted); } +.results-section .text-link { color: #bce8a5; } +.result-panel { min-width: 0; margin: 0; padding: clamp(1.2rem, 3vw, 2.2rem); border: 1px solid rgba(244, 239, 221, .18); border-radius: 1.1rem; background: #f4efdd; color: #271f16; box-shadow: 0 2rem 5rem -3rem rgba(0,0,0,.6); transform: rotate(.65deg); } +.result-panel figcaption { display: flex; padding-bottom: 1rem; justify-content: space-between; border-bottom: 1px solid rgba(39,31,22,.16); } +.result-panel figcaption div { display: grid; gap: .12rem; } +.result-panel figcaption span, .result-panel > p { color: #766b59; font-family: var(--font-mono); font-size: .58rem; letter-spacing: .07em; text-transform: uppercase; } +.result-panel figcaption strong { font-family: var(--font-mono); font-size: .74rem; } +.plot { padding-block: 1.5rem; } +.plot-row { display: grid; padding-block: .7rem; align-items: center; grid-template-columns: minmax(7.5rem, .9fr) 1.4fr 3.6rem; gap: .9rem; } +.plot-row > div:first-child { display: grid; } +.plot-row span { font-size: .68rem; font-weight: 630; }.plot-row small { color: #766b59; font-family: var(--font-mono); font-size: .54rem; } +.bar-track { height: .52rem; border-radius: 1rem; background: #ddd6c3; }.bar-track i { display: block; width: var(--bar); height: 100%; border-radius: inherit; background: #4c823a; } +.plot-row b { font-family: var(--font-mono); font-size: .65rem; text-align: right; } +.fixture-table-wrap { overflow-x: auto; border-top: 1px solid rgba(39,31,22,.16); } +.fixture-table-wrap table { min-width: 32rem; font-size: .62rem; } +.fixture-table-wrap th, .fixture-table-wrap td { padding: .5rem .35rem; border-bottom: 1px solid rgba(39,31,22,.1); text-align: left; }.fixture-table-wrap thead th { color: #766b59; font-family: var(--font-mono); font-weight: 520; }.fixture-table-wrap tbody th { font-weight: 620; } +.result-panel > p { margin: 1rem 0 0; } + +.context-section { padding-block: clamp(5rem, 9vw, 8rem); border-bottom: 1px solid var(--line); background: var(--paper); } +.context-grid { display: grid; grid-template-columns: .45fr 1.2fr .55fr; gap: clamp(2rem, 6vw, 6rem); align-items: start; } +.context-index { color: var(--green); font-family: var(--font-mono); font-size: clamp(1.5rem, 3vw, 2.8rem); font-weight: 650; letter-spacing: -.06em; line-height: 1.25; } +.context-grid h2 { max-width: 18ch; margin-bottom: 1.5rem; font-size: clamp(2.2rem, 4vw, 4rem); font-weight: 610; letter-spacing: -.058em; line-height: 1; } +.context-grid > div:nth-child(2) > p:not(.eyebrow) { max-width: 47rem; color: var(--muted); font-size: 1rem; } +.context-grid > div:nth-child(2) a { color: var(--green); font-weight: 620; } +.context-grid .source-note { padding-left: .9rem; border-left: 2px solid var(--green); font-family: var(--font-mono); font-size: .7rem !important; } +.context-grid aside { display: grid; border-top: 1px solid var(--line-strong); } +.context-grid aside span { padding-block: .8rem; color: var(--faint); font-family: var(--font-mono); font-size: .61rem; letter-spacing: .1em; } +.context-grid aside a { display: flex; padding-block: .85rem; justify-content: space-between; border-top: 1px solid var(--line); color: var(--ink); font-size: .76rem; font-weight: 590; text-decoration: none; } +.context-grid aside a:hover { color: var(--green); } + +.path-grid { display: grid; grid-template-columns: 1.1fr .95fr .95fr; border-top: 1px solid var(--line-strong); } +.path { display: flex; min-height: 25rem; padding: 2rem; flex-direction: column; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); } +.path:last-child { border-right: 0; } +.path-primary { background: var(--paper-green); } +.path > span, .requirements-grid article > span { color: var(--faint); font-family: var(--font-mono); font-size: .63rem; letter-spacing: .1em; } +.path h3 { margin: auto 0 .8rem; font-size: 2rem; font-weight: 610; letter-spacing: -.045em; } +.path p { color: var(--muted); font-size: .9rem; } +.path a { margin-top: 1rem; color: var(--green); font-size: .82rem; font-weight: 640; text-decoration: none; } + +.requirements-section { border-block: 1px solid var(--line); background: var(--cream-deep); } +.requirements-grid { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--line-strong); } +.requirements-grid article { padding: 1.7rem; border-right: 1px solid var(--line); } +.requirements-grid article:last-child { border-right: 0; } +.requirements-grid h3 { margin: 4rem 0 1rem; font-size: 1.35rem; letter-spacing: -.035em; } +.requirements-grid ul { margin: 0; padding: 0; color: var(--muted); font-size: .82rem; list-style: none; } +.requirements-grid li { padding-block: .55rem; border-top: 1px solid var(--line); } +.ecosystem-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; } +.ecosystem-grid article { display: grid; padding-top: 1.4rem; grid-template-columns: 3rem 1fr; gap: 1rem; border-top: 1px solid var(--line-strong); } +.eco-icon { display: grid; width: 2.5rem; height: 2.5rem; place-items: center; border-radius: .55rem; background: var(--paper-green); color: var(--green); font-family: var(--font-mono); font-size: .8rem; font-weight: 680; } +.ecosystem h3 { margin-bottom: .5rem; font-size: 1.35rem; letter-spacing: -.035em; }.ecosystem p { color: var(--muted); font-size: .86rem; }.ecosystem a { color: var(--green); font-size: .78rem; font-weight: 630; text-decoration: none; } + +.faq-section { padding-block: clamp(6rem, 10vw, 9rem); border-top: 1px solid var(--line); background: var(--paper); } +.faq-grid { display: grid; grid-template-columns: .65fr 1fr; gap: clamp(3rem, 8vw, 8rem); } +.faq-grid > div:first-child > p:not(.eyebrow) { max-width: 30rem; color: var(--muted); } +.faq-list { border-top: 1px solid var(--line-strong); } +.faq-list details { border-bottom: 1px solid var(--line); } +.faq-list summary { display: flex; min-height: 4.8rem; padding-block: 1rem; align-items: center; justify-content: space-between; gap: 1rem; font-weight: 600; cursor: pointer; list-style: none; } +.faq-list summary::-webkit-details-marker { display: none; } +.faq-list summary span { position: relative; width: 1.2rem; height: 1.2rem; flex: none; } +.faq-list summary span::before, .faq-list summary span::after { position: absolute; top: 50%; left: 50%; width: .8rem; height: 1px; background: var(--green); content: ''; transform: translate(-50%,-50%); }.faq-list summary span::after { transform: translate(-50%,-50%) rotate(90deg); transition: transform .15s ease; }.faq-list details[open] summary span::after { transform: translate(-50%,-50%); } +.faq-list details p { max-width: 48rem; padding: 0 3rem 1.4rem 0; color: var(--muted); font-size: .9rem; } + +.final-cta { display: grid; margin-block: 2rem; padding: clamp(3rem, 7vw, 6rem); grid-template-columns: 1fr auto; gap: 3rem; align-items: end; border-radius: 1.5rem; background: var(--green); color: var(--cream); } +.final-cta h2 { max-width: 13ch; margin: 0; }.final-cta .eyebrow { color: var(--cream); }.final-cta > div:last-child { display: grid; gap: 1.2rem; }.button-cream { border-color: var(--cream); background: var(--cream); color: var(--ink); }.button-cream:hover { border-color: var(--paper-green); background: var(--paper-green); color: #271f16; }.footer-github { color: inherit; font-size: .8rem; text-align: center; text-decoration: none; } +footer { border-top: 1px solid var(--line); }.footer-inner { display: flex; min-height: 7rem; align-items: center; gap: 2rem; }.footer-brand { margin-right: auto; }.footer-inner p { margin: 0; color: var(--muted); font-size: .76rem; }.footer-inner nav { display: flex; gap: 1.3rem; }.footer-inner nav a { color: var(--muted); font-size: .76rem; text-decoration: none; } + +@media (max-width: 70rem) { + .desktop-nav { display: none; }.mobile-menu { display: block; }.github-link { display: none; } + .hero { min-height: auto; grid-template-columns: 1fr 24rem; gap: 3rem; }.hero h1 { font-size: clamp(3.5rem, 7vw, 5.5rem); }.hero-art { min-height: 31rem; } + .requirements-grid { grid-template-columns: repeat(2, 1fr); }.requirements-grid article:nth-child(2) { border-right: 0; }.requirements-grid article:nth-child(-n+2) { border-bottom: 1px solid var(--line); } +} +@media (max-width: 52rem) { + .shell { width: min(100% - 2rem, var(--max)); } + .hero { padding-top: 4rem; grid-template-columns: 1fr; }.hero-copy { max-width: 46rem; }.hero h1 { font-size: clamp(3.4rem, 13vw, 6rem); }.hero-art { width: min(100%, 33rem); min-height: 34rem; margin-inline: auto; } + .signal-inner { padding-block: 1.3rem; align-items: flex-start; flex-direction: column; gap: .8rem; }.signal-inner ul { gap: .7rem 1rem; }.signal-inner li + li::before { display: none; } + .split-intro, .results-grid, .faq-grid, .context-grid { grid-template-columns: 1fr; gap: 2rem; }.split-intro > p { margin-top: 0; } + .context-index { display: none; }.context-grid aside { max-width: 24rem; } + .workflow { grid-template-columns: 1fr; }.workflow li { border-right: 0; }.workflow li:nth-child(2n) { border-right: 0; } + .path-grid { grid-template-columns: 1fr; }.path { min-height: 19rem; border-right: 0; }.path h3 { margin-top: 3rem; } + .ecosystem-grid { grid-template-columns: 1fr; } + .final-cta { grid-template-columns: 1fr; align-items: start; } + .footer-inner { padding-block: 2rem; align-items: flex-start; flex-direction: column; gap: 1rem; }.footer-brand { margin: 0; } +} +@media (max-width: 36rem) { + .header-inner { min-height: 4.1rem; }.version, .header-actions > .button-small { display: none; }.brand { font-size: 1rem; }.brand-mark { width: 1.8rem; height: 1.8rem; } + .hero { min-height: auto; padding-block: 3.5rem 4.5rem; }.hero h1 { font-size: clamp(3.25rem, 17vw, 5rem); }.hero-actions { align-items: flex-start; flex-direction: column; }.install-row { width: 100%; }.install-row code { flex: 1; } + .hero-art { min-height: 28rem; border-radius: 1.1rem; }.code-ticket { top: 8%; left: 4%; width: 58%; }.phone { top: 21%; right: 3%; width: 45%; min-width: 9.5rem; }.phone-screen { min-height: 18.5rem; padding-inline: .8rem; }.route-line { display: none; } + .section { padding-block: 5rem; }.section-intro { margin-bottom: 2.5rem; }.section-intro h2, .results-copy h2, .faq-grid h2, .final-cta h2 { font-size: 2.55rem; } + .workflow li { min-height: 29rem; padding: 1.25rem; }.step-index { margin-bottom: 3rem; } + .plot-row { grid-template-columns: 6.5rem 1fr 3.2rem; gap: .5rem; }.result-panel { transform: none; }.fixture-table-wrap { margin-inline: -.25rem; } + .requirements-grid { grid-template-columns: 1fr; }.requirements-grid article { border-right: 0; border-bottom: 1px solid var(--line); }.requirements-grid article:nth-child(2) { border-right: 0; }.requirements-grid h3 { margin-top: 2.5rem; } + .final-cta { margin-block: 1rem; padding: 2rem 1.4rem; border-radius: 1rem; } +} +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; } +} diff --git a/apps/marketing/tsconfig.json b/apps/marketing/tsconfig.json new file mode 100644 index 0000000..70fba30 --- /dev/null +++ b/apps/marketing/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"], + "compilerOptions": { + "baseUrl": "." + } +} diff --git a/apps/marketing/vercel.json b/apps/marketing/vercel.json new file mode 100644 index 0000000..cfaf5dd --- /dev/null +++ b/apps/marketing/vercel.json @@ -0,0 +1,353 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": "astro", + "installCommand": "cd ../.. && bun install --frozen-lockfile", + "buildCommand": "cd ../.. && bun run generate && bun run build:marketing", + "outputDirectory": "dist", + "redirects": [ + { + "source": "/analyze-results/outputs", + "destination": "https://docs.mobench.org/outputs/", + "permanent": true + }, + { + "source": "/analyze-results/profiling", + "destination": "https://docs.mobench.org/profiling/", + "permanent": true + }, + { + "source": "/analyze-results/regressions", + "destination": "https://docs.mobench.org/regressions/", + "permanent": true + }, + { + "source": "/app-automate", + "destination": "https://docs.mobench.org/browserstack/", + "permanent": true + }, + { + "source": "/authoring", + "destination": "https://docs.mobench.org/benchmark-functions/", + "permanent": true + }, + { + "source": "/basic-example", + "destination": "https://docs.mobench.org/basic-example/", + "permanent": true + }, + { + "source": "/benchmark-functions", + "destination": "https://docs.mobench.org/benchmark-functions/", + "permanent": true + }, + { + "source": "/benchmark-quality", + "destination": "https://docs.mobench.org/benchmark-quality/", + "permanent": true + }, + { + "source": "/browserstack", + "destination": "https://docs.mobench.org/browserstack/", + "permanent": true + }, + { + "source": "/build", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/build-artifacts", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/ci", + "destination": "https://docs.mobench.org/ci/", + "permanent": true + }, + { + "source": "/cli", + "destination": "https://docs.mobench.org/cli/", + "permanent": true + }, + { + "source": "/cli-man-pages", + "destination": "https://docs.mobench.org/cli/", + "permanent": true + }, + { + "source": "/cli-reference", + "destination": "https://docs.mobench.org/cli/", + "permanent": true + }, + { + "source": "/codebase", + "destination": "https://docs.mobench.org/troubleshooting/", + "permanent": true + }, + { + "source": "/compatibility", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/concepts", + "destination": "https://docs.mobench.org/configuration/", + "permanent": true + }, + { + "source": "/configuration", + "destination": "https://docs.mobench.org/configuration/", + "permanent": true + }, + { + "source": "/current-spec", + "destination": "https://docs.mobench.org/schemas/", + "permanent": true + }, + { + "source": "/device-matrices", + "destination": "https://docs.mobench.org/device-matrices/", + "permanent": true + }, + { + "source": "/diagrams", + "destination": "https://docs.mobench.org/device-matrices/", + "permanent": true + }, + { + "source": "/docs", + "destination": "https://docs.mobench.org/", + "permanent": true + }, + { + "source": "/docs/:path*", + "destination": "https://docs.mobench.org/:path*", + "permanent": true + }, + { + "source": "/examples", + "destination": "https://docs.mobench.org/basic-example/", + "permanent": true + }, + { + "source": "/examples/basic", + "destination": "https://docs.mobench.org/basic-example/", + "permanent": true + }, + { + "source": "/examples/ffi", + "destination": "https://docs.mobench.org/ffi-example/", + "permanent": true + }, + { + "source": "/ffi-example", + "destination": "https://docs.mobench.org/ffi-example/", + "permanent": true + }, + { + "source": "/get-started/installation", + "destination": "https://docs.mobench.org/installation/", + "permanent": true + }, + { + "source": "/get-started/quickstart", + "destination": "https://docs.mobench.org/quickstart/", + "permanent": true + }, + { + "source": "/help/troubleshooting", + "destination": "https://docs.mobench.org/troubleshooting/", + "permanent": true + }, + { + "source": "/home", + "destination": "https://docs.mobench.org/", + "permanent": true + }, + { + "source": "/host-preflight", + "destination": "https://docs.mobench.org/host-preflight/", + "permanent": true + }, + { + "source": "/install", + "destination": "https://docs.mobench.org/installation/", + "permanent": true + }, + { + "source": "/installation", + "destination": "https://docs.mobench.org/installation/", + "permanent": true + }, + { + "source": "/local-devices", + "destination": "https://docs.mobench.org/host-preflight/", + "permanent": true + }, + { + "source": "/outputs", + "destination": "https://docs.mobench.org/outputs/", + "permanent": true + }, + { + "source": "/outputs-and-reports", + "destination": "https://docs.mobench.org/outputs/", + "permanent": true + }, + { + "source": "/overview", + "destination": "https://docs.mobench.org/", + "permanent": true + }, + { + "source": "/profiling", + "destination": "https://docs.mobench.org/profiling/", + "permanent": true + }, + { + "source": "/public-api", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/quickstart", + "destination": "https://docs.mobench.org/quickstart/", + "permanent": true + }, + { + "source": "/reference", + "destination": "https://docs.mobench.org/schemas/", + "permanent": true + }, + { + "source": "/reference/cli", + "destination": "https://docs.mobench.org/cli/", + "permanent": true + }, + { + "source": "/reference/compatibility", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/reference/configuration", + "destination": "https://docs.mobench.org/configuration/", + "permanent": true + }, + { + "source": "/reference/device-matrices", + "destination": "https://docs.mobench.org/device-matrices/", + "permanent": true + }, + { + "source": "/reference/schemas", + "destination": "https://docs.mobench.org/schemas/", + "permanent": true + }, + { + "source": "/regressions", + "destination": "https://docs.mobench.org/regressions/", + "permanent": true + }, + { + "source": "/reports", + "destination": "https://docs.mobench.org/outputs/", + "permanent": true + }, + { + "source": "/run-benchmarks/browserstack", + "destination": "https://docs.mobench.org/browserstack/", + "permanent": true + }, + { + "source": "/run-benchmarks/ci", + "destination": "https://docs.mobench.org/ci/", + "permanent": true + }, + { + "source": "/run-benchmarks/preflight", + "destination": "https://docs.mobench.org/host-preflight/", + "permanent": true + }, + { + "source": "/schemas", + "destination": "https://docs.mobench.org/schemas/", + "permanent": true + }, + { + "source": "/sdk", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/sdk-integration", + "destination": "https://docs.mobench.org/compatibility/", + "permanent": true + }, + { + "source": "/setup-and-teardown", + "destination": "https://docs.mobench.org/setup-teardown/", + "permanent": true + }, + { + "source": "/setup-teardown", + "destination": "https://docs.mobench.org/setup-teardown/", + "permanent": true + }, + { + "source": "/testing", + "destination": "https://docs.mobench.org/troubleshooting/", + "permanent": true + }, + { + "source": "/troubleshooting", + "destination": "https://docs.mobench.org/troubleshooting/", + "permanent": true + }, + { + "source": "/write-benchmarks/benchmark-functions", + "destination": "https://docs.mobench.org/benchmark-functions/", + "permanent": true + }, + { + "source": "/write-benchmarks/quality", + "destination": "https://docs.mobench.org/benchmark-quality/", + "permanent": true + }, + { + "source": "/write-benchmarks/setup-teardown", + "destination": "https://docs.mobench.org/setup-teardown/", + "permanent": true + }, + { + "source": "/writing", + "destination": "https://docs.mobench.org/benchmark-functions/", + "permanent": true + }, + { + "source": "/writing-benchmarks", + "destination": "https://docs.mobench.org/benchmark-functions/", + "permanent": true + } + ], + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "Referrer-Policy", + "value": "strict-origin-when-cross-origin" + }, + { + "key": "Permissions-Policy", + "value": "camera=(), microphone=(), geolocation=()" + } + ] + } + ] +} diff --git a/bun.lock b/bun.lock index d7b1448..f62b8c6 100644 --- a/bun.lock +++ b/bun.lock @@ -4,125 +4,328 @@ "workspaces": { "": { "name": "mobench-org", + "devDependencies": { + "@axe-core/playwright": "4.12.1", + "@lhci/cli": "0.15.1", + "@playwright/test": "1.61.1", + "ajv": "8.20.0", + "yaml": "2.9.0", + }, + }, + "apps/docs": { + "name": "@mobench/docs", + "version": "1.0.0", + "dependencies": { + "@astrojs/sitemap": "^3.7.3", + "@astrojs/starlight": "^0.41.3", + "@mobench/site-config": "workspace:*", + "@vercel/analytics": "2.0.1", + "astro": "7.0.6", + "sharp": "0.35.3", + }, + "devDependencies": { + "@astrojs/check": "^0.9.6", + "typescript": "^6.0.3", + }, + }, + "apps/marketing": { + "name": "@mobench/marketing", + "version": "1.0.0", "dependencies": { - "@radix-ui/react-accordion": "^1.2.14", - "@radix-ui/react-slot": "^1.3.0", - "@tanstack/react-router": "^1.170.16", - "@tanstack/react-router-devtools": "^1.167.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^1.21.0", - "mermaid": "11.15.0", - "react": "^19.2.7", - "react-dom": "^19.2.7", - "tailwind-merge": "^3.6.0", - "tailwindcss-animate": "^1.0.7", + "@astrojs/sitemap": "^3.7.3", + "@mobench/site-config": "workspace:*", + "@mobench/truth": "workspace:*", + "@vercel/analytics": "2.0.1", + "astro": "7.0.6", + "sharp": "0.35.3", }, "devDependencies": { - "@tailwindcss/vite": "^4.3.1", - "@tanstack/router-plugin": "^1.168.18", - "@types/node": "^26.0.0", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "tailwindcss": "^4.3.1", + "@astrojs/check": "^0.9.6", "typescript": "^6.0.3", - "vite": "^8.0.16", }, }, + "packages/site-config": { + "name": "@mobench/site-config", + "version": "1.0.0", + "dependencies": { + "@mobench/truth": "workspace:*", + }, + }, + "packages/truth": { + "name": "@mobench/truth", + "version": "0.1.43", + }, }, "packages": { - "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], + "@astrojs/check": ["@astrojs/check@0.9.9", "", { "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": "^5.0.0 || ^6.0.0" }, "bin": { "astro-check": "bin/astro-check.js" } }, "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg=="], + + "@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="], + + "@astrojs/compiler-binding": ["@astrojs/compiler-binding@0.3.0", "", { "optionalDependencies": { "@astrojs/compiler-binding-darwin-arm64": "0.3.0", "@astrojs/compiler-binding-darwin-x64": "0.3.0", "@astrojs/compiler-binding-linux-arm64-gnu": "0.3.0", "@astrojs/compiler-binding-linux-arm64-musl": "0.3.0", "@astrojs/compiler-binding-linux-x64-gnu": "0.3.0", "@astrojs/compiler-binding-linux-x64-musl": "0.3.0", "@astrojs/compiler-binding-wasm32-wasi": "0.3.0", "@astrojs/compiler-binding-win32-arm64-msvc": "0.3.0", "@astrojs/compiler-binding-win32-x64-msvc": "0.3.0" } }, "sha512-zlsOT5COD9hRwplJCgQhS21unxON5AKirf0vgt1ijXwuseYIaZdm2ZOpF8fsz+DY9EyXx+I/ukxtg7uoBep68A=="], + + "@astrojs/compiler-binding-darwin-arm64": ["@astrojs/compiler-binding-darwin-arm64@0.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3n0uu+uJpnCq8b4JFi3uGDsIisAvHctxSmH+cIO9Gbei1H1Y1QXaYboXyiWJugUmprr3OEYP7+LdodzpVFzLMQ=="], - "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], + "@astrojs/compiler-binding-darwin-x64": ["@astrojs/compiler-binding-darwin-x64@0.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-scxNGKjOBydMo1QR4LtK0FMgh7ubQomJDv953nz2msQFkPKke/0FpPv/cQM0T/kuZdReZQFU8Oz3iOrP/6WHEg=="], - "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], + "@astrojs/compiler-binding-linux-arm64-gnu": ["@astrojs/compiler-binding-linux-arm64-gnu@0.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-NZrWLolVUANmrnl0zrFK/Sx5Sock1gEUT49ALfMTTCA5Ya2ec/BoJXMIg4KgE+wZcrdXJ8e+WyEhM7YLk/FJkA=="], - "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", "@babel/helper-module-transforms": "^7.29.7", "@babel/helpers": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="], + "@astrojs/compiler-binding-linux-arm64-musl": ["@astrojs/compiler-binding-linux-arm64-musl@0.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PjwRmKgMFDsFhg82g0poXlIY8Qn3fMA3hXjaR0coJWJzTJsRH9ATU0j2ocigjtU1h3vL/yR7yLUxGj/lTCq73g=="], - "@babel/generator": ["@babel/generator@7.29.7", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ=="], + "@astrojs/compiler-binding-linux-x64-gnu": ["@astrojs/compiler-binding-linux-x64-gnu@0.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Dr69VJYlnSfyL8gzELW6S4mE41P7TDPn1IKjwMnjdZ7+dxgJI50oMLFSk1LVe26bHmWB3ktuh8fDVK1THI9e9A=="], - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], + "@astrojs/compiler-binding-linux-x64-musl": ["@astrojs/compiler-binding-linux-x64-musl@0.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-AEt+bRw8PfImCcyRH1lpXVB8CdmQ1K/wPo5u99iec4/U/XdNvQZ715YVuNzIJpbJXelgQeZ5H2+Ea7XwRyWY5g=="], - "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], + "@astrojs/compiler-binding-wasm32-wasi": ["@astrojs/compiler-binding-wasm32-wasi@0.3.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-U80tA1j8V6LjhiTZzVCtG4E8hrNVVNXDGV5fCgJ94q8FU9CPH+XwdDDhLzBybfWhKfyItXmQiZNRPTiPCYTpVg=="], - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], + "@astrojs/compiler-binding-win32-arm64-msvc": ["@astrojs/compiler-binding-win32-arm64-msvc@0.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-CpY1RII2r1XMpOUVD1VR/F2wtuRsiOCkFULS10Khyj8/DFZMtxVuUCAWGw+CW2Ka0h6eP3Xc1CA+glFlvXMPxA=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], + "@astrojs/compiler-binding-win32-x64-msvc": ["@astrojs/compiler-binding-win32-x64-msvc@0.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-qmFbs769oeeGrRebAnCW7aBk8m71vf85W/dX/jddfx5Z06/w0wf7TZCfJPOX1Fld2t+4N+iXzfGEJG+zJQ+bzg=="], + + "@astrojs/compiler-rs": ["@astrojs/compiler-rs@0.3.0", "", { "dependencies": { "@astrojs/compiler-binding": "0.3.0" } }, "sha512-J2qEVHtIDjEM9TxwmwuebOGmZNwhKu/dR7P7qBpnJKGmBBX0vdweQ/4cEXhj8fBbWVUB5V12xWChri3CgKNULQ=="], + + "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.10.1", "", { "dependencies": { "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "js-yaml": "^4.1.1", "picomatch": "^4.0.4", "retext-smartypants": "^6.2.0", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "unified": "^11.0.5" } }, "sha512-5phcroT/vmOOrYuuAxtkbPixy5hePtlz9i8K4OeDv3dNK6/UQRuXPOSRTxIOBbUY5Sonw2UaxjbuVc43Mcir6Q=="], + + "@astrojs/language-server": ["@astrojs/language-server@2.16.11", "", { "dependencies": { "@astrojs/compiler": "^2.13.1", "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", "tinyglobby": "^0.2.16", "volar-service-css": "0.0.71", "volar-service-emmet": "0.0.71", "volar-service-html": "0.0.71", "volar-service-prettier": "0.0.71", "volar-service-typescript": "0.0.71", "volar-service-typescript-twoslash-queries": "0.0.71", "volar-service-yaml": "0.0.71", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "./bin/nodeServer.js" } }, "sha512-sJ/EfnFp0+gurTrkvONtd9qRqmMZLT9bHelfI1SA35CaQVTrRrA74qteOcNT/al1b9Atg3IiH1Jk/qfckyC+fg=="], + + "@astrojs/markdown-remark": ["@astrojs/markdown-remark@7.2.1", "", { "dependencies": { "@astrojs/internal-helpers": "0.10.1", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-jPVNIqTvk+yKviikszv/Y1U4jGUSKpp/Nw48QZV4qjWgp70j4Lkq3lhSDRbWwCfgKvEyO9GHuVbV1dM2WYXy1w=="], + + "@astrojs/markdown-satteri": ["@astrojs/markdown-satteri@0.3.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.10.1", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", "satteri": "^0.9.1" } }, "sha512-Lje33Ittd8UQGgbIIWQvhPkj5X5c4b1sZnZWX3JQV/AWpfbuQGxVi2ONt6+ScydcwfR4egilslEWyczMclrJ1g=="], + + "@astrojs/mdx": ["@astrojs/mdx@7.0.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.10.1", "@astrojs/markdown-remark": "7.2.1", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.16.0", "es-module-lexer": "^2.0.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "peerDependencies": { "@astrojs/markdown-satteri": "^0.3.1", "astro": "^7.0.0" }, "optionalPeers": ["@astrojs/markdown-satteri"] }, "sha512-l+sJY5U1KkGZUdr+bIL4Y6BefeS549qoSHVSkUSs6A9INwdCND+/0+vN0NroPBXwl5Vcg5u78t7VQRsJjePxbw=="], + + "@astrojs/prism": ["@astrojs/prism@4.0.2", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA=="], + + "@astrojs/sitemap": ["@astrojs/sitemap@3.7.3", "", { "dependencies": { "sitemap": "^9.0.0", "stream-replace-string": "^2.0.0", "zod": "^4.3.6" } }, "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA=="], + + "@astrojs/starlight": ["@astrojs/starlight@0.41.3", "", { "dependencies": { "@astrojs/markdown-satteri": "^0.3.2", "@astrojs/mdx": "^7.0.0", "@astrojs/sitemap": "^3.7.2", "@pagefind/default-ui": "^1.3.0", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/mdast": "^4.0.4", "astro-expressive-code": "^0.44.0", "bcp-47": "^2.1.0", "hast-util-from-html": "^2.0.3", "hast-util-select": "^6.0.4", "hast-util-to-string": "^3.0.1", "hastscript": "^9.0.1", "i18next": "^26.0.7", "js-yaml": "^4.1.1", "klona": "^2.0.6", "magic-string": "^0.30.21", "mdast-util-directive": "^3.1.0", "mdast-util-to-markdown": "^2.1.2", "mdast-util-to-string": "^4.0.0", "pagefind": "^1.5.2", "rehype": "^13.0.2", "rehype-format": "^5.0.1", "remark-directive": "^4.0.0", "satteri": "^0.9.1", "ultrahtml": "^1.6.0", "unified": "^11.0.5", "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "peerDependencies": { "@astrojs/markdown-remark": "^7.2.0", "astro": "^7.0.2" }, "optionalPeers": ["@astrojs/markdown-remark"] }, "sha512-8xsG6UpK581TJmtOc7/pnxHKEbP16rV06VLWaVa7FOyE/VEwnaHOsLtL+miifCEfuiuv0Wn+j8u3JSluRQesMQ=="], + + "@astrojs/telemetry": ["@astrojs/telemetry@3.3.2", "", { "dependencies": { "ci-info": "^4.4.0", "dset": "^3.1.4", "is-docker": "^4.0.0", "is-wsl": "^3.1.1", "which-pm-runs": "^1.1.0" } }, "sha512-j8DNruA8ors99Al39RYZPJK4DC1bKkoNm93mAMuBhY9TCNC4R8n1q7ovFnJ5qhGh5Lsh7pa1gpQVpYpsJPeTHQ=="], + + "@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.4", "", { "dependencies": { "yaml": "^2.8.3" } }, "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A=="], + + "@axe-core/playwright": ["@axe-core/playwright@4.12.1", "", { "dependencies": { "axe-core": "~4.12.1" }, "peerDependencies": { "playwright-core": ">= 1.0.0" } }, "sha512-rMd7xriptqKpP+w5265i4Hdkv2X5kbu6uiBi/B2I7uf3hieRBM3qDCfaKPtxfiYb2mKXfF+yLODJwIx+Jv1GDw=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], + "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], - "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], + "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - "@babel/parser": ["@babel/parser@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg=="], + "@bruits/satteri-darwin-arm64": ["@bruits/satteri-darwin-arm64@0.9.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow=="], - "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], + "@bruits/satteri-darwin-x64": ["@bruits/satteri-darwin-x64@0.9.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q=="], - "@babel/traverse": ["@babel/traverse@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" } }, "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw=="], + "@bruits/satteri-linux-arm64-gnu": ["@bruits/satteri-linux-arm64-gnu@0.9.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA=="], - "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], + "@bruits/satteri-linux-arm64-musl": ["@bruits/satteri-linux-arm64-musl@0.9.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ=="], + + "@bruits/satteri-linux-x64-gnu": ["@bruits/satteri-linux-x64-gnu@0.9.5", "", { "os": "linux", "cpu": "x64" }, "sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw=="], + + "@bruits/satteri-linux-x64-musl": ["@bruits/satteri-linux-x64-musl@0.9.5", "", { "os": "linux", "cpu": "x64" }, "sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q=="], + + "@bruits/satteri-wasm32-wasi": ["@bruits/satteri-wasm32-wasi@0.9.5", "", { "dependencies": { "@emnapi/core": "1.11.1", "@emnapi/runtime": "1.11.1", "@napi-rs/wasm-runtime": "^1.1.6" }, "cpu": "none" }, "sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ=="], + + "@bruits/satteri-win32-arm64-msvc": ["@bruits/satteri-win32-arm64-msvc@0.9.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg=="], + + "@bruits/satteri-win32-x64-msvc": ["@bruits/satteri-win32-x64-msvc@0.9.5", "", { "os": "win32", "cpu": "x64" }, "sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g=="], + + "@capsizecss/unpack": ["@capsizecss/unpack@4.0.1", "", { "dependencies": { "fontkitten": "^1.0.3" } }, "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ=="], + + "@clack/core": ["@clack/core@1.4.3", "", { "dependencies": { "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ=="], + + "@clack/prompts": ["@clack/prompts@1.7.0", "", { "dependencies": { "@clack/core": "1.4.3", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" } }, "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A=="], + + "@ctrl/tinycolor": ["@ctrl/tinycolor@4.2.0", "", {}, "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A=="], + + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], + + "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], + + "@emmetio/css-parser": ["@emmetio/css-parser@0.4.1", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ=="], + + "@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="], + + "@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="], + + "@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="], + + "@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="], + + "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="], - "@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="], - "@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="], - "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="], - "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="], - "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="], - "@iconify/utils": ["@iconify/utils@3.1.3", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "import-meta-resolve": "^4.2.0" } }, "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="], - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], + + "@expressive-code/core": ["@expressive-code/core@0.44.0", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-xgiF2P6tYUbrhi3+x0S8xHZWT1t3Bvb3U91tAtRbLb9HLejLvYc5GZUqKICKLaUN4iSGhhNJu2fM/aH8e5yCMg=="], + + "@expressive-code/plugin-frames": ["@expressive-code/plugin-frames@0.44.0", "", { "dependencies": { "@expressive-code/core": "^0.44.0" } }, "sha512-V6M6+zVc1GzqCvXkQHc2m5rcFOIVzJgMq5gnfrMnVf2gwtj/sg4H93c1f/mGeqHycubwkHFUDyParAOiGeDZeA=="], + + "@expressive-code/plugin-shiki": ["@expressive-code/plugin-shiki@0.44.0", "", { "dependencies": { "@expressive-code/core": "^0.44.0", "shiki": "^4.0.2" } }, "sha512-RZsdaqlbGqyAQKuoX4myQXxjmiE2l5KBpJ/gKPh62tCdIdpWyjbzVqSo8+5XsezZxkfi8AJ/J6EUaBTPROFX/Q=="], + + "@expressive-code/plugin-text-markers": ["@expressive-code/plugin-text-markers@0.44.0", "", { "dependencies": { "@expressive-code/core": "^0.44.0" } }, "sha512-0/m3A5b+lz2upyNq+wzZ1S69HRoJmyFs5LsR42lVZ9pmGRlBiSBYQpvqlji4DBj1+Riamxc0AvcCr5kuzOQeWA=="], + + "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.6", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.2", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw=="], + + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="], + + "@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.4", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/icu-skeleton-parser": "1.8.16", "tslib": "^2.8.0" } }, "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw=="], + + "@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "tslib": "^2.8.0" } }, "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ=="], + + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.2", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.2" }, "os": "darwin", "cpu": "arm64" }, "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.2" }, "os": "darwin", "cpu": "x64" }, "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w=="], + + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.3", "", { "dependencies": { "@img/sharp-wasm32": "0.35.3" }, "os": "freebsd" }, "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.2", "", { "os": "linux", "cpu": "arm" }, "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.2", "", { "os": "linux", "cpu": "none" }, "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.2" }, "os": "linux", "cpu": "arm" }, "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.2" }, "os": "linux", "cpu": "arm64" }, "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.2" }, "os": "linux", "cpu": "ppc64" }, "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.2" }, "os": "linux", "cpu": "none" }, "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.2" }, "os": "linux", "cpu": "s390x" }, "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.2" }, "os": "linux", "cpu": "x64" }, "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" }, "os": "linux", "cpu": "arm64" }, "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.3", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.2" }, "os": "linux", "cpu": "x64" }, "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.3", "", { "dependencies": { "@emnapi/runtime": "^1.11.1" } }, "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w=="], + + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.3", "", { "dependencies": { "@img/sharp-wasm32": "0.35.3" }, "cpu": "none" }, "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.3", "", { "os": "win32", "cpu": "x64" }, "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@lhci/cli": ["@lhci/cli@0.15.1", "", { "dependencies": { "@lhci/utils": "0.15.1", "chrome-launcher": "^0.13.4", "compression": "^1.7.4", "debug": "^4.3.1", "express": "^4.17.1", "inquirer": "^6.3.1", "isomorphic-fetch": "^3.0.0", "lighthouse": "12.6.1", "lighthouse-logger": "1.2.0", "open": "^7.1.0", "proxy-agent": "^6.4.0", "tmp": "^0.1.0", "uuid": "^8.3.1", "yargs": "^15.4.1", "yargs-parser": "^13.1.2" }, "bin": { "lhci": "./src/cli.js" } }, "sha512-yhC0oXnXqGHYy1xl4D8YqaydMZ/khFAnXGY/o2m/J3PqPa/D0nj3V6TLoH02oVMFeEF2AQim7UbmdXMiXx2tOw=="], - "@mermaid-js/parser": ["@mermaid-js/parser@1.1.1", "", { "dependencies": { "@chevrotain/types": "~11.1.1" } }, "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw=="], + "@lhci/utils": ["@lhci/utils@0.15.1", "", { "dependencies": { "debug": "^4.3.1", "isomorphic-fetch": "^3.0.0", "js-yaml": "^3.13.1", "lighthouse": "12.6.1", "tree-kill": "^1.2.1" } }, "sha512-WclJnUQJeOMY271JSuaOjCv/aA0pgvuHZS29NFNdIeI14id8eiFsjith85EGKYhljgoQhJ2SiW4PsVfFiakNNw=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], - "@oxc-project/types": ["@oxc-project/types@0.133.0", "", {}, "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="], + "@mobench/docs": ["@mobench/docs@workspace:apps/docs"], - "@radix-ui/primitive": ["@radix-ui/primitive@1.1.4", "", {}, "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ=="], + "@mobench/marketing": ["@mobench/marketing@workspace:apps/marketing"], - "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collapsible": "1.1.14", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw=="], + "@mobench/site-config": ["@mobench/site-config@workspace:packages/site-config"], - "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA=="], + "@mobench/truth": ["@mobench/truth@workspace:packages/truth"], - "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.10", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], - "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="], + "@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="], - "@radix-ui/react-context": ["@radix-ui/react-context@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg=="], + "@oxc-project/types": ["@oxc-project/types@0.133.0", "", {}, "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="], + + "@pagefind/darwin-arm64": ["@pagefind/darwin-arm64@1.5.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ=="], + + "@pagefind/darwin-x64": ["@pagefind/darwin-x64@1.5.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw=="], + + "@pagefind/default-ui": ["@pagefind/default-ui@1.5.2", "", {}, "sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg=="], - "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="], + "@pagefind/freebsd-x64": ["@pagefind/freebsd-x64@1.5.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA=="], - "@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="], + "@pagefind/linux-arm64": ["@pagefind/linux-arm64@1.5.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw=="], - "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.6", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ=="], + "@pagefind/linux-x64": ["@pagefind/linux-x64@1.5.2", "", { "os": "linux", "cpu": "x64" }, "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.6", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g=="], + "@pagefind/windows-arm64": ["@pagefind/windows-arm64@1.5.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g=="], - "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="], + "@pagefind/windows-x64": ["@pagefind/windows-x64@1.5.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg=="], - "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.3", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA=="], + "@paulirish/trace_engine": ["@paulirish/trace_engine@0.0.53", "", { "dependencies": { "legacy-javascript": "latest", "third-party-web": "latest" } }, "sha512-PUl/vlfo08Oj804VI5nDPeSk9vyslnBlVzDDwFt8SUVxY8+KdGMkra/vrXjEEHe8gb7+RqVTfOIlGw0nyrEelA=="], - "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.3", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA=="], + "@playwright/test": ["@playwright/test@1.61.1", "", { "dependencies": { "playwright": "1.61.1" }, "bin": { "playwright": "cli.js" } }, "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig=="], - "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="], + "@puppeteer/browsers": ["@puppeteer/browsers@2.13.2", "", { "dependencies": { "debug": "^4.4.3", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.7.4", "tar-fs": "^3.1.1", "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" } }, "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw=="], "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.3", "", { "os": "android", "cpu": "arm64" }, "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw=="], @@ -156,422 +359,1496 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], - "@tailwindcss/node": ["@tailwindcss/node@4.3.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.1" } }, "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A=="], + "@rollup/pluginutils": ["@rollup/pluginutils@5.4.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg=="], - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.1", "@tailwindcss/oxide-darwin-arm64": "4.3.1", "@tailwindcss/oxide-darwin-x64": "4.3.1", "@tailwindcss/oxide-freebsd-x64": "4.3.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", "@tailwindcss/oxide-linux-x64-musl": "4.3.1", "@tailwindcss/oxide-wasm32-wasi": "4.3.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA=="], + "@sentry-internal/tracing": ["@sentry-internal/tracing@7.120.4", "", { "dependencies": { "@sentry/core": "7.120.4", "@sentry/types": "7.120.4", "@sentry/utils": "7.120.4" } }, "sha512-Fz5+4XCg3akeoFK+K7g+d7HqGMjmnLoY2eJlpONJmaeT9pXY7yfUyXKZMmMajdE2LxxKJgQ2YKvSCaGVamTjHw=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.1", "", { "os": "android", "cpu": "arm64" }, "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ=="], + "@sentry/core": ["@sentry/core@7.120.4", "", { "dependencies": { "@sentry/types": "7.120.4", "@sentry/utils": "7.120.4" } }, "sha512-TXu3Q5kKiq8db9OXGkWyXUbIxMMuttB5vJ031yolOl5T/B69JRyAoKuojLBjRv1XX583gS1rSSoX8YXX7ATFGA=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA=="], + "@sentry/integrations": ["@sentry/integrations@7.120.4", "", { "dependencies": { "@sentry/core": "7.120.4", "@sentry/types": "7.120.4", "@sentry/utils": "7.120.4", "localforage": "^1.8.1" } }, "sha512-kkBTLk053XlhDCg7OkBQTIMF4puqFibeRO3E3YiVc4PGLnocXMaVpOSCkMqAc1k1kZ09UgGi8DxfQhnFEjUkpA=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg=="], + "@sentry/node": ["@sentry/node@7.120.4", "", { "dependencies": { "@sentry-internal/tracing": "7.120.4", "@sentry/core": "7.120.4", "@sentry/integrations": "7.120.4", "@sentry/types": "7.120.4", "@sentry/utils": "7.120.4" } }, "sha512-qq3wZAXXj2SRWhqErnGCSJKUhPSlZ+RGnCZjhfjHpP49KNpcd9YdPTIUsFMgeyjdh6Ew6aVCv23g1hTP0CHpYw=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g=="], + "@sentry/types": ["@sentry/types@7.120.4", "", {}, "sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg=="], + "@sentry/utils": ["@sentry/utils@7.120.4", "", { "dependencies": { "@sentry/types": "7.120.4" } }, "sha512-zCKpyDIWKHwtervNK2ZlaK8mMV7gVUijAgFeJStH+CU/imcdquizV3pFLlSQYRswG+Lbyd6CT/LGRh3IbtkCFw=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ=="], + "@shikijs/core": ["@shikijs/core@4.3.1", "", { "dependencies": { "@shikijs/primitive": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA=="], + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.3.1", "", { "dependencies": { "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg=="], + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.3.1", "", { "dependencies": { "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ=="], + "@shikijs/langs": ["@shikijs/langs@4.3.1", "", { "dependencies": { "@shikijs/types": "4.3.1" } }, "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.1", "", { "cpu": "none" }, "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA=="], + "@shikijs/primitive": ["@shikijs/primitive@4.3.1", "", { "dependencies": { "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg=="], + "@shikijs/themes": ["@shikijs/themes@4.3.1", "", { "dependencies": { "@shikijs/types": "4.3.1" } }, "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA=="], + "@shikijs/types": ["@shikijs/types@4.3.1", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.3.1", "", { "dependencies": { "@tailwindcss/node": "4.3.1", "@tailwindcss/oxide": "4.3.1", "tailwindcss": "4.3.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ=="], + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@tanstack/history": ["@tanstack/history@1.162.0", "", {}, "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA=="], + "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="], - "@tanstack/react-router": ["@tanstack/react-router@1.170.16", "", { "dependencies": { "@tanstack/history": "1.162.0", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.171.13", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-w6eq1IJklujs1tESazaK/FxH0+H2l8vm/QPuu1cD3oRW/ubgKneQpd7b64ti/8gUyEimzimJQZDmJr6YHfP5+g=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], - "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.167.0", "", { "dependencies": { "@tanstack/router-devtools-core": "1.168.0" }, "peerDependencies": { "@tanstack/react-router": "^1.170.0", "@tanstack/router-core": "^1.170.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w=="], + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "*" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], - "@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], - "@tanstack/router-core": ["@tanstack/router-core@1.171.13", "", { "dependencies": { "@tanstack/history": "1.162.0", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-+NOwEj1kO/6IGmpHRIZHasYxYWpyBQGNIZAST9aNrk9Q3YlU9SgqVnl1pbLa9qAKfeNdXQIRve0RQb/0kyDeDA=="], + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], - "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.168.0", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/router-core": "^1.170.0", "csstype": "^3.0.10" } }, "sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.167.17", "", { "dependencies": { "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.13", "@tanstack/router-utils": "1.162.2", "@tanstack/virtual-file-routes": "1.162.0", "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", "zod": "^4.4.3" } }, "sha512-xtB9tB2Ws0tWR6Pi7nc3Qk9IYgoh1mQCKWjHqIl9tf6BNUpKoqniJoPAQ4+LGrK8FeZYU0o0p/qlZEyj9FAulA=="], + "@types/js-yaml": ["@types/js-yaml@4.0.9", "", {}, "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.168.18", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.171.13", "@tanstack/router-generator": "1.167.17", "@tanstack/router-utils": "1.162.2", "chokidar": "^5.0.0", "unplugin": "^3.0.0", "zod": "^4.4.3" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "^1.170.15", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "vite-plugin-solid", "webpack"] }, "sha512-MofS28/axfnfnhOD2RSgJEaU882aX5RsAzhGz5Vc4XhAmvCjy919u9JrNs4QsTWFbTD1P7IJ8WFlFVsrg0pStg=="], + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], - "@tanstack/router-utils": ["@tanstack/router-utils@1.162.2", "", { "dependencies": { "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ansis": "^4.1.0", "babel-dead-code-elimination": "^1.0.12", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ=="], + "@types/mdx": ["@types/mdx@2.0.14", "", {}, "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg=="], - "@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.162.0", "", {}, "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA=="], + "@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], + "@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="], - "@types/d3": ["@types/d3@7.4.3", "", { "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww=="], + "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="], - "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], - "@types/d3-axis": ["@types/d3-axis@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw=="], + "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], - "@types/d3-brush": ["@types/d3-brush@3.0.6", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A=="], + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.2", "", {}, "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA=="], - "@types/d3-chord": ["@types/d3-chord@3.0.6", "", {}, "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg=="], + "@vercel/analytics": ["@vercel/analytics@2.0.1", "", { "peerDependencies": { "@remix-run/react": "^2", "@sveltejs/kit": "^1 || ^2", "next": ">= 13", "nuxt": ">= 3", "react": "^18 || ^19 || ^19.0.0-rc", "svelte": ">= 4", "vue": "^3", "vue-router": "^4" }, "optionalPeers": ["@remix-run/react", "@sveltejs/kit", "next", "nuxt", "react", "svelte", "vue", "vue-router"] }, "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g=="], - "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + "@volar/kit": ["@volar/kit@2.4.28", "", { "dependencies": { "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg=="], - "@types/d3-contour": ["@types/d3-contour@3.0.6", "", { "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg=="], + "@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="], - "@types/d3-delaunay": ["@types/d3-delaunay@6.0.4", "", {}, "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw=="], + "@volar/language-server": ["@volar/language-server@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "path-browserify": "^1.0.1", "request-light": "^0.7.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw=="], - "@types/d3-dispatch": ["@types/d3-dispatch@3.0.7", "", {}, "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA=="], + "@volar/language-service": ["@volar/language-service@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw=="], - "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], + "@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="], - "@types/d3-dsv": ["@types/d3-dsv@3.0.7", "", {}, "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g=="], + "@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="], - "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + "@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="], - "@types/d3-fetch": ["@types/d3-fetch@3.0.7", "", { "dependencies": { "@types/d3-dsv": "*" } }, "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA=="], + "@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="], - "@types/d3-force": ["@types/d3-force@3.0.10", "", {}, "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw=="], + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], - "@types/d3-format": ["@types/d3-format@3.0.4", "", {}, "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g=="], + "acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="], - "@types/d3-geo": ["@types/d3-geo@3.1.0", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ=="], + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "@types/d3-hierarchy": ["@types/d3-hierarchy@3.1.7", "", {}, "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], - "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], - "@types/d3-polygon": ["@types/d3-polygon@3.0.2", "", {}, "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA=="], + "ajv-i18n": ["ajv-i18n@4.2.0", "", { "peerDependencies": { "ajv": "^8.0.0-beta.0" } }, "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg=="], - "@types/d3-quadtree": ["@types/d3-quadtree@3.0.6", "", {}, "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg=="], + "am-i-vibing": ["am-i-vibing@0.4.0", "", { "dependencies": { "process-ancestry": "^0.1.0" }, "bin": { "am-i-vibing": "dist/cli.mjs" } }, "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg=="], - "@types/d3-random": ["@types/d3-random@3.0.3", "", {}, "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ=="], + "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], - "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + "ansi-escapes": ["ansi-escapes@3.2.0", "", {}, "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="], - "@types/d3-scale-chromatic": ["@types/d3-scale-chromatic@3.1.0", "", {}, "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ=="], + "ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], - "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], + "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], - "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], - "@types/d3-time-format": ["@types/d3-time-format@4.0.3", "", {}, "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg=="], + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], - "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], + "array-iterate": ["array-iterate@2.0.1", "", {}, "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg=="], - "@types/geojson": ["@types/geojson@7946.0.16", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="], + "ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="], - "@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="], + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], - "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="], + "astro": ["astro@7.0.6", "", { "dependencies": { "@astrojs/compiler-rs": "^0.3.0", "@astrojs/internal-helpers": "0.10.1", "@astrojs/markdown-satteri": "0.3.3", "@astrojs/telemetry": "3.3.2", "@capsizecss/unpack": "^4.0.0", "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "am-i-vibing": "^0.4.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", "devalue": "^5.8.1", "diff": "^8.0.3", "dset": "^3.1.4", "es-module-lexer": "^2.0.0", "esbuild": "^0.28.0", "flattie": "^1.1.1", "fontace": "~0.4.1", "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.4", "semver": "^7.7.4", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "svgo": "^4.0.1", "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unstorage": "^1.17.5", "vite": "^8.0.13", "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", "zod": "^4.3.6" }, "optionalDependencies": { "sharp": "^0.34.0 || ^0.35.0" }, "peerDependencies": { "@astrojs/markdown-remark": "7.2.1" }, "optionalPeers": ["@astrojs/markdown-remark"], "bin": { "astro": "./bin/astro.mjs" } }, "sha512-Myw0sFia+zs/Y0yqfZEsUYXfDPh3ELcLf1f0Q/qQzVXBh/af1qO62WNT+P89DCcfGVV51nMoQhEfkBYqJmoUOQ=="], - "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + "astro-expressive-code": ["astro-expressive-code@0.44.0", "", { "dependencies": { "rehype-expressive-code": "^0.44.0", "url-extras": "^0.1.0" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0" } }, "sha512-b1wN/ZvbJprzxlGKIpIes2kQrCY5KRLwys2tWbZAZyjGZcW5ZtgneZnBwzNRiBna9/48d4mQl19KLjcRuhO1hw=="], - "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], + "axe-core": ["axe-core@4.12.1", "", {}, "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA=="], - "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="], + "b4a": ["b4a@1.8.1", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw=="], - "ansis": ["ansis@4.3.1", "", {}, "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA=="], + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], - "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.38", "", { "bin": "dist/cli.cjs" }, "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw=="], + "bare-events": ["bare-events@2.9.1", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg=="], - "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": "cli.js" }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + "bare-fs": ["bare-fs@4.7.4", "", { "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", "bare-stream": "^2.6.4", "bare-url": "^2.2.2", "fast-fifo": "^1.3.2" }, "peerDependencies": { "bare-buffer": "*" }, "optionalPeers": ["bare-buffer"] }, "sha512-y1kC+ffIx/tPLdTE693uNjHfzTfr+ravR5tvWlMXe25nELbkqV400S71qHDwbkAQ1FVEZobB1NFRzFbCCcyBCQ=="], - "caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="], + "bare-path": ["bare-path@3.1.1", "", {}, "sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ=="], - "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "bare-stream": ["bare-stream@2.13.3", "", { "dependencies": { "b4a": "^1.8.1", "streamx": "^2.25.0", "teex": "^1.0.1" }, "peerDependencies": { "bare-abort-controller": "*", "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-abort-controller", "bare-buffer", "bare-events"] }, "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ=="], - "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + "bare-url": ["bare-url@2.4.5", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ=="], - "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "basic-ftp": ["basic-ftp@5.3.1", "", {}, "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw=="], + + "bcp-47": ["bcp-47@2.1.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-KLw+H/gd2p4zly1X7Yh/qziuyae5/w/QFnvTng9eZL5fvszL7Whl3MBoWF8yxL7ksUjBfOD+OxkytiqbBpG+Fw=="], - "commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], + "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="], - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "body-parser": ["body-parser@1.20.5", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA=="], - "cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="], + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], + "brace-expansion": ["brace-expansion@1.1.16", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw=="], - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], - "cytoscape": ["cytoscape@3.34.0", "", {}, "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], - "cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - "cytoscape-fcose": ["cytoscape-fcose@2.2.0", "", { "dependencies": { "cose-base": "^2.2.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ=="], + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "d3": ["d3@7.9.0", "", { "dependencies": { "d3-array": "3", "d3-axis": "3", "d3-brush": "3", "d3-chord": "3", "d3-color": "3", "d3-contour": "4", "d3-delaunay": "6", "d3-dispatch": "3", "d3-drag": "3", "d3-dsv": "3", "d3-ease": "3", "d3-fetch": "3", "d3-force": "3", "d3-format": "3", "d3-geo": "3", "d3-hierarchy": "3", "d3-interpolate": "3", "d3-path": "3", "d3-polygon": "3", "d3-quadtree": "3", "d3-random": "3", "d3-scale": "4", "d3-scale-chromatic": "3", "d3-selection": "3", "d3-shape": "3", "d3-time": "3", "d3-time-format": "4", "d3-timer": "3", "d3-transition": "3", "d3-zoom": "3" } }, "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA=="], + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], - "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "d3-axis": ["d3-axis@3.0.0", "", {}, "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw=="], + "chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - "d3-brush": ["d3-brush@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "3", "d3-transition": "3" } }, "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ=="], + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], - "d3-chord": ["d3-chord@3.0.1", "", { "dependencies": { "d3-path": "1 - 3" } }, "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g=="], + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], - "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "d3-contour": ["d3-contour@4.0.2", "", { "dependencies": { "d3-array": "^3.2.0" } }, "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA=="], + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], - "d3-delaunay": ["d3-delaunay@6.0.4", "", { "dependencies": { "delaunator": "5" } }, "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A=="], + "chardet": ["chardet@0.7.0", "", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], - "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], + "chrome-launcher": ["chrome-launcher@0.13.4", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^1.0.5", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^0.5.3", "rimraf": "^3.0.2" } }, "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A=="], - "d3-dsv": ["d3-dsv@3.0.1", "", { "dependencies": { "commander": "7", "iconv-lite": "0.6", "rw": "1" }, "bin": { "csv2json": "bin/dsv2json.js", "csv2tsv": "bin/dsv2dsv.js", "dsv2dsv": "bin/dsv2dsv.js", "dsv2json": "bin/dsv2json.js", "json2csv": "bin/json2dsv.js", "json2dsv": "bin/json2dsv.js", "json2tsv": "bin/json2dsv.js", "tsv2csv": "bin/dsv2dsv.js", "tsv2json": "bin/dsv2json.js" } }, "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q=="], + "chromium-bidi": ["chromium-bidi@14.0.0", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw=="], - "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - "d3-fetch": ["d3-fetch@3.0.1", "", { "dependencies": { "d3-dsv": "1 - 3" } }, "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw=="], + "cli-cursor": ["cli-cursor@2.1.0", "", { "dependencies": { "restore-cursor": "^2.0.0" } }, "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw=="], - "d3-force": ["d3-force@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", "d3-timer": "1 - 3" } }, "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg=="], + "cli-width": ["cli-width@2.2.1", "", {}, "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="], - "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + "cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], - "d3-geo": ["d3-geo@3.1.1", "", { "dependencies": { "d3-array": "2.5.0 - 3" } }, "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], + + "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + + "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], + + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], - "d3-hierarchy": ["d3-hierarchy@3.1.2", "", {}, "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA=="], + "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], - "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + "configstore": ["configstore@5.0.1", "", { "dependencies": { "dot-prop": "^5.2.0", "graceful-fs": "^4.1.2", "make-dir": "^3.0.0", "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" } }, "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA=="], - "d3-polygon": ["d3-polygon@3.0.1", "", {}, "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg=="], + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], - "d3-quadtree": ["d3-quadtree@3.0.1", "", {}, "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw=="], + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], - "d3-random": ["d3-random@3.0.1", "", {}, "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ=="], + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], - "d3-sankey": ["d3-sankey@0.12.3", "", { "dependencies": { "d3-array": "1 - 2", "d3-shape": "^1.2.0" } }, "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ=="], + "cookie-es": ["cookie-es@1.2.3", "", {}, "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw=="], - "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + "cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="], - "d3-scale-chromatic": ["d3-scale-chromatic@3.1.0", "", { "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" } }, "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ=="], + "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], - "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], + "crypto-random-string": ["crypto-random-string@2.0.0", "", {}, "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="], - "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + "csp_evaluator": ["csp_evaluator@1.1.5", "", {}, "sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw=="], - "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], - "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + "css-selector-parser": ["css-selector-parser@3.3.0", "", {}, "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g=="], - "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + "css-tree": ["css-tree@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], - "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], - "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - "dagre-d3-es": ["dagre-d3-es@7.0.14", "", { "dependencies": { "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg=="], + "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], - "dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="], + "data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "delaunator": ["delaunator@5.1.0", "", { "dependencies": { "robust-predicates": "^3.0.2" } }, "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ=="], + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], + + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + + "define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], + + "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], + + "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "devalue": ["devalue@5.8.1", "", {}, "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "devtools-protocol": ["devtools-protocol@0.0.1467305", "", {}, "sha512-LxwMLqBoPPGpMdRL4NkLFRNy3QLp6Uqa7GNp1v6JaBheop2QrB9Q7q0A/q/CYYP9sBfZdHOyszVx4gc9zyk7ow=="], + "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], - "dompurify": ["dompurify@3.4.11", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw=="], + "direction": ["direction@2.0.1", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + + "dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "electron-to-chromium": ["electron-to-chromium@1.5.376", "", {}, "sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA=="], + "enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="], - "enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "es-toolkit": ["es-toolkit@1.48.1", "", {}, "sha512-wfnXlwd5I75eXRtdD2vuEs50xHHESECDsGD7yiQnfFVNoa5522NwXEbmgo98LfiukSQHs+mBM7/YG3qKJB9/mQ=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-module-lexer": ["es-module-lexer@2.3.0", "", {}, "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw=="], + + "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "unist-util-position-from-estree": "^2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], + + "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], + + "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], + + "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="], + + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + + "estree-util-scope": ["estree-util-scope@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0" } }, "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ=="], + + "estree-util-to-js": ["estree-util-to-js@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "astring": "^1.8.0", "source-map": "^0.7.0" } }, "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg=="], + + "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], + + "express": ["express@4.22.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q=="], + + "expressive-code": ["expressive-code@0.44.0", "", { "dependencies": { "@expressive-code/core": "^0.44.0", "@expressive-code/plugin-frames": "^0.44.0", "@expressive-code/plugin-shiki": "^0.44.0", "@expressive-code/plugin-text-markers": "^0.44.0" } }, "sha512-JXVWVNCKlLuZLMQH8cOiDUSosT0Bb+elwE/dbAkpwFwDFmyFyWlECoWZIohh2FkIF1iI67TQJ+Ts9k7oNDh2qA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "external-editor": ["external-editor@3.1.0", "", { "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew=="], + + "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + + "fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="], + + "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], + + "fast-uri": ["fast-uri@3.1.3", "", {}, "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg=="], + + "fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="], + + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="], + + "finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], + + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="], + + "fontace": ["fontace@0.4.1", "", { "dependencies": { "fontkitten": "^1.0.2" } }, "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw=="], + + "fontkitten": ["fontkitten@1.0.3", "", { "dependencies": { "tiny-inflate": "^1.0.3" } }, "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + "get-tsconfig": ["get-tsconfig@5.0.0-beta.4", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ=="], - "goober": ["goober@2.1.19", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg=="], + "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="], + + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], + "h3": ["h3@1.15.11", "", { "dependencies": { "cookie-es": "^1.2.3", "crossws": "^0.3.5", "defu": "^6.1.6", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg=="], - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], - "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - "internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], - "isbot": ["isbot@5.1.43", "", {}, "sha512-drJhFmibra4LO6Wd7D3Oi6UICRK9244vSZkmxzhlZP0TTdwCA2ueK4PEkUkzPYeuqug9+cqqdWPgihjk5+83Cg=="], + "hast-util-embedded": ["hast-util-embedded@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA=="], - "jiti": ["jiti@2.7.0", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "hast-util-format": ["hast-util-format@1.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-minify-whitespace": "^1.0.0", "hast-util-phrasing": "^3.0.0", "hast-util-whitespace": "^3.0.0", "html-whitespace-sensitive-tag-names": "^3.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA=="], - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], - "json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "hast-util-has-property": ["hast-util-has-property@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA=="], - "katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="], + "hast-util-is-body-ok-link": ["hast-util-is-body-ok-link@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ=="], - "khroma": ["khroma@2.1.0", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], + "hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="], - "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], + "hast-util-minify-whitespace": ["hast-util-minify-whitespace@1.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-is-element": "^3.0.0", "hast-util-whitespace": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw=="], - "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + "hast-util-phrasing": ["hast-util-phrasing@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-embedded": "^3.0.0", "hast-util-has-property": "^3.0.0", "hast-util-is-body-ok-link": "^3.0.0", "hast-util-is-element": "^3.0.0" } }, "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-from-parse5": "^8.0.0", "hast-util-to-parse5": "^8.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "parse5": "^7.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + "hast-util-select": ["hast-util-select@6.0.4", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "bcp-47-match": "^2.0.0", "comma-separated-tokens": "^2.0.0", "css-selector-parser": "^3.0.0", "devlop": "^1.0.0", "direction": "^2.0.0", "hast-util-has-property": "^3.0.0", "hast-util-to-string": "^3.0.0", "hast-util-whitespace": "^3.0.0", "nth-check": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + "hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-attach-comments": "^3.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "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" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "web-namespaces": "^2.0.0", "zwitch": "^2.0.0" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + "hast-util-to-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + "hast-util-to-text": ["hast-util-to-text@4.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "hast-util-is-element": "^3.0.0", "unist-util-find-after": "^5.0.0" } }, "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], - "lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], + "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], - "lucide-react": ["lucide-react@1.21.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ=="], + "html-whitespace-sensitive-tag-names": ["html-whitespace-sensitive-tag-names@3.0.1", "", {}, "sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA=="], - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], - "marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], - "mermaid": ["mermaid@11.15.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.1.1", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.1", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.19", "dompurify": "^3.3.1", "es-toolkit": "^1.45.1", "katex": "^0.16.25", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw=="], + "http-link-header": ["http-link-header@1.1.3", "", {}, "sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ=="], - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - "nanoid": ["nanoid@3.3.14", "", { "bin": "bin/nanoid.cjs" }, "sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "node-releases": ["node-releases@2.0.48", "", {}, "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA=="], + "i18next": ["i18next@26.3.5", "", { "peerDependencies": { "typescript": "^5 || ^6" }, "optionalPeers": ["typescript"] }, "sha512-cd5lgkvjYQAPDfP3bbrAIE1wJmjTIlsrsjDqlvsHn4wFAerP5O0NfAe8RiDcXRfukN5ETe7Tlmfp6DkyuqDn6Q=="], - "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "path-data-parser": ["path-data-parser@0.1.0", "", {}, "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="], + "image-ssim": ["image-ssim@0.2.0", "", {}, "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg=="], - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - "points-on-curve": ["points-on-curve@0.2.0", "", {}, "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "points-on-path": ["points-on-path@0.2.1", "", { "dependencies": { "path-data-parser": "0.1.0", "points-on-curve": "0.2.0" } }, "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g=="], + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], - "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + "inquirer": ["inquirer@6.5.2", "", { "dependencies": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", "string-width": "^2.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" } }, "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ=="], - "prettier": ["prettier@3.8.4", "", { "bin": "bin/prettier.cjs" }, "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q=="], + "intl-messageformat": ["intl-messageformat@10.7.18", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.4", "tslib": "^2.8.0" } }, "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g=="], - "react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="], + "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], - "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="], + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], - "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], - "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], - "rolldown": ["rolldown@1.0.3", "", { "dependencies": { "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.3", "@rolldown/binding-darwin-arm64": "1.0.3", "@rolldown/binding-darwin-x64": "1.0.3", "@rolldown/binding-freebsd-x64": "1.0.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", "@rolldown/binding-linux-arm64-gnu": "1.0.3", "@rolldown/binding-linux-arm64-musl": "1.0.3", "@rolldown/binding-linux-ppc64-gnu": "1.0.3", "@rolldown/binding-linux-s390x-gnu": "1.0.3", "@rolldown/binding-linux-x64-gnu": "1.0.3", "@rolldown/binding-linux-x64-musl": "1.0.3", "@rolldown/binding-openharmony-arm64": "1.0.3", "@rolldown/binding-wasm32-wasi": "1.0.3", "@rolldown/binding-win32-arm64-msvc": "1.0.3", "@rolldown/binding-win32-x64-msvc": "1.0.3" }, "bin": "bin/cli.mjs" }, "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g=="], + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], - "roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], - "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], - "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], - "semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], - "seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="], + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], - "seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], - "stylis": ["stylis@4.4.0", "", {}, "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA=="], + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], - "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], + "isomorphic-fetch": ["isomorphic-fetch@3.0.0", "", { "dependencies": { "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" } }, "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA=="], - "tailwindcss": ["tailwindcss@4.3.1", "", {}, "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q=="], + "jiti": ["jiti@2.7.0", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], - "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], - "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + "js-library-detector": ["js-library-detector@6.7.0", "", {}, "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA=="], - "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], + "js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="], - "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "ts-dedent": ["ts-dedent@2.3.0", "", {}, "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg=="], + "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], - "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + "klona": ["klona@2.0.6", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="], - "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + "legacy-javascript": ["legacy-javascript@0.0.1", "", {}, "sha512-lPyntS4/aS7jpuvOlitZDFifBCb4W8L/3QU0PLbUTUj+zYah8rfVjYic88yG7ZKTxhS5h9iz7duT8oUXKszLhg=="], - "unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="], + "lie": ["lie@3.1.1", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw=="], - "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "lighthouse": ["lighthouse@12.6.1", "", { "dependencies": { "@paulirish/trace_engine": "0.0.53", "@sentry/node": "^7.0.0", "axe-core": "^4.10.3", "chrome-launcher": "^1.2.0", "configstore": "^5.0.1", "csp_evaluator": "1.1.5", "devtools-protocol": "0.0.1467305", "enquirer": "^2.3.6", "http-link-header": "^1.1.1", "intl-messageformat": "^10.5.3", "jpeg-js": "^0.4.4", "js-library-detector": "^6.7.0", "lighthouse-logger": "^2.0.1", "lighthouse-stack-packs": "1.12.2", "lodash-es": "^4.17.21", "lookup-closest-locale": "6.2.0", "metaviewport-parser": "0.3.0", "open": "^8.4.0", "parse-cache-control": "1.0.1", "puppeteer-core": "^24.10.0", "robots-parser": "^3.0.1", "semver": "^5.3.0", "speedline-core": "^1.4.3", "third-party-web": "^0.26.6", "tldts-icann": "^6.1.16", "ws": "^7.0.0", "yargs": "^17.3.1", "yargs-parser": "^21.0.0" }, "bin": { "lighthouse": "cli/index.js", "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js", "chrome-debug": "core/scripts/manual-chrome-launcher.js" } }, "sha512-85WDkjcXAVdlFem9Y6SSxqoKiz/89UsDZhLpeLJIsJ4LlHxw047XTZhlFJmjYCB7K5S1erSBAf5cYLcfyNbH3A=="], - "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + "lighthouse-logger": ["lighthouse-logger@1.2.0", "", { "dependencies": { "debug": "^2.6.8", "marky": "^1.2.0" } }, "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw=="], - "uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="], + "lighthouse-stack-packs": ["lighthouse-stack-packs@1.12.2", "", {}, "sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw=="], - "vite": ["vite@8.0.16", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@vitejs/devtools", "esbuild", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw=="], + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], - "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], - "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "localforage": ["localforage@1.10.0", "", { "dependencies": { "lie": "3.1.1" } }, "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg=="], + + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "lodash": ["lodash@4.18.1", "", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="], + + "lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], + + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + + "lookup-closest-locale": ["lookup-closest-locale@6.2.0", "", {}, "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ=="], + + "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "magicast": ["magicast@0.5.3", "", { "dependencies": { "@babel/parser": "^7.29.3", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw=="], + + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], + + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + + "marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-definitions": ["mdast-util-definitions@6.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ=="], + + "mdast-util-directive": ["mdast-util-directive@3.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q=="], + + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + + "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "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" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + + "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], + + "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + + "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + + "metaviewport-parser": ["metaviewport-parser@0.3.0", "", {}, "sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ=="], + + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], + + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-directive": ["micromark-extension-directive@4.0.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "parse-entities": "^4.0.0" } }, "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + + "micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="], + + "micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="], + + "micromark-extension-mdx-md": ["micromark-extension-mdx-md@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ=="], + + "micromark-extension-mdxjs": ["micromark-extension-mdxjs@3.0.0", "", { "dependencies": { "acorn": "^8.0.0", "acorn-jsx": "^5.0.0", "micromark-extension-mdx-expression": "^3.0.0", "micromark-extension-mdx-jsx": "^3.0.0", "micromark-extension-mdx-md": "^2.0.0", "micromark-extension-mdxjs-esm": "^3.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ=="], + + "micromark-extension-mdxjs-esm": ["micromark-extension-mdxjs-esm@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-mdx-expression": ["micromark-factory-mdx-expression@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-position-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-events-to-acorn": ["micromark-util-events-to-acorn@2.0.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "estree-util-visit": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], + + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], + + "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], + + "mute-stream": ["mute-stream@0.0.7", "", {}, "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ=="], + + "nanoid": ["nanoid@3.3.14", "", { "bin": "bin/nanoid.cjs" }, "sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ=="], + + "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], + + "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], + + "netmask": ["netmask@2.1.1", "", {}, "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA=="], + + "nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + + "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "obug": ["obug@2.1.3", "", {}, "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg=="], + + "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "onetime": ["onetime@2.0.1", "", { "dependencies": { "mimic-fn": "^1.0.0" } }, "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ=="], + + "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], + + "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], + + "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + + "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], + + "p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="], + + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "p-queue": ["p-queue@9.3.1", "", { "dependencies": { "eventemitter3": "^5.0.4", "p-timeout": "^7.0.0" } }, "sha512-POWdiIPmsUPGwb4FeQ4OBg46aqmcInSWe45CKDsGHiOBiVQM9chqfQTuqhuTzcg2Vz9faTI65at0KkVyVEiCHw=="], + + "p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "pac-proxy-agent": ["pac-proxy-agent@7.2.0", "", { "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", "socks-proxy-agent": "^8.0.5" } }, "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA=="], + + "pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="], + + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + + "pagefind": ["pagefind@1.5.2", "", { "optionalDependencies": { "@pagefind/darwin-arm64": "1.5.2", "@pagefind/darwin-x64": "1.5.2", "@pagefind/freebsd-x64": "1.5.2", "@pagefind/linux-arm64": "1.5.2", "@pagefind/linux-x64": "1.5.2", "@pagefind/windows-arm64": "1.5.2", "@pagefind/windows-x64": "1.5.2" }, "bin": { "pagefind": "lib/runner/bin.cjs" } }, "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q=="], + + "parse-cache-control": ["parse-cache-control@1.0.1", "", {}, "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="], + + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + + "parse-latin": ["parse-latin@7.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-to-regexp": ["path-to-regexp@0.1.13", "", {}, "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA=="], + + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + + "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "playwright": ["playwright@1.61.1", "", { "dependencies": { "playwright-core": "1.61.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ=="], + + "playwright-core": ["playwright-core@1.61.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg=="], + + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + + "postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], + + "prettier": ["prettier@3.8.4", "", { "bin": "bin/prettier.cjs" }, "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q=="], + + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], + + "process-ancestry": ["process-ancestry@0.1.0", "", {}, "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg=="], + + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "property-information": ["property-information@7.2.0", "", {}, "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], + + "puppeteer-core": ["puppeteer-core@24.43.1", "", { "dependencies": { "@puppeteer/browsers": "2.13.2", "chromium-bidi": "14.0.0", "debug": "^4.4.3", "devtools-protocol": "0.0.1608973", "typed-query-selector": "^2.12.2", "webdriver-bidi-protocol": "0.4.1", "ws": "^8.20.0" } }, "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw=="], + + "qs": ["qs@6.15.3", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A=="], + + "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], + + "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "^5.0.0", "estree-util-to-js": "^2.0.0", "recma-parse": "^1.0.0", "recma-stringify": "^1.0.0", "unified": "^11.0.0" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], + + "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "esast-util-from-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="], + + "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-to-js": "^2.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="], + + "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], + + "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], + + "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + + "rehype": ["rehype@13.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "rehype-parse": "^9.0.0", "rehype-stringify": "^10.0.0", "unified": "^11.0.0" } }, "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A=="], + + "rehype-expressive-code": ["rehype-expressive-code@0.44.0", "", { "dependencies": { "expressive-code": "^0.44.0" } }, "sha512-5r74C5F2sMR3X+QJH8OKWgZBO/cqRw5W1fLT6GVlSfLqepk+4j8tGFkyPqZYWjwntsBHzKPDH2zI68sZ7ScLfA=="], + + "rehype-format": ["rehype-format@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-format": "^1.0.0" } }, "sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ=="], + + "rehype-parse": ["rehype-parse@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", "unified": "^11.0.0" } }, "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag=="], + + "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", "vfile": "^6.0.0" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], + + "rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="], + + "rehype-stringify": ["rehype-stringify@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" } }, "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA=="], + + "remark-directive": ["remark-directive@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-directive": "^3.0.0", "micromark-extension-directive": "^4.0.0", "unified": "^11.0.0" } }, "sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA=="], + + "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + + "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], + + "remark-smartypants": ["remark-smartypants@3.0.2", "", { "dependencies": { "retext": "^9.0.0", "retext-smartypants": "^6.0.0", "unified": "^11.0.4", "unist-util-visit": "^5.0.0" } }, "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "restore-cursor": ["restore-cursor@2.0.0", "", { "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q=="], + + "retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="], + + "retext-latin": ["retext-latin@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "parse-latin": "^7.0.0", "unified": "^11.0.0" } }, "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA=="], + + "retext-smartypants": ["retext-smartypants@6.2.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ=="], + + "retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], + + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "robots-parser": ["robots-parser@3.0.1", "", {}, "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ=="], + + "rolldown": ["rolldown@1.0.3", "", { "dependencies": { "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.3", "@rolldown/binding-darwin-arm64": "1.0.3", "@rolldown/binding-darwin-x64": "1.0.3", "@rolldown/binding-freebsd-x64": "1.0.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", "@rolldown/binding-linux-arm64-gnu": "1.0.3", "@rolldown/binding-linux-arm64-musl": "1.0.3", "@rolldown/binding-linux-ppc64-gnu": "1.0.3", "@rolldown/binding-linux-s390x-gnu": "1.0.3", "@rolldown/binding-linux-x64-gnu": "1.0.3", "@rolldown/binding-linux-x64-musl": "1.0.3", "@rolldown/binding-openharmony-arm64": "1.0.3", "@rolldown/binding-wasm32-wasi": "1.0.3", "@rolldown/binding-win32-arm64-msvc": "1.0.3", "@rolldown/binding-win32-x64-msvc": "1.0.3" }, "bin": "bin/cli.mjs" }, "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g=="], + + "run-async": ["run-async@2.4.1", "", {}, "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="], + + "rxjs": ["rxjs@6.6.7", "", { "dependencies": { "tslib": "^1.9.0" } }, "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "satteri": ["satteri@0.9.5", "", { "dependencies": { "@types/estree-jsx": "^1.0.5", "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "@types/unist": "^3.0.3" }, "optionalDependencies": { "@bruits/satteri-darwin-arm64": "0.9.5", "@bruits/satteri-darwin-x64": "0.9.5", "@bruits/satteri-linux-arm64-gnu": "0.9.5", "@bruits/satteri-linux-arm64-musl": "0.9.5", "@bruits/satteri-linux-x64-gnu": "0.9.5", "@bruits/satteri-linux-x64-musl": "0.9.5", "@bruits/satteri-wasm32-wasi": "0.9.5", "@bruits/satteri-win32-arm64-msvc": "0.9.5", "@bruits/satteri-win32-x64-msvc": "0.9.5" } }, "sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w=="], + + "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], + + "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "sharp": ["sharp@0.35.3", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.5" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.3", "@img/sharp-darwin-x64": "0.35.3", "@img/sharp-freebsd-wasm32": "0.35.3", "@img/sharp-libvips-darwin-arm64": "1.3.2", "@img/sharp-libvips-darwin-x64": "1.3.2", "@img/sharp-libvips-linux-arm": "1.3.2", "@img/sharp-libvips-linux-arm64": "1.3.2", "@img/sharp-libvips-linux-ppc64": "1.3.2", "@img/sharp-libvips-linux-riscv64": "1.3.2", "@img/sharp-libvips-linux-s390x": "1.3.2", "@img/sharp-libvips-linux-x64": "1.3.2", "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", "@img/sharp-libvips-linuxmusl-x64": "1.3.2", "@img/sharp-linux-arm": "0.35.3", "@img/sharp-linux-arm64": "0.35.3", "@img/sharp-linux-ppc64": "0.35.3", "@img/sharp-linux-riscv64": "0.35.3", "@img/sharp-linux-s390x": "0.35.3", "@img/sharp-linux-x64": "0.35.3", "@img/sharp-linuxmusl-arm64": "0.35.3", "@img/sharp-linuxmusl-x64": "0.35.3", "@img/sharp-webcontainers-wasm32": "0.35.3", "@img/sharp-win32-arm64": "0.35.3", "@img/sharp-win32-ia32": "0.35.3", "@img/sharp-win32-x64": "0.35.3" } }, "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q=="], + + "shiki": ["shiki@4.3.1", "", { "dependencies": { "@shikijs/core": "4.3.1", "@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-oniguruma": "4.3.1", "@shikijs/langs": "4.3.1", "@shikijs/themes": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw=="], + + "side-channel": ["side-channel@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4", "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ=="], + + "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + + "sitemap": ["sitemap@9.0.1", "", { "dependencies": { "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { "sitemap": "dist/esm/cli.js" } }, "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ=="], + + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "smol-toml": ["smol-toml@1.7.0", "", {}, "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ=="], + + "socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], + + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "speedline-core": ["speedline-core@1.4.3", "", { "dependencies": { "@types/node": "*", "image-ssim": "^0.2.0", "jpeg-js": "^0.4.1" } }, "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="], + + "streamx": ["streamx@2.28.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw=="], + + "string-width": ["string-width@2.1.1", "", { "dependencies": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw=="], + + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + + "strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + + "supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], + + "tar-fs": ["tar-fs@3.1.3", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ=="], + + "tar-stream": ["tar-stream@3.2.0", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg=="], + + "teex": ["teex@1.0.1", "", { "dependencies": { "streamx": "^2.12.5" } }, "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg=="], + + "text-decoder": ["text-decoder@1.2.7", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ=="], + + "third-party-web": ["third-party-web@0.26.7", "", {}, "sha512-buUzX4sXC4efFX6xg2bw6/eZsCUh8qQwSavC4D9HpONMFlRbcHhD8Je5qwYdCpViR6q0qla2wPP+t91a2vgolg=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="], + + "tinyclip": ["tinyclip@0.1.15", "", {}, "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A=="], + + "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], + + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + + "tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + + "tldts-icann": ["tldts-icann@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" } }, "sha512-NFxmRT2lAEMcCOBgeZ0NuM0zsK/xgmNajnY6n4S1mwAKocft2s2ise1O3nQxrH3c+uY6hgHUV9GGNVp7tUE4Sg=="], + + "tmp": ["tmp@0.1.0", "", { "dependencies": { "rimraf": "^2.6.3" } }, "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + + "tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + + "typed-query-selector": ["typed-query-selector@2.12.2", "", {}, "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ=="], + + "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], + + "typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="], + + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="], + + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], + + "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="], + + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], + + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unifont": ["unifont@0.7.4", "", { "dependencies": { "css-tree": "^3.1.0", "ofetch": "^1.5.1", "ohash": "^2.0.11" } }, "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg=="], + + "unique-string": ["unique-string@2.0.0", "", { "dependencies": { "crypto-random-string": "^2.0.0" } }, "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg=="], + + "unist-util-find-after": ["unist-util-find-after@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-modify-children": ["unist-util-modify-children@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" } }, "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="], + + "unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], + + "unist-util-visit-children": ["unist-util-visit-children@3.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "unstorage": ["unstorage@1.17.5", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.10", "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg=="], + + "url-extras": ["url-extras@0.1.0", "", {}, "sha512-8tzwTeXFPuX/5PHuCDQE5Dd9Ts4rwoq2t9aIT+HS4iAVpmj5l4Ao7Q+BuuFjvWRqrLswBhQDk8O96ZicgCqQqw=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], + + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + + "vite": ["vite@8.0.16", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@vitejs/devtools", "esbuild", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw=="], + + "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], + + "volar-service-css": ["volar-service-css@0.0.71", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw=="], + + "volar-service-emmet": ["volar-service-emmet@0.0.71", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA=="], + + "volar-service-html": ["volar-service-html@0.0.71", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw=="], + + "volar-service-prettier": ["volar-service-prettier@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg=="], + + "volar-service-typescript": ["volar-service-typescript@0.0.71", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw=="], + + "volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A=="], + + "volar-service-yaml": ["volar-service-yaml@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.23.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q=="], + + "vscode-css-languageservice": ["vscode-css-languageservice@6.3.10", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA=="], + + "vscode-html-languageservice": ["vscode-html-languageservice@5.6.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="], + + "vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="], + + "vscode-jsonrpc": ["vscode-jsonrpc@9.0.1", "", {}, "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw=="], + + "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], + + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.18.2", "", { "dependencies": { "vscode-jsonrpc": "9.0.1", "vscode-languageserver-types": "3.18.0" } }, "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg=="], + + "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.18.0", "", {}, "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g=="], + + "vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="], + + "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], + + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], + + "webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], + + "which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="], + + "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], + + "ws": ["ws@7.5.11", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA=="], + + "xdg-basedir": ["xdg-basedir@4.0.0", "", {}, "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="], + + "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="], + + "y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + + "yaml-language-server": ["yaml-language-server@1.23.0", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-i18n": "^4.2.0", "prettier": "^3.8.1", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.8.3" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A=="], + + "yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + + "yargs-parser": ["yargs-parser@13.1.2", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg=="], + + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], + + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + + "@astrojs/check/yargs": ["yargs@17.7.3", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], + + "@astrojs/telemetry/is-docker": ["is-docker@4.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA=="], + + "@astrojs/telemetry/is-wsl": ["is-wsl@3.1.1", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw=="], + + "@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@formatjs/ecma402-abstract/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@formatjs/fast-memoize/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@formatjs/icu-messageformat-parser/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@formatjs/icu-skeleton-parser/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@formatjs/intl-localematcher/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@lhci/utils/js-yaml": ["js-yaml@3.15.0", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog=="], + + "@mdx-js/mdx/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "@paulirish/trace_engine/third-party-web": ["third-party-web@0.29.2", "", {}, "sha512-fegtha91tq2DHphyoiBXVHjVi2YG9zFaRnboT9C28tO1en9Y3wJsfspuy40F+u5wl3hHVbw7cnd1b67kEGHb8g=="], + + "@puppeteer/browsers/yargs": ["yargs@17.7.3", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.5", "", { "dependencies": { "@tybys/wasm-util": "^0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q=="], + + "@tybys/wasm-util/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@vscode/emmet-helper/jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="], + + "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + + "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "ast-types/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "astro/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], + + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "enquirer/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "estree-util-build-jsx/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "external-editor/tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "intl-messageformat/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + + "lighthouse/chrome-launcher": ["chrome-launcher@1.2.1", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^2.0.1" }, "bin": { "print-chrome-path": "bin/print-chrome-path.cjs" } }, "sha512-qmFR5PLMzHyuNJHwOloHPAHhbaNglkfeV/xDtt5b7xiFFyU1I+AZZX0PYseMuhenJSSirgxELYIbswcoc+5H4A=="], + + "lighthouse/lighthouse-logger": ["lighthouse-logger@2.0.2", "", { "dependencies": { "debug": "^4.4.1", "marky": "^1.2.2" } }, "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg=="], + + "lighthouse/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], + + "lighthouse/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "lighthouse/yargs": ["yargs@17.7.3", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], + + "lighthouse/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "puppeteer-core/devtools-protocol": ["devtools-protocol@0.0.1608973", "", {}, "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ=="], + + "puppeteer-core/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "sitemap/@types/node": ["@types/node@24.13.3", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q=="], + + "string-width/strip-ansi": ["strip-ansi@4.0.0", "", { "dependencies": { "ansi-regex": "^3.0.0" } }, "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow=="], + + "tmp/rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="], + + "unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "unstorage/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "vscode-css-languageservice/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + + "vscode-languageserver/vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="], + + "yaml-language-server/yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + + "@astrojs/check/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "@astrojs/check/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "@astrojs/check/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "@astrojs/check/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "@lhci/utils/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "@puppeteer/browsers/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "@puppeteer/browsers/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "@puppeteer/browsers/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "@puppeteer/browsers/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], + + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], + + "enquirer/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "lighthouse/chrome-launcher/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "lighthouse/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "lighthouse/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "lighthouse/yargs/y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "sitemap/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + + "string-width/strip-ansi/ansi-regex": ["ansi-regex@3.0.1", "", {}, "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="], + + "unstorage/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + + "vscode-languageserver/vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + + "vscode-languageserver/vscode-languageserver-protocol/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + + "wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "wrap-ansi/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@astrojs/check/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@astrojs/check/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "@astrojs/check/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "@astrojs/check/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@puppeteer/browsers/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@puppeteer/browsers/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "@puppeteer/browsers/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "@puppeteer/browsers/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@rolldown/binding-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "lighthouse/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "lighthouse/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "lighthouse/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "lighthouse/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@astrojs/check/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@astrojs/check/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "@astrojs/check/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@puppeteer/browsers/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "@puppeteer/browsers/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "lighthouse/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "lighthouse/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "lighthouse/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], + "@astrojs/check/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "d3-dsv/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "d3-sankey/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], + "lighthouse/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "d3-sankey/d3-shape": ["d3-shape@1.3.7", "", { "dependencies": { "d3-path": "1" } }, "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw=="], + "@astrojs/check/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], + "@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], + "lighthouse/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], } } diff --git a/components.json b/components.json deleted file mode 100644 index d3184c8..0000000 --- a/components.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "", - "css": "src/styles.css", - "baseColor": "stone", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "iconLibrary": "lucide" -} diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..ab6a371 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,46 @@ +# Architecture + +## Boundaries + +The workspace contains two independent static outputs: + +| Surface | Canonical origin | Responsibility | +| --- | --- | --- | +| Marketing | `https://mobench.org` | Product story, capability summary, proof, requirements, and task entry points | +| Documentation | `https://docs.mobench.org` | Guides, search, examples, generated reference, release applicability, and troubleshooting | + +The marketing application must not render documentation aliases. The documentation application must not mirror the marketing landing page. Redirects enforce the boundary at the edge. + +## Truth flow + +```text +mobile-bench-rs release tests + -> mobench-site-manifest-v1.json release asset + -> pinned manifest + checksum in packages/truth + -> generated reference, validation, llms files, and capability copy + -> both static Astro builds +``` + +The website build is offline and deterministic. A release-sync command may download an explicitly requested release into a temporary directory, validate it, and prepare a reviewable update. It must never read an unpinned upstream branch during a production build. + +Capabilities use exactly four states: `supported`, `preview`, `planned`, and `unsupported`. Each entry cites an upstream test or source identifier. Authored prose may explain a capability but cannot override its state. + +## Rendering + +- Astro emits complete HTML, metadata, canonical URLs, structured data, navigation, highlighted code, diagrams, sitemaps, and AI-readable text. +- Starlight supplies the documentation shell and Pagefind index. +- Framework-free scripts progressively enhance theme selection, mobile controls, copy, and tabs. +- Diagrams are accessible SVG or semantic HTML with adjacent text summaries. Mermaid is never shipped to browsers. +- Media declares dimensions and responsive sources. Font files are self-hosted and subset. + +## URL contract + +- Documentation home: `https://docs.mobench.org/` +- Documentation page: `https://docs.mobench.org//` +- Marketing documentation paths, `/docs`, `/overview`, and legacy documentation aliases return permanent redirects. +- Unknown paths return a branded HTTP 404 response. +- Sitemaps contain canonical URLs only. + +## Analytics contract + +Analytics are aggregate and non-identifying. Allowed events have fixed names and enum-like properties. Search queries, copied text, credentials, repository names, benchmark names, device IDs, and user-provided URLs are never transmitted. diff --git a/docs/AUTHORING.md b/docs/AUTHORING.md new file mode 100644 index 0000000..d7bad65 --- /dev/null +++ b/docs/AUTHORING.md @@ -0,0 +1,62 @@ +# Documentation authoring + +Documentation lives in `apps/docs/src/content/docs` as MDX. Prefer task-oriented prose and executable examples over feature inventories. + +## Required frontmatter + +Every page declares: + +```yaml +--- +title: First BrowserStack run +slug: first-browserstack-run +description: Build an Android runner and execute it on one hosted device. +section: Run benchmarks +order: 1 +audience: [benchmark-author, ci-engineer] +release: 0.1.43 +lastVerified: 2026-07-15 +sourceRefs: + - label: BrowserStack execution path + url: https://github.com/worldcoin/mobile-bench-rs/blob/d1a3176f9144f35e777e83fd07045116144da257/crates/mobench/src/browserstack.rs + evidence: source-browserstack-run +aliases: + - /app-automate +draft: false +--- +``` + +The required `slug` is the flat canonical route, independent of the authoring folder. Aliases begin with `/`, cannot collide with a canonical slug or another alias, and always redirect to a canonical page. + +## Commands and claims + +- Use `mobench` for stable `0.1.43` commands. Do not publish `cargo mobench` until the wrapper fix appears in the pinned release manifest and passes both invocation smokes. +- Ordinary mobile benchmark execution is a BrowserStack capability in the current release. +- `--local-only` is build/preflight behavior; it does not execute a benchmark on an attached phone, emulator, or simulator. +- Describe local profiling only where the manifest marks the exact platform/backend combination supported. +- Copy option names, defaults, artifact names, and configuration keys from the pinned upstream manifest. +- Never invent coverage percentages, energy metrics, benchmark results, or device-support claims. Link to a fixture, test, case study, or upstream source. + +All `bash`, `console`, and `sh` fences containing a `mobench` command are parser-tested against the pinned command tree. Use ordinary fenced blocks: + +````md +```console +mobench ci run --target android --output-dir target/mobench/ci --fetch +``` +```` + +JSON examples that represent an upstream schema use `test=schema:` and are validated during `bun run check`. + +TOML examples for published Mobench configuration use `test=config:mobench.toml` or `test=config:bench-config.toml`. Every tagged key must exist in the pinned manifest. + +## Links and media + +- Prefer canonical internal links without hostnames. +- External behavioral claims need a `sourceRefs` entry and a nearby human-readable link. +- Give meaningful images alt text, fixed dimensions, and responsive sources. +- Give every chart a table or definition list containing the same information. +- Give every diagram a visible summary that remains useful without the image. + +## Copy Markdown + +The Copy Markdown action returns the authored page body with headings, links, lists, and code fences intact. It must not copy navigation, analytics data, generated prompts, or hidden provider payloads. Assistant links, if present, contain only a short prompt and the canonical page URL. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..fa6571f --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,33 @@ +# Deployment and smoke checks + +## Vercel projects + +Configure two projects from the same repository: + +| Project | Root directory | Production domain | +| --- | --- | --- | +| Marketing | `apps/marketing` | `mobench.org` | +| Documentation | `apps/docs` | `docs.mobench.org` | + +Both projects use Bun and static Astro output. Preserve the previous successful deployment until the live smoke passes. + +## Preview gate + +- Run the complete Bun validation suite from the repository root. +- Confirm full HTML, unique metadata, canonical tags, `og:image:alt`, structured data, and navigation with JavaScript disabled. +- Exercise keyboard navigation, Pagefind search, copy success/failure, theme controls, mobile drawers, hashes, and browser history at 375, 768, 1024, 1280, and 1440 pixels. +- Run axe and screen-reader smoke checks; verify visible focus, focus restoration, reduced motion, target sizes, 200%/400% zoom, and semantic chart/diagram alternatives. +- Inspect responsive screenshots for the landing page, documentation home, search, a long reference page, both 404s, and both themes. +- Enforce initial JavaScript and hero budgets from the root test configuration. + +## HTTP smoke + +- Canonical marketing and documentation pages return `200` with complete HTML. +- Cross-host duplicates and legacy aliases return `308` to their one canonical URL. +- Unknown paths return `404` and use the matching surface's metadata. +- `robots.txt` is plain text and each sitemap is valid canonical-only XML. +- Hydration or progressive enhancement does not change titles, descriptions, canonicals, or structured data. + +## Live check and rollback + +Repeat the HTTP and critical browser smokes on both production domains. Roll back if canonical routing, Quickstart, search, copy, mobile navigation, or error status behavior regresses. After launch, monitor Core Web Vitals, 404s, redirect failures, search zero-result counts, and aggregate Quickstart exits without collecting raw query text or personal data. diff --git a/docs/RELEASE_SYNC.md b/docs/RELEASE_SYNC.md new file mode 100644 index 0000000..81c0df4 --- /dev/null +++ b/docs/RELEASE_SYNC.md @@ -0,0 +1,41 @@ +# Upstream release sync + +The site follows the latest stable mobench release. It does not consume `mobile-bench-rs/main` during builds. + +## Inputs + +A release update requires: + +1. A signed or otherwise verified upstream tag and commit SHA. +2. `mobench-site-manifest-v1.json` from that release. +3. The manifest SHA-256 checksum. +4. Referenced JSON schemas and deterministic fixtures. +5. Successful direct-executable and Cargo-wrapper smoke results recorded by upstream. + +## Update flow + +1. Download the manifest checksum asset from the upstream release, then run the sync command with an explicit tag and expected checksum: + + ```bash + gh release download vX.Y.Z \ + --repo worldcoin/mobile-bench-rs \ + --pattern 'mobench-site-manifest-v1.json.sha256' \ + --dir /tmp/mobench-release + bun run sync:release -- \ + --tag vX.Y.Z \ + --expected-manifest-sha256 "$(awk '{print $1}' /tmp/mobench-release/mobench-site-manifest-v1.json.sha256)" + ``` + + The command resolves the tag object to its commit, requires the manifest release identity to match, fetches schemas and fixtures from that immutable commit, validates their checksums and JSON contracts, and updates the offline truth package. It never fetches `main`. + +2. Review manifest and schema diffs. Capability changes require source evidence. +3. Run `bun install`, then `bun run generate` to rebuild the generated CLI/configuration references, Pagefind inputs, sitemaps, OG inputs, `llms.txt`, and `llms-full.txt`. +4. Run command parsing, schema validation, content, type, unit, E2E, accessibility, visual, HTTP, and performance checks. +5. Open a pull request showing the old/new release, commit SHA, checksum, capability changes, route changes, and screenshots. +6. Merge only after both preview deployments pass smoke checks. + +The scheduled `.github/workflows/release-sync.yml` watcher performs the same checksum-gated sync and opens an `automation/mobench-release-*` pull request. It never commits directly to the default branch and cannot silently relax a capability state because content validation rechecks every evidence identifier, command, configuration key, schema, and fixture. + +## Cargo wrapper rule + +`cargo mobench` becomes publishable only when the pinned manifest reports it supported and upstream tests prove that Cargo's injected leading `mobench` argument is removed while direct `mobench` invocation remains unchanged. Until then, generated examples use `mobench`. diff --git a/docs/licenses/Geist-OFL.txt b/docs/licenses/Geist-OFL.txt new file mode 100644 index 0000000..5971548 --- /dev/null +++ b/docs/licenses/Geist-OFL.txt @@ -0,0 +1,94 @@ +Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font) +Geist-Italic[wght].ttf: Copyright 2024 The Geist Project Authors +(https://github.com/vercel/geist-font) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/index.html b/index.html deleted file mode 100644 index 40982a1..0000000 --- a/index.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - mobench - Rust mobile benchmarking CLI and SDK - - - - - - - - - - - - - - - - -
- - - diff --git a/lighthouserc.docs.cjs b/lighthouserc.docs.cjs new file mode 100644 index 0000000..bdce86f --- /dev/null +++ b/lighthouserc.docs.cjs @@ -0,0 +1,25 @@ +module.exports = { + ci: { + collect: { + staticDistDir: './apps/docs/dist', + url: ['http://localhost/', 'http://localhost/quickstart/', 'http://localhost/cli/'], + numberOfRuns: 1, + settings: { + preset: 'desktop', + chromeFlags: '--headless --no-sandbox --disable-dev-shm-usage', + }, + }, + assert: { + assertions: { + 'categories:performance': ['error', { minScore: 0.9 }], + 'categories:accessibility': ['error', { minScore: 0.95 }], + 'categories:best-practices': ['error', { minScore: 0.9 }], + 'categories:seo': ['error', { minScore: 0.95 }], + 'largest-contentful-paint': ['error', { maxNumericValue: 2500 }], + 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }], + 'total-blocking-time': ['error', { maxNumericValue: 200 }], + }, + }, + upload: { target: 'filesystem', outputDir: '.lighthouseci/docs' }, + }, +} diff --git a/lighthouserc.marketing.cjs b/lighthouserc.marketing.cjs new file mode 100644 index 0000000..e6261d7 --- /dev/null +++ b/lighthouserc.marketing.cjs @@ -0,0 +1,25 @@ +module.exports = { + ci: { + collect: { + staticDistDir: './apps/marketing/dist', + url: ['http://localhost/', 'http://localhost/privacy/'], + numberOfRuns: 1, + settings: { + preset: 'desktop', + chromeFlags: '--headless --no-sandbox --disable-dev-shm-usage', + }, + }, + assert: { + assertions: { + 'categories:performance': ['error', { minScore: 0.9 }], + 'categories:accessibility': ['error', { minScore: 0.95 }], + 'categories:best-practices': ['error', { minScore: 0.9 }], + 'categories:seo': ['error', { minScore: 0.95 }], + 'largest-contentful-paint': ['error', { maxNumericValue: 2500 }], + 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }], + 'total-blocking-time': ['error', { maxNumericValue: 200 }], + }, + }, + upload: { target: 'filesystem', outputDir: '.lighthouseci/marketing' }, + }, +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 70762fa..0000000 --- a/package-lock.json +++ /dev/null @@ -1,2636 +0,0 @@ -{ - "name": "mobench-org", - "version": "0.3.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "mobench-org", - "version": "0.3.0", - "dependencies": { - "@radix-ui/react-accordion": "^1.2.14", - "@radix-ui/react-slot": "^1.3.0", - "@tanstack/react-router": "^1.170.16", - "@tanstack/react-router-devtools": "^1.167.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^1.21.0", - "react": "^19.2.7", - "react-dom": "^19.2.7", - "tailwind-merge": "^3.6.0", - "tailwindcss-animate": "^1.0.7" - }, - "devDependencies": { - "@tailwindcss/vite": "^4.3.1", - "@tanstack/router-plugin": "^1.168.18", - "@types/node": "^26.0.0", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "tailwindcss": "^4.3.1", - "typescript": "^6.0.3", - "vite": "^8.0.16" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.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/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "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/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", - "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.133.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", - "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", - "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", - "license": "MIT" - }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.14.tgz", - "integrity": "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collapsible": "1.1.14", - "@radix-ui/react-collection": "1.1.10", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-primitive": "2.1.6", - "@radix-ui/react-use-controllable-state": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.14.tgz", - "integrity": "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.6", - "@radix-ui/react-use-controllable-state": "1.2.3", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.10.tgz", - "integrity": "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-primitive": "2.1.6", - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", - "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", - "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", - "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", - "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", - "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz", - "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.3.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", - "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", - "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.3", - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", - "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", - "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", - "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", - "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", - "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", - "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", - "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", - "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", - "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", - "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", - "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", - "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", - "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", - "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", - "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", - "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", - "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tailwindcss/node": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", - "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "5.21.6", - "jiti": "^2.7.0", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.3.1" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", - "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.1", - "@tailwindcss/oxide-darwin-arm64": "4.3.1", - "@tailwindcss/oxide-darwin-x64": "4.3.1", - "@tailwindcss/oxide-freebsd-x64": "4.3.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", - "@tailwindcss/oxide-linux-x64-musl": "4.3.1", - "@tailwindcss/oxide-wasm32-wasi": "4.3.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", - "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", - "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", - "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", - "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", - "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", - "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", - "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", - "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", - "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", - "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.10.0", - "@emnapi/runtime": "^1.10.0", - "@emnapi/wasi-threads": "^1.2.1", - "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.2", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", - "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", - "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz", - "integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.3.1", - "@tailwindcss/oxide": "4.3.1", - "tailwindcss": "4.3.1" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7 || ^8" - } - }, - "node_modules/@tanstack/history": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.162.0.tgz", - "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==", - "license": "MIT", - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-router": { - "version": "1.170.16", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.170.16.tgz", - "integrity": "sha512-w6eq1IJklujs1tESazaK/FxH0+H2l8vm/QPuu1cD3oRW/ubgKneQpd7b64ti/8gUyEimzimJQZDmJr6YHfP5+g==", - "license": "MIT", - "dependencies": { - "@tanstack/history": "1.162.0", - "@tanstack/react-store": "^0.9.3", - "@tanstack/router-core": "1.171.13", - "isbot": "^5.1.22" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" - } - }, - "node_modules/@tanstack/react-router-devtools": { - "version": "1.167.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.167.0.tgz", - "integrity": "sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w==", - "license": "MIT", - "dependencies": { - "@tanstack/router-devtools-core": "1.168.0" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@tanstack/react-router": "^1.170.0", - "@tanstack/router-core": "^1.170.0", - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0" - }, - "peerDependenciesMeta": { - "@tanstack/router-core": { - "optional": true - } - } - }, - "node_modules/@tanstack/react-store": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.9.3.tgz", - "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==", - "license": "MIT", - "dependencies": { - "@tanstack/store": "0.9.3", - "use-sync-external-store": "^1.6.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/router-core": { - "version": "1.171.13", - "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.171.13.tgz", - "integrity": "sha512-+NOwEj1kO/6IGmpHRIZHasYxYWpyBQGNIZAST9aNrk9Q3YlU9SgqVnl1pbLa9qAKfeNdXQIRve0RQb/0kyDeDA==", - "license": "MIT", - "dependencies": { - "@tanstack/history": "1.162.0", - "cookie-es": "^3.0.0", - "seroval": "^1.5.4", - "seroval-plugins": "^1.5.4" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/router-devtools-core": { - "version": "1.168.0", - "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.168.0.tgz", - "integrity": "sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg==", - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1", - "goober": "^2.1.16" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@tanstack/router-core": "^1.170.0", - "csstype": "^3.0.10" - }, - "peerDependenciesMeta": { - "csstype": { - "optional": true - } - } - }, - "node_modules/@tanstack/router-generator": { - "version": "1.167.17", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.167.17.tgz", - "integrity": "sha512-xtB9tB2Ws0tWR6Pi7nc3Qk9IYgoh1mQCKWjHqIl9tf6BNUpKoqniJoPAQ4+LGrK8FeZYU0o0p/qlZEyj9FAulA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.171.13", - "@tanstack/router-utils": "1.162.2", - "@tanstack/virtual-file-routes": "1.162.0", - "jiti": "^2.7.0", - "magic-string": "^0.30.21", - "prettier": "^3.5.0", - "zod": "^4.4.3" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/router-plugin": { - "version": "1.168.18", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.18.tgz", - "integrity": "sha512-MofS28/axfnfnhOD2RSgJEaU882aX5RsAzhGz5Vc4XhAmvCjy919u9JrNs4QsTWFbTD1P7IJ8WFlFVsrg0pStg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "@tanstack/router-core": "1.171.13", - "@tanstack/router-generator": "1.167.17", - "@tanstack/router-utils": "1.162.2", - "chokidar": "^5.0.0", - "unplugin": "^3.0.0", - "zod": "^4.4.3" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@rsbuild/core": ">=1.0.2 || ^2.0.0", - "@tanstack/react-router": "^1.170.15", - "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", - "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", - "webpack": ">=5.92.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - }, - "@tanstack/react-router": { - "optional": true - }, - "vite": { - "optional": true - }, - "vite-plugin-solid": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/@tanstack/router-utils": { - "version": "1.162.2", - "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.2.tgz", - "integrity": "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.28.5", - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "ansis": "^4.1.0", - "babel-dead-code-elimination": "^1.0.12", - "diff": "^8.0.2", - "pathe": "^2.0.3", - "tinyglobby": "^0.2.15" - }, - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/store": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", - "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/virtual-file-routes": { - "version": "1.162.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.162.0.tgz", - "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/node": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", - "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", - "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, - "node_modules/ansis": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", - "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - } - }, - "node_modules/babel-dead-code-elimination": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", - "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.38", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", - "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie-es": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", - "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", - "license": "MIT" - }, - "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==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.376", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.376.tgz", - "integrity": "sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA==", - "dev": true, - "license": "ISC" - }, - "node_modules/enhanced-resolve": { - "version": "5.21.6", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", - "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "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/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/goober": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.19.tgz", - "integrity": "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==", - "license": "MIT", - "peerDependencies": { - "csstype": "^3.0.10" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/isbot": { - "version": "5.1.43", - "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.43.tgz", - "integrity": "sha512-drJhFmibra4LO6Wd7D3Oi6UICRK9244vSZkmxzhlZP0TTdwCA2ueK4PEkUkzPYeuqug9+cqqdWPgihjk5+83Cg==", - "license": "Unlicense", - "engines": { - "node": ">=18" - } - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.21.0.tgz", - "integrity": "sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "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/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.14", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.14.tgz", - "integrity": "sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ==", - "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/node-releases": { - "version": "2.0.48", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", - "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "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/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "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.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prettier": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", - "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.7" - } - }, - "node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/rolldown": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", - "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.133.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.3", - "@rolldown/binding-darwin-arm64": "1.0.3", - "@rolldown/binding-darwin-x64": "1.0.3", - "@rolldown/binding-freebsd-x64": "1.0.3", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", - "@rolldown/binding-linux-arm64-gnu": "1.0.3", - "@rolldown/binding-linux-arm64-musl": "1.0.3", - "@rolldown/binding-linux-ppc64-gnu": "1.0.3", - "@rolldown/binding-linux-s390x-gnu": "1.0.3", - "@rolldown/binding-linux-x64-gnu": "1.0.3", - "@rolldown/binding-linux-x64-musl": "1.0.3", - "@rolldown/binding-openharmony-arm64": "1.0.3", - "@rolldown/binding-wasm32-wasi": "1.0.3", - "@rolldown/binding-win32-arm64-msvc": "1.0.3", - "@rolldown/binding-win32-x64-msvc": "1.0.3" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/seroval": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", - "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/seroval-plugins": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.4.tgz", - "integrity": "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "seroval": "^1.0" - } - }, - "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/tailwind-merge": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", - "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", - "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", - "license": "MIT" - }, - "node_modules/tailwindcss-animate": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", - "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", - "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unplugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", - "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "picomatch": "^4.0.3", - "webpack-virtual-modules": "^0.6.2" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/vite": { - "version": "8.0.16", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", - "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.15", - "rolldown": "1.0.3", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/package.json b/package.json index dd46858..864beb2 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,38 @@ { - "name": "mobench-org", + "name": "mobench-site", "private": true, - "version": "0.3.0", - "type": "module", + "version": "1.0.0", + "packageManager": "bun@1.3.13", + "workspaces": [ + "apps/*", + "packages/*" + ], "scripts": { - "dev": "vite --port 3000", - "build": "vite build && node scripts/generate-route-html.mjs", - "og:generate": "python3 scripts/generate-og-images.py", - "serve": "vite preview", - "start": "vite" - }, - "dependencies": { - "@radix-ui/react-accordion": "^1.2.14", - "@radix-ui/react-slot": "^1.3.0", - "@tanstack/react-router": "^1.170.16", - "@tanstack/react-router-devtools": "^1.167.0", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^1.21.0", - "mermaid": "11.15.0", - "react": "^19.2.7", - "react-dom": "^19.2.7", - "tailwind-merge": "^3.6.0", - "tailwindcss-animate": "^1.0.7" + "dev": "bun run dev:marketing", + "dev:marketing": "bun run --cwd apps/marketing dev", + "dev:docs": "bun run --cwd apps/docs dev", + "build": "bun run build:marketing && bun run build:docs", + "build:marketing": "bun run --cwd apps/marketing build", + "build:docs": "bun run --cwd apps/docs build", + "generate": "bun scripts/generate-content.ts && bun scripts/generate-og.ts", + "generate:check": "bun scripts/generate-content.ts --check && bun scripts/generate-og.ts --check", + "sync:release": "bun scripts/sync-release.ts", + "check:sync": "bun scripts/sync-release.ts --help", + "validate:content": "bun scripts/validate-content.ts", + "check": "bun run check:sync && bun run validate:content && bun run generate:check && bun run check:marketing && bun run check:docs", + "check:marketing": "bun run --cwd apps/marketing check", + "check:docs": "bun run --cwd apps/docs check", + "test": "bun run build && bun test tests/build-contracts.test.ts --timeout 30000", + "test:e2e": "playwright test", + "test:lighthouse": "lhci autorun --config=lighthouserc.marketing.cjs && lhci autorun --config=lighthouserc.docs.cjs", + "preview:marketing": "bun run --cwd apps/marketing preview", + "preview:docs": "bun run --cwd apps/docs preview" }, "devDependencies": { - "@tailwindcss/vite": "^4.3.1", - "@tanstack/router-plugin": "^1.168.18", - "@types/node": "^26.0.0", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "tailwindcss": "^4.3.1", - "typescript": "^6.0.3", - "vite": "^8.0.16" + "@axe-core/playwright": "4.12.1", + "@lhci/cli": "0.15.1", + "@playwright/test": "1.61.1", + "ajv": "8.20.0", + "yaml": "2.9.0" } } diff --git a/packages/site-config/package.json b/packages/site-config/package.json new file mode 100644 index 0000000..478f41a --- /dev/null +++ b/packages/site-config/package.json @@ -0,0 +1,10 @@ +{ + "name": "@mobench/site-config", + "version": "1.0.0", + "private": true, + "type": "module", + "exports": "./src/index.ts", + "dependencies": { + "@mobench/truth": "workspace:*" + } +} diff --git a/packages/site-config/src/index.ts b/packages/site-config/src/index.ts new file mode 100644 index 0000000..e4b4afe --- /dev/null +++ b/packages/site-config/src/index.ts @@ -0,0 +1,22 @@ +import pin from '@mobench/truth/pin' + +export const site = { + marketingUrl: 'https://mobench.org', + docsUrl: 'https://docs.mobench.org', + repositoryUrl: 'https://github.com/worldcoin/mobile-bench-rs', + websiteRepositoryUrl: 'https://github.com/worldfnd/mobench.org', + release: pin.release, + crateVersion: pin.version, +} as const + +export const supportedPlatforms = ['android', 'ios'] as const + +export const analyticsEvents = [ + 'quickstart_opened', + 'install_copied', + 'github_opened', + 'search_result_opened', + 'search_zero_results', +] as const + +export type AnalyticsEvent = (typeof analyticsEvents)[number] diff --git a/packages/site-config/tsconfig.json b/packages/site-config/tsconfig.json new file mode 100644 index 0000000..2d384be --- /dev/null +++ b/packages/site-config/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "composite": true, + "declaration": true, + "emitDeclarationOnly": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "target": "ES2022" + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/truth/README.md b/packages/truth/README.md new file mode 100644 index 0000000..c5ed32d --- /dev/null +++ b/packages/truth/README.md @@ -0,0 +1,7 @@ +# Pinned mobench truth + +This package is the offline input for both website builds. It pins upstream release `v0.1.43` at commit `d1a3176f9144f35e777e83fd07045116144da257` and the exact SHA-256 checksum of `mobench-site-manifest-v1.json`. + +Do not edit the manifest, schemas, or fixtures by hand. Regenerate them from a tagged `mobile-bench-rs` release, verify their checksums, and update them through the release-sync workflow documented in `docs/RELEASE_SYNC.md`. + +The canonical executable and Cargo-wrapper status come from the pinned manifest. Generated website commands must keep using the canonical supported binary until a later release changes that contract and the invocation smokes pass. diff --git a/packages/truth/fixtures/summary-basic.json b/packages/truth/fixtures/summary-basic.json new file mode 100644 index 0000000..ff47d09 --- /dev/null +++ b/packages/truth/fixtures/summary-basic.json @@ -0,0 +1,84 @@ +{ + "summary": { + "generated_at": "2026-03-26T00:00:00Z", + "generated_at_unix": 1774483200, + "target": "android", + "function": "multiple", + "iterations": 5, + "warmup": 1, + "devices": [ + "Google Pixel 8-14.0", + "Samsung Galaxy S23-14.0" + ], + "device_summaries": [ + { + "device": "Google Pixel 8-14.0", + "benchmarks": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 100000000, + "median_ns": 100000000, + "p95_ns": 105000000, + "min_ns": 95000000, + "max_ns": 105000000 + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 145000000, + "median_ns": 145000000, + "p95_ns": 151000000, + "min_ns": 140000000, + "max_ns": 151000000 + } + ] + }, + { + "device": "Samsung Galaxy S23-14.0", + "benchmarks": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 94000000, + "median_ns": 94000000, + "p95_ns": 98000000, + "min_ns": 90000000, + "max_ns": 98000000 + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 136000000, + "median_ns": 136000000, + "p95_ns": 140000000, + "min_ns": 132000000, + "max_ns": 140000000 + } + ] + } + ] + }, + "benchmark_results": { + "Google Pixel 8-14.0": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": [95000000, 98000000, 100000000, 102000000, 105000000] + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": [140000000, 142000000, 145000000, 147000000, 151000000] + } + ], + "Samsung Galaxy S23-14.0": [ + { + "function": "basic_benchmark::bench_fibonacci", + "samples": [90000000, 92000000, 94000000, 96000000, 98000000] + }, + { + "function": "basic_benchmark::bench_checksum", + "samples": [132000000, 134000000, 136000000, 138000000, 140000000] + } + ] + } +} diff --git a/packages/truth/fixtures/summary-ffi.json b/packages/truth/fixtures/summary-ffi.json new file mode 100644 index 0000000..be49897 --- /dev/null +++ b/packages/truth/fixtures/summary-ffi.json @@ -0,0 +1,84 @@ +{ + "summary": { + "generated_at": "2026-03-26T00:00:00Z", + "generated_at_unix": 1774483200, + "target": "android", + "function": "multiple", + "iterations": 5, + "warmup": 1, + "devices": [ + "Google Pixel 8 Pro-14.0", + "OnePlus 12-14.0" + ], + "device_summaries": [ + { + "device": "Google Pixel 8 Pro-14.0", + "benchmarks": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 112000000, + "median_ns": 112000000, + "p95_ns": 118000000, + "min_ns": 108000000, + "max_ns": 118000000 + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 159000000, + "median_ns": 159000000, + "p95_ns": 165000000, + "min_ns": 154000000, + "max_ns": 165000000 + } + ] + }, + { + "device": "OnePlus 12-14.0", + "benchmarks": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": 5, + "mean_ns": 103000000, + "median_ns": 103000000, + "p95_ns": 107000000, + "min_ns": 99000000, + "max_ns": 107000000 + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": 5, + "mean_ns": 149000000, + "median_ns": 149000000, + "p95_ns": 153000000, + "min_ns": 145000000, + "max_ns": 153000000 + } + ] + } + ] + }, + "benchmark_results": { + "Google Pixel 8 Pro-14.0": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": [108000000, 110000000, 112000000, 114000000, 118000000] + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": [154000000, 156000000, 159000000, 161000000, 165000000] + } + ], + "OnePlus 12-14.0": [ + { + "function": "ffi_benchmark::bench_fibonacci", + "samples": [99000000, 101000000, 103000000, 105000000, 107000000] + }, + { + "function": "ffi_benchmark::bench_checksum", + "samples": [145000000, 147000000, 149000000, 151000000, 153000000] + } + ] + } +} diff --git a/packages/truth/mobench-site-manifest-v1.json b/packages/truth/mobench-site-manifest-v1.json new file mode 100644 index 0000000..9333624 --- /dev/null +++ b/packages/truth/mobench-site-manifest-v1.json @@ -0,0 +1,9063 @@ +{ + "schema_version": 1, + "release": { + "version": "0.1.43", + "tag": "v0.1.43", + "sha": "d1a3176f9144f35e777e83fd07045116144da257", + "repository": "https://github.com/worldcoin/mobile-bench-rs" + }, + "msrv": "1.85", + "binaries": [ + { + "name": "mobench", + "invocation": "mobench ", + "canonical_for_release": true, + "status": "supported", + "note": "Canonical executable for the pinned v0.1.43 release." + }, + { + "name": "cargo-mobench", + "invocation": "cargo mobench ", + "canonical_for_release": false, + "status": "unsupported", + "note": "The published v0.1.43 wrapper forwards Cargo's injected `mobench` token. A source fix is integration-tested but requires a later release." + } + ], + "command_tree": { + "name": "mobench", + "path": "mobench", + "about": "Mobile Rust benchmarking orchestrator", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "version", + "long": "version", + "short": "V", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Version", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print version" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "build", + "path": "mobench build", + "about": "Build mobile artifacts from the resolved benchmark crate", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate (default: auto-detect bench-mobile/ or crates/{crate})" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "check", + "path": "mobench check", + "about": "Check prerequisites for building mobile artifacts", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": "Output format (text or json)" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "target", + "long": "target", + "short": "t", + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Target platform (android or ios)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "ci", + "path": "mobench ci", + "about": "CI helpers (workflow and action scaffolding)", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "check-run", + "path": "mobench ci check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [ + { + "id": "annotation_path", + "long": "annotation-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANNOTATION_PATH" + ], + "possible_values": [], + "defaults": [ + "src/lib.rs" + ], + "environment": null, + "help": "File path used in Check Run annotations (relative to repo root)" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional baseline JSON for regression detection" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "name", + "long": "name", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "NAME" + ], + "possible_values": [], + "defaults": [ + "Mobench" + ], + "environment": null, + "help": "Check Run name displayed in the PR" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage" + }, + { + "id": "repo", + "long": "repo", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REPO" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "GitHub repository (owner/repo format)" + }, + { + "id": "results", + "long": "results", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to summary JSON with benchmark results" + }, + { + "id": "results_dir", + "long": "results-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing summary JSON files (processes all)" + }, + { + "id": "sha", + "long": "sha", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SHA" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Git commit SHA to annotate" + }, + { + "id": "token", + "long": "token", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "TOKEN" + ], + "possible_values": [], + "defaults": [], + "environment": "GITHUB_TOKEN", + "help": "GitHub App token (from GITHUB_TOKEN env var or actions/create-github-app-token)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench ci help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "check-run", + "path": "mobench ci help check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench ci help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench ci help init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench ci help merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench ci help run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench ci help summarize", + "about": "Summarize benchmark results with device metrics", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench ci init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [ + { + "id": "action_dir", + "long": "action-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ACTION_DIR" + ], + "possible_values": [], + "defaults": [ + ".github/actions/mobench" + ], + "environment": null, + "help": "Directory to write the local GitHub Action" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "workflow", + "long": "workflow", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WORKFLOW" + ], + "possible_values": [], + "defaults": [ + ".github/workflows/mobile-bench.yml" + ], + "environment": null, + "help": "Path to write the workflow file" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench ci merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [ + { + "id": "device", + "long": "device", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device label all samples must match" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified benchmark function all samples must contain" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Expected measured sample count" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory to write merged summary.json, summary.md, and results.csv" + }, + { + "id": "samples_dir", + "long": "samples-dir", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SAMPLES_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing sample-*/summary.json one-sample CI outputs" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [ + "0" + ], + "environment": null, + "help": "Warmup count reported in merged CI summaries" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench ci run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [ + { + "id": "android_benchmark_timeout_secs", + "long": "android-benchmark-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_BENCHMARK_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark watchdog timeout in seconds for the generated harness" + }, + { + "id": "android_heartbeat_interval_secs", + "long": "android-heartbeat-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_HEARTBEAT_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark heartbeat interval in seconds for the generated harness" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline summary source (path|url|artifact:)" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device matrix YAML file to load device names from" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "devices", + "long": "devices", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICES" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device identifiers or labels (BrowserStack devices)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fetch", + "long": "fetch", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FETCH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Fetch BrowserStack artifacts after the run completes" + }, + { + "id": "fetch_output_dir", + "long": "fetch-output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_poll_interval_secs", + "long": "fetch-poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_timeout_secs", + "long": "fetch-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "300" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to benchmark (single function)" + }, + { + "id": "functions", + "long": "functions", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "FUNCTIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Multiple benchmark functions (comma-separated or JSON array). Runs each in sequence." + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "ios_app", + "long": "ios-app", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_APP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "ios_test_suite", + "long": "ios-test-suite", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_TEST_SUITE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS XCUITest test suite package (.zip or .ipa)" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [ + "100" + ], + "environment": null, + "help": null + }, + { + "id": "junit", + "long": "junit", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "JUNIT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write JUnit XML report to the given path" + }, + { + "id": "local_only", + "long": "local-only", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "LOCAL_ONLY" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Skip mobile builds and write host-side preflight/spec output without mobile execution" + }, + { + "id": "mobench_ref", + "long": "mobench-ref", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "MOBENCH_REF" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: git ref/sha for this mobench invocation" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci" + ], + "environment": null, + "help": "Output directory for CI contract files" + }, + { + "id": "plots", + "long": "plots", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLOTS" + ], + "possible_values": [ + "auto", + "off", + "require" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "pr_number", + "long": "pr-number", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PR_NUMBER" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: pull request number" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage when comparing to baseline" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode (recommended for BrowserStack to reduce APK size and upload time)" + }, + { + "id": "request_command", + "long": "request-command", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REQUEST_COMMAND" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: original command requested by the caller" + }, + { + "id": "requested_by", + "long": "requested-by", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REQUESTED_BY" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Metadata: user or actor that requested the run" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [ + "10" + ], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench ci summarize", + "about": "Summarize benchmark results with device metrics", + "options": [ + { + "id": "build_id", + "long": "build-id", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BUILD_ID" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "BrowserStack build ID to enrich results with device metrics (requires --results-dir)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_file", + "long": "output-file", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write output to file in addition to stdout" + }, + { + "id": "output_format", + "long": "output-format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FORMAT" + ], + "possible_values": [ + "json", + "markdown", + "table" + ], + "defaults": [ + "table" + ], + "environment": null, + "help": "Output format: table (terminal), markdown, or json" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Platform filter (show only one platform)" + }, + { + "id": "results_dir", + "long": "results-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "RESULTS_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Directory containing summary.json/CSV results (offline mode)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "compare", + "path": "mobench compare", + "about": "Compare two run summaries for regressions", + "options": [ + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline JSON summary to compare against" + }, + { + "id": "candidate", + "long": "candidate", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CANDIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Candidate JSON summary to compare" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional output path for markdown report" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "config", + "path": "mobench config", + "about": "Validate run configuration and associated files", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "help", + "path": "mobench config help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "help", + "path": "mobench config help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "validate", + "path": "mobench config help validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "validate", + "path": "mobench config validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "devices", + "path": "mobench devices", + "about": "List available BrowserStack devices for testing", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "json", + "long": "json", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "JSON" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Output as JSON" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Filter by platform (android or ios)" + }, + { + "id": "validate", + "long": "validate", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "VALIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Validate device specs against available devices" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "help", + "path": "mobench devices help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "help", + "path": "mobench devices help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "resolve", + "path": "mobench devices help resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "resolve", + "path": "mobench devices resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to run config file (optional source for matrix/tags)" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to device matrix YAML file" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "platform", + "long": "platform", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLATFORM" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to resolve (defaults to `default`)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "doctor", + "path": "mobench doctor", + "about": "Validate local + CI prerequisites and configuration", + "options": [ + { + "id": "browserstack", + "long": "browserstack", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BROWSERSTACK" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "true" + ], + "environment": null, + "help": "Validate BrowserStack credentials" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to run config file to validate" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to device matrix YAML file to validate" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "fetch", + "path": "mobench fetch", + "about": "Fetch BrowserStack build artifacts (logs, session JSON) for CI", + "options": [ + { + "id": "build_id", + "long": "build-id", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BUILD_ID" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "poll_interval_secs", + "long": "poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "10" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "timeout_secs", + "long": "timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "1800" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "wait", + "long": "wait", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "WAIT" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "true" + ], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "fixture", + "path": "mobench fixture", + "about": "Fixture lifecycle helpers for reproducible CI setup", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "build", + "path": "mobench fixture build", + "about": "Build fixture artifacts using existing build commands", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to benchmark crate" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench fixture cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag for keying" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench fixture help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench fixture help build", + "about": "Build fixture artifacts using existing build commands", + "options": [], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench fixture help cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench fixture help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench fixture help init", + "about": "Create starter fixture files for CI runs", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench fixture help verify", + "about": "Verify fixture files and optional profile filtering", + "options": [], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench fixture help verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench fixture init", + "about": "Create starter fixture files for CI runs", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [ + "device-matrix.yaml" + ], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "force", + "long": "force", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FORCE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Overwrite existing fixture files" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench fixture verify", + "about": "Verify fixture files and optional profile filtering", + "options": [ + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "json", + "text" + ], + "defaults": [ + "text" + ], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to verify" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench fixture verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fixture", + "long": null, + "short": null, + "positional_index": 1, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FIXTURE" + ], + "possible_values": [ + "basic", + "ffi" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for rendered fixture artifacts (defaults under target/mobench/plot-fixtures)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "help", + "path": "mobench help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench help build", + "about": "Build mobile artifacts from the resolved benchmark crate", + "options": [], + "subcommands": [] + }, + { + "name": "check", + "path": "mobench help check", + "about": "Check prerequisites for building mobile artifacts", + "options": [], + "subcommands": [] + }, + { + "name": "ci", + "path": "mobench help ci", + "about": "CI helpers (workflow and action scaffolding)", + "options": [], + "subcommands": [ + { + "name": "check-run", + "path": "mobench help ci check-run", + "about": "Create a GitHub Check Run with benchmark results", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help ci init", + "about": "Generate GitHub Actions workflow + local action wrapper", + "options": [], + "subcommands": [] + }, + { + "name": "merge-split-runs", + "path": "mobench help ci merge-split-runs", + "about": "Merge one-sample CI summaries into a normal CI output set", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench help ci run", + "about": "Run a full CI benchmark flow with stable output contract", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help ci summarize", + "about": "Summarize benchmark results with device metrics", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "compare", + "path": "mobench help compare", + "about": "Compare two run summaries for regressions", + "options": [], + "subcommands": [] + }, + { + "name": "config", + "path": "mobench help config", + "about": "Validate run configuration and associated files", + "options": [], + "subcommands": [ + { + "name": "validate", + "path": "mobench help config validate", + "about": "Validate bench-config.toml and referenced matrix/settings", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "devices", + "path": "mobench help devices", + "about": "List available BrowserStack devices for testing", + "options": [], + "subcommands": [ + { + "name": "resolve", + "path": "mobench help devices resolve", + "about": "Resolve devices from a matrix deterministically for CI usage", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "doctor", + "path": "mobench help doctor", + "about": "Validate local + CI prerequisites and configuration", + "options": [], + "subcommands": [] + }, + { + "name": "fetch", + "path": "mobench help fetch", + "about": "Fetch BrowserStack build artifacts (logs, session JSON) for CI", + "options": [], + "subcommands": [] + }, + { + "name": "fixture", + "path": "mobench help fixture", + "about": "Fixture lifecycle helpers for reproducible CI setup", + "options": [], + "subcommands": [ + { + "name": "build", + "path": "mobench help fixture build", + "about": "Build fixture artifacts using existing build commands", + "options": [], + "subcommands": [] + }, + { + "name": "cache-key", + "path": "mobench help fixture cache-key", + "about": "Compute deterministic fixture cache key from config/toolchain inputs", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help fixture init", + "about": "Create starter fixture files for CI runs", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench help fixture verify", + "about": "Verify fixture files and optional profile filtering", + "options": [], + "subcommands": [] + }, + { + "name": "verify-plots", + "path": "mobench help fixture verify-plots", + "about": "Render and verify checked-in plot fixtures", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "help", + "path": "mobench help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "init", + "path": "mobench help init", + "about": "Scaffold a base config file for the CLI", + "options": [], + "subcommands": [] + }, + { + "name": "init-sdk", + "path": "mobench help init-sdk", + "about": "Initialize a new benchmark project with the SDK templates", + "options": [], + "subcommands": [] + }, + { + "name": "list", + "path": "mobench help list", + "about": "List all discovered benchmark functions", + "options": [], + "subcommands": [] + }, + { + "name": "package-ipa", + "path": "mobench help package-ipa", + "about": "Package iOS app as IPA for distribution or testing", + "options": [], + "subcommands": [] + }, + { + "name": "package-xcuitest", + "path": "mobench help package-xcuitest", + "about": "Package XCUITest runner for BrowserStack testing", + "options": [], + "subcommands": [] + }, + { + "name": "plan", + "path": "mobench help plan", + "about": "Generate a sample device matrix file", + "options": [], + "subcommands": [] + }, + { + "name": "profile", + "path": "mobench help profile", + "about": "Profiling helpers for native profile capture and summary rendering", + "options": [], + "subcommands": [ + { + "name": "diff", + "path": "mobench help profile diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench help profile run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help profile summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "report", + "path": "mobench help report", + "about": "Reporting helpers for CI summaries and PR comments", + "options": [], + "subcommands": [ + { + "name": "github", + "path": "mobench help report github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench help report summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench help run", + "about": "Build mobile artifacts, write host preflight output, or run on BrowserStack devices", + "options": [], + "subcommands": [] + }, + { + "name": "summary", + "path": "mobench help summary", + "about": "Display summary statistics from a benchmark report JSON file", + "options": [], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench help verify", + "about": "Verify benchmark setup: registry, spec, artifacts, and optional smoke test", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "init", + "path": "mobench init", + "about": "Scaffold a base config file for the CLI", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [ + "bench-config.toml" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [ + "android" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "init-sdk", + "path": "mobench init-sdk", + "about": "Initialize a new benchmark project with the SDK templates", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "examples", + "long": "examples", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "EXAMPLES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Generate example benchmarks" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "." + ], + "environment": null, + "help": null + }, + { + "id": "project_name", + "long": "project-name", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_NAME" + ], + "possible_values": [], + "defaults": [ + "bench-project" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "list", + "path": "mobench list", + "about": "List all discovered benchmark functions", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "package-ipa", + "path": "mobench package-ipa", + "about": "Package iOS app as IPA for distribution or testing", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "method", + "long": "method", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "METHOD" + ], + "possible_values": [ + "adhoc", + "development" + ], + "defaults": [ + "adhoc" + ], + "environment": null, + "help": "Signing method" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "scheme", + "long": "scheme", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SCHEME" + ], + "possible_values": [], + "defaults": [ + "BenchRunner" + ], + "environment": null, + "help": "Xcode scheme to build" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "package-xcuitest", + "path": "mobench package-xcuitest", + "about": "Package XCUITest runner for BrowserStack testing", + "options": [ + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "scheme", + "long": "scheme", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SCHEME" + ], + "possible_values": [], + "defaults": [ + "BenchRunner" + ], + "environment": null, + "help": "Xcode scheme to build" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "plan", + "path": "mobench plan", + "about": "Generate a sample device matrix file", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [ + "device-matrix.yaml" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "profile", + "path": "mobench profile", + "about": "Profiling helpers for native profile capture and summary rendering", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "diff", + "path": "mobench profile diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [ + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the baseline profile.json manifest" + }, + { + "id": "candidate", + "long": "candidate", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CANDIDATE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the candidate profile.json manifest" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "normalize", + "long": "normalize", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NORMALIZE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Normalize baseline sample counts to candidate totals before diffing" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile/diff" + ], + "environment": null, + "help": "Output directory for differential profile artifacts" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench profile help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "diff", + "path": "mobench profile help diff", + "about": "Generate a differential flamegraph bundle from two normalized profile manifests", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench profile help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "run", + "path": "mobench profile help run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench profile help summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench profile run", + "about": "Plan or execute a native profiling session; local android-native and ios-instruments now attempt real native capture", + "options": [ + { + "id": "backend", + "long": "backend", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BACKEND" + ], + "possible_values": [ + "android-native", + "auto", + "ios-instruments", + "rust-tracing" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device", + "long": "device", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Explicit BrowserStack device name to resolve for this profiling request" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to device matrix YAML file used with --profile or config-based device tags" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "both", + "native", + "processed" + ], + "defaults": [ + "both" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to profile" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "os_version", + "long": "os-version", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OS_VERSION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "OS version for --device (for example `16` or `14.0`)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile" + ], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device profile/tag to resolve (for example `high-spec`)" + }, + { + "id": "provider", + "long": "provider", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROVIDER" + ], + "possible_values": [ + "browserstack", + "local" + ], + "defaults": [ + "local" + ], + "environment": null, + "help": null + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "trace_events_output", + "long": "trace-events-output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TRACE_EVENTS_OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write machine-readable trace/event JSON to this path for downstream consumers" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup_mode", + "long": "warmup-mode", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP_MODE" + ], + "possible_values": [ + "cold", + "warm" + ], + "defaults": [], + "environment": null, + "help": "Warm or cold capture mode for local native profiling (defaults to warm for local Android/iOS native backends)" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench profile summarize", + "about": "Render markdown or JSON from a normalized profile manifest", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "output_format", + "long": "output-format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_FORMAT" + ], + "possible_values": [ + "json", + "markdown" + ], + "defaults": [ + "markdown" + ], + "environment": null, + "help": null + }, + { + "id": "profile", + "long": "profile", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROFILE" + ], + "possible_values": [], + "defaults": [ + "target/mobench/profile/profile.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "report", + "path": "mobench report", + "about": "Reporting helpers for CI summaries and PR comments", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [ + { + "name": "github", + "path": "mobench report github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "marker", + "long": "marker", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "MARKER" + ], + "possible_values": [], + "defaults": [ + "" + ], + "environment": null, + "help": null + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write generated comment body to file" + }, + { + "id": "pr", + "long": "pr", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Pull request number (auto-detected from GITHUB_REF if omitted)" + }, + { + "id": "publish", + "long": "publish", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PUBLISH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Publish via GitHub API using GITHUB_TOKEN" + }, + { + "id": "summary", + "long": "summary", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SUMMARY" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci/summary.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench report help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [ + { + "name": "github", + "path": "mobench report help github", + "about": "Generate/publish sticky GitHub PR comment from summary output", + "options": [], + "subcommands": [] + }, + { + "name": "help", + "path": "mobench report help help", + "about": "Print this message or the help of the given subcommand(s)", + "options": [], + "subcommands": [] + }, + { + "name": "summarize", + "path": "mobench report help summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [], + "subcommands": [] + } + ] + }, + { + "name": "summarize", + "path": "mobench report summarize", + "about": "Generate markdown summary from standardized output JSON", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write markdown output to file" + }, + { + "id": "plots", + "long": "plots", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PLOTS" + ], + "possible_values": [ + "auto", + "off", + "require" + ], + "defaults": [ + "auto" + ], + "environment": null, + "help": null + }, + { + "id": "summary", + "long": "summary", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SUMMARY" + ], + "possible_values": [], + "defaults": [ + "target/mobench/ci/summary.json" + ], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + { + "name": "run", + "path": "mobench run", + "about": "Build mobile artifacts, write host preflight output, or run on BrowserStack devices", + "options": [ + { + "id": "android_benchmark_timeout_secs", + "long": "android-benchmark-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_BENCHMARK_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark watchdog timeout in seconds for the generated harness" + }, + { + "id": "android_heartbeat_interval_secs", + "long": "android-heartbeat-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ANDROID_HEARTBEAT_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Android benchmark heartbeat interval in seconds for the generated harness" + }, + { + "id": "baseline", + "long": "baseline", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "BASELINE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Baseline summary source (path|url|artifact:)" + }, + { + "id": "ci", + "long": "ci", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "CI" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Enable CI mode (job summary, optional JUnit, regression exit codes)" + }, + { + "id": "config", + "long": "config", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CONFIG" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional path to config file" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "device_matrix", + "long": "device-matrix", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "DEVICE_MATRIX" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device matrix YAML file to load device names from" + }, + { + "id": "device_tags", + "long": "device-tags", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICE_TAGS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device tags to select from the device matrix (comma-separated or repeatable)" + }, + { + "id": "devices", + "long": "devices", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Append", + "value_names": [ + "DEVICES" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Device identifiers or labels (BrowserStack devices)" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "fetch", + "long": "fetch", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "FETCH" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Fetch BrowserStack artifacts after the run completes" + }, + { + "id": "fetch_output_dir", + "long": "fetch-output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [ + "target/browserstack" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_poll_interval_secs", + "long": "fetch-poll-interval-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_POLL_INTERVAL_SECS" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": null + }, + { + "id": "fetch_timeout_secs", + "long": "fetch-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FETCH_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [ + "300" + ], + "environment": null, + "help": null + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Fully-qualified Rust function to benchmark" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "ios_app", + "long": "ios-app", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_APP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS app bundle (.ipa or zipped .app) for BrowserStack XCUITest" + }, + { + "id": "ios_completion_timeout_secs", + "long": "ios-completion-timeout-secs", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": true, + "action": "Set", + "value_names": [ + "IOS_COMPLETION_TIMEOUT_SECS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Deprecated compatibility flag for generated XCUITest harness timeout" + }, + { + "id": "ios_deployment_target", + "long": "ios-deployment-target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_DEPLOYMENT_TARGET" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "iOS deployment target for generated app and XCUITest targets" + }, + { + "id": "ios_runner", + "long": "ios-runner", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_RUNNER" + ], + "possible_values": [ + "swiftui", + "uikit-legacy" + ], + "defaults": [], + "environment": null, + "help": "iOS runner template (swiftui or uikit-legacy)" + }, + { + "id": "ios_test_suite", + "long": "ios-test-suite", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "IOS_TEST_SUITE" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to iOS XCUITest test suite package (.zip or .ipa)" + }, + { + "id": "iterations", + "long": "iterations", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "ITERATIONS" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "junit", + "long": "junit", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "JUNIT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Write JUnit XML report to the given path" + }, + { + "id": "local_only", + "long": "local-only", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "LOCAL_ONLY" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Skip mobile builds and write host-side preflight/spec output without mobile execution" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output", + "long": "output", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Optional output path for JSON report" + }, + { + "id": "progress", + "long": "progress", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "PROGRESS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Show simplified step-by-step progress output" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "regression_threshold_pct", + "long": "regression-threshold-pct", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REGRESSION_THRESHOLD_PCT" + ], + "possible_values": [], + "defaults": [ + "5" + ], + "environment": null, + "help": "Regression threshold percentage when comparing to baseline" + }, + { + "id": "release", + "long": "release", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "RELEASE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Build in release mode (recommended for BrowserStack to reduce APK size and upload time)" + }, + { + "id": "summary_csv", + "long": "summary-csv", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "SUMMARY_CSV" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Write CSV summary alongside JSON" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "ios" + ], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "warmup", + "long": "warmup", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "WARMUP" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": null + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "summary", + "path": "mobench summary", + "about": "Display summary statistics from a benchmark report JSON file", + "options": [ + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "format", + "long": "format", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FORMAT" + ], + "possible_values": [ + "csv", + "json", + "text" + ], + "defaults": [], + "environment": null, + "help": "Output format: text (default), json, or csv" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "report", + "long": null, + "short": null, + "positional_index": 1, + "required": true, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "REPORT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark report JSON file" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + }, + { + "name": "verify", + "path": "mobench verify", + "about": "Verify benchmark setup: registry, spec, artifacts, and optional smoke test", + "options": [ + { + "id": "check_artifacts", + "long": "check-artifacts", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "CHECK_ARTIFACTS" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Check that build artifacts exist" + }, + { + "id": "crate_path", + "long": "crate-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "CRATE_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to the benchmark crate directory containing Cargo.toml" + }, + { + "id": "dry_run", + "long": "dry-run", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "DRY_RUN" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print what would be done without actually doing it" + }, + { + "id": "function", + "long": "function", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "FUNCTION" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Function name to verify/smoke test" + }, + { + "id": "help", + "long": "help", + "short": "h", + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Help", + "value_names": [], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Print help (see more with '--help')" + }, + { + "id": "non_interactive", + "long": "non-interactive", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "NON_INTERACTIVE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Disable interactive prompts (fail instead)" + }, + { + "id": "output_dir", + "long": "output-dir", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "OUTPUT_DIR" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Output directory for mobile artifacts (default: target/mobench)" + }, + { + "id": "project_root", + "long": "project-root", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "PROJECT_ROOT" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Project root containing mobench.toml or the Cargo workspace" + }, + { + "id": "smoke_test", + "long": "smoke-test", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "SMOKE_TEST" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Run a local smoke test with minimal iterations" + }, + { + "id": "spec_path", + "long": "spec-path", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "SPEC_PATH" + ], + "possible_values": [], + "defaults": [], + "environment": null, + "help": "Path to bench_spec.json to validate" + }, + { + "id": "target", + "long": "target", + "short": null, + "positional_index": null, + "required": false, + "global": false, + "hidden": false, + "action": "Set", + "value_names": [ + "TARGET" + ], + "possible_values": [ + "android", + "both", + "ios" + ], + "defaults": [], + "environment": null, + "help": "Target platform to verify artifacts for" + }, + { + "id": "verbose", + "long": "verbose", + "short": "v", + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "VERBOSE" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Print verbose output including all commands" + }, + { + "id": "yes", + "long": "yes", + "short": null, + "positional_index": null, + "required": false, + "global": true, + "hidden": false, + "action": "SetTrue", + "value_names": [ + "YES" + ], + "possible_values": [ + "false", + "true" + ], + "defaults": [ + "false" + ], + "environment": null, + "help": "Assume yes to prompts and allow overwriting files" + } + ], + "subcommands": [] + } + ] + }, + "config": [ + { + "file": "mobench.toml", + "keys": [ + { + "path": "project.crate", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "project.library_name", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "project.output_dir", + "value_type": "path|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.package", + "value_type": "string", + "required": false, + "default": "dev.world.bench", + "evidence_id": "source-mobench-config" + }, + { + "path": "android.min_sdk", + "value_type": "integer", + "required": false, + "default": 24, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.target_sdk", + "value_type": "integer", + "required": false, + "default": 34, + "evidence_id": "source-mobench-config" + }, + { + "path": "android.abis", + "value_type": "string[]|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.bundle_id", + "value_type": "string", + "required": false, + "default": "dev.world.bench", + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.deployment_target", + "value_type": "string", + "required": false, + "default": "15.0", + "evidence_id": "source-mobench-config" + }, + { + "path": "ios.team_id", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_function", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_iterations", + "value_type": "integer", + "required": false, + "default": 100, + "evidence_id": "source-mobench-config" + }, + { + "path": "benchmarks.default_warmup", + "value_type": "integer", + "required": false, + "default": 10, + "evidence_id": "source-mobench-config" + }, + { + "path": "browserstack.ios_completion_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-mobench-config" + } + ] + }, + { + "file": "bench-config.toml", + "keys": [ + { + "path": "target", + "value_type": "android|ios", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "function", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "iterations", + "value_type": "integer", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "warmup", + "value_type": "integer", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "device_matrix", + "value_type": "path", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "device_tags", + "value_type": "string[]|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.app_automate_username", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.app_automate_access_key", + "value_type": "string", + "required": true, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.project", + "value_type": "string|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.ios_completion_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.android_benchmark_timeout_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "browserstack.android_heartbeat_interval_secs", + "value_type": "integer|null", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "ios_xcuitest.app", + "value_type": "path", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + }, + { + "path": "ios_xcuitest.test_suite", + "value_type": "path", + "required": false, + "default": null, + "evidence_id": "source-bench-config" + } + ] + } + ], + "artifacts": [ + { + "id": "benchmark-spec", + "path_pattern": "target/mobench/{android|ios}/**/bench_spec.json", + "produced_by": [ + "mobench run", + "mobench build" + ], + "description": "Resolved benchmark request embedded in generated runners.", + "evidence_id": "source-run-artifacts" + }, + { + "id": "benchmark-metadata", + "path_pattern": "target/mobench/{android|ios}/**/bench_meta.json", + "produced_by": [ + "mobench run", + "mobench build" + ], + "description": "Build metadata embedded beside the benchmark spec.", + "evidence_id": "source-run-artifacts" + }, + { + "id": "android-app", + "path_pattern": "target/mobench/android/app/build/outputs/apk/{debug|release}/*.apk", + "produced_by": [ + "mobench build", + "mobench run" + ], + "description": "Generated Android app and instrumentation packages.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-framework", + "path_pattern": "target/mobench/ios/.xcframework", + "produced_by": [ + "mobench build", + "mobench run" + ], + "description": "Generated iOS xcframework.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-app", + "path_pattern": "target/mobench/ios/BenchRunner.ipa", + "produced_by": [ + "mobench package-ipa", + "mobench run" + ], + "description": "Packaged iOS benchmark application.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ios-test-suite", + "path_pattern": "target/mobench/ios/BenchRunnerUITests.zip", + "produced_by": [ + "mobench package-xcuitest", + "mobench run" + ], + "description": "Packaged XCUITest suite for BrowserStack.", + "evidence_id": "source-build-artifacts" + }, + { + "id": "ci-summary-json", + "path_pattern": "/summary.json", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Machine-readable benchmark summary.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "ci-summary-markdown", + "path_pattern": "/summary.md", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Human-readable benchmark summary.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "ci-results-csv", + "path_pattern": "/results.csv", + "produced_by": [ + "mobench ci run", + "mobench ci merge-split-runs" + ], + "description": "Tabular benchmark results.", + "evidence_id": "test-ci-artifacts" + }, + { + "id": "profile-manifest", + "path_pattern": "//profile.json", + "produced_by": [ + "mobench profile run" + ], + "description": "Normalized profile manifest, plus a latest convenience copy.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-summary", + "path_pattern": "//summary.md", + "produced_by": [ + "mobench profile run" + ], + "description": "Profile summary, plus a latest convenience copy.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-folded-stacks", + "path_pattern": "//artifacts/processed/stacks.folded", + "produced_by": [ + "mobench profile run" + ], + "description": "Processed native stack samples when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-native-report", + "path_pattern": "//artifacts/processed/native-report.txt", + "produced_by": [ + "mobench profile run" + ], + "description": "Symbolized native profiler report when available.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-flamegraphs", + "path_pattern": "//artifacts/processed/flamegraph.{full|focused}.svg", + "produced_by": [ + "mobench profile run" + ], + "description": "Full and benchmark-focused flamegraph SVGs when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "profile-viewer", + "path_pattern": "//artifacts/processed/flamegraph.html", + "produced_by": [ + "mobench profile run" + ], + "description": "Standalone profile viewer when capture succeeds.", + "evidence_id": "test-profile-artifacts" + }, + { + "id": "trace-events", + "path_pattern": "", + "produced_by": [ + "mobench profile run" + ], + "description": "Machine-readable structured trace-event contract.", + "evidence_id": "test-trace-events" + } + ], + "schemas": [ + { + "id": "summary-v1", + "path": "docs/schemas/summary-v1.schema.json", + "checksum_sha256": "dd67ff6dbf57e06acd3516b1f41f1b76654baf351a2a2fbc9ade2db1406a70fc" + }, + { + "id": "ci-contract-v1", + "path": "docs/schemas/ci-contract-v1.schema.json", + "checksum_sha256": "eff1ddfc6800a6a990cd85a3bf02feb03e0c71aac9ea64cd499e41790703e962" + }, + { + "id": "trace-events-v1", + "path": "docs/schemas/trace-events-v1.schema.json", + "checksum_sha256": "da8309604422fa31f653be40c0fafdcbc5dfbc8c001da78fc5f7e185f7c861ac" + }, + { + "id": "mobench-site-manifest-v1", + "path": "docs/schemas/mobench-site-manifest-v1.schema.json", + "checksum_sha256": "84bd1985e3a0025d56df39392a08f8f52631676b6ecc0173990d12be8828bb27" + } + ], + "capabilities": [ + { + "id": "benchmark.build.android", + "status": "supported", + "summary": "Build generated Android benchmark artifacts.", + "evidence_ids": [ + "source-build-artifacts" + ] + }, + { + "id": "benchmark.build.ios", + "status": "supported", + "summary": "Build generated iOS benchmark artifacts.", + "evidence_ids": [ + "source-build-artifacts" + ] + }, + { + "id": "benchmark.execute.browserstack.android", + "status": "supported", + "summary": "Execute Android benchmarks through BrowserStack App Automate when devices and credentials are provided.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.browserstack.ios", + "status": "supported", + "summary": "Execute iOS benchmarks through BrowserStack XCUITest when devices, credentials, and packages are provided.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.local-only", + "status": "unsupported", + "summary": "`--local-only` writes preflight/spec outputs but skips the mobile build and does not execute the requested benchmark in v0.1.43.", + "evidence_ids": [ + "source-local-only" + ] + }, + { + "id": "benchmark.execute.attached-device", + "status": "unsupported", + "summary": "Ordinary `mobench run` does not execute on an attached phone in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.android-emulator", + "status": "unsupported", + "summary": "Ordinary `mobench run` has no Android emulator execution provider in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.execute.ios-simulator", + "status": "unsupported", + "summary": "Ordinary `mobench run` has no iOS simulator execution provider in v0.1.43.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "benchmark.build-without-devices", + "status": "supported", + "summary": "With no BrowserStack devices, `mobench run` builds artifacts and skips upload/execution.", + "evidence_ids": [ + "source-browserstack-run" + ] + }, + { + "id": "profile.local.android-native", + "status": "supported", + "summary": "Attempt local Android simpleperf capture, symbolization, and flamegraph generation when required tools and a device are available.", + "evidence_ids": [ + "source-android-profile", + "test-android-profile" + ] + }, + { + "id": "profile.local.ios-instruments", + "status": "supported", + "summary": "Attempt local iOS simulator-host sample capture and flamegraph generation when required tools are available.", + "evidence_ids": [ + "source-ios-profile", + "test-ios-profile" + ] + }, + { + "id": "profile.local.rust-tracing", + "status": "planned", + "summary": "The manifest/trace contract exists, but local rust-tracing capture is not implemented.", + "evidence_ids": [ + "source-rust-tracing" + ] + }, + { + "id": "profile.browserstack.android-native", + "status": "unsupported", + "summary": "BrowserStack native Android stack capture is not implemented.", + "evidence_ids": [ + "test-browserstack-profile" + ] + }, + { + "id": "profile.browserstack.ios-instruments", + "status": "unsupported", + "summary": "BrowserStack native iOS Instruments capture is not implemented.", + "evidence_ids": [ + "test-browserstack-profile" + ] + }, + { + "id": "profile.browserstack.rust-tracing", + "status": "unsupported", + "summary": "BrowserStack rust-tracing capture is not implemented.", + "evidence_ids": [ + "source-rust-tracing" + ] + } + ], + "evidence": [ + { + "id": "source-mobench-config", + "kind": "source", + "reference": "crates/mobench/src/config.rs#MobenchConfig" + }, + { + "id": "source-bench-config", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#BenchConfig" + }, + { + "id": "source-run-artifacts", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#persist_mobile_spec" + }, + { + "id": "source-build-artifacts", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#cmd_build" + }, + { + "id": "source-browserstack-run", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#run_from" + }, + { + "id": "source-local-only", + "kind": "source", + "reference": "crates/mobench/src/lib.rs#run_from:local_only" + }, + { + "id": "source-android-profile", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_local_android_capture" + }, + { + "id": "source-ios-profile", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_local_ios_capture" + }, + { + "id": "source-rust-tracing", + "kind": "source", + "reference": "crates/mobench/src/profile.rs#execute_capture" + }, + { + "id": "test-ci-artifacts", + "kind": "test", + "reference": "crates/mobench/src/split_runs.rs#merge_split_run_summaries" + }, + { + "id": "test-profile-artifacts", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#profile_run_writes_run_scoped_and_latest_manifest_files" + }, + { + "id": "test-trace-events", + "kind": "test", + "reference": "crates/mobench/tests/profile_cli.rs#profile_run_dry_run_writes_trace_events_output_for_downstream_consumers" + }, + { + "id": "test-android-profile", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#android_backend_builds_capture_plan_with_flamegraph_artifacts" + }, + { + "id": "test-ios-profile", + "kind": "test", + "reference": "crates/mobench/src/profile.rs#ios_backend_allocates_sample_and_flamegraph_artifacts" + }, + { + "id": "test-browserstack-profile", + "kind": "test", + "reference": "crates/mobench/tests/profile_cli.rs#browserstack_profile_run_reports_unsupported_native_capture" + }, + { + "id": "test-cargo-wrapper", + "kind": "test", + "reference": "crates/mobench/tests/invocation_cli.rs#cargo_mobench_invocation_works_through_cargo" + } + ] +} diff --git a/packages/truth/package.json b/packages/truth/package.json new file mode 100644 index 0000000..a82ae3c --- /dev/null +++ b/packages/truth/package.json @@ -0,0 +1,12 @@ +{ + "name": "@mobench/truth", + "version": "0.1.43", + "private": true, + "type": "module", + "exports": { + "./manifest": "./mobench-site-manifest-v1.json", + "./pin": "./pin.json", + "./fixtures/basic": "./fixtures/summary-basic.json", + "./fixtures/ffi": "./fixtures/summary-ffi.json" + } +} diff --git a/packages/truth/pin.json b/packages/truth/pin.json new file mode 100644 index 0000000..b4b084b --- /dev/null +++ b/packages/truth/pin.json @@ -0,0 +1,10 @@ +{ + "schemaVersion": 1, + "repository": "https://github.com/worldcoin/mobile-bench-rs", + "release": "v0.1.43", + "version": "0.1.43", + "commitSha": "d1a3176f9144f35e777e83fd07045116144da257", + "manifestSha256": "b2de1cc240f21e7bde6f6386ac8d7aaee1ef2710b2bbf26c5e2d7fde95e561f5", + "syncedAt": "2026-07-15", + "buildPolicy": "offline-pinned" +} diff --git a/packages/truth/schemas/ci-contract-v1.schema.json b/packages/truth/schemas/ci-contract-v1.schema.json new file mode 100644 index 0000000..6d1d5a4 --- /dev/null +++ b/packages/truth/schemas/ci-contract-v1.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/ci-contract-v1.schema.json", + "title": "Mobench CI Contract v1", + "type": "object", + "required": ["ci"], + "properties": { + "ci": { + "type": "object", + "required": ["metadata", "outputs"], + "properties": { + "metadata": { + "type": "object", + "required": ["requested_by", "request_command", "mobench_version"], + "properties": { + "requested_by": { "type": "string" }, + "pr_number": { "type": ["string", "null"] }, + "request_command": { "type": "string" }, + "mobench_ref": { "type": ["string", "null"] }, + "mobench_version": { "type": "string" } + } + }, + "outputs": { + "type": "object", + "required": ["summary_json", "summary_md", "results_csv"], + "properties": { + "summary_json": { "type": "string" }, + "summary_md": { "type": "string" }, + "results_csv": { "type": "string" } + } + } + } + } + }, + "additionalProperties": true +} diff --git a/packages/truth/schemas/mobench-site-manifest-v1.schema.json b/packages/truth/schemas/mobench-site-manifest-v1.schema.json new file mode 100644 index 0000000..74adf44 --- /dev/null +++ b/packages/truth/schemas/mobench-site-manifest-v1.schema.json @@ -0,0 +1,152 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://mobench.org/schemas/mobench-site-manifest-v1.schema.json", + "title": "Mobench website release manifest v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "release", + "msrv", + "binaries", + "command_tree", + "config", + "artifacts", + "schemas", + "capabilities", + "evidence" + ], + "properties": { + "schema_version": { "const": 1 }, + "release": { + "type": "object", + "additionalProperties": false, + "required": ["version", "tag", "sha", "repository"], + "properties": { + "version": { "type": "string", "minLength": 1 }, + "tag": { "type": "string", "pattern": "^v" }, + "sha": { "type": "string", "pattern": "^[0-9a-fA-F]{40}$" }, + "repository": { "type": "string", "format": "uri" } + } + }, + "msrv": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+" }, + "binaries": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/binary" } }, + "command_tree": { "$ref": "#/$defs/command" }, + "config": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/config" } }, + "artifacts": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/artifact" } }, + "schemas": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/schema" } }, + "capabilities": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/capability" } }, + "evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/evidence" } } + }, + "$defs": { + "status": { "enum": ["supported", "preview", "planned", "unsupported"] }, + "binary": { + "type": "object", + "additionalProperties": false, + "required": ["name", "invocation", "canonical_for_release", "status", "note"], + "properties": { + "name": { "type": "string" }, + "invocation": { "type": "string" }, + "canonical_for_release": { "type": "boolean" }, + "status": { "$ref": "#/$defs/status" }, + "note": { "type": "string" } + } + }, + "command": { + "type": "object", + "additionalProperties": false, + "required": ["name", "path", "about", "options", "subcommands"], + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "about": { "type": ["string", "null"] }, + "options": { "type": "array", "items": { "$ref": "#/$defs/option" } }, + "subcommands": { "type": "array", "items": { "$ref": "#/$defs/command" } } + } + }, + "option": { + "type": "object", + "additionalProperties": false, + "required": ["id", "long", "short", "positional_index", "required", "global", "hidden", "action", "value_names", "possible_values", "defaults", "environment", "help"], + "properties": { + "id": { "type": "string" }, + "long": { "type": ["string", "null"] }, + "short": { "type": ["string", "null"], "maxLength": 1 }, + "positional_index": { "type": ["integer", "null"], "minimum": 1 }, + "required": { "type": "boolean" }, + "global": { "type": "boolean" }, + "hidden": { "type": "boolean" }, + "action": { "type": "string" }, + "value_names": { "type": "array", "items": { "type": "string" } }, + "possible_values": { "type": "array", "items": { "type": "string" } }, + "defaults": { "type": "array", "items": { "type": "string" } }, + "environment": { "type": ["string", "null"] }, + "help": { "type": ["string", "null"] } + } + }, + "config": { + "type": "object", + "additionalProperties": false, + "required": ["file", "keys"], + "properties": { + "file": { "type": "string" }, + "keys": { "type": "array", "items": { "$ref": "#/$defs/configKey" } } + } + }, + "configKey": { + "type": "object", + "additionalProperties": false, + "required": ["path", "value_type", "required", "default", "evidence_id"], + "properties": { + "path": { "type": "string" }, + "value_type": { "type": "string" }, + "required": { "type": "boolean" }, + "default": {}, + "evidence_id": { "type": "string" } + } + }, + "artifact": { + "type": "object", + "additionalProperties": false, + "required": ["id", "path_pattern", "produced_by", "description", "evidence_id"], + "properties": { + "id": { "type": "string" }, + "path_pattern": { "type": "string" }, + "produced_by": { "type": "array", "items": { "type": "string" } }, + "description": { "type": "string" }, + "evidence_id": { "type": "string" } + } + }, + "schema": { + "type": "object", + "additionalProperties": false, + "required": ["id", "path", "checksum_sha256"], + "properties": { + "id": { "type": "string" }, + "path": { "type": "string" }, + "checksum_sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" } + } + }, + "capability": { + "type": "object", + "additionalProperties": false, + "required": ["id", "status", "summary", "evidence_ids"], + "properties": { + "id": { "type": "string" }, + "status": { "$ref": "#/$defs/status" }, + "summary": { "type": "string" }, + "evidence_ids": { "type": "array", "minItems": 1, "items": { "type": "string" } } + } + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": ["id", "kind", "reference"], + "properties": { + "id": { "type": "string" }, + "kind": { "enum": ["source", "test"] }, + "reference": { "type": "string" } + } + } + } +} diff --git a/packages/truth/schemas/summary-v1.schema.json b/packages/truth/schemas/summary-v1.schema.json new file mode 100644 index 0000000..9f452ae --- /dev/null +++ b/packages/truth/schemas/summary-v1.schema.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/summary-v1.schema.json", + "title": "Mobench Summary v1", + "type": "object", + "required": ["summary"], + "properties": { + "summary": { + "type": "object", + "required": [ + "generated_at", + "generated_at_unix", + "target", + "function", + "iterations", + "warmup", + "devices", + "device_summaries" + ], + "properties": { + "generated_at": { "type": "string" }, + "generated_at_unix": { "type": "integer" }, + "target": { "type": "string", "enum": ["android", "ios"] }, + "function": { "type": "string" }, + "iterations": { "type": "integer" }, + "warmup": { "type": "integer" }, + "devices": { + "type": "array", + "items": { "type": "string" } + }, + "device_summaries": { + "type": "array", + "items": { + "type": "object", + "required": ["device", "benchmarks"], + "properties": { + "device": { "type": "string" }, + "benchmarks": { + "type": "array", + "items": { + "type": "object", + "required": ["function", "samples"], + "properties": { + "function": { "type": "string" }, + "samples": { "type": "integer" }, + "mean_ns": { "type": ["integer", "null"] }, + "median_ns": { "type": ["integer", "null"] }, + "p95_ns": { "type": ["integer", "null"] }, + "min_ns": { "type": ["integer", "null"] }, + "max_ns": { "type": ["integer", "null"] }, + "resource_usage": { + "type": ["object", "null"], + "properties": { + "cpu_total_ms": { "type": ["integer", "null"] }, + "cpu_median_ms": { "type": ["integer", "null"] }, + "peak_memory_kb": { "type": ["integer", "null"] }, + "peak_memory_growth_kb": { "type": ["integer", "null"] }, + "process_peak_memory_kb": { "type": ["integer", "null"] }, + "total_pss_kb": { "type": ["integer", "null"] }, + "private_dirty_kb": { "type": ["integer", "null"] }, + "native_heap_kb": { "type": ["integer", "null"] }, + "java_heap_kb": { "type": ["integer", "null"] } + } + } + } + } + } + } + } + } + } + } + }, + "additionalProperties": true +} diff --git a/packages/truth/schemas/trace-events-v1.schema.json b/packages/truth/schemas/trace-events-v1.schema.json new file mode 100644 index 0000000..73e866e --- /dev/null +++ b/packages/truth/schemas/trace-events-v1.schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://world.org/mobench/schemas/trace-events-v1.schema.json", + "title": "Mobench Trace Events v1", + "type": "object", + "required": ["source", "total_duration_ns", "lanes"], + "properties": { + "source": { + "type": "object", + "required": ["kind", "profiler", "origin"], + "properties": { + "kind": { "type": "string" }, + "profiler": { "type": "string" }, + "origin": { "type": "string", "enum": ["local", "browserstack"] } + }, + "additionalProperties": false + }, + "total_duration_ns": { "type": "integer", "minimum": 0 }, + "lanes": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "label", "events"], + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "events": { + "type": "array", + "items": { + "type": "object", + "required": [ + "event_kind", + "start_offset_ns", + "end_offset_ns", + "frames", + "phase", + "iteration" + ], + "properties": { + "event_kind": { "type": "string" }, + "start_offset_ns": { "type": "integer", "minimum": 0 }, + "end_offset_ns": { "type": ["integer", "null"], "minimum": 0 }, + "frames": { + "type": "array", + "items": { "type": "string" } + }, + "phase": { "type": ["string", "null"] }, + "iteration": { "type": ["integer", "null"], "minimum": 0 } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false +} diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..eb0ca52 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,36 @@ +import { defineConfig } from '@playwright/test' + +export default defineConfig({ + testDir: './tests/e2e', + timeout: 30_000, + fullyParallel: false, + forbidOnly: true, + retries: 0, + reporter: [['list']], + snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}', + expect: { + timeout: 8_000, + // Chromium text rasterization differs between macOS review captures and Linux CI. + // Keep the budget below the size of a meaningful component or layout regression. + toHaveScreenshot: { maxDiffPixelRatio: 0.06 }, + }, + use: { + browserName: 'chromium', + trace: 'retain-on-failure', + screenshot: 'only-on-failure', + }, + webServer: [ + { + command: 'bun run --cwd apps/marketing preview --host 127.0.0.1', + url: 'http://127.0.0.1:3000', + reuseExistingServer: true, + timeout: 30_000, + }, + { + command: 'bun run --cwd apps/docs preview --host 127.0.0.1', + url: 'http://127.0.0.1:3001', + reuseExistingServer: true, + timeout: 30_000, + }, + ], +}) diff --git a/scripts/generate-content.ts b/scripts/generate-content.ts new file mode 100644 index 0000000..b548a45 --- /dev/null +++ b/scripts/generate-content.ts @@ -0,0 +1,378 @@ +import { parse as parseYaml } from 'yaml' +import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises' +import { dirname, join, relative, resolve } from 'node:path' + +const root = resolve(import.meta.dir, '..') +const docsRoot = join(root, 'apps/docs/src/content/docs') +const docsPublic = join(root, 'apps/docs/public') +const marketingPublic = join(root, 'apps/marketing/public') +const truthRoot = join(root, 'packages/truth') +const checkOnly = process.argv.includes('--check') + +type Frontmatter = { + slug: string + title: string + description: string + section?: string + order?: number + release?: string | number + draft?: boolean + aliases?: string[] + sourceRefs?: Array<{ label: string; url: string; evidence?: string }> +} +type Page = Frontmatter & { route: string; authoringRoute: string; body: string; file: string } + +type Redirect = { source: string; destination: string; permanent: true } + +type ManifestOption = { + id: string + long: string | null + short: string | null + positional_index: number | null + required: boolean + global: boolean + hidden: boolean + action: string + value_names: string[] + possible_values: string[] + defaults: string[] + environment: string | null + help: string | null +} +type ManifestCommand = { + name: string + path: string + about: string | null + options: ManifestOption[] + subcommands: ManifestCommand[] +} +type Manifest = { + release: { version: string; tag: string; sha: string; repository: string } + command_tree: ManifestCommand + config: Array<{ + file: string + keys: Array<{ path: string; value_type: string; required: boolean; default: unknown; evidence_id: string }> + }> + binaries: Array<{ name: string; canonical_for_release: boolean; status: string; note: string }> +} +type Pin = { version: string; release: string; commitSha: string } + +const legacyAliases = new Map([ + ['/home/', '/'], + ['/diagrams/', '/device-matrices/'], +]) + +async function filesUnder(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }) + return (await Promise.all(entries.map(async (entry) => { + const path = join(directory, entry.name) + return entry.isDirectory() ? filesUnder(path) : [path] + }))).flat().sort() +} + +async function loadPages(): Promise { + const pages: Page[] = [] + for (const file of (await filesUnder(docsRoot)).filter((path) => /\.mdx?$/.test(path))) { + const source = await readFile(file, 'utf8') + const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(source) + if (!match) throw new Error(`${file} has no frontmatter`) + const data = parseYaml(match[1]) as Frontmatter + if (data.draft) continue + const route = data.slug === 'index' ? '/' : `/${data.slug}/` + const authoredSlug = relative(docsRoot, file).replaceAll('\\', '/').replace(/\.mdx?$/, '') + const authoringRoute = authoredSlug === 'index' ? '/' : `/${authoredSlug.replace(/\/index$/, '')}/` + pages.push({ ...data, file, route, authoringRoute, body: source.slice(match[0].length).trim() }) + } + return pages.sort((a, b) => (a.section ?? '').localeCompare(b.section ?? '') || (a.order ?? 999) - (b.order ?? 999) || a.title.localeCompare(b.title)) +} + +function normalizeRoute(pathname: string) { + return pathname === '/' ? '/' : `/${pathname.replace(/^\/+|\/+$/g, '')}/` +} + +function markdownCell(value: unknown) { + if (value === null || value === undefined || value === '') return '—' + const rendered = typeof value === 'string' ? value : JSON.stringify(value) + return rendered + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('{', '{') + .replaceAll('}', '}') + .replaceAll('|', '\\|') + .replaceAll('\n', ' ') +} + +function commandRows(rootCommand: ManifestCommand) { + const rows: ManifestCommand[] = [] + const visit = (command: ManifestCommand) => { + if (command.path !== rootCommand.path && !command.path.split(' ').includes('help')) rows.push(command) + for (const subcommand of command.subcommands) visit(subcommand) + } + visit(rootCommand) + return rows +} + +function flagLabel(option: ManifestOption) { + const names = [option.short ? `\`-${option.short}\`` : '', option.long ? `\`--${option.long}\`` : ''].filter(Boolean) + if (names.length) return names.join(', ') + return `\`<${option.value_names[0] ?? option.id}>\`` +} + +function valueContract(option: ManifestOption) { + if (option.action === 'SetTrue' || option.action === 'SetFalse') return 'boolean' + const values = option.possible_values.length ? option.possible_values.join(' | ') : option.value_names.join(', ') + return values ? `\`${values.replaceAll('|', '\\|')}\`` : 'boolean' +} + +function generatedCliReference(manifest: Manifest) { + const commands = commandRows(manifest.command_tree) + const globalOptions = manifest.command_tree.options.filter((option) => !option.hidden && option.long !== 'help' && option.long !== 'version') + const localOptions = new Map(commands.map((command) => [ + command.path, + command.options.filter((option) => !option.hidden && !option.global && option.long !== 'help'), + ])) + return [ + '{/* BEGIN GENERATED CLI REFERENCE */}', + '{/* Generated from @mobench/truth. Do not edit this section by hand. */}', + '', + '## Global flags', + '', + '| Flag | Value | Default | Purpose |', + '| --- | --- | --- | --- |', + ...globalOptions.map((option) => `| ${flagLabel(option)} | ${valueContract(option)} | ${markdownCell(option.defaults.join(', '))} | ${markdownCell(option.help)} |`), + '', + 'The generated CLI also provides `--help`, `-h`, `--version`, and `-V` where Clap exposes them.', + '', + '## Command index', + '', + '| Command | Purpose |', + '| --- | --- |', + ...commands.map((command) => `| \`${command.path}\` | ${markdownCell(command.about)} |`), + '', + '## Complete command flag index', + '', + 'Global flags above are omitted from each command row. Positional arguments use angle brackets.', + '', + ...commands.flatMap((command) => { + const options = localOptions.get(command.path) ?? [] + if (!options.length) return [] + return [ + `### \`${command.path}\``, + '', + '| Flag or argument | Value | Requirement | Purpose |', + '| --- | --- | --- | --- |', + ...options.map((option) => { + const requirement = option.required + ? 'required' + : option.defaults.length + ? `default: ${markdownCell(option.defaults.join(', '))}` + : 'optional' + return `| ${flagLabel(option)} | ${valueContract(option)} | ${requirement} | ${markdownCell(option.help)} |` + }), + '', + ] + }), + '', + '{/* END GENERATED CLI REFERENCE */}', + ].join('\n') +} + +function generatedConfigReference(manifest: Manifest) { + const lines = [ + '{/* BEGIN GENERATED CONFIG REFERENCE */}', + '{/* Generated from @mobench/truth. Do not edit this section by hand. */}', + '', + '## Published configuration keys', + '', + 'These are the complete configuration keys in the pinned release contract. Example files below may use only a task-specific subset.', + '', + ] + for (const config of manifest.config) { + lines.push( + `### \`${config.file}\``, + '', + '| Key | Value | Required | Default | Evidence |', + '| --- | --- | --- | --- | --- |', + ...config.keys.map((key) => `| \`${key.path}\` | \`${key.value_type}\` | ${key.required ? 'yes' : 'no'} | ${markdownCell(key.default)} | \`${key.evidence_id}\` |`), + '', + ) + } + lines.push('{/* END GENERATED CONFIG REFERENCE */}') + return lines.join('\n') +} + +async function syncGeneratedSection(path: string, label: string, generated: string) { + const source = await readFile(path, 'utf8') + const pattern = new RegExp(`\\{\\/\\* BEGIN GENERATED ${label} \\*\\/\\}[\\s\\S]*?\\{\\/\\* END GENERATED ${label} \\*\\/\\}`) + if (!pattern.test(source)) throw new Error(`${relative(root, path)} is missing the generated ${label.toLowerCase()} markers`) + await emit(path, source.replace(pattern, generated)) +} + +function vercelSource(route: string) { + return route === '/' ? '/' : route.replace(/\/$/, '') +} + +function routeAliases(pages: Page[]) { + const aliases = new Map(legacyAliases) + for (const page of pages) { + if (page.authoringRoute !== page.route) aliases.set(page.authoringRoute, page.route) + for (const alias of page.aliases ?? []) aliases.set(normalizeRoute(alias), page.route) + } + return aliases +} + +function redirectsForDocs(pages: Page[]): Redirect[] { + return [...routeAliases(pages)] + .filter(([source, destination]) => source !== destination) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([source, destination]) => ({ + source: vercelSource(source), + destination, + permanent: true as const, + })) +} + +function redirectsForMarketing(pages: Page[]): Redirect[] { + const redirects = new Map() + redirects.set('/docs/:path*', 'https://docs.mobench.org/:path*') + for (const page of pages) { + if (page.route !== '/') redirects.set(vercelSource(page.route), `https://docs.mobench.org${page.route}`) + } + for (const [source, destination] of routeAliases(pages)) { + redirects.set(vercelSource(source), `https://docs.mobench.org${destination}`) + } + return [...redirects] + .sort(([left], [right]) => left.localeCompare(right)) + .map(([source, destination]) => ({ source, destination, permanent: true as const })) +} + +function vercelConfig(surface: 'marketing' | 'docs', redirects: Redirect[]) { + return { + $schema: 'https://openapi.vercel.sh/vercel.json', + framework: 'astro', + installCommand: 'cd ../.. && bun install --frozen-lockfile', + buildCommand: `cd ../.. && bun run generate && bun run build:${surface}`, + outputDirectory: 'dist', + redirects, + headers: [{ + source: '/(.*)', + headers: [ + { key: 'X-Content-Type-Options', value: 'nosniff' }, + { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }, + { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }, + ], + }], + } +} + +function renderIndex(pages: Page[], manifest: Manifest, pin: Pin) { + const canonicalBinary = manifest.binaries.find((binary) => binary.canonical_for_release) + const cargoWrapper = manifest.binaries.find((binary) => binary.name === 'cargo-mobench') + const lines = [ + '# mobench', + '', + `> Source-backed documentation for mobench ${pin.version}: build Android and iOS runners, execute ordinary benchmarks on BrowserStack devices, and analyze stable reports or supported local native profiles.`, + '', + 'Canonical documentation: https://docs.mobench.org/', + `Source: ${manifest.release.repository}/tree/${pin.release}`, + `Pinned release SHA: ${pin.commitSha}`, + '', + '## Capability boundary', + '', + `- Use the \`${canonicalBinary?.name ?? 'mobench'}\` executable for release ${pin.version}.${cargoWrapper?.status === 'unsupported' ? ' The published `cargo mobench` wrapper is unsupported.' : ''}`, + '- Ordinary mobile benchmarks execute through BrowserStack when devices are selected.', + '- `--local-only` is host preflight and does not measure Android or iOS execution.', + '- Local native profiling has a separate Android simpleperf and iOS simulator-host capability matrix.', + '- The release does not define an energy or battery measurement contract.', + '', + '## Documentation', + '', + ] + for (const page of pages) { + lines.push(`- [${page.title}](https://docs.mobench.org${page.route}): ${page.description}`) + } + lines.push( + '', + '## Stable command entry points', + '', + '```bash', + `cargo install mobench --version ${pin.version}`, + 'mobench list --crate-path bench-mobile', + 'mobench run --target android --function bench_mobile::checksum --local-only --output target/mobench/preflight.json', + 'mobench run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output target/mobench/results.json', + 'mobench ci run --target android --function bench_mobile::checksum --devices "Google Pixel 7-13.0" --release --fetch --output-dir target/mobench/ci', + 'mobench profile run --target android --provider local --backend android-native --function bench_mobile::checksum --output-dir target/mobench/profile', + '```', + '', + 'Full authored documentation: https://docs.mobench.org/llms-full.txt', + '', + ) + return lines.join('\n') +} + +function renderFull(pages: Page[], pin: Pin) { + return [ + '# mobench documentation — full authored text', + '', + `Release: ${pin.version}`, + 'Canonical origin: https://docs.mobench.org/', + '', + ...pages.flatMap((page) => [ + `# ${page.title}`, + '', + `Canonical URL: https://docs.mobench.org${page.route}`, + `Description: ${page.description}`, + ...(page.sourceRefs ?? []).map((source) => `Source: ${source.label} — ${source.url}${source.evidence ? ` — ${source.evidence}` : ''}`), + '', + page.body, + '', + ]), + ].join('\n') +} + +async function emit(path: string, content: string) { + const normalized = content.endsWith('\n') ? content : `${content}\n` + if (checkOnly) { + let existing = '' + try { existing = await readFile(path, 'utf8') } catch {} + if (existing !== normalized) throw new Error(`${relative(root, path)} is stale; run bun run generate`) + return + } + await mkdir(dirname(path), { recursive: true }) + await writeFile(path, normalized) +} + +const manifest = JSON.parse(await readFile(join(truthRoot, 'mobench-site-manifest-v1.json'), 'utf8')) as Manifest +const pin = JSON.parse(await readFile(join(truthRoot, 'pin.json'), 'utf8')) as Pin +await syncGeneratedSection( + join(docsRoot, 'reference/cli.mdx'), + 'CLI REFERENCE', + generatedCliReference(manifest), +) +await syncGeneratedSection( + join(docsRoot, 'reference/configuration.mdx'), + 'CONFIG REFERENCE', + generatedConfigReference(manifest), +) +const pages = await loadPages() +const index = renderIndex(pages, manifest, pin) +await emit(join(docsPublic, 'llms.txt'), index) +await emit(join(marketingPublic, 'llms.txt'), index) +await emit(join(docsPublic, 'llms-full.txt'), renderFull(pages, pin)) +for (const schema of ['summary-v1.schema.json', 'ci-contract-v1.schema.json', 'trace-events-v1.schema.json', 'mobench-site-manifest-v1.schema.json']) { + await emit(join(docsPublic, 'schemas', schema), await readFile(join(truthRoot, 'schemas', schema), 'utf8')) +} +await emit(join(docsPublic, 'manifests', 'mobench-site-manifest-v1.json'), await readFile(join(truthRoot, 'mobench-site-manifest-v1.json'), 'utf8')) +for (const fixture of ['summary-basic.json', 'summary-ffi.json']) { + await emit(join(docsPublic, 'fixtures', fixture), await readFile(join(truthRoot, 'fixtures', fixture), 'utf8')) +} +await emit( + join(root, 'apps/marketing/vercel.json'), + JSON.stringify(vercelConfig('marketing', redirectsForMarketing(pages)), null, 2), +) +await emit( + join(root, 'apps/docs/vercel.json'), + JSON.stringify(vercelConfig('docs', redirectsForDocs(pages)), null, 2), +) +console.log(`${checkOnly ? 'Checked' : 'Generated'} llms, truth assets, and redirect contracts from ${pages.length} authored pages.`) diff --git a/scripts/generate-og-images.py b/scripts/generate-og-images.py deleted file mode 100644 index c28fe12..0000000 --- a/scripts/generate-og-images.py +++ /dev/null @@ -1,240 +0,0 @@ -#!/usr/bin/env python3 -import json -from pathlib import Path - -from PIL import Image, ImageDraw, ImageFilter, ImageFont - - -ROOT = Path(__file__).resolve().parents[1] -OUT_DIR = ROOT / "public" / "og" -DATA = json.loads((ROOT / "src" / "og-pages.json").read_text()) -ARTWORK = Image.open(ROOT / "public" / "assets" / "mobench-bench.png").convert("RGB") - -W, H = 1200, 630 -PALETTE = { - "cream": "#f4efdd", - "cream_hi": "#fff9e9", - "ink": "#33271a", - "soft": "#46402f", - "muted": "#6e6453", - "faint": "#998c6f", - "green": "#3f7a2e", - "leaf": "#e6f1d5", - "line": "#d5cbb5", -} - -GROUP_ACCENTS = { - "Start": "#3f7a2e", - "Authoring": "#c2521d", - "Guides": "#287a8a", - "Reference": "#5e6f2f", - "Specs": "#9a6411", - "Codebase": "#356b26", - "Help": "#a7432a", -} - -SHORT_DESCRIPTIONS = { - "landing": "Benchmark Rust workloads on real Android and iOS devices.", - "docs": "Install, author, run, profile, and ship mobile Rust benchmarks.", - "overview": "What mobench is, why it exists, and where to go next.", - "quickstart": "Install mobench and run your first mobile benchmark.", - "install": "Set up Rust, Android, iOS, BrowserStack, and mobench.", - "concepts": "Understand runners, providers, reports, schemas, and profiling.", - "authoring": "Write #[benchmark] functions mobile runners can discover.", - "setup-teardown": "Keep setup and cleanup outside measured benchmark samples.", - "sdk": "Use mobench-sdk, runner backends, and native FFI exports.", - "build": "Generate and verify Android and iOS runner artifacts.", - "local-devices": "Run on attached devices, emulators, and simulators.", - "browserstack": "Run hosted real-device benchmarks in BrowserStack CI.", - "app-automate": "Upload Espresso and XCUITest suites to App Automate.", - "profiling": "Capture native traces, phases, flamegraphs, and profile diffs.", - "reports": "Read JSON summaries, Markdown reports, CSV rows, and artifacts.", - "cli-reference": "Every mobench command, flag, input, output, and example.", - "schemas": "Contracts for CI, summaries, traces, and fixtures.", - "examples": "Walk through benchmark and FFI examples.", - "diagrams": "Architecture, lifecycle, CI, profiling, and responsibility maps.", - "current-spec": f"Current behavior and API contracts for release {DATA['site']['version']}.", - "codebase": "Workspace layout, runtime layers, templates, and integrations.", - "testing": "Host tests, smoke checks, fixtures, CI, and profiling validation.", - "public-api": "Crates, feature flags, contracts, semver, MSRV, and releases.", - "troubleshooting": "Fix setup, build, provider, schema, and result issues.", -} - - -def font(size: int, bold: bool = False): - candidates = [ - "/System/Library/Fonts/Supplemental/Arial Bold.ttf" if bold else "/System/Library/Fonts/Supplemental/Arial.ttf", - "/System/Library/Fonts/Helvetica.ttc", - "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", - ] - for candidate in candidates: - try: - return ImageFont.truetype(candidate, size=size) - except OSError: - pass - return ImageFont.load_default(size=size) - - -FONT_LABEL = font(22, True) -FONT_BRAND = font(34, True) -FONT_VERSION = font(19) -FONT_PATH = font(19) -FONT_CHIP = font(18, True) - - -def text_width(draw: ImageDraw.ImageDraw, text: str, fnt: ImageFont.FreeTypeFont) -> int: - box = draw.textbbox((0, 0), text, font=fnt) - return box[2] - box[0] - - -def wrap(draw: ImageDraw.ImageDraw, text: str, fnt: ImageFont.FreeTypeFont, max_width: int, max_lines: int): - words = text.split() - lines = [] - line = "" - for word in words: - candidate = f"{line} {word}".strip() - if line and text_width(draw, candidate, fnt) > max_width: - lines.append(line) - line = word - else: - line = candidate - if len(lines) == max_lines: - break - if line and len(lines) < max_lines: - lines.append(line) - return lines - - -def rounded_paste(base: Image.Image, image: Image.Image, xy, radius: int): - mask = Image.new("L", image.size, 0) - mask_draw = ImageDraw.Draw(mask) - mask_draw.rounded_rectangle((0, 0, image.size[0], image.size[1]), radius=radius, fill=255) - base.paste(image, xy, mask) - - -def crop_artwork(size=(396, 486)): - target_w, target_h = size - src_w, src_h = ARTWORK.size - scale = max(target_w / src_w, target_h / src_h) - resized = ARTWORK.resize((round(src_w * scale), round(src_h * scale)), Image.Resampling.LANCZOS) - left = (resized.size[0] - target_w) // 2 - top = (resized.size[1] - target_h) // 2 - return resized.crop((left, top, left + target_w, top + target_h)) - - -def draw_background(draw: ImageDraw.ImageDraw, accent: str): - draw.rectangle((0, 0, W, H), fill=PALETTE["cream"]) - for x in range(0, W, 44): - draw.line((x, 0, x, H), fill="#e7dec8", width=1) - for y in range(0, H, 44): - draw.line((0, y, W, y), fill="#e7dec8", width=1) - draw.ellipse((858, -182, 1294, 254), fill="#dcebc9") - draw.ellipse((930, -28, 1214, 256), outline="#b7cba3", width=2) - draw.arc((-90, 438, 740, 740), 192, 350, fill="#c0d0a8", width=4) - draw.rounded_rectangle((38, 38, 1162, 592), radius=36, outline="#ded4bd", width=2) - draw.rounded_rectangle((54, 54, 1146, 576), radius=28, outline="#f8f2df", width=1) - - -def draw_artwork_card(base: Image.Image): - shadow = Image.new("RGBA", (510, 598), (0, 0, 0, 0)) - shadow_draw = ImageDraw.Draw(shadow) - shadow_draw.rounded_rectangle((36, 36, 472, 562), radius=38, fill=(51, 39, 26, 88)) - shadow = shadow.filter(ImageFilter.GaussianBlur(22)) - base.alpha_composite(shadow, (674, 20)) - - card = Image.new("RGBA", (436, 526), PALETTE["cream_hi"]) - card_draw = ImageDraw.Draw(card) - card_draw.rounded_rectangle((0, 0, 435, 525), radius=38, fill=PALETTE["cream_hi"], outline="#d7ccb7", width=2) - photo = crop_artwork() - rounded_paste(card, photo.convert("RGBA"), (20, 20), 30) - card_draw.rounded_rectangle((20, 20, 416, 506), radius=30, outline=(255, 255, 255, 136), width=2) - base.alpha_composite(card, (710, 52)) - - -def draw_chips(draw: ImageDraw.ImageDraw, items, accent: str): - x = 70 - for index, item in enumerate(items[:4]): - width = max(96, text_width(draw, item, FONT_CHIP) + 34) - fill = accent if index == 0 else PALETTE["leaf"] - text = "#fffdf4" if index == 0 else PALETTE["ink"] - outline = accent if index != 0 else None - draw.rounded_rectangle((x, 512, x + width, 554), radius=21, fill=fill, outline=outline, width=1) - draw.text((x + 17, 523), item, font=FONT_CHIP, fill=text) - x += width + 16 - - -def draw_card(filename: str, title: str, eyebrow: str, description: str, page_path: str, accent: str, chip_items): - canvas = Image.new("RGBA", (W, H), PALETTE["cream"]) - draw = ImageDraw.Draw(canvas) - draw_background(draw, accent) - draw_artwork_card(canvas) - - draw.text((70, 74), eyebrow.upper(), font=FONT_LABEL, fill=accent) - draw.text((70, 119), "mobench", font=FONT_BRAND, fill=PALETTE["ink"]) - version_x = 70 + text_width(draw, "mobench", FONT_BRAND) + 22 - draw.text((version_x, 133), DATA["site"]["version"], font=FONT_VERSION, fill=PALETTE["muted"]) - - title_font = font(76, True) - title_lines = wrap(draw, title, title_font, 610, 2) - if len(title_lines) == 1: - title_font = font(84, True) - title_lines = wrap(draw, title, title_font, 610, 1) - title_y = 194 - desc_y = 352 - else: - title_y = 184 - desc_y = 374 - - for i, line in enumerate(title_lines): - draw.text((70, title_y + i * 82), line, font=title_font, fill=PALETTE["ink"]) - - desc_font = font(34, True) - desc_lines = wrap(draw, description, desc_font, 620, 2) - for i, line in enumerate(desc_lines): - draw.text((73, desc_y + i * 44), line, font=desc_font, fill=PALETTE["soft"]) - - draw_chips(draw, chip_items, accent) - draw.text((70, 570), page_path, font=FONT_PATH, fill=PALETTE["faint"]) - canvas.convert("RGB").save(OUT_DIR / f"{filename}.jpg", quality=92, optimize=True, progressive=True) - - -def main(): - OUT_DIR.mkdir(parents=True, exist_ok=True) - for old_svg in OUT_DIR.glob("*.svg"): - old_svg.unlink() - - draw_card( - "landing", - "Benchmark Rust on real mobile", - DATA["landing"]["eyebrow"], - SHORT_DESCRIPTIONS["landing"], - "/", - PALETTE["green"], - ["Rust", "Android", "iOS", "BrowserStack"], - ) - draw_card( - "docs", - "Docs for mobile Rust benchmarking", - DATA["docsRoot"]["eyebrow"], - SHORT_DESCRIPTIONS["docs"], - "/docs", - PALETTE["green"], - ["CLI", "SDK", "Reports", "Profiling"], - ) - - for page in DATA["docsPages"]: - draw_card( - page["id"], - page["label"], - f'{page["group"]} / docs', - SHORT_DESCRIPTIONS.get(page["id"], page["description"]), - "/docs" if page["id"] == "overview" else f'/{page["id"]}', - GROUP_ACCENTS.get(page["group"], PALETTE["green"]), - [page["group"], "mobench", DATA["site"]["version"]], - ) - - print(f"Generated {2 + len(DATA['docsPages'])} OG JPGs in public/og") - - -if __name__ == "__main__": - main() diff --git a/scripts/generate-og.ts b/scripts/generate-og.ts new file mode 100644 index 0000000..2864270 --- /dev/null +++ b/scripts/generate-og.ts @@ -0,0 +1,123 @@ +import sharp from 'sharp' +import { parse as parseYaml } from 'yaml' +import { createHash } from 'node:crypto' +import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises' +import { dirname, join, relative, resolve } from 'node:path' +import pin from '@mobench/truth/pin' + +const root = resolve(import.meta.dir, '..') +const docsRoot = join(root, 'apps/docs/src/content/docs') +const checkOnly = process.argv.includes('--check') + +type Page = { title: string; description: string; section?: string; slug: string; release: string | number; draft?: boolean } + +async function filesUnder(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }) + return (await Promise.all(entries.map(async (entry) => { + const path = join(directory, entry.name) + return entry.isDirectory() ? filesUnder(path) : [path] + }))).flat().sort() +} + +function escapeXml(value: string) { + return value.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"') +} + +function wrapTitle(title: string, max = 26) { + const lines: string[] = [] + let line = '' + for (const word of title.split(/\s+/)) { + if (line && `${line} ${word}`.length > max) { + lines.push(line) + line = word + } else { + line = line ? `${line} ${word}` : word + } + } + if (line) lines.push(line) + return lines.slice(0, 3) +} + +function artwork(page: Page) { + const title = wrapTitle(page.title) + const titleLines = title.map((line, index) => `${escapeXml(line)}`).join('') + return ` + + + + + + m + mobench docs + + v${escapeXml(String(page.release))} + ${escapeXml((page.section ?? 'DOCUMENTATION').toUpperCase())} + ${titleLines} + + + + MOBILE RUNNER + RUST + + docs.mobench.org/${page.slug === 'index' ? '' : escapeXml(page.slug)} + ` +} + +async function emit(path: string, output: Buffer) { + if (checkOnly) { + let existing: Buffer | undefined + try { existing = await readFile(path) } catch {} + if (!existing?.equals(output)) throw new Error(`${relative(root, path)} is stale; run bun run generate`) + } else { + await mkdir(dirname(path), { recursive: true }) + await writeFile(path, output) + } +} + +async function emitPng(path: string, svg: string) { + if (checkOnly) { + let existing: Buffer + try { + existing = await readFile(path) + } catch { + throw new Error(`${relative(root, path)} is missing; run bun run generate`) + } + const metadata = await sharp(existing).metadata() + if (metadata.format !== 'png' || metadata.width !== 1200 || metadata.height !== 630) { + throw new Error(`${relative(root, path)} must be a 1200x630 PNG; run bun run generate`) + } + return + } + await emit(path, await sharp(Buffer.from(svg)).png({ compressionLevel: 9, palette: true }).toBuffer()) +} + +function sourceHash(svg: string) { + return createHash('sha256').update(svg).digest('hex') +} + +const pages: Page[] = [] +for (const file of (await filesUnder(docsRoot)).filter((path) => /\.mdx?$/.test(path))) { + const source = await readFile(file, 'utf8') + const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---/.exec(source) + if (!frontmatter) throw new Error(`${file} has no frontmatter`) + const page = parseYaml(frontmatter[1]) as Page + if (!page.draft) pages.push(page) +} +const docsSources: Record = {} +for (const page of pages) { + const svg = artwork(page) + docsSources[`${page.slug}.png`] = sourceHash(svg) + await emitPng(join(root, 'apps/docs/public/og', `${page.slug}.png`), svg) +} +const landing: Page = { title: 'Rust benchmarks, measured on mobile.', description: '', section: 'mobench', slug: 'landing', release: pin.version } +const landingSvg = artwork(landing) +await emitPng(join(root, 'apps/marketing/public/og/landing.png'), landingSvg) +await emit( + join(root, 'apps/docs/public/og/sources.json'), + Buffer.from(`${JSON.stringify(docsSources, null, 2)}\n`), +) +await emit( + join(root, 'apps/marketing/public/og/sources.json'), + Buffer.from(`${JSON.stringify({ 'landing.png': sourceHash(landingSvg) }, null, 2)}\n`), +) +console.log(`${checkOnly ? 'Checked' : 'Generated'} ${pages.length + 1} responsive social images.`) diff --git a/scripts/generate-route-html.mjs b/scripts/generate-route-html.mjs deleted file mode 100644 index c9b8f0f..0000000 --- a/scripts/generate-route-html.mjs +++ /dev/null @@ -1,82 +0,0 @@ -import fs from 'node:fs' -import path from 'node:path' - -const root = process.cwd() -const distDir = path.join(root, 'dist') -const data = JSON.parse(fs.readFileSync(path.join(root, 'src/og-pages.json'), 'utf8')) -const baseHtml = fs.readFileSync(path.join(distDir, 'index.html'), 'utf8') - -function absoluteUrl(base, routePath) { - return `${base}${routePath.startsWith('/') ? routePath : `/${routePath}`}` -} - -function replaceAttr(html, selector, attr, value) { - const escaped = value.replaceAll('&', '&').replaceAll('"', '"') - if (selector.startsWith('title')) { - return html.replace(/.*?<\/title>/, `<title>${escaped}`) - } - - if (selector.startsWith('link')) { - return html.replace(//, ``) - } - - const key = selector.match(/\[(name|property)="([^"]+)"\]/) - if (!key) return html - const [_, kind, name] = key - const pattern = new RegExp(``) - return html.replace(pattern, ``) -} - -function pageHtml({ title, description, url, image }) { - let html = baseHtml - html = replaceAttr(html, 'title', 'content', title) - html = replaceAttr(html, 'meta[name="description"]', 'content', description) - html = replaceAttr(html, 'link[rel="canonical"]', 'href', url) - html = replaceAttr(html, 'meta[property="og:title"]', 'content', title) - html = replaceAttr(html, 'meta[property="og:description"]', 'content', description) - html = replaceAttr(html, 'meta[property="og:url"]', 'content', url) - html = replaceAttr(html, 'meta[property="og:image"]', 'content', image) - html = replaceAttr(html, 'meta[name="twitter:title"]', 'content', title) - html = replaceAttr(html, 'meta[name="twitter:description"]', 'content', description) - html = replaceAttr(html, 'meta[name="twitter:image"]', 'content', image) - return html -} - -function writeRoute(routePath, target) { - const clean = routePath.replace(/^\/+|\/+$/g, '') - const outputDir = clean ? path.join(distDir, clean) : distDir - fs.mkdirSync(outputDir, { recursive: true }) - fs.writeFileSync(path.join(outputDir, 'index.html'), pageHtml(target)) -} - -writeRoute('/docs', { - title: 'mobench docs - Rust mobile benchmark documentation', - description: data.docsRoot.description, - url: absoluteUrl(data.site.docsUrl, '/docs'), - image: absoluteUrl(data.site.docsUrl, data.docsRoot.image), -}) - -for (const page of data.docsPages) { - const routePath = page.id === 'overview' ? '/overview' : `/${page.id}` - writeRoute(routePath, { - title: `${page.label} - mobench docs`, - description: page.description, - url: absoluteUrl(data.site.docsUrl, routePath), - image: absoluteUrl(data.site.docsUrl, `/og/${page.id}.jpg`), - }) -} - -for (const [alias, id] of Object.entries(data.aliases)) { - if (alias === 'docs') continue - const page = data.docsPages.find((candidate) => candidate.id === id) - if (!page) continue - const routePath = `/${alias}` - writeRoute(routePath, { - title: `${page.label} - mobench docs`, - description: page.description, - url: absoluteUrl(data.site.docsUrl, routePath), - image: absoluteUrl(data.site.docsUrl, `/og/${page.id}.jpg`), - }) -} - -console.log('Generated static route HTML for docs Open Graph metadata') diff --git a/scripts/sync-release.ts b/scripts/sync-release.ts new file mode 100644 index 0000000..e1ef86c --- /dev/null +++ b/scripts/sync-release.ts @@ -0,0 +1,221 @@ +import Ajv2020 from 'ajv/dist/2020' +import { createHash } from 'node:crypto' +import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises' +import { basename, dirname, join, resolve } from 'node:path' + +const root = resolve(import.meta.dir, '..') +const truthRoot = join(root, 'packages/truth') +const upstreamRepository = 'https://github.com/worldcoin/mobile-bench-rs' +const upstreamSlug = 'worldcoin/mobile-bench-rs' +const manifestName = 'mobench-site-manifest-v1.json' + +const usage = `Usage: + bun run sync:release -- --tag vX.Y.Z --expected-manifest-sha256 + +Downloads the manifest release asset, resolves the exact tag commit, verifies all +schema and fixture snapshots against that commit, then updates the offline truth +package. The command never reads mobile-bench-rs/main. + +Required: + --tag Explicit stable release tag + --expected-manifest-sha256 Trusted SHA-256 from the release checksum asset + +Environment: + GH_TOKEN or GITHUB_TOKEN Optional for local use; required in GitHub Actions +` + +type Arguments = { tag?: string; expectedManifestSha256?: string; help: boolean } +type ReleaseAsset = { name: string; url: string } +type Release = { tag_name: string; draft: boolean; prerelease: boolean; assets: ReleaseAsset[] } +type GitObject = { type: 'commit' | 'tag'; sha: string } +type GitRef = { object: GitObject } +type GitTag = { object: GitObject } +type Manifest = { + schema_version: number + release: { version: string; tag: string; sha: string; repository: string } + schemas: Array<{ id: string; path: string; checksum_sha256: string }> +} +type Pin = { + schemaVersion: number + repository: string + release: string + version: string + commitSha: string + manifestSha256: string + syncedAt: string + buildPolicy: string +} + +function parseArguments(argv: string[]): Arguments { + const parsed: Arguments = { help: false } + for (let index = 0; index < argv.length; index += 1) { + const argument = argv[index] + if (argument === '--help' || argument === '-h') { + parsed.help = true + continue + } + const value = argv[index + 1] + if (!value || value.startsWith('--')) throw new Error(`${argument} requires a value`) + if (argument === '--tag') parsed.tag = value + else if (argument === '--expected-manifest-sha256') parsed.expectedManifestSha256 = value.toLowerCase() + else throw new Error(`Unknown argument: ${argument}`) + index += 1 + } + return parsed +} + +function sha256(bytes: Uint8Array | string) { + return createHash('sha256').update(bytes).digest('hex') +} + +function requestHeaders(accept = 'application/vnd.github+json') { + const token = process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN + return { + Accept: accept, + 'User-Agent': 'mobench-site-release-sync', + 'X-GitHub-Api-Version': '2022-11-28', + ...(token ? { Authorization: `Bearer ${token}` } : {}), + } +} + +async function fetchBytes(url: string, accept?: string) { + const response = await fetch(url, { headers: requestHeaders(accept), redirect: 'follow' }) + if (!response.ok) throw new Error(`${response.status} ${response.statusText} while fetching ${url}`) + return new Uint8Array(await response.arrayBuffer()) +} + +async function fetchJson(url: string): Promise { + return JSON.parse(new TextDecoder().decode(await fetchBytes(url))) as T +} + +function githubApi(path: string) { + return `https://api.github.com/repos/${upstreamSlug}${path}` +} + +async function resolveTagCommit(tag: string) { + const reference = await fetchJson(githubApi(`/git/ref/tags/${encodeURIComponent(tag)}`)) + let object = reference.object + for (let depth = 0; object.type === 'tag' && depth < 4; depth += 1) { + object = (await fetchJson(githubApi(`/git/tags/${object.sha}`))).object + } + if (object.type !== 'commit') throw new Error(`Tag ${tag} did not resolve to a commit`) + return object.sha +} + +async function filesUnder(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }) + return (await Promise.all(entries.map(async (entry) => { + const path = join(directory, entry.name) + return entry.isDirectory() ? filesUnder(path) : [path] + }))).flat().sort() +} + +async function verifiedReleaseInputs(tag: string, expectedChecksum: string) { + const release = await fetchJson(githubApi(`/releases/tags/${encodeURIComponent(tag)}`)) + if (release.tag_name !== tag || release.draft || release.prerelease) throw new Error(`${tag} is not a published stable release`) + const asset = release.assets.find((candidate) => candidate.name === manifestName) + if (!asset) throw new Error(`${tag} does not publish ${manifestName}`) + const manifestBytes = await fetchBytes(asset.url, 'application/octet-stream') + const actualChecksum = sha256(manifestBytes) + if (actualChecksum !== expectedChecksum) { + throw new Error(`Manifest checksum mismatch: expected ${expectedChecksum}, received ${actualChecksum}`) + } + const manifest = JSON.parse(new TextDecoder().decode(manifestBytes)) as Manifest + const version = tag.replace(/^v/, '') + const commitSha = await resolveTagCommit(tag) + if (manifest.schema_version !== 1) throw new Error(`Unsupported manifest schema ${manifest.schema_version}`) + if (manifest.release.tag !== tag || manifest.release.version !== version) throw new Error('Manifest release identity does not match the requested tag') + if (manifest.release.sha !== commitSha) throw new Error('Manifest commit does not match the resolved release tag') + if (manifest.release.repository !== upstreamRepository) throw new Error(`Unexpected manifest repository: ${manifest.release.repository}`) + + const snapshots = new Map() + for (const schema of manifest.schemas) { + const bytes = await fetchBytes(`https://raw.githubusercontent.com/${upstreamSlug}/${commitSha}/${schema.path}`) + if (sha256(bytes) !== schema.checksum_sha256) throw new Error(`Schema checksum mismatch for ${schema.id}`) + snapshots.set(`schemas/${basename(schema.path)}`, bytes) + } + for (const [source, target] of [ + ['examples/fixtures/basic/summary.json', 'fixtures/summary-basic.json'], + ['examples/fixtures/ffi/summary.json', 'fixtures/summary-ffi.json'], + ] as const) { + snapshots.set(target, await fetchBytes(`https://raw.githubusercontent.com/${upstreamSlug}/${commitSha}/${source}`)) + } + + const manifestSchema = snapshots.get('schemas/mobench-site-manifest-v1.schema.json') + const summarySchema = snapshots.get('schemas/summary-v1.schema.json') + if (!manifestSchema || !summarySchema) throw new Error('Manifest does not reference the required website and summary schemas') + const ajv = new Ajv2020({ allErrors: true, strict: false, validateFormats: false }) + const validateManifest = ajv.compile(JSON.parse(new TextDecoder().decode(manifestSchema))) + if (!validateManifest(manifest)) throw new Error(`Manifest schema errors: ${ajv.errorsText(validateManifest.errors)}`) + const validateSummary = ajv.compile(JSON.parse(new TextDecoder().decode(summarySchema))) + for (const fixture of ['fixtures/summary-basic.json', 'fixtures/summary-ffi.json']) { + const value = JSON.parse(new TextDecoder().decode(snapshots.get(fixture)!)) + if (!validateSummary(value)) throw new Error(`${fixture} schema errors: ${ajv.errorsText(validateSummary.errors)}`) + } + return { manifest, manifestBytes, snapshots, version, commitSha, actualChecksum } +} + +function replaceReleaseIdentity(source: string, previous: Pin, next: Pin) { + return source + .replaceAll(previous.commitSha, next.commitSha) + .replaceAll(previous.release, next.release) + .replaceAll(previous.version, next.version) + .replace(/^lastVerified:\s*\d{4}-\d{2}-\d{2}$/gm, `lastVerified: ${next.syncedAt}`) +} + +async function writeVerifiedInputs(input: Awaited>, previous: Pin) { + const next: Pin = { + schemaVersion: 1, + repository: upstreamRepository, + release: input.manifest.release.tag, + version: input.manifest.release.version, + commitSha: input.commitSha, + manifestSha256: input.actualChecksum, + syncedAt: new Date().toISOString().slice(0, 10), + buildPolicy: 'offline-pinned', + } + await writeFile(join(truthRoot, manifestName), input.manifestBytes) + for (const [relativePath, bytes] of input.snapshots) { + const path = join(truthRoot, relativePath) + await mkdir(dirname(path), { recursive: true }) + await writeFile(path, bytes) + } + await writeFile(join(truthRoot, 'pin.json'), `${JSON.stringify(next, null, 2)}\n`) + + const packagePath = join(truthRoot, 'package.json') + const packageJson = JSON.parse(await readFile(packagePath, 'utf8')) as Record + packageJson.version = next.version + await writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`) + + const versionedFiles = [ + ...(await filesUnder(join(root, 'apps/docs/src/content/docs'))).filter((path) => /\.mdx?$/.test(path)), + join(root, 'apps/marketing/src/pages/index.astro'), + join(root, 'README.md'), + join(root, 'docs/AUTHORING.md'), + join(root, 'packages/truth/README.md'), + ] + for (const path of versionedFiles) { + const source = await readFile(path, 'utf8') + const updated = replaceReleaseIdentity(source, previous, next) + if (updated !== source) await writeFile(path, updated) + } + console.log(`Pinned mobench ${next.release} at ${next.commitSha} (${next.manifestSha256}).`) + console.log('Run bun install, bun run generate, and the complete validation suite before opening a pull request.') +} + +async function main() { + const args = parseArguments(process.argv.slice(2)) + if (args.help) { + console.log(usage) + return + } + if (!args.tag || !/^v\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(args.tag)) throw new Error('--tag must be an explicit vX.Y.Z release tag') + if (!args.expectedManifestSha256 || !/^[0-9a-f]{64}$/.test(args.expectedManifestSha256)) { + throw new Error('--expected-manifest-sha256 must be a 64-character hexadecimal checksum') + } + const previous = JSON.parse(await readFile(join(truthRoot, 'pin.json'), 'utf8')) as Pin + const input = await verifiedReleaseInputs(args.tag, args.expectedManifestSha256) + await writeVerifiedInputs(input, previous) +} + +await main() diff --git a/scripts/validate-content.ts b/scripts/validate-content.ts new file mode 100644 index 0000000..f09c8f7 --- /dev/null +++ b/scripts/validate-content.ts @@ -0,0 +1,303 @@ +import { parse as parseYaml } from 'yaml' +import Ajv2020 from 'ajv/dist/2020' +import { createHash } from 'node:crypto' +import { readFile, readdir } from 'node:fs/promises' +import { extname, join, relative, resolve } from 'node:path' + +const root = resolve(import.meta.dir, '..') +const docsRoot = join(root, 'apps/docs/src/content/docs') +const manifestPath = join(root, 'packages/truth/mobench-site-manifest-v1.json') +const pinPath = join(root, 'packages/truth/pin.json') + +type OptionContract = { long: string | null } +type CommandContract = { + name: string + path: string + options: OptionContract[] + subcommands: CommandContract[] +} +type Manifest = { + schema_version: number + release: { version: string; tag: string; sha: string; repository: string } + binaries: Array<{ name: string; canonical_for_release: boolean; status: string }> + command_tree: CommandContract + schemas: Array<{ id: string; path: string; checksum_sha256: string }> + config: Array<{ + file: string + keys: Array<{ path: string; evidence_id: string }> + }> + capabilities: Array<{ id: string; status: string; evidence_ids: string[] }> + evidence: Array<{ id: string }> +} +type Frontmatter = { + slug?: string + title?: string + description?: string + release?: string | number + lastVerified?: string | Date + sourceRefs?: Array<{ label?: string; url?: string; evidence?: string }> + aliases?: string[] + draft?: boolean +} +type Page = { + file: string + route: string + data: Frontmatter + body: string +} + +const failures: string[] = [] +const fail = (message: string) => failures.push(message) + +async function filesUnder(directory: string): Promise { + const entries = await readdir(directory, { withFileTypes: true }) + const nested = await Promise.all(entries.map(async (entry) => { + const path = join(directory, entry.name) + return entry.isDirectory() ? filesUnder(path) : [path] + })) + return nested.flat().sort() +} + +function parsePage(file: string, source: string): Page { + const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(source) + if (!match) throw new Error('missing YAML frontmatter') + const data = parseYaml(match[1]) as Frontmatter + const path = relative(docsRoot, file).replaceAll('\\', '/').replace(/\.mdx?$/, '') + const slug = data.slug ?? (path === 'index' ? 'index' : path.replace(/\/index$/, '')) + return { file, route: slug === 'index' ? '/' : `/${slug}/`, data, body: source.slice(match[0].length) } +} + +function shellTokens(command: string): string[] { + return command.match(/(?:"[^"]*"|'[^']*'|[^\s])+/g)?.map((token) => token.replace(/^(?:"|')|(?:"|')$/g, '')) ?? [] +} + +function commandLines(body: string): string[] { + const commands: string[] = [] + const fence = /```(?:bash|console|sh)(?:[^\n]*)\n([\s\S]*?)```/g + for (const block of body.matchAll(fence)) { + let pending = '' + for (const rawLine of block[1].split(/\r?\n/)) { + const line = rawLine.trim().replace(/^\$\s+/, '') + if (!line || line.startsWith('#')) continue + if (/^(export|unset)\s/.test(line)) continue + pending += `${pending ? ' ' : ''}${line.replace(/\\$/, '').trim()}` + if (!line.endsWith('\\')) { + if (pending.startsWith('mobench ')) commands.push(pending) + pending = '' + } + } + if (pending.startsWith('mobench ')) commands.push(pending) + } + return commands +} + +function taggedJsonExamples(body: string) { + return [...body.matchAll(/```json[^\n]*\btest=schema:([^\s]+)[^\n]*\n([\s\S]*?)```/g)] + .map((match) => ({ schemaId: match[1], source: match[2] })) +} + +function taggedConfigExamples(body: string) { + return [...body.matchAll(/```toml[^\n]*\btest=config:([^\s]+)[^\n]*\n([\s\S]*?)```/g)] + .map((match) => ({ file: match[1], source: match[2] })) +} + +function tomlKeyPaths(source: string) { + const keys: string[] = [] + let section = '' + for (const rawLine of source.split(/\r?\n/)) { + const line = rawLine.replace(/\s+#.*$/, '').trim() + const sectionMatch = /^\[([A-Za-z0-9_.-]+)\]$/.exec(line) + if (sectionMatch) { + section = sectionMatch[1] + continue + } + const keyMatch = /^([A-Za-z0-9_.-]+)\s*=/.exec(line) + if (keyMatch) keys.push(section ? `${section}.${keyMatch[1]}` : keyMatch[1]) + } + return keys +} + +function validateCommand(command: string, rootCommand: CommandContract, context: string) { + const tokens = shellTokens(command) + if (tokens[0] !== 'mobench') return + let current = rootCommand + const chain = [rootCommand] + for (const token of tokens.slice(1)) { + if (token.startsWith('-')) continue + const next = current.subcommands.find((candidate) => candidate.name === token) + if (!next) continue + current = next + chain.push(next) + } + const allowed = new Set(chain.flatMap((node) => node.options.flatMap((option) => option.long ? [`--${option.long}`] : []))) + for (const token of tokens.slice(1)) { + if (!token.startsWith('--')) continue + const flag = token.split('=', 1)[0] + if (!allowed.has(flag)) fail(`${context}: unknown option ${flag} in \`${command}\``) + } + const commandPath = chain.map((node) => node.name).join(' ') + const flags = new Set(tokens.filter((token) => token.startsWith('--')).map((token) => token.split('=', 1)[0])) + if (commandPath === 'mobench ci run' && flags.has('--browserstack')) fail(`${context}: ci run does not accept --browserstack`) + if (commandPath === 'mobench ci run' && flags.has('--output')) fail(`${context}: ci run requires --output-dir`) + if (commandPath === 'mobench profile run' && flags.has('--output')) fail(`${context}: profile run requires --output-dir`) +} + +function normalizeRoute(pathname: string) { + if (extname(pathname)) return pathname + return pathname === '/' ? '/' : `${pathname.replace(/\/$/, '')}/` +} + +function validateLinks(page: Page, canonicalRoutes: Set, aliasRoutes: Set) { + for (const match of page.body.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)) { + const href = match[1].trim().replace(/^<|>$/g, '') + if (!href || href.startsWith('#') || /^[a-z][a-z0-9+.-]*:/i.test(href)) continue + const resolved = new URL(href, `https://docs.mobench.org${page.route}`) + const route = normalizeRoute(resolved.pathname) + if (!canonicalRoutes.has(route) && !aliasRoutes.has(route)) { + fail(`${relative(root, page.file)}: internal link ${href} resolves to missing ${route}`) + } + } +} + +async function main() { + const [manifestSource, pinSource] = await Promise.all([ + readFile(manifestPath, 'utf8'), + readFile(pinPath, 'utf8'), + ]) + const manifest = JSON.parse(manifestSource) as Manifest + const pin = JSON.parse(pinSource) as { + release: string + version: string + commitSha: string + manifestSha256: string + } + const manifestChecksum = createHash('sha256').update(manifestSource).digest('hex') + if (manifestChecksum !== pin.manifestSha256) fail('pinned manifest checksum does not match pin.json') + if (manifest.schema_version !== 1) fail(`unsupported manifest schema ${manifest.schema_version}`) + if (manifest.release.tag !== pin.release || manifest.release.version !== pin.version || manifest.release.sha !== pin.commitSha) { + fail('manifest release identity does not match pin.json') + } + if (manifest.release.repository !== 'https://github.com/worldcoin/mobile-bench-rs') fail('unexpected upstream repository') + const ajv = new Ajv2020({ allErrors: true, strict: false, validateFormats: false }) + const manifestSchemaSource = await readFile(join(root, 'packages/truth/schemas/mobench-site-manifest-v1.schema.json'), 'utf8') + const validateManifest = ajv.compile(JSON.parse(manifestSchemaSource)) + if (!validateManifest(manifest)) fail(`manifest JSON Schema errors: ${ajv.errorsText(validateManifest.errors)}`) + const schemaValidators = new Map>() + for (const schema of manifest.schemas) { + const source = await readFile(join(root, 'packages/truth/schemas', schema.path.split('/').at(-1)!), 'utf8') + const checksum = createHash('sha256').update(source).digest('hex') + if (checksum !== schema.checksum_sha256) fail(`schema checksum mismatch for ${schema.id}`) + schemaValidators.set( + schema.id, + schema.id === 'mobench-site-manifest-v1' ? validateManifest : ajv.compile(JSON.parse(source)), + ) + } + const validateSummary = schemaValidators.get('summary-v1')! + for (const fixture of ['summary-basic.json', 'summary-ffi.json']) { + const value = JSON.parse(await readFile(join(root, 'packages/truth/fixtures', fixture), 'utf8')) + if (!validateSummary(value)) fail(`${fixture} schema errors: ${ajv.errorsText(validateSummary.errors)}`) + } + const canonicalBinary = manifest.binaries.find((binary) => binary.canonical_for_release) + if (canonicalBinary?.name !== 'mobench' || canonicalBinary.status !== 'supported') fail('mobench must be the supported canonical release binary') + const cargoWrapper = manifest.binaries.find((binary) => binary.name === 'cargo-mobench') + if (!cargoWrapper) fail('manifest must describe the cargo-mobench wrapper') + if (cargoWrapper?.canonical_for_release) fail('cargo-mobench must not replace the canonical mobench executable') + const evidenceIds = new Set(manifest.evidence.map((item) => item.id)) + for (const capability of manifest.capabilities) { + if (!['supported', 'preview', 'planned', 'unsupported'].includes(capability.status)) fail(`invalid capability status for ${capability.id}`) + if (!capability.evidence_ids.length || capability.evidence_ids.some((id) => !evidenceIds.has(id))) fail(`capability ${capability.id} has invalid evidence`) + } + const configKeys = new Map(manifest.config.map((entry) => [ + entry.file, + new Set(entry.keys.map((key) => key.path)), + ])) + + const pages: Page[] = [] + for (const file of (await filesUnder(docsRoot)).filter((path) => /\.mdx?$/.test(path))) { + try { + pages.push(parsePage(file, await readFile(file, 'utf8'))) + } catch (error) { + fail(`${relative(root, file)}: ${error instanceof Error ? error.message : error}`) + } + } + const canonicalRoutes = new Set() + const aliasRoutes = new Set() + let cliPage: Page | undefined + let configurationPage: Page | undefined + for (const page of pages) { + const name = relative(root, page.file) + if (canonicalRoutes.has(page.route)) fail(`${name}: duplicate route ${page.route}`) + canonicalRoutes.add(page.route) + if (!page.data.title || !page.data.description) fail(`${name}: title and description are required`) + if (String(page.data.release) !== pin.version) fail(`${name}: release must be ${pin.version}`) + if (!page.data.lastVerified) fail(`${name}: lastVerified is required`) + if (!page.data.sourceRefs?.length) fail(`${name}: at least one sourceRefs entry is required`) + for (const source of page.data.sourceRefs ?? []) { + if (!source.label || !source.url || !source.evidence) fail(`${name}: each source reference needs label, url, and evidence`) + if (source.url?.includes('github.com/worldfnd/mobile-bench-rs')) fail(`${name}: source URL uses the wrong GitHub organization`) + } + for (const alias of page.data.aliases ?? []) { + const route = normalizeRoute(alias) + if (aliasRoutes.has(route)) fail(`${name}: duplicate alias ${route}`) + aliasRoutes.add(route) + } + const copy = `${page.data.title}\n${page.data.description}\n${page.body}` + if (cargoWrapper?.status !== 'supported' && /cargo\s+mobench\b/.test(copy)) fail(`${name}: stable examples must use the mobench executable`) + if (/--local(?!-only)\b/.test(copy)) fail(`${name}: invalid --local option`) + if (/95\s*[%–-]\s*99\s*%|95%\s*(?:to|[-–])\s*99%/i.test(copy)) fail(`${name}: unsupported device-coverage percentage`) + if (/(?:runs?|exercises?) (?:only )?the host harness/i.test(copy)) fail(`${name}: --local-only must not imply benchmark execution`) + for (const command of commandLines(page.body)) validateCommand(command, manifest.command_tree, name) + for (const example of taggedConfigExamples(page.body)) { + const allowed = configKeys.get(example.file) + if (!allowed) { + fail(`${name}: unknown configuration contract ${example.file}`) + continue + } + for (const key of tomlKeyPaths(example.source)) { + if (!allowed.has(key)) fail(`${name}: ${key} is not published in ${example.file}`) + } + } + for (const example of taggedJsonExamples(page.body)) { + const validate = schemaValidators.get(example.schemaId) + if (!validate) { + fail(`${name}: unknown schema contract ${example.schemaId}`) + continue + } + try { + const value = JSON.parse(example.source) + if (!validate(value)) fail(`${name}: ${example.schemaId} errors: ${ajv.errorsText(validate.errors)}`) + } catch (error) { + fail(`${name}: invalid JSON for ${example.schemaId}: ${error instanceof Error ? error.message : error}`) + } + } + if (page.route === '/cli/') cliPage = page + if (page.route === '/configuration/') configurationPage = page + } + if (!cliPage?.body.includes('Generated from @mobench/truth')) fail('CLI reference must contain the generated truth section') + if (!configurationPage?.body.includes('Generated from @mobench/truth')) fail('configuration reference must contain the generated truth section') + const visitCommand = (command: CommandContract) => { + if (command.path !== 'mobench' && !command.path.split(' ').includes('help') && !cliPage?.body.includes(`\`${command.path}\``)) { + fail(`CLI reference is missing generated command ${command.path}`) + } + for (const subcommand of command.subcommands) visitCommand(subcommand) + } + visitCommand(manifest.command_tree) + for (const config of manifest.config) { + for (const key of config.keys) { + if (!configurationPage?.body.includes(`\`${key.path}\``)) fail(`configuration reference is missing generated key ${key.path}`) + } + } + for (const alias of aliasRoutes) { + if (canonicalRoutes.has(alias)) fail(`alias ${alias} collides with a canonical route`) + } + for (const page of pages) validateLinks(page, canonicalRoutes, aliasRoutes) + + if (failures.length) { + console.error(`Content contract failed with ${failures.length} issue(s):`) + for (const issue of failures) console.error(`- ${issue}`) + process.exit(1) + } + console.log(`Validated ${pages.length} docs pages, ${manifest.capabilities.length} capabilities, and the pinned ${pin.release} manifest.`) +} + +await main() diff --git a/src/components/app-head.tsx b/src/components/app-head.tsx deleted file mode 100644 index 898faf1..0000000 --- a/src/components/app-head.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useEffect } from 'react' -import { useRouterState } from '@tanstack/react-router' -import ogPages from '@/og-pages.json' - -type DocsPageOg = { - id: string - label: string - group: string - description: string -} - -type OgTarget = { - title: string - description: string - url: string - image: string -} - -const LANDING_TITLE = 'mobench - Rust mobile benchmarking CLI and SDK' -const DOCS_TITLE = 'mobench docs - Rust mobile benchmark documentation' - -function absoluteUrl(base: string, path: string) { - return `${base}${path.startsWith('/') ? path : `/${path}`}` -} - -function setMeta(selector: string, attr: 'content' | 'href', value: string) { - let element = document.head.querySelector(selector) - - if (!element) { - if (selector.startsWith('link')) { - element = document.createElement('link') - element.setAttribute('rel', 'canonical') - } else { - element = document.createElement('meta') - const property = selector.match(/property="([^"]+)"/)?.[1] - const name = selector.match(/name="([^"]+)"/)?.[1] - if (property) element.setAttribute('property', property) - if (name) element.setAttribute('name', name) - } - document.head.appendChild(element) - } - - element.setAttribute(attr, value) -} - -function docsPageForPath(pathname: string): DocsPageOg | null { - const slug = pathname.replace(/^\/+|\/+$/g, '').toLowerCase() - if (!slug) return null - if (slug === 'docs') return null - - const aliased = (ogPages.aliases as Record)[slug] ?? slug - return ogPages.docsPages.find((page) => page.id === aliased) ?? null -} - -function ogForPath(pathname: string): OgTarget { - const isDocsSubdomain = typeof window !== 'undefined' && window.location.hostname === 'docs.mobench.org' - const docsPage = docsPageForPath(pathname) - - if (docsPage) { - const path = `/${docsPage.id}` - return { - title: `${docsPage.label} - mobench docs`, - description: docsPage.description, - url: absoluteUrl(ogPages.site.docsUrl, path), - image: absoluteUrl(ogPages.site.docsUrl, `/og/${docsPage.id}.jpg`), - } - } - - if (pathname === '/docs' || pathname === '/docs/' || (isDocsSubdomain && pathname === '/')) { - return { - title: DOCS_TITLE, - description: ogPages.docsRoot.description, - url: absoluteUrl(ogPages.site.docsUrl, isDocsSubdomain ? '/' : '/docs'), - image: absoluteUrl(ogPages.site.docsUrl, ogPages.docsRoot.image), - } - } - - return { - title: LANDING_TITLE, - description: ogPages.landing.description, - url: absoluteUrl(ogPages.site.landingUrl, '/'), - image: absoluteUrl(ogPages.site.landingUrl, ogPages.landing.image), - } -} - -export function AppHead() { - const pathname = useRouterState({ select: (state) => state.location.pathname }) - - useEffect(() => { - const target = ogForPath(pathname) - - document.title = target.title - setMeta('meta[name="description"]', 'content', target.description) - setMeta('link[rel="canonical"]', 'href', target.url) - setMeta('meta[property="og:type"]', 'content', 'website') - setMeta('meta[property="og:site_name"]', 'content', 'mobench') - setMeta('meta[property="og:title"]', 'content', target.title) - setMeta('meta[property="og:description"]', 'content', target.description) - setMeta('meta[property="og:url"]', 'content', target.url) - setMeta('meta[property="og:image"]', 'content', target.image) - setMeta('meta[property="og:image:width"]', 'content', '1200') - setMeta('meta[property="og:image:height"]', 'content', '630') - setMeta('meta[name="twitter:card"]', 'content', 'summary_large_image') - setMeta('meta[name="twitter:title"]', 'content', target.title) - setMeta('meta[name="twitter:description"]', 'content', target.description) - setMeta('meta[name="twitter:image"]', 'content', target.image) - }, [pathname]) - - return null -} diff --git a/src/components/code-highlight.tsx b/src/components/code-highlight.tsx deleted file mode 100644 index 3e45cd2..0000000 --- a/src/components/code-highlight.tsx +++ /dev/null @@ -1,315 +0,0 @@ -import { useEffect, useRef, type ReactNode } from 'react' -import { cn } from '@/lib/utils' - -const KEYWORDS = new Set([ - 'as', - 'async', - 'await', - 'const', - 'crate', - 'else', - 'enum', - 'false', - 'fn', - 'for', - 'if', - 'impl', - 'in', - 'let', - 'match', - 'mod', - 'move', - 'mut', - 'pub', - 'ref', - 'return', - 'self', - 'Self', - 'static', - 'struct', - 'super', - 'trait', - 'true', - 'type', - 'use', - 'where', - 'while', -]) - -const TYPES = new Set([ - 'AndroidBuilder', - 'BenchError', - 'BenchmarkBuilder', - 'BenchSample', - 'BenchSpec', - 'BenchSummary', - 'BuildConfig', - 'BuildProfile', - 'BuildResult', - 'DeviceSelection', - 'IosBuilder', - 'MobileTarget', - 'Option', - 'Report', - 'Result', - 'RunRequest', - 'RunResult', - 'RunnerReport', - 'SemanticPhase', - 'SigningMethod', - 'String', - 'Target', - 'Vec', -]) - -function escapeHtml(value: string) { - return value - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') -} - -function span(className: string, value: string) { - return `${escapeHtml(value)}` -} - -function highlightText(value: string) { - let html = '' - const tokenPattern = /--[A-Za-z0-9_-]+|[A-Za-z_][A-Za-z0-9_]*!?|\d[\d_]*(?:\.\d+)?|::|->|=>|==|!=|<=|>=|[{}()[\].,;:=<>+\-*/&|?]|\s+|./g - - for (const match of value.matchAll(tokenPattern)) { - const token = match[0] - const index = match.index ?? 0 - - if (/^\s+$/.test(token)) { - html += token - } else if (token.startsWith('--')) { - html += span('code-flag', token) - } else if (/^\d/.test(token)) { - html += span('code-number', token) - } else if (/^[A-Za-z_][A-Za-z0-9_]*!?$/.test(token)) { - const bare = token.endsWith('!') ? token.slice(0, -1) : token - const following = value.slice(index + token.length).trimStart() - - if (token.endsWith('!')) { - html += span('code-macro', token) - } else if (KEYWORDS.has(token)) { - html += span('code-keyword', token) - } else if (TYPES.has(token) || /^[A-Z]/.test(token)) { - html += span('code-type', token) - } else if (following.startsWith('(')) { - html += span('code-function', token) - } else if (bare === 'cargo' || bare === 'rustup' || bare === 'export' || bare === 'println') { - html += span('code-command', token) - } else { - html += escapeHtml(token) - } - } else if (/^(::|->|=>|==|!=|<=|>=|[{}()[\].,;:=<>+\-*/&|?])$/.test(token)) { - html += span('code-operator', token) - } else { - html += escapeHtml(token) - } - } - - return html -} - -function splitRustSegments(line: string) { - const segments: { kind: 'text' | 'string' | 'comment' | 'attribute'; value: string }[] = [] - let cursor = 0 - - while (cursor < line.length) { - if (line.startsWith('//', cursor)) { - segments.push({ kind: 'comment', value: line.slice(cursor) }) - break - } - - if (line.startsWith('#[', cursor)) { - const end = line.indexOf(']', cursor + 2) - segments.push({ kind: 'attribute', value: line.slice(cursor, end === -1 ? line.length : end + 1) }) - cursor = end === -1 ? line.length : end + 1 - continue - } - - if (line[cursor] === '"') { - let end = cursor + 1 - while (end < line.length) { - if (line[end] === '\\') { - end += 2 - continue - } - if (line[end] === '"') { - end += 1 - break - } - end += 1 - } - segments.push({ kind: 'string', value: line.slice(cursor, end) }) - cursor = end - continue - } - - let next = cursor + 1 - while (next < line.length && !line.startsWith('//', next) && !line.startsWith('#[', next) && line[next] !== '"') { - next += 1 - } - segments.push({ kind: 'text', value: line.slice(cursor, next) }) - cursor = next - } - - return segments -} - -function highlightShellText(value: string) { - const tokenPattern = /\$[A-Za-z_][A-Za-z0-9_]*|\$\{[^}]+}|%[A-Za-z_][A-Za-z0-9_]*%|--?[A-Za-z0-9][A-Za-z0-9_-]*|[A-Za-z0-9_.+/@:-]+|\d[\d_]*(?:\.\d+)?|[|&;()=<>]+|\s+|./g - let html = '' - let sawCommand = false - - for (const match of value.matchAll(tokenPattern)) { - const token = match[0] - const previous = value.slice(0, match.index ?? 0) - const commandPosition = !sawCommand && !/^\s*$/.test(token) && /(^|\|\s*|&&\s*|;\s*)$/.test(previous) - - if (/^\s+$/.test(token)) { - html += token - } else if (/^(\$[A-Za-z_][A-Za-z0-9_]*|\$\{[^}]+}|%[A-Za-z_][A-Za-z0-9_]*%)$/.test(token)) { - html += span('code-key', token) - } else if (/^--?[A-Za-z0-9][A-Za-z0-9_-]*$/.test(token)) { - html += span('code-flag', token) - } else if (/^\d/.test(token)) { - html += span('code-number', token) - } else if (commandPosition && /^[A-Za-z0-9_.+/@:-]+$/.test(token)) { - sawCommand = true - html += span('code-command', token) - } else if (/^[|&;()=<>]+$/.test(token)) { - html += span('code-operator', token) - if (/^(\||&&|;)$/.test(token)) sawCommand = false - } else { - html += escapeHtml(token) - } - } - - return html -} - -function splitShellSegments(line: string) { - const segments: { kind: 'text' | 'string' | 'comment'; value: string }[] = [] - let cursor = 0 - - while (cursor < line.length) { - if (line[cursor] === '#') { - segments.push({ kind: 'comment', value: line.slice(cursor) }) - break - } - - if (line[cursor] === '"' || line[cursor] === "'") { - const quote = line[cursor] - let end = cursor + 1 - while (end < line.length) { - if (line[end] === '\\') { - end += 2 - continue - } - if (line[end] === quote) { - end += 1 - break - } - end += 1 - } - segments.push({ kind: 'string', value: line.slice(cursor, end) }) - cursor = end - continue - } - - let next = cursor + 1 - while (next < line.length && line[next] !== '#' && line[next] !== '"' && line[next] !== "'") { - next += 1 - } - segments.push({ kind: 'text', value: line.slice(cursor, next) }) - cursor = next - } - - return segments -} - -function highlightShellSegments(line: string) { - return splitShellSegments(line) - .map((segment) => { - if (segment.kind === 'string') return span('code-string', segment.value) - if (segment.kind === 'comment') return span('code-comment', segment.value) - return highlightShellText(segment.value) - }) - .join('') -} - -function highlightLine(line: string, language = '') { - const shellLike = /^(bash|zsh|sh|shell|powershell)$/i.test(language) - if (shellLike) { - if (/^\s*\$/.test(line)) { - const [, indent = '', rest = ''] = line.match(/^(\s*)\$\s?(.*)$/) ?? [] - return `${escapeHtml(indent)}${span('code-prompt', '$')}${rest ? ` ${highlightShellSegments(rest)}` : ''}` - } - - return highlightShellSegments(line) - } - - if (/^\s*\$/.test(line)) { - const [, indent = '', rest = ''] = line.match(/^(\s*)\$\s?(.*)$/) ?? [] - return `${escapeHtml(indent)}${span('code-prompt', '$')}${rest ? ` ${highlightText(rest)}` : ''}` - } - - if (/^\s*[A-Za-z0-9_.-]+\s*=/.test(line)) { - const [, indent = '', key = '', rest = ''] = line.match(/^(\s*)([A-Za-z0-9_.-]+)(\s*=.*)$/) ?? [] - return `${escapeHtml(indent)}${span('code-key', key)}${highlightRustSegments(rest)}` - } - - return highlightRustSegments(line) -} - -function highlightRustSegments(line: string) { - return splitRustSegments(line) - .map((segment) => { - if (segment.kind === 'string') return span('code-string', segment.value) - if (segment.kind === 'comment') return span('code-comment', segment.value) - if (segment.kind === 'attribute') return span('code-attribute', segment.value) - return highlightText(segment.value) - }) - .join('') -} - -function getCodeLines(element: HTMLElement) { - const children = Array.from(element.children) - if (children.length === 0) { - return element.textContent?.split('\n') ?? [] - } - return children.map((child) => child.textContent ?? '') -} - -export function SyntaxHighlightedCode({ - children, - className, -}: { - children: ReactNode - className?: string -}) { - const ref = useRef(null) - - useEffect(() => { - const element = ref.current - if (!element) return - - const lines = getCodeLines(element) - const language = Array.from(element.classList) - .find((className) => className.startsWith('language-')) - ?.replace('language-', '') ?? '' - element.innerHTML = lines.map((line) => `
${highlightLine(line, language)}
`).join('') - }, [children, className]) - - return ( -
- {children} -
- ) -} diff --git a/src/components/icons.tsx b/src/components/icons.tsx deleted file mode 100644 index 64aed38..0000000 --- a/src/components/icons.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import type { SVGProps } from 'react' - -export function GithubIcon(props: SVGProps) { - return ( - - - - ) -} - -export function WorldMark(props: SVGProps) { - return ( - - - - ) -} - -export function Wordmark({ tag }: { tag?: string }) { - return ( - - - mobench - - {tag ? ( - - {tag} - - ) : null} - - ) -} - -export const GITHUB_URL = 'https://github.com/worldcoin/mobile-bench-rs' -export const WORLD_URL = 'https://world.org' -export const BROWSERSTACK_URL = 'https://www.browserstack.com/' -export const MOBENCH_VERSION = '0.1.43' diff --git a/src/components/theme-toggle.tsx b/src/components/theme-toggle.tsx deleted file mode 100644 index 7b07193..0000000 --- a/src/components/theme-toggle.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useEffect, useState } from 'react' -import { Moon, Sun } from 'lucide-react' -import { cn } from '@/lib/utils' - -type Theme = 'light' | 'dark' - -const STORAGE_KEY = 'mobench-theme' - -function systemTheme(): Theme { - if (typeof window === 'undefined') return 'light' - return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' -} - -function applyTheme(theme: Theme) { - document.documentElement.dataset.theme = theme - document.documentElement.style.colorScheme = theme -} - -function storedTheme(): Theme | null { - if (typeof window === 'undefined') return null - try { - const value = window.localStorage?.getItem?.(STORAGE_KEY) - return value === 'light' || value === 'dark' ? value : null - } catch { - return null - } -} - -export function ThemeToggle({ className }: { className?: string }) { - const [theme, setTheme] = useState(() => { - if (typeof document === 'undefined') return 'light' - return document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light' - }) - - useEffect(() => { - const media = window.matchMedia('(prefers-color-scheme: dark)') - - const syncTheme = () => { - const next = storedTheme() ?? (media.matches ? 'dark' : 'light') - applyTheme(next) - setTheme(next) - } - - syncTheme() - media.addEventListener('change', syncTheme) - window.addEventListener('storage', syncTheme) - - return () => { - media.removeEventListener('change', syncTheme) - window.removeEventListener('storage', syncTheme) - } - }, []) - - const nextTheme = theme === 'dark' ? 'light' : 'dark' - const Icon = theme === 'dark' ? Sun : Moon - - return ( - - ) -} diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx deleted file mode 100644 index e96bf84..0000000 --- a/src/components/ui/accordion.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import * as React from 'react' -import * as AccordionPrimitive from '@radix-ui/react-accordion' -import { cn } from '@/lib/utils' - -function Accordion({ - ...props -}: React.ComponentProps) { - return -} - -function AccordionItem({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AccordionTrigger({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - - - {children} - - - ) -} - -function AccordionContent({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - -
{children}
-
- ) -} - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index 862f08e..0000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import * as React from 'react' -import { Slot } from '@radix-ui/react-slot' -import { cva, type VariantProps } from 'class-variance-authority' -import { cn } from '@/lib/utils' - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[10px] text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 outline-none focus-visible:ring-2 focus-visible:ring-green/40 cursor-pointer [&_svg]:pointer-events-none [&_svg]:shrink-0", - { - variants: { - variant: { - default: 'bg-green text-cream hover:bg-green-dark', - ink: 'bg-ink text-cream hover:bg-ink/90', - outline: - 'border border-[rgba(20,18,12,0.18)] bg-white text-ink hover:border-green/50', - ghost: 'text-ink hover:bg-[rgba(63,122,46,0.06)]', - link: 'text-green underline-offset-4 hover:underline', - }, - size: { - default: 'h-11 px-[22px] py-3.5', - sm: 'h-9 px-4', - lg: 'h-12 px-6 text-base', - }, - }, - defaultVariants: { - variant: 'default', - size: 'default', - }, - }, -) - -function Button({ - className, - variant, - size, - asChild = false, - ...props -}: React.ComponentProps<'button'> & - VariantProps & { asChild?: boolean }) { - const Comp = asChild ? Slot : 'button' - return ( - - ) -} - -export { Button, buttonVariants } diff --git a/src/lib/utils.ts b/src/lib/utils.ts deleted file mode 100644 index fed2fe9..0000000 --- a/src/lib/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx, type ClassValue } from 'clsx' -import { twMerge } from 'tailwind-merge' - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} diff --git a/src/main.tsx b/src/main.tsx deleted file mode 100644 index 4b1c74f..0000000 --- a/src/main.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import { RouterProvider, createRouter } from '@tanstack/react-router' -import { routeTree } from './routeTree.gen' -import './styles.css' - -const router = createRouter({ - routeTree, - defaultPreload: 'intent', - scrollRestoration: true, -}) - -declare module '@tanstack/react-router' { - interface Register { - router: typeof router - } -} - -const rootElement = document.getElementById('app')! -if (!rootElement.innerHTML) { - const root = createRoot(rootElement) - root.render( - - - , - ) -} diff --git a/src/og-pages.json b/src/og-pages.json deleted file mode 100644 index c6cd62a..0000000 --- a/src/og-pages.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "site": { - "name": "mobench", - "version": "0.1.43", - "landingUrl": "https://mobench.org", - "docsUrl": "https://docs.mobench.org" - }, - "landing": { - "id": "landing", - "path": "/", - "image": "/og/landing.jpg", - "title": "mobench", - "eyebrow": "Rust mobile benchmarking", - "description": "Benchmark intense Rust workloads on real Android and iOS devices with CLI, SDK, BrowserStack CI, reports, and profiling." - }, - "docsRoot": { - "id": "docs", - "path": "/docs", - "image": "/og/docs.jpg", - "title": "mobench docs", - "eyebrow": "Technical documentation", - "description": "Architecture, install paths, CLI man pages, SDK integration, BrowserStack App Automate, profiling, schemas, and examples." - }, - "docsPages": [ - { "id": "overview", "label": "Overview", "group": "Start", "description": "mobench is a Rust mobile benchmarking toolkit for Android and iOS, with a CLI, SDK runtime, macro-based benchmarks, generated mobile runners, CI reports, and profiling artifacts." }, - { "id": "quickstart", "label": "Quickstart", "group": "Start", "description": "Install the CLI, register a benchmark, build mobile runners, and run locally, on emulators or simulators, or on BrowserStack." }, - { "id": "install", "label": "Installation", "group": "Start", "description": "Set up the Rust workspace, mobile toolchains, BrowserStack credentials when needed, and the project configuration file." }, - { "id": "concepts", "label": "Concepts", "group": "Start", "description": "Understand benchmark definitions, generated runners, local and hosted providers, reports, schemas, and profiling output." }, - { "id": "authoring", "label": "Writing benchmarks", "group": "Authoring", "description": "Use the benchmark macro, setup inputs, teardown functions, and registry discovery rules to expose Rust functions to mobench." }, - { "id": "setup-teardown", "label": "Setup & teardown", "group": "Authoring", "description": "Keep expensive initialization and cleanup outside measured samples while still giving every iteration the input shape it needs." }, - { "id": "sdk", "label": "SDK integration", "group": "Guides", "description": "Add mobench-sdk to a crate, configure runner backends, export native C ABI when needed, and use public runtime types." }, - { "id": "build", "label": "Build artifacts", "group": "Guides", "description": "Generate Android and iOS runner projects, understand runner backends, and verify outputs under target/mobench." }, - { "id": "local-devices", "label": "Local devices", "group": "Guides", "description": "Run against connected phones, Android emulators via Android Studio and ADB, and iOS simulators or connected devices via Xcode." }, - { "id": "browserstack", "label": "BrowserStack CI", "group": "Guides", "description": "Use hosted real devices, matrix resolution, split-sample merging, PR reporting, artifact fetching, and normalized resource metrics." }, - { "id": "app-automate", "label": "App Automate setup", "group": "Guides", "description": "Set up BrowserStack App Automate for mobench Android Espresso and iOS XCUITest runs, including API uploads, build execution, devices, trial limits, and pricing expectations." }, - { "id": "profiling", "label": "Profiling", "group": "Guides", "description": "Run local native profiling, produce trace events, semantic phase summaries, flamegraphs, and profile diffs." }, - { "id": "reports", "label": "Outputs & reports", "group": "Reference", "description": "Understand summary JSON, Markdown summaries, CSV rows, split-run outputs, BrowserStack artifacts, PR comments, and profiling bundles." }, - { "id": "cli-reference", "label": "CLI man pages", "group": "Reference", "description": "Exhaustive command reference for mobench: commands, subcommands, flags, expected inputs, outputs, defaults, and common examples." }, - { "id": "schemas", "label": "Schemas", "group": "Reference", "description": "Machine-readable contracts for CI metadata, benchmark summaries, trace events, and fixture payloads." }, - { "id": "examples", "label": "Examples explained", "group": "Reference", "description": "What the basic benchmark and native C ABI / FFI examples demonstrate, and how their fixture outputs map to reports." }, - { "id": "diagrams", "label": "Diagrams", "group": "Reference", "description": "Architecture, benchmark lifecycle, BrowserStack CI, profiling artifacts, and SDK versus CLI responsibility diagrams." }, - { "id": "current-spec", "label": "Current behavior", "group": "Specs", "description": "Current behavior and API contract for release 0.1.43: CLI, config, runners, public APIs, schemas, and compatibility boundaries." }, - { "id": "codebase", "label": "Codebase architecture", "group": "Codebase", "description": "Workspace layout, runtime layers, generated templates, integrations, stack, and ownership boundaries." }, - { "id": "testing", "label": "Testing strategy", "group": "Codebase", "description": "Host tests, CLI smoke checks, split-run merge validation, CI contract checks, BrowserStack smoke tests, and profiling checks." }, - { "id": "public-api", "label": "Public API", "group": "Codebase", "description": "Published crates, feature flags, serialized contracts, error boundaries, semver policy, MSRV, and release readiness." }, - { "id": "troubleshooting", "label": "Troubleshooting", "group": "Help", "description": "Common setup, build, discovery, BrowserStack, profiling, schema, and result-quality issues." } - ], - "aliases": { - "docs": "overview", - "home": "overview", - "installation": "install", - "writing": "authoring", - "writing-benchmarks": "authoring", - "setup-and-teardown": "setup-teardown", - "sdk-integration": "sdk", - "build-artifacts": "build", - "outputs-and-reports": "reports", - "cli-man-pages": "cli-reference", - "reference": "cli-reference" - } -} diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts deleted file mode 100644 index 1f3cdd3..0000000 --- a/src/routeTree.gen.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* eslint-disable */ - -// @ts-nocheck - -// noinspection JSUnusedGlobalSymbols - -// This file was automatically generated by TanStack Router. -// You should NOT make any changes in this file as it will be overwritten. -// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. - -import { Route as rootRouteImport } from './routes/__root' -import { Route as DocsRouteImport } from './routes/docs' -import { Route as DocSlugRouteImport } from './routes/$docSlug' -import { Route as IndexRouteImport } from './routes/index' - -const DocsRoute = DocsRouteImport.update({ - id: '/docs', - path: '/docs', - getParentRoute: () => rootRouteImport, -} as any) -const DocSlugRoute = DocSlugRouteImport.update({ - id: '/$docSlug', - path: '/$docSlug', - getParentRoute: () => rootRouteImport, -} as any) -const IndexRoute = IndexRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => rootRouteImport, -} as any) - -export interface FileRoutesByFullPath { - '/': typeof IndexRoute - '/$docSlug': typeof DocSlugRoute - '/docs': typeof DocsRoute -} -export interface FileRoutesByTo { - '/': typeof IndexRoute - '/$docSlug': typeof DocSlugRoute - '/docs': typeof DocsRoute -} -export interface FileRoutesById { - __root__: typeof rootRouteImport - '/': typeof IndexRoute - '/$docSlug': typeof DocSlugRoute - '/docs': typeof DocsRoute -} -export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/$docSlug' | '/docs' - fileRoutesByTo: FileRoutesByTo - to: '/' | '/$docSlug' | '/docs' - id: '__root__' | '/' | '/$docSlug' | '/docs' - fileRoutesById: FileRoutesById -} -export interface RootRouteChildren { - IndexRoute: typeof IndexRoute - DocSlugRoute: typeof DocSlugRoute - DocsRoute: typeof DocsRoute -} - -declare module '@tanstack/react-router' { - interface FileRoutesByPath { - '/docs': { - id: '/docs' - path: '/docs' - fullPath: '/docs' - preLoaderRoute: typeof DocsRouteImport - parentRoute: typeof rootRouteImport - } - '/$docSlug': { - id: '/$docSlug' - path: '/$docSlug' - fullPath: '/$docSlug' - preLoaderRoute: typeof DocSlugRouteImport - parentRoute: typeof rootRouteImport - } - '/': { - id: '/' - path: '/' - fullPath: '/' - preLoaderRoute: typeof IndexRouteImport - parentRoute: typeof rootRouteImport - } - } -} - -const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - DocSlugRoute: DocSlugRoute, - DocsRoute: DocsRoute, -} -export const routeTree = rootRouteImport - ._addFileChildren(rootRouteChildren) - ._addFileTypes() diff --git a/src/routes/$docSlug.tsx b/src/routes/$docSlug.tsx deleted file mode 100644 index 12251e9..0000000 --- a/src/routes/$docSlug.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { createFileRoute, Link } from '@tanstack/react-router' -import { AlertTriangle } from 'lucide-react' -import { Docs, getDocsPageBySlug } from './docs' - -export const Route = createFileRoute('/$docSlug')({ - component: DocsSlugRoute, -}) - -function DocsSlugRoute() { - const { docSlug } = Route.useParams() - const page = getDocsPageBySlug(docSlug) - - if (!page) { - return - } - - return -} - -function DocsNotFound({ slug }: { slug: string }) { - return ( -
-
-
- -
-

404

-

Docs page not found

-

- No Mobench docs page matches /{slug}. -

-
- - Go to docs - - - Go home - -
-
-
- ) -} diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx deleted file mode 100644 index b4c5b5b..0000000 --- a/src/routes/__root.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createRootRoute, Link, Outlet } from '@tanstack/react-router' -import { AlertTriangle } from 'lucide-react' -import { AppHead } from '@/components/app-head' - -export const Route = createRootRoute({ - component: () => ( - <> - - - - ), - notFoundComponent: RootNotFound, -}) - -function RootNotFound() { - return ( -
-
-
- -
-

404

-

Page not found

-

That URL does not match an existing Mobench page.

-
- - Go to docs - - - Go home - -
-
-
- ) -} diff --git a/src/routes/docs.tsx b/src/routes/docs.tsx deleted file mode 100644 index 858b21b..0000000 --- a/src/routes/docs.tsx +++ /dev/null @@ -1,3625 +0,0 @@ -import { isValidElement, useEffect, useMemo, useRef, useState, type ComponentType, type MouseEvent, type ReactNode, type SVGProps } from 'react' -import { createFileRoute, Link, useNavigate } from '@tanstack/react-router' -import { - Activity, - AlertTriangle, - BarChart3, - BookOpen, - Boxes, - Check, - ChevronDown, - Cloud, - Code2, - Compass, - Copy, - Cpu, - Database, - ExternalLink, - FileCode2, - FileJson, - Layers, - ListChecks, - Maximize2, - MessageCircle, - Network, - PackageCheck, - Rocket, - Search, - ShieldCheck, - Smartphone, - Terminal, - TestTube2, - Workflow, - Wrench, - X, -} from 'lucide-react' -import { SyntaxHighlightedCode } from '@/components/code-highlight' -import { ThemeToggle } from '@/components/theme-toggle' -import { MOBENCH_VERSION } from '@/components/icons' -import { cn } from '@/lib/utils' - -export const Route = createFileRoute('/docs')({ - component: Docs, -}) - -type Icon = ComponentType> - -type PageId = - | 'overview' - | 'quickstart' - | 'install' - | 'concepts' - | 'authoring' - | 'setup-teardown' - | 'sdk' - | 'build' - | 'local-devices' - | 'browserstack' - | 'app-automate' - | 'profiling' - | 'reports' - | 'cli-reference' - | 'schemas' - | 'examples' - | 'diagrams' - | 'current-spec' - | 'codebase' - | 'testing' - | 'public-api' - | 'troubleshooting' - -type PageDef = { - id: PageId - label: string - group: string - description: string - icon: Icon - toc: string[] -} - -type Section = { -title: string -body?: ReactNode[] -bullets?: ReactNode[] -image?: { - src: string - alt: string - caption?: string -} -codeVariants?: readonly { - id: string - label: string - language: string - value: string -}[] -code?: { -language: string -value: string -} -} - -const DOCSRS = { - mobench: 'https://docs.rs/mobench/latest/mobench/', - sdk: 'https://docs.rs/mobench-sdk/latest/mobench_sdk/', - macros: 'https://docs.rs/mobench-macros/latest/mobench_macros/', -} - -const LANDING_URL = 'https://mobench.org' -const GITHUB_REPO = 'https://github.com/worldcoin/mobile-bench-rs' -const DEEPWIKI_URL = 'https://deepwiki.com/worldcoin/mobile-bench-rs' -const DEEPWIKI_OVERVIEW_URL = 'https://deepwiki.com/worldcoin/mobile-bench-rs/1-overview' -const EXTERNAL_DOCS = { - rust: 'https://www.rust-lang.org/tools/install', - browserstack: 'https://www.browserstack.com/', - appAutomate: 'https://www.browserstack.com/app-automate', - appAutomateApi: 'https://www.browserstack.com/docs/app-automate/api-reference/introduction', - appAutomateEspresso: 'https://www.browserstack.com/docs/app-automate/espresso/getting-started', - appAutomateXcuitest: 'https://www.browserstack.com/docs/app-automate/xcuitest', - espresso: 'https://developer.android.com/training/testing/espresso', - xctest: 'https://developer.apple.com/documentation/xctest', - uniffi: 'https://github.com/mozilla/uniffi-rs', - boltffi: 'https://github.com/boltffi/boltffi', - androidStudio: 'https://developer.android.com/studio', - android: 'https://developer.android.com/', - xcode: 'https://developer.apple.com/xcode/', - ios: 'https://developer.apple.com/ios/', - worldApp: 'http://world.org/world-app', - worldId: 'https://docs.world.org/world-id', - provekit: 'https://provekit.org/', -} as const - -type BrandLogoName = 'rust' | 'browserstack' | 'androidStudio' | 'android' | 'xcode' | 'ios' - -const BRAND_LOGOS: Record = { - rust: { src: '/assets/logo-rust.svg', alt: 'Rust' }, - browserstack: { src: '/assets/logo-browserstack.svg', alt: 'BrowserStack' }, - androidStudio: { src: '/assets/logo-android-studio.svg', alt: 'Android Studio' }, - android: { src: '/assets/logo-android.svg', alt: 'Android' }, - xcode: { src: '/assets/logo-xcode.svg', alt: 'Xcode' }, - ios: { src: '/assets/logo-apple.svg', alt: 'Apple' }, -} - -const INSTALL_COMMANDS = [ - { - id: 'mac', - label: 'Mac', - language: 'bash', - value: `# macOS without Homebrew -# Xcode/iOS support is macOS-only and may require App Store sign-in. -xcode-select --install || true -open "macappstore://apps.apple.com/app/xcode/id497799835" - -# Android Studio installs the Android SDK, emulator, and SDK manager UI. -open "https://developer.android.com/studio" - -# Rust and mobench. -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -. "$HOME/.cargo/env" -cargo install mobench - -# After Android Studio installs Platform Tools, reopen the terminal and verify. -adb version -mobench --version`, - }, - { - id: 'brew', - label: 'Brew', - language: 'bash', - value: `# macOS with Homebrew -if ! command -v brew >/dev/null 2>&1; then - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -fi - -brew install android-platform-tools -brew install --cask android-studio -xcode-select --install || true -open "macappstore://apps.apple.com/app/xcode/id497799835" - -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -. "$HOME/.cargo/env" -cargo install mobench - -adb version -mobench --version`, - }, - { - id: 'windows', - label: 'Windows', - language: 'powershell', - value: `# Windows PowerShell -winget install -e --id Rustlang.Rustup -winget install -e --id Google.PlatformTools -winget install -e --id Google.AndroidStudio - -# Open a new PowerShell after winget finishes so PATH refreshes. -cargo install mobench - -adb version -mobench --version`, - }, - { - id: 'linux', - label: 'Linux', - language: 'bash', - value: `# Linux: Debian/Ubuntu, Fedora, or Arch -if command -v apt-get >/dev/null 2>&1; then - sudo apt-get update - sudo apt-get install -y curl build-essential pkg-config libssl-dev unzip adb -elif command -v dnf >/dev/null 2>&1; then - sudo dnf install -y curl gcc gcc-c++ make openssl-devel unzip android-tools -elif command -v pacman >/dev/null 2>&1; then - sudo pacman -Syu --needed curl base-devel openssl unzip android-tools -else - echo "Install curl, compiler toolchain, OpenSSL headers, unzip, and Android platform-tools for your distro." -fi - -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -. "$HOME/.cargo/env" -cargo install mobench - -adb version -mobench --version`, - }, -] as const - -const PAGES: PageDef[] = [ - { - id: 'overview', - label: 'Overview', - group: 'Start', - description: 'mobench is a Rust mobile benchmarking toolkit for Android and iOS, with a CLI, SDK runtime, macro-based benchmarks, generated mobile runners, CI reports, and profiling artifacts.', - icon: BookOpen, - toc: ['Why mobench exists', 'What mobench provides', 'How pieces fit', 'Where to go next'], - }, - { - id: 'quickstart', - label: 'Quickstart', - group: 'Start', - description: 'Install the CLI, register a benchmark, build mobile runners, and run locally, on emulators or simulators, or on BrowserStack.', - icon: Rocket, - toc: ['Command path', 'Local targets', 'First benchmark'], - }, - { - id: 'install', - label: 'Installation', - group: 'Start', - description: 'Set up the Rust workspace, mobile toolchains, BrowserStack credentials when needed, and the project configuration file.', - icon: PackageCheck, - toc: ['Copy-paste install', 'Rust and CLI', 'Android and iOS', 'BrowserStack credentials'], - }, - { - id: 'concepts', - label: 'Concepts', - group: 'Start', - description: 'Understand benchmark definitions, generated runners, local and hosted providers, reports, schemas, and profiling output.', - icon: Compass, - toc: ['Product surfaces', 'Crates', 'Artifact flow'], - }, - { - id: 'authoring', - label: 'Writing benchmarks', - group: 'Authoring', - description: 'Use the benchmark macro, setup inputs, teardown functions, and registry discovery rules to expose Rust functions to mobench.', - icon: Code2, - toc: ['Macro shape', 'Discovery', 'Best practices'], - }, - { - id: 'setup-teardown', - label: 'Setup & teardown', - group: 'Authoring', - description: 'Keep expensive initialization and cleanup outside measured samples while still giving every iteration the input shape it needs.', - icon: Wrench, - toc: ['Setup modes', 'Teardown', 'Compatibility'], - }, - { - id: 'sdk', - label: 'SDK integration', - group: 'Guides', - description: 'Add mobench-sdk to a crate, configure runner backends, export native C ABI when needed, and use public runtime types.', - icon: FileCode2, - toc: ['Dependencies', 'Runtime APIs', 'Choosing an FFI backend', 'Native C ABI'], - }, - { - id: 'build', - label: 'Build artifacts', - group: 'Guides', - description: 'Generate Android and iOS runner projects, understand runner backends, and verify outputs under target/mobench.', - icon: Terminal, - toc: ['Prerequisites', 'Build commands', 'Outputs'], - }, - { - id: 'local-devices', - label: 'Local devices', - group: 'Guides', - description: 'Run against connected phones, Android emulators via Android Studio and ADB, and iOS simulators or connected devices via Xcode.', - icon: Smartphone, - toc: ['Android', 'iOS', 'Host-only smoke runs'], - }, - { - id: 'browserstack', - label: 'BrowserStack CI', - group: 'Guides', - description: 'Use hosted real devices, matrix resolution, split-sample merging, PR reporting, artifact fetching, and normalized resource metrics.', - icon: Cloud, - toc: ['Credentials', 'Device resolution', 'CI contract', 'Split-sample merge'], - }, - { - id: 'app-automate', - label: 'App Automate setup', - group: 'Guides', - description: 'Set up BrowserStack App Automate for mobench Android Espresso and iOS XCUITest runs, including API uploads, build execution, devices, trial limits, and pricing expectations.', - icon: Layers, - toc: ['Account and pricing', 'Espresso on Android', 'XCUITest on iOS', 'API lifecycle', 'Devices'], - }, - - { - id: 'profiling', - label: 'Profiling', - group: 'Guides', - description: 'Run local native profiling, produce trace events, semantic phase summaries, flamegraphs, and profile diffs.', - icon: Activity, - toc: ['Capability matrix', 'Artifacts', 'Flamegraph viewer', 'Phases'], - }, - { - id: 'reports', - label: 'Outputs & reports', - group: 'Reference', - description: 'Understand summary JSON, Markdown summaries, CSV rows, split-run outputs, BrowserStack artifacts, PR comments, and profiling bundles.', - icon: BarChart3, - toc: ['Output layout', 'Split-run outputs', 'Report helpers', 'Fixtures'], - }, - { - id: 'cli-reference', - label: 'CLI man pages', - group: 'Reference', - description: 'Exhaustive command reference for mobench: commands, subcommands, flags, expected inputs, outputs, defaults, and common examples.', - icon: Terminal, - toc: ['Command model', 'Benchmark runs', 'Build and project setup', 'CI commands', 'Device and config helpers', 'Reports and profiling', 'Outputs and contracts'], - }, - { - id: 'schemas', - label: 'Schemas', - group: 'Reference', - description: 'Machine-readable contracts for CI metadata, benchmark summaries, trace events, and fixture payloads.', - icon: FileJson, - toc: ['CI contract', 'Summary', 'Trace events'], - }, - { - id: 'examples', - label: 'Examples explained', - group: 'Reference', - description: 'What the basic benchmark and native C ABI / FFI examples demonstrate, and how their fixture outputs map to reports.', - icon: Boxes, - toc: ['Basic benchmark', 'FFI benchmark', 'Fixture outputs'], - }, - { - id: 'diagrams', - label: 'Diagrams', - group: 'Reference', - description: 'Architecture, benchmark lifecycle, BrowserStack CI, profiling artifacts, and SDK versus CLI responsibility diagrams.', - icon: Workflow, - toc: ['Crate architecture', 'Benchmark lifecycle', 'Provider flow'], - }, - { - id: 'current-spec', - label: 'Current behavior', - group: 'Specs', - description: 'Current behavior and API contract for release 0.1.43: CLI, config, runners, public APIs, schemas, and compatibility boundaries.', - icon: ListChecks, - toc: ['Scope', 'Contracts', 'Compatibility'], - }, - { - id: 'codebase', - label: 'Codebase architecture', - group: 'Codebase', - description: 'Workspace layout, runtime layers, generated templates, integrations, stack, and ownership boundaries.', - icon: Network, - toc: ['Workspace', 'Runtime layers', 'Integrations'], - }, - { - id: 'testing', - label: 'Testing strategy', - group: 'Codebase', - description: 'Host tests, CLI smoke checks, split-run merge validation, CI contract checks, BrowserStack smoke tests, and profiling checks.', - icon: TestTube2, - toc: ['Test taxonomy', 'CI checks', 'Profiling checks'], - }, - { - id: 'public-api', - label: 'Public API', - group: 'Codebase', - description: 'Published crates, feature flags, serialized contracts, error boundaries, semver policy, MSRV, and release readiness.', - icon: ShieldCheck, - toc: ['Crates', 'Feature flags', 'Release checks'], - }, - { - id: 'troubleshooting', - label: 'Troubleshooting', - group: 'Help', - description: 'Common setup, build, discovery, BrowserStack, profiling, schema, and result-quality issues.', - icon: AlertTriangle, - toc: ['Setup', 'Runs', 'Reports'], - }, -] - -const DOCS_PAGE_ALIASES: Partial> = { - docs: 'overview', - overview: 'overview', - home: 'overview', - installation: 'install', - install: 'install', - authoring: 'authoring', - writing: 'authoring', - 'writing-benchmarks': 'authoring', - 'setup-and-teardown': 'setup-teardown', - 'sdk-integration': 'sdk', - 'build-artifacts': 'build', - 'local-devices': 'local-devices', - 'browserstack-ci': 'browserstack', - browserstack: 'browserstack', - 'app-automate-setup': 'app-automate', - 'outputs-and-reports': 'reports', - 'cli-man-pages': 'cli-reference', - reference: 'cli-reference', -} - -export function docsPathForPage(id: PageId) { - return id === 'overview' ? '/docs' : `/${id}` -} - -export function getDocsPageBySlug(slug: string | undefined) { - const normalized = (slug ?? 'docs').toLowerCase().replace(/^\/+|\/+$/g, '') - const aliased = DOCS_PAGE_ALIASES[normalized] - const id = aliased ?? (PAGES.some((page) => page.id === normalized) ? normalized as PageId : null) - return id ? PAGES.find((page) => page.id === id) ?? null : null -} - -const CONTENT: Record = { - overview: [ - { - title: 'Why mobench exists', - body: [ - <>mobench came from an internal need to benchmark intense Rust workloads in mobile environments representative of real World App users. That means runs cannot only target flagship phones; the matrix also needs medium-tier devices, low-end devices, and even older 32-bit devices that may still be in circulation roughly a decade later., - <>The practical goal was confidence across the device range that matters for ProveKit, the cryptography library that powers World ID. mobench helps teams measure whether heavy cryptographic paths hold up for the 95%-99% of users whose real phones define production performance, thermal behavior, and reliability., - ], - }, - { - title: 'What mobench provides', - body: [ - <>mobench keeps benchmark definitions in Rust and runs them in places mobile code actually pays its costs: Android iOS runners, host-only smoke runs, connected local devices, emulators simulators, BrowserStack devices, profiling flows., - ], - bullets: [ - <>A cargo mobench CLI for build, run, CI, reporting, BrowserStack, device resolution, profiling commands., - <>A mobench-sdk runtime with timing, registry, runner builders, mobile builders, profiling helpers, UniFFI compatibility, BoltFFI support, and native C ABI support., - <>A mobench-macros crate registers #[benchmark] functions through inventory., - <>Stable output artifacts: JSON summaries, Markdown summaries, CSV rows, optional plots, profiling manifests, trace-event JSON, and flamegraph bundles., - ], - }, - { - title: 'How the pieces fit', - body: [ - <>The CLI resolves project configuration, builds generated Android or iOS runner projects, invokes a local or hosted provider, fetches artifacts, and writes normalized reports. The SDK owns benchmark execution, timing, registry lookup, setup and teardown handling, runner reports, and public types., - ], - code: { - language: 'text', - value: `benchmark crate - -> mobench-sdk registry and timing - -> generated Android / iOS runner - -> local device, emulator, simulator, host-only, or BrowserStack provider - -> summary.json, summary.md, results.csv, plots, profile artifacts`, - }, - }, - { - title: 'Where to go next', - bullets: [ - <>Start with Quickstart for the smallest working path., - <>Use Local devices when you want connected phones, Android Studio emulators, ADB, Xcode simulators, or connected iOS devices., - <>Use BrowserStack CI for hosted real-device runs and PR reporting., - <>Use Outputs, Schemas, and Examples when wiring downstream tooling., - ], - }, - { - title: 'External AI documentation', - body: [ - <> - DeepWiki by Cognition indexes the upstream repository into an external technical wiki that can be used as AI-readable context for Devin and other coding assistants. Use it when you want repo-wide navigation, source-linked explanations, or a fast second view beside these authored docs. - , - ], - bullets: [ - <> - DeepWiki overview summarizes purpose, crate architecture, generated runner flow, reporting, and native profiling. - , - <> - DeepWiki index exposes the topic map for system architecture, CLI, SDK, macros, BrowserStack, templates, profiling, CI, examples, dependencies, and glossary pages. - , - <>The “Copy page” action copies this authored page or sends it to an assistant; pair that with DeepWiki when you want an AI to answer from both local docs and source-indexed context., - ], - }, - ], - quickstart: [ - { - title: 'Command path', - body: [ - <>The fast path is install, initialize config, check prerequisites, build a target runner, then run locally or through a provider., - ], - code: { - language: 'bash', - value: `cargo install mobench -cargo mobench init -cargo mobench doctor -cargo mobench build --target android --release -cargo mobench run --local --function fibonacci_30 --iterations 100 --warmup 10 -cargo mobench ci run --target android --browserstack --output target/mobench/ci`, - }, - }, - { - title: 'Local targets', - body: [ - <>Local does not only mean a physical phone. Android can run through connected devices or Android emulators managed by Android Studio and ADB. iOS can run through Xcode-managed simulators or connected iOS devices. BrowserStack is the hosted-device path, useful for shared CI and reproducible remote devices., - ], - }, - { - title: 'First benchmark', - code: { - language: 'rust', - value: `use mobench_sdk::benchmark; - -#[benchmark] -pub fn fibonacci_30() { - let result = fibonacci(30); - std::hint::black_box(result); -} - -fn setup_data() -> Vec { - vec![42; 1024 * 1024] -} - -#[benchmark(setup = setup_data)] -pub fn checksum(data: &Vec) { - let sum: u64 = data.iter().map(|byte| *byte as u64).sum(); - std::hint::black_box(sum); -}`, - }, - }, - ], - install: [ - { - title: 'Copy-paste install', - body: [ - <>Use the matching section for your operating system to install ADB/platform tools, Android Studio, Rust, and mobench. Xcode and iOS simulator support are macOS-only; the command opens Apple installers where an interactive sign-in is required., - ], - codeVariants: INSTALL_COMMANDS, - }, - { - title: 'Rust and CLI', - bullets: [ - <>Install Rust with rustup. Use Rust 2024-compatible toolchains; current workspace release line is 0.1.43 and documented MSRV is Rust 1.85., - <>Install CLI cargo install mobench or build from repository when developing mobench itself., - <>Add mobench-sdk, inventory, and required crate types to benchmark crates., - ], - code: { - language: 'toml', - value: `[dependencies] -mobench-sdk = "0.1.43" -inventory = "0.3" - -[lib] -crate-type = ["cdylib", "staticlib", "lib"]`, - }, - }, - { - title: 'Android and iOS', - bullets: [ - <>Android Studio is the normal route for installing Android SDKs, managing emulators, and exposing devices through ADB., - <>Xcode provides command-line tools, simulators, signing, and connected-device support for iOS generated runner projects., - <>Use cargo mobench check --target android and cargo mobench check --target ios before chasing build failures., - ], - }, - { - title: 'BrowserStack credentials', - body: [ - <>BrowserStack is optional local development, but required hosted real-device CI jobs. mobench uses App Automate when runs need BrowserStack Android Espresso or iOS XCUITest execution., - ], - code: { - language: 'bash', - value: `export BROWSERSTACK_USERNAME="your_username" -export BROWSERSTACK_ACCESS_KEY="your_access_key" -export BROWSERSTACK_PROJECT="mobile-benchmarks"`, - }, - }, - ], - concepts: [ - { - title: 'Product surfaces', - bullets: [ - <>Benchmark execution builds mobile artifacts, runs benchmarks host-only, locally, or on BrowserStack, and writes report artifacts., - <>Local native profiling runs capture plans and produces normalized profile manifests, flamegraph artifacts, semantic phase summaries, and diffs., - ], - }, - { - title: 'Crates', - bullets: [ - <>mobench: CLI, BrowserStack client, CI and reporting entry points, and programmatic command types., - <>mobench-sdk: timing harness, benchmark registry, generated runner support, mobile builders, profiling helpers, UniFFI, and native C ABI., - <>mobench-macros: the #[benchmark] proc macro., - ], - }, - { - title: 'Artifact flow', - body: [ - <>Runs produce normalized artifacts under target/mobench/. BrowserStack fetches also place raw provider artifacts under a BrowserStack output root. Profiling creates trace events and flamegraph-ready bundles., - ], - }, - ], - authoring: [ - { - title: 'Macro shape', - body: [ - <>Simple benchmark functions take no parameters, return (), and should use std::hint::black_box for values the optimizer might otherwise erase., - ], - code: { - language: 'rust', - value: `use mobench_sdk::benchmark; - -#[benchmark] -pub fn checksum_bench() { - let data = [1u8; 1024]; - let sum: u64 = data.iter().map(|b| *b as u64).sum(); - std::hint::black_box(sum); -}`, - }, - }, - { - title: 'Discovery', - bullets: [ - <>Benchmarks are registered at compile time through inventory., - <>Generated runners discover registered functions through SDK registry APIs., - <>Macro validation rejects unsupported signatures early, including parameters on simple benchmarks or non-unit returns., - ], - }, - { - title: 'Best practices', - bullets: [ - <>Keep input generation outside measured work unless the input generation is itself what you are benchmarking., - <>Use per-iteration setup for mutable or consumed input., - <>Prefer stable iterations and warmup settings in config so CI reports are comparable., - ], - }, - ], - 'setup-teardown': [ - { - title: 'Setup modes', - body: [ - <>Setup runs before measured samples and passes the setup value into the benchmark. Per-iteration setup runs before each measured iteration and is useful for mutable input., - ], - code: { - language: 'rust', - value: `fn create_input() -> Vec { - vec![42; 1024 * 1024] -} - -#[benchmark(setup = create_input)] -pub fn process_data(data: &Vec) { - std::hint::black_box(data.iter().sum::()); -} - -fn unsorted_vec() -> Vec { - (0..1000).rev().collect() -} - -#[benchmark(setup = unsorted_vec, per_iteration)] -pub fn sort_vec(mut data: Vec) { - data.sort(); - std::hint::black_box(data); -}`, - }, - }, - { - title: 'Teardown', - body: [ - <>Teardown receives setup state after measured execution and is intended for cleanup such as temporary files, handles, connections, or test data. Teardown itself is outside the measured sample., - ], - code: { - language: 'rust', - value: `#[benchmark(setup = setup_temp_file, teardown = cleanup_temp_file)] -pub fn parse_file(input: &TempFile) { - parse(input.path()); -}`, - }, - }, - { - title: 'Compatibility', - bullets: [ - <>Simple benchmarks keep their existing behavior., - <>Setup benchmarks accept one input compatible with the setup return type., - <>Native runner paths serialize specs and reports through the same public contracts., - ], - }, - ], - sdk: [ - { - title: 'Dependencies', - body: [ - <>Use the full SDK for normal benchmark crates. Runtime-only registry crates can use narrower feature flags., - ], - code: { - language: 'toml', - value: `[dependencies] -mobench-sdk = "0.1.43" -inventory = "0.3" - -# Narrow registry-only form: -mobench-sdk = { version = "0.1.43", default-features = false, features = ["registry"] }`, - }, - }, - { - title: 'Runtime APIs', - bullets: [ - <>BenchSpec names the benchmark and sets measured iterations and warmup iterations., - <>BenchSample records wall-clock duration plus optional CPU and memory measurements., - <>BenchReport contains samples, statistics helpers, semantic phases, and timeline spans., - <>Target, FfiBackend, builders, and runner report types shape generated runner behavior., - ], - }, - { - title: 'Choosing an FFI backend', - body: [ - <>If you need generated bindings, choose between BoltFFI and UniFFI based on maturity versus overhead., - <>The practical recommendation for performance-sensitive mobile benchmarks is still to write native FFI bindings for the benchmark boundary. AI agents make those bindings much easier to build, test, review, and maintain, and native bindings keep benchmark overhead explicit instead of hiding it inside a general-purpose binding layer., - ], - bullets: [ - <>BoltFFI: fast, newer, and designed for smaller overhead than UniFFI, but not as mature yet., - <>UniFFI: more mature and battle-tested, but usually carries larger binding overhead., - <>Native FFI: recommended for serious benchmark paths because Android/iOS callers can use the narrow ABI the benchmark actually needs., - ], - }, - { - title: 'Native C ABI', - body: [ - <>The native C ABI lets generated runners call the benchmark crate directly without UniFFI bindings in the measured path., - ], - code: { - language: 'rust', - value: `mobench_sdk::export_native_c_abi!(); - -// Exports: -// mobench_run_benchmark_json(spec_ptr, spec_len, out) -> i32 -// mobench_free_buf(buf) -// mobench_last_error_message() -> *const c_char`, - }, - }, - ], - build: [ - { - title: 'Prerequisites', - bullets: [ - <>Android: install SDK tooling, make ADB available, and create emulator profiles in Android Studio when simulator-style local runs are needed., - <>iOS: install Xcode command-line tools and use Xcode to manage simulators, signing, and connected devices., - <>Run cargo mobench check for target-specific diagnostics before build commands., - ], - }, - { - title: 'Build commands', - code: { - language: 'bash', - value: `cargo mobench check --target android -cargo mobench check --target ios -cargo mobench build --target android --progress -cargo mobench build --target ios --progress -cargo mobench build --target both --release`, - }, - }, - { - title: 'Outputs', - bullets: [ - <>Android builds produce generated projects, APK or test APK artifacts, native libraries, and runner metadata., - <>iOS builds produce generated Xcode projects, simulator and device slices, test bundles, and runner metadata., - <>Outputs default to target/mobench/; release builds are smaller and better suited for uploads., - ], - }, - ], - 'local-devices': [ - { - title: 'Android', - bullets: [ - <>Use physical phones through ADB when you need device-specific CPU, memory, thermal, or ABI behavior., - <>Use Android Studio emulators for fast local iteration, SDK compatibility checks, and repeatable development smoke runs., - <>ADB is the local control layer for listing devices, installing generated APKs, and running generated Android test harnesses., - ], - code: { - language: 'bash', - value: `adb devices -cargo mobench build --target android -cargo mobench run --target android --local --function my_crate::checksum_bench`, - }, - }, - { - title: 'iOS', - bullets: [ - <>Use Xcode simulators for local iteration without requiring a physical iPhone., - <>Use connected iOS devices when hardware behavior, signing, device OS version, or performance fidelity matters., - <>Xcode owns simulator runtimes, device trust, signing, XCUITest execution generated iOS harnesses., - ], - }, - { - title: 'Host-only smoke runs', - body: [ - <>Host-only runs are useful for verifying benchmark discovery and report wiring without building mobile artifacts. They are not a replacement for measuring mobile FFI and scheduler behavior., - ], - code: { - language: 'bash', - value: `cargo mobench run \\ - --target android \\ - --function my_bench_crate::checksum_bench \\ - --local-only \\ - --iterations 100 \\ - --warmup 10`, - }, - }, - ], - browserstack: [ - { - title: 'Credentials', - body: [ - <>BrowserStack credentials can come from environment variables or local configuration. For mobench CI, they enable App Automate hosted real-device runs. Keep credentials out of committed files., - ], - code: { - language: 'bash', - value: `export BROWSERSTACK_USERNAME="your_username" -export BROWSERSTACK_ACCESS_KEY="your_access_key" -export BROWSERSTACK_PROJECT="mobile-benchmarks"`, - }, - }, - { - title: 'Device resolution', - bullets: [ - <>Use explicit BrowserStack App Automate devices for one-off runs., - <>Use matrix files and tags when CI jobs need stable cross-device coverage., - <>Resolution commands help validate BrowserStack availability before running expensive hosted-device jobs., - ], - code: { - language: 'bash', - value: `cargo mobench devices --platform android -cargo mobench devices resolve --platform android --device-matrix .github/mobench-devices.yml -cargo mobench ci run --target android --device-matrix .github/mobench-devices.yml --fetch`, - }, - }, - { - title: 'CI contract', - bullets: [ - <>CI runs write summary.json, summary.md, and results.csv., - <>PR reporting can post sticky summaries and compare baselines., - <>Fetch commands retrieve raw BrowserStack artifacts after hosted runs., - <>Use App Automate REST API docs when wiring custom artifact fetchers or provider debugging., - ], - }, - { - title: 'Split-sample merge', - body: [ - <>For long or fragile BrowserStack lanes, run each measured sample as a separate ci run job, store the outputs as sample-*/summary.json, then merge them back into the standard CI contract., - ], - bullets: [ - <>Every input must contain exactly one device, one benchmark, and one measured sample., - <>The command validates the requested function, device, target consistency, and exact measured sample count., - <>Merged timing statistics, raw samples_ns, and resource columns are recomputed for downstream reports, plots, comparisons, and PR comments., - ], - code: { - language: 'bash', - value: `cargo mobench ci merge-split-runs \\ - --samples-dir target/mobench/ci/android/sample_fns__fibonacci/device/split \\ - --output-dir target/mobench/ci/android/sample_fns__fibonacci/device \\ - --function sample_fns::fibonacci \\ - --device "Google Pixel 7-13.0" \\ - --iterations 5 \\ - --warmup 1`, - }, - }, -], -'app-automate': [ - { - title: 'Account and pricing', - body: [ - <>BrowserStack App Automate is hosted real-device automation product mobench uses generated Android Espresso and iOS XCUITest harnesses instead local devices., - <>Create a BrowserStack account, then copy username and access key into CI secrets or local environment variables. Pricing and trial limits change over time, so use BrowserStack's own product and pricing pages as the source of truth., - ], - bullets: [ - <>Product page: BrowserStack App Automate., - <>Pricing page: BrowserStack pricing., - <>Trial FAQ: trial entitlements., - ], - code: { - language: 'bash', - value: `export BROWSERSTACK_USERNAME="your_username" -export BROWSERSTACK_ACCESS_KEY="your_access_key" -export BROWSERSTACK_PROJECT="mobench"`, - }, - }, - { - title: 'Espresso on Android', - body: [ - <>Espresso is Google's Android UI testing framework. In mobench, generated Android runner packaged application under test plus Android instrumentation test APK. BrowserStack Espresso App Automate receives both files, runs suite on real Android devices, exposes status, logs, video, device logs, artifacts through App Automate dashboard API., - ], - bullets: [ - <>Upload app as .apk or .aab to POST /app-automate/espresso/v2/app., - <>Upload Espresso test suite APK to POST /app-automate/espresso/v2/test-suite., - <>Start execution with POST /app-automate/espresso/v2/build, passing app, testSuite, and Android devices., - ], - code: { - language: 'bash', - value: `# Upload Android app -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/app" \\ - -F "file=@target/mobench/android/app-release.apk" \\ - -F "custom_id=mobench-android-app" - -# Upload Espresso test APK -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/test-suite" \\ - -F "file=@target/mobench/android/app-release-androidTest.apk" \\ - -F "custom_id=mobench-android-tests" - -# Start an Espresso build -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \\ - -H "Content-Type: application/json" \\ - -d '{"app":"mobench-android-app","testSuite":"mobench-android-tests","project":"mobench","devices":["Google Pixel 7-13.0"]}'`, - }, - }, - { - title: 'XCUITest on iOS', - body: [ - <>XCUITest is Apple's UI testing framework for iOS apps built with Xcode. In mobench, generated iOS runner is built into installable app XCUITest bundle archive. BrowserStack XCUITest App Automate runs suite on real iOS devices returns build IDs plus per-session logs media., - ], - bullets: [ - <>Upload iOS app as an .ipa to POST /app-automate/xcuitest/v2/app., - <>Upload XCUITest suite as .zip to POST /app-automate/xcuitest/v2/test-suite., - <>Start execution with POST /app-automate/xcuitest/v2/build, passing app, testSuite, and iOS devices., - ], - code: { - language: 'bash', - value: `# Upload iOS app -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/app" \\ - -F "file=@target/mobench/ios/MobenchRunner.ipa" \\ - -F "custom_id=mobench-ios-app" - -# Upload XCUITest bundle -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/test-suite" \\ - -F "file=@target/mobench/ios/MobenchRunnerUITests.zip" \\ - -F "custom_id=mobench-ios-tests" - -# Start an XCUITest build -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X POST "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/build" \\ - -H "Content-Type: application/json" \\ - -d '{"app":"mobench-ios-app","testSuite":"mobench-ios-tests","project":"mobench","devices":["iPhone 14-16"]}'`, - }, - }, - { - title: 'API lifecycle', - body: [ - <>The App Automate REST API uses JSON over the base URL https://api-cloud.browserstack.com/. The usual CI lifecycle uploads app and test-suite artifacts, creates a build, polls build or session status, fetches logs and media, then normalizes results into mobench summaries., - ], - bullets: [ - <>Authentication uses BrowserStack username and access key over basic auth., - <>Uploads return bs://... URLs and optional custom_id aliases. Use custom IDs in CI when scripts should refer to the latest uploaded app or test suite without rewriting every build request., - <>A build represents execution of a framework-specific test suite on one or more devices; BrowserStack returns build_id for status and artifact lookup., - <>CI should avoid upload loops and respect BrowserStack API limits., - ], - code: { - language: 'bash', - value: `curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X GET "https://api-cloud.browserstack.com/app-automate/devices.json" - -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X GET "https://api-cloud.browserstack.com/app-automate/espresso/v2/builds" - -curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \\ - -X GET "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/builds"`, - }, - }, - { - title: 'Devices', - body: [ - <>BrowserStack App Automate runs on physical devices hosted by BrowserStack, not emulators or simulators. Pick exact names and OS versions from BrowserStack App Automate devices, then keep CI matrices small enough for your plan's parallel capacity., - ], - bullets: [ - <>Use GET /app-automate/devices.json when generating or validating mobench device matrices., - <>The device API response includes OS, OS version, device name, real-device flag, tier, and limit fields., - ], - }, -], -profiling: [ - { - title: 'Capability matrix', - bullets: [ - <>Local native profiling is the supported path for native stack capture and flamegraph-style artifacts., - <>BrowserStack benchmark runs can still report timing and resource metrics, but native stack capture and flamegraph generation are local capabilities., - <>Profile commands use the same target, device, matrix, and function concepts as benchmark runs., - ], - }, - { - title: 'Artifacts', - body: [ - <>Each profiling session writes a run-specific directory under target/mobench/profile/<run-id>/ and refreshes convenience copies under target/mobench/profile/., - ], - bullets: [ - <>profile.json: normalized manifest with capture metadata, native capture records, semantic phases, and viewer hints., - <>summary.md: human-readable profile summary., - <>artifacts/processed/stacks.folded: folded stack input used for flamegraph rendering., - <>artifacts/processed/native-report.txt: backend-specific native profiling report., - <>artifacts/processed/flamegraph.full.svg: full-process static flamegraph., - <>artifacts/processed/flamegraph.focused.svg: benchmark-focused static flamegraph., - <>artifacts/processed/flamegraph.html: interactive viewer with mode switching, timeline, search, selection, and legend controls., - <>artifacts/semantic/phases.json: semantic phase data when benchmarks emit phase markers., - ], - code: { - language: 'bash', - value: `cargo mobench profile run \\ - --target android \\ - --function sample_fns::fibonacci \\ - --provider local \\ - --backend android-native \\ - --trace-events-output target/mobench/profile/trace-events.json - -cargo mobench profile summarize \\ - --profile target/mobench/profile/profile.json - -cargo mobench profile diff \\ - --baseline target/mobench/profile/baseline/profile.json \\ - --candidate target/mobench/profile/candidate/profile.json \\ - --normalize`, - }, - }, - { - title: 'Flamegraph viewer', - body: [ - <>Open artifacts/processed/flamegraph.html after profile run or profile diff to inspect the interactive flamegraph. The viewer combines the full-process stack view, a benchmark-focused view, optional harness timeline spans, source-link metadata when symbolization can recover it, and a right-side self-time frame list., - <>For differential profiles, red means a frame is hotter in the candidate profile and blue means it is hotter in the baseline. Frame widths follow candidate sample counts, so the widest red frames are usually the first places to inspect., - ], - bullets: [ - <>Benchmark Only: focus the flamegraph on frames below mobench benchmark anchors, hiding unrelated process/runtime work., - <>Full Process: show all sampled stacks captured by the backend, useful for spotting runtime, FFI, allocator, or harness overhead., - <>Timeline: show chronological harness spans such as warmup, measured benchmark iterations, teardown, and exact harness duration., - <>Back, Forward, and Reset: navigate zoom history and return to the full root., - <>Fullscreen: expand the viewer when frame labels or deep stacks need more room., - <>Legend: explain color semantics, differential heat, and sample-width meaning., - <>Search: find frames by function/module text, then zoom or inspect matching stacks., - <>Self time: use the right rail to inspect the highest self-sample frames; click a frame in the graph to update selection details., - ], - image: { - src: '/assets/flamegraph-viewer.png', - alt: 'Screenshot of the mobench flamegraph viewer showing benchmark-only and full-process modes, timeline spans, search controls, and the self-time frame list.', - caption: 'The generated flamegraph viewer lets you switch between benchmark-only and full-process views, inspect timeline spans, search stack frames, and use the self-time rail to find hot functions.', - }, - code: { - language: 'bash', - value: `# Open the latest interactive viewer after profile run. -open target/mobench/profile/artifacts/processed/flamegraph.html - -# Open a specific run's viewer. -open target/mobench/profile//artifacts/processed/flamegraph.html - -# Open a differential viewer after profile diff. -open target/mobench/profile/diff/artifacts/processed/flamegraph.html`, - }, - }, - { - title: 'Phases', - body: [ - <>Semantic phases label meaningful periods inside benchmark execution so trace-event summaries and the viewer timeline can distinguish setup, warmup, measured iterations, teardown, and runner overhead., - ], - code: { - language: 'rust', - value: `use mobench_sdk::{benchmark, profile_phase}; - -#[benchmark] -pub fn prove_and_verify() { - let proof = profile_phase("prove", || prove()); - profile_phase("verify", || verify(&proof)); -}`, - }, - }, -], - reports: [ - { - title: 'Output layout', - bullets: [ - <>summary.json: normalized machine-readable summary., - <>summary.md: human-readable run summary for CI and PR comments., - <>results.csv: rows for spreadsheet and dashboard ingestion., - <>Optional plot SVGs and profiling bundles live beside run outputs when requested., - ], - }, - { - title: 'Split-run outputs', - bullets: [ - <>Release 0.1.43 can merge sample-*/summary.json inputs from one-sample CI jobs into the same summary.json, summary.md, and results.csv contract., - <>The merged JSON preserves raw samples, recomputes min, max, mean, median, and p95 timing statistics, and combines available resource measurements., - <>Existing report, plot, comparison, and PR-comment tooling can consume merged output without a separate format adapter., - ], - }, - { - title: 'Report helpers', - code: { - language: 'bash', - value: `cargo mobench summary target/mobench/results.json -cargo mobench summary --format json target/mobench/results.json -cargo mobench summary --format csv target/mobench/results.json -cargo mobench report summarize --summary target/mobench/ci/summary.json -cargo mobench report github --pr 123 --summary target/mobench/ci/summary.json`, - }, - }, - { - title: 'Fixtures', - body: [ - <>The repository examples include basic, FFI, and profiling fixtures so downstream tooling can validate summary and trace-event parsing without running device jobs., - ], - }, - ], - 'cli-reference': [ - { - title: 'Command model', - body: [ - <>Use mobench directly, or cargo mobench when installed as a Cargo subcommand. Commands share the same global flags and most commands resolve project layout from explicit flags, config files, Cargo metadata, or workspace defaults., - ], - bullets: [ - <>--dry-run: print the actions that would run without mutating files, invoking providers, or publishing reports., - <>-v / --verbose: print verbose command output and invoked tool commands., - <>--yes: assume yes for overwrite prompts., - <>--non-interactive: disable prompts and fail instead of asking., - <>Common targets: android, ios, or both where supported. BrowserStack run targets use android or ios., - <>Common output formats: text, json, csv, table, markdown, depending on command., - ], - code: { - language: 'text', - value: `mobench [GLOBAL OPTIONS] -cargo mobench [GLOBAL OPTIONS] - -Global options: - --dry-run Print what would be done without doing it. - -v, --verbose Print verbose command/tool output. - --yes Assume yes for overwrite prompts. - --non-interactive Disable prompts and fail instead. - -h, --help Print command help. - -V, --version Print version. - -Top-level commands: - run, init, plan, config, doctor, ci, fetch, compare, init-sdk, build, - package-ipa, package-xcuitest, list, verify, summary, devices, fixture, - report, profile, check`, - }, - }, - { - title: 'Benchmark runs', - body: [ - <>Use run for a one-off benchmark execution and ci run for the stable CI contract. Both can build mobile artifacts, run host-only smoke tests, target BrowserStack devices, fetch artifacts, compare baselines, and write machine-readable outputs., - ], - code: { - language: 'text', - value: `mobench run -Purpose: - Build, package, execute, and optionally fetch benchmark results for a single run. - -Usage: - mobench run [OPTIONS] - -Inputs and flags: - --target Platform to run. - --function Fully-qualified Rust benchmark function. - --project-root Root containing mobench.toml or Cargo workspace. - --crate-path Benchmark crate containing Cargo.toml. - --iterations Measured iterations. Default: command/config dependent. - --warmup Warmup iterations. Default: command/config dependent. - --devices BrowserStack device label; repeatable. - --device-matrix YAML device matrix. - --device-tags Device matrix tags; repeatable. - --config Run config file. - --output JSON report path. - --summary-csv Write CSV summary beside JSON. - --ci Enable CI behavior: summaries, JUnit, regression exits. - --baseline Baseline summary source. - --regression-threshold-pct Regression threshold. Default: 5. - --junit JUnit XML output path. - --local-only Skip mobile builds and run host harness only. - --release Release mobile build; recommended for BrowserStack. - --ios-app Existing .ipa or zipped .app for BrowserStack XCUITest. - --ios-test-suite Existing XCUITest .zip or .ipa. - --ios-deployment-target Generated iOS app/test deployment target. - --ios-runner Generated iOS runner template. - --android-benchmark-timeout-secs Android harness watchdog timeout. - --android-heartbeat-interval-secs Android harness heartbeat interval. - --fetch Fetch BrowserStack artifacts after run. - --fetch-output-dir Default: target/browserstack. - --fetch-poll-interval-secs Default: 5. - --fetch-timeout-secs Default: 300. - --progress Simplified step-by-step progress. - -Outputs: - JSON report at --output when provided. - Optional CSV when --summary-csv is set. - Optional JUnit XML when --junit is set. - BrowserStack raw artifacts under --fetch-output-dir when --fetch is set. - Provider logs, status, and normalized benchmark summaries. - -Examples: - cargo mobench run --target android --function sample_fns::fibonacci --local-only - cargo mobench run --target android --function sample_fns::fibonacci --devices "Google Pixel 7-13.0" --release --fetch - -mobench ci run -Purpose: - Run the stable CI contract for one or more benchmark functions. - -Usage: - mobench ci run --target [OPTIONS] - -Additional CI flags: - --functions Multiple benchmark functions; comma-separated. - --output-dir CI contract output directory. Default: target/mobench/ci. - --requested-by Metadata: actor/user that requested run. - --pr-number Metadata: pull request number. - --request-command Metadata: original command. - --mobench-ref Metadata: mobench git ref/sha. - --plots Plot behavior. Default: auto. - -Outputs: - target/mobench/ci/summary.json Machine-readable CI summary. - target/mobench/ci/summary.md Markdown summary for logs or PR comments. - target/mobench/ci/results.csv Tabular result rows. - Optional JUnit XML, plots, fetched BrowserStack artifacts. - -Examples: - cargo mobench ci run --target android --function sample_fns::fibonacci --local-only - cargo mobench ci run --target both --functions sample_fns::fibonacci,sample_fns::sort --device-tags smoke --release --fetch`, - }, - }, - { - title: 'Build and project setup', - body: [ - <>These commands create config files, project templates, generated mobile runners, packaging artifacts, and validation reports before a benchmark run., - ], - code: { - language: 'text', - value: `mobench init -Purpose: - Scaffold a base run config. -Usage: - mobench init [--output ] [--target ] -Defaults: - --output bench-config.toml - --target android -Outputs: - A TOML config file suitable for run/ci workflows. - -mobench plan -Purpose: - Generate a sample BrowserStack device matrix. -Usage: - mobench plan [--output ] -Default: - --output device-matrix.yaml -Outputs: - YAML device matrix with platform/profile entries. - -mobench init-sdk -Purpose: - Generate an SDK benchmark project template. -Usage: - mobench init-sdk --target [--project-name ] [--output-dir ] [--examples] -Defaults: - --project-name bench-project - --output-dir . -Outputs: - Cargo project files, mobile integration scaffolding, optional example benchmarks. - -mobench build -Purpose: - Build generated Android/iOS benchmark artifacts from a resolved benchmark crate. -Usage: - mobench build --target [OPTIONS] -Flags: - --release Release build. - --project-root Root containing mobench.toml or Cargo workspace. - --output-dir Default: target/mobench. - --crate-path Benchmark crate; default auto-detects bench-mobile/ or crates/{crate}. - --ios-deployment-target Generated iOS deployment target. - --ios-runner Generated iOS runner template. - --progress Simplified progress output. -Outputs: - Android Gradle runner, APK/test APKs, native libs, bench_spec.json. - iOS Xcode runner, xcframework/native libs, app/test artifacts. - -mobench package-ipa -Purpose: - Package generated iOS app as an IPA for distribution testing or BrowserStack. -Usage: - mobench package-ipa [--scheme ] [--method ] [--project-root ] [--crate-path ] [--output-dir ] -Defaults: - --scheme BenchRunner - --method adhoc - --output-dir target/mobench -Outputs: - IPA or zipped app artifact under the iOS output directory. - -mobench package-xcuitest -Purpose: - Package generated XCUITest runner for BrowserStack upload. -Usage: - mobench package-xcuitest [--scheme ] [--project-root ] [--crate-path ] [--output-dir ] -Defaults: - --scheme BenchRunner - --output-dir target/mobench -Outputs: - target/mobench/ios/BenchRunnerUITests.zip by default. - -mobench check -Purpose: - Validate prerequisites before mobile builds. -Usage: - mobench check --target [--format ] -Checks: - Android: ANDROID_NDK_HOME, cargo-ndk, Android Rust targets. - iOS: Xcode, xcodegen, iOS Rust targets. - Both: cargo, rustup. -Outputs: - Text diagnostics or JSON diagnostics. - -mobench doctor -Purpose: - Validate local and CI configuration, including optional BrowserStack credentials. -Usage: - mobench doctor [--target ] [--config ] [--device-matrix ] [--device-tags ] [--browserstack [true|false]] [--format ] -Defaults: - --target both - --browserstack true - --format text -Outputs: - Human-readable or JSON preflight diagnostics.`, - }, - }, - { - title: 'CI commands', - body: [ - <>CI helpers scaffold workflows, summarize offline results, and create GitHub Check Runs. Use ci run for the actual benchmark execution contract., - ], - code: { - language: 'text', - value: `mobench ci init -Purpose: - Generate a GitHub Actions workflow and local action wrapper. -Usage: - mobench ci init [--workflow ] [--action-dir ] -Defaults: - --workflow .github/workflows/mobile-bench.yml - --action-dir .github/actions/mobench -Outputs: - Workflow YAML and local composite/action files. - -mobench ci summarize -Purpose: - Summarize benchmark results and optional BrowserStack metrics. -Usage: - mobench ci summarize [--build-id ] [--results-dir ] [--output-format ] [--output-file ] [--platform ] -Defaults: - --output-format table -Inputs: - --results-dir should contain summary.json/CSV results. - --build-id enriches with BrowserStack device metrics when paired with --results-dir. -Outputs: - Terminal table, Markdown, or JSON summary; optional output file. - -mobench ci merge-split-runs -Purpose: - Merge one-measured-sample CI summaries into the standard CI output contract. -Usage: - mobench ci merge-split-runs --samples-dir --output-dir --function --device