From 31f58ae699b83a5ace0b664116eb0d5ace89e72d Mon Sep 17 00:00:00 2001 From: AlexYue Date: Fri, 20 Mar 2026 14:11:56 +0800 Subject: [PATCH] docs: add VitePress documentation site (#112) - Add VitePress with full navigation, sidebar, i18n (en/zh), local search - Create 50+ doc pages: guide, adapters (browser + desktop), developer, advanced - Migrate content from README.md, CONTRIBUTING.md, TESTING.md, CDP.md, CLI-ELECTRON.md - Migrate all 11 adapter READMEs to structured documentation - Add new pages: architecture, yaml-adapter guide, ts-adapter guide, ai-workflow - Add GitHub Actions workflow for deploying to GitHub Pages - Add Chinese locale pages (getting-started, installation, browser-bridge, etc.) - Add docs:dev, docs:build, docs:preview npm scripts --- .github/workflows/docs.yml | 52 + .gitignore | 4 + docs/.vitepress/config.mts | 193 ++ docs/adapters/browser/apple-podcasts.md | 28 + docs/adapters/browser/bbc.md | 26 + docs/adapters/browser/bilibili.md | 38 + docs/adapters/browser/boss.md | 28 + docs/adapters/browser/coupang.md | 28 + docs/adapters/browser/ctrip.md | 27 + docs/adapters/browser/github.md | 26 + docs/adapters/browser/hackernews.md | 26 + docs/adapters/browser/linkedin.md | 27 + docs/adapters/browser/reddit.md | 41 + docs/adapters/browser/reuters.md | 27 + docs/adapters/browser/smzdm.md | 27 + docs/adapters/browser/twitter.md | 47 + docs/adapters/browser/v2ex.md | 32 + docs/adapters/browser/weibo.md | 27 + docs/adapters/browser/xiaohongshu.md | 32 + docs/adapters/browser/xiaoyuzhou.md | 28 + docs/adapters/browser/xueqiu.md | 32 + docs/adapters/browser/yahoo-finance.md | 26 + docs/adapters/browser/youtube.md | 29 + docs/adapters/browser/zhihu.md | 30 + docs/adapters/desktop/antigravity.md | 46 + docs/adapters/desktop/chatgpt.md | 43 + docs/adapters/desktop/chatwise.md | 38 + docs/adapters/desktop/codex.md | 32 + docs/adapters/desktop/cursor.md | 33 + docs/adapters/desktop/discord.md | 28 + docs/adapters/desktop/feishu.md | 20 + docs/adapters/desktop/neteasemusic.md | 31 + docs/adapters/desktop/notion.md | 29 + docs/adapters/desktop/wechat.md | 28 + docs/adapters/index.md | 49 + docs/advanced/cdp.md | 103 + docs/advanced/download.md | 63 + docs/advanced/electron.md | 125 ++ docs/advanced/remote-chrome.md | 72 + docs/developer/ai-workflow.md | 66 + docs/developer/architecture.md | 90 + docs/developer/contributing.md | 136 ++ docs/developer/testing.md | 237 +++ docs/developer/ts-adapter.md | 87 + docs/developer/yaml-adapter.md | 108 + docs/guide/browser-bridge.md | 38 + docs/guide/getting-started.md | 56 + docs/guide/installation.md | 37 + docs/guide/troubleshooting.md | 56 + docs/index.md | 35 + docs/zh/adapters/index.md | 5 + docs/zh/advanced/cdp.md | 3 + docs/zh/developer/contributing.md | 24 + docs/zh/guide/browser-bridge.md | 25 + docs/zh/guide/getting-started.md | 40 + docs/zh/guide/installation.md | 37 + docs/zh/index.md | 29 + package-lock.json | 2405 ++++++++++++++++++++++- package.json | 8 +- 59 files changed, 5138 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/.vitepress/config.mts create mode 100644 docs/adapters/browser/apple-podcasts.md create mode 100644 docs/adapters/browser/bbc.md create mode 100644 docs/adapters/browser/bilibili.md create mode 100644 docs/adapters/browser/boss.md create mode 100644 docs/adapters/browser/coupang.md create mode 100644 docs/adapters/browser/ctrip.md create mode 100644 docs/adapters/browser/github.md create mode 100644 docs/adapters/browser/hackernews.md create mode 100644 docs/adapters/browser/linkedin.md create mode 100644 docs/adapters/browser/reddit.md create mode 100644 docs/adapters/browser/reuters.md create mode 100644 docs/adapters/browser/smzdm.md create mode 100644 docs/adapters/browser/twitter.md create mode 100644 docs/adapters/browser/v2ex.md create mode 100644 docs/adapters/browser/weibo.md create mode 100644 docs/adapters/browser/xiaohongshu.md create mode 100644 docs/adapters/browser/xiaoyuzhou.md create mode 100644 docs/adapters/browser/xueqiu.md create mode 100644 docs/adapters/browser/yahoo-finance.md create mode 100644 docs/adapters/browser/youtube.md create mode 100644 docs/adapters/browser/zhihu.md create mode 100644 docs/adapters/desktop/antigravity.md create mode 100644 docs/adapters/desktop/chatgpt.md create mode 100644 docs/adapters/desktop/chatwise.md create mode 100644 docs/adapters/desktop/codex.md create mode 100644 docs/adapters/desktop/cursor.md create mode 100644 docs/adapters/desktop/discord.md create mode 100644 docs/adapters/desktop/feishu.md create mode 100644 docs/adapters/desktop/neteasemusic.md create mode 100644 docs/adapters/desktop/notion.md create mode 100644 docs/adapters/desktop/wechat.md create mode 100644 docs/adapters/index.md create mode 100644 docs/advanced/cdp.md create mode 100644 docs/advanced/download.md create mode 100644 docs/advanced/electron.md create mode 100644 docs/advanced/remote-chrome.md create mode 100644 docs/developer/ai-workflow.md create mode 100644 docs/developer/architecture.md create mode 100644 docs/developer/contributing.md create mode 100644 docs/developer/testing.md create mode 100644 docs/developer/ts-adapter.md create mode 100644 docs/developer/yaml-adapter.md create mode 100644 docs/guide/browser-bridge.md create mode 100644 docs/guide/getting-started.md create mode 100644 docs/guide/installation.md create mode 100644 docs/guide/troubleshooting.md create mode 100644 docs/index.md create mode 100644 docs/zh/adapters/index.md create mode 100644 docs/zh/advanced/cdp.md create mode 100644 docs/zh/developer/contributing.md create mode 100644 docs/zh/guide/browser-bridge.md create mode 100644 docs/zh/guide/getting-started.md create mode 100644 docs/zh/guide/installation.md create mode 100644 docs/zh/index.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..1402ea1 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,52 @@ +name: Deploy Docs + +on: + push: + branches: [main] + paths: ['docs/**'] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build docs + run: npm run docs:build + + - uses: actions/configure-pages@v4 + + - uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 38760ce..3e317f1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ dist/ .mcp.json *.log +# VitePress +docs/.vitepress/dist +docs/.vitepress/cache + # Extensions & Secrets *.pem *.crx diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts new file mode 100644 index 0000000..4fa4f8f --- /dev/null +++ b/docs/.vitepress/config.mts @@ -0,0 +1,193 @@ +import { defineConfig } from 'vitepress' + +export default defineConfig({ + title: 'OpenCLI', + description: 'Make any website or Electron App your CLI — AI-powered, account-safe, self-healing.', + + head: [ + ['meta', { property: 'og:title', content: 'OpenCLI Documentation' }], + ['meta', { property: 'og:description', content: 'Make any website or Electron App your CLI.' }], + ['meta', { name: 'twitter:card', content: 'summary_large_image' }], + ], + + locales: { + root: { + label: 'English', + lang: 'en', + themeConfig: { + nav: [ + { text: 'Guide', link: '/guide/getting-started' }, + { text: 'Adapters', link: '/adapters/' }, + { text: 'Developer', link: '/developer/contributing' }, + { text: 'Advanced', link: '/advanced/cdp' }, + ], + sidebar: { + '/guide/': [ + { + text: 'Guide', + items: [ + { text: 'Getting Started', link: '/guide/getting-started' }, + { text: 'Installation', link: '/guide/installation' }, + { text: 'Browser Bridge', link: '/guide/browser-bridge' }, + { text: 'Troubleshooting', link: '/guide/troubleshooting' }, + ], + }, + ], + '/adapters/': [ + { + text: 'Adapters Overview', + items: [ + { text: 'All Adapters', link: '/adapters/' }, + ], + }, + { + text: 'Browser Adapters', + collapsed: false, + items: [ + { text: 'Twitter / X', link: '/adapters/browser/twitter' }, + { text: 'Reddit', link: '/adapters/browser/reddit' }, + { text: 'Bilibili', link: '/adapters/browser/bilibili' }, + { text: 'Zhihu', link: '/adapters/browser/zhihu' }, + { text: 'Xiaohongshu', link: '/adapters/browser/xiaohongshu' }, + { text: 'Weibo', link: '/adapters/browser/weibo' }, + { text: 'YouTube', link: '/adapters/browser/youtube' }, + { text: 'Xueqiu', link: '/adapters/browser/xueqiu' }, + { text: 'V2EX', link: '/adapters/browser/v2ex' }, + { text: 'LinkedIn', link: '/adapters/browser/linkedin' }, + { text: 'Coupang', link: '/adapters/browser/coupang' }, + { text: 'BOSS Zhipin', link: '/adapters/browser/boss' }, + { text: 'Ctrip', link: '/adapters/browser/ctrip' }, + { text: 'Reuters', link: '/adapters/browser/reuters' }, + { text: 'SMZDM', link: '/adapters/browser/smzdm' }, + ], + }, + { + text: 'Public API Adapters', + collapsed: false, + items: [ + { text: 'HackerNews', link: '/adapters/browser/hackernews' }, + { text: 'GitHub', link: '/adapters/browser/github' }, + { text: 'BBC', link: '/adapters/browser/bbc' }, + { text: 'Apple Podcasts', link: '/adapters/browser/apple-podcasts' }, + { text: 'Xiaoyuzhou', link: '/adapters/browser/xiaoyuzhou' }, + { text: 'Yahoo Finance', link: '/adapters/browser/yahoo-finance' }, + ], + }, + { + text: 'Desktop Adapters', + collapsed: false, + items: [ + { text: 'Cursor', link: '/adapters/desktop/cursor' }, + { text: 'Codex', link: '/adapters/desktop/codex' }, + { text: 'Antigravity', link: '/adapters/desktop/antigravity' }, + { text: 'ChatGPT', link: '/adapters/desktop/chatgpt' }, + { text: 'ChatWise', link: '/adapters/desktop/chatwise' }, + { text: 'Notion', link: '/adapters/desktop/notion' }, + { text: 'Discord', link: '/adapters/desktop/discord' }, + { text: 'Feishu', link: '/adapters/desktop/feishu' }, + { text: 'WeChat', link: '/adapters/desktop/wechat' }, + { text: 'NeteaseMusic', link: '/adapters/desktop/neteasemusic' }, + ], + }, + ], + '/developer/': [ + { + text: 'Developer Guide', + items: [ + { text: 'Contributing', link: '/developer/contributing' }, + { text: 'Testing', link: '/developer/testing' }, + { text: 'Architecture', link: '/developer/architecture' }, + { text: 'YAML Adapter Guide', link: '/developer/yaml-adapter' }, + { text: 'TypeScript Adapter Guide', link: '/developer/ts-adapter' }, + { text: 'AI Workflow', link: '/developer/ai-workflow' }, + ], + }, + ], + '/advanced/': [ + { + text: 'Advanced', + items: [ + { text: 'Chrome DevTools Protocol', link: '/advanced/cdp' }, + { text: 'Electron Apps', link: '/advanced/electron' }, + { text: 'Remote Chrome', link: '/advanced/remote-chrome' }, + { text: 'Download Support', link: '/advanced/download' }, + ], + }, + ], + }, + }, + }, + zh: { + label: '中文', + lang: 'zh-CN', + link: '/zh/', + themeConfig: { + nav: [ + { text: '指南', link: '/zh/guide/getting-started' }, + { text: '适配器', link: '/zh/adapters/' }, + { text: '开发者', link: '/zh/developer/contributing' }, + { text: '进阶', link: '/zh/advanced/cdp' }, + ], + sidebar: { + '/zh/guide/': [ + { + text: '指南', + items: [ + { text: '快速开始', link: '/zh/guide/getting-started' }, + { text: '安装', link: '/zh/guide/installation' }, + { text: 'Browser Bridge', link: '/zh/guide/browser-bridge' }, + { text: '问题排查', link: '/zh/guide/troubleshooting' }, + ], + }, + ], + '/zh/adapters/': [ + { + text: '适配器概览', + items: [ + { text: '所有适配器', link: '/zh/adapters/' }, + ], + }, + ], + '/zh/developer/': [ + { + text: '开发者指南', + items: [ + { text: '贡献指南', link: '/zh/developer/contributing' }, + { text: '测试', link: '/zh/developer/testing' }, + ], + }, + ], + '/zh/advanced/': [ + { + text: '进阶', + items: [ + { text: 'Chrome DevTools Protocol', link: '/zh/advanced/cdp' }, + ], + }, + ], + }, + }, + }, + }, + + themeConfig: { + search: { + provider: 'local', + }, + + socialLinks: [ + { icon: 'github', link: 'https://github.com/jackwener/opencli' }, + { icon: 'npm', link: 'https://www.npmjs.com/package/@jackwener/opencli' }, + ], + + editLink: { + pattern: 'https://github.com/jackwener/opencli/edit/main/docs/:path', + text: 'Edit this page on GitHub', + }, + + footer: { + message: 'Released under the Apache-2.0 License.', + copyright: 'Copyright © 2024-present jackwener', + }, + }, +}) diff --git a/docs/adapters/browser/apple-podcasts.md b/docs/adapters/browser/apple-podcasts.md new file mode 100644 index 0000000..c133e08 --- /dev/null +++ b/docs/adapters/browser/apple-podcasts.md @@ -0,0 +1,28 @@ +# Apple Podcasts + +**Mode**: 🌐 Public · **Domain**: `podcasts.apple.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli apple-podcasts search` | | +| `opencli apple-podcasts episodes` | | +| `opencli apple-podcasts top` | | + +## Usage Examples + +```bash +# Quick start +opencli apple-podcasts search --limit 5 + +# JSON output +opencli apple-podcasts search -f json + +# Verbose mode +opencli apple-podcasts search -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/bbc.md b/docs/adapters/browser/bbc.md new file mode 100644 index 0000000..c61c501 --- /dev/null +++ b/docs/adapters/browser/bbc.md @@ -0,0 +1,26 @@ +# BBC News + +**Mode**: 🌐 Public · **Domain**: `bbc.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli bbc news` | | + +## Usage Examples + +```bash +# Quick start +opencli bbc news --limit 5 + +# JSON output +opencli bbc news -f json + +# Verbose mode +opencli bbc news -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/bilibili.md b/docs/adapters/browser/bilibili.md new file mode 100644 index 0000000..f9474df --- /dev/null +++ b/docs/adapters/browser/bilibili.md @@ -0,0 +1,38 @@ +# Bilibili + +**Mode**: 🔐 Browser · **Domain**: `bilibili.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli bilibili hot` | | +| `opencli bilibili search` | | +| `opencli bilibili me` | | +| `opencli bilibili favorite` | | +| `opencli bilibili history` | | +| `opencli bilibili feed` | | +| `opencli bilibili subtitle` | | +| `opencli bilibili dynamic` | | +| `opencli bilibili ranking` | | +| `opencli bilibili following` | | +| `opencli bilibili user-videos` | | +| `opencli bilibili download` | | + +## Usage Examples + +```bash +# Quick start +opencli bilibili hot --limit 5 + +# JSON output +opencli bilibili hot -f json + +# Verbose mode +opencli bilibili hot -v +``` + +## Prerequisites + +- Chrome running and **logged into** bilibili.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/boss.md b/docs/adapters/browser/boss.md new file mode 100644 index 0000000..343753e --- /dev/null +++ b/docs/adapters/browser/boss.md @@ -0,0 +1,28 @@ +# BOSS Zhipin + +**Mode**: 🔐 Browser · **Domain**: `zhipin.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli boss search` | | +| `opencli boss detail` | | + +## Usage Examples + +```bash +# Quick start +opencli boss search --limit 5 + +# JSON output +opencli boss search -f json + +# Verbose mode +opencli boss search -v +``` + +## Prerequisites + +- Chrome running and **logged into** zhipin.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/coupang.md b/docs/adapters/browser/coupang.md new file mode 100644 index 0000000..2827fcc --- /dev/null +++ b/docs/adapters/browser/coupang.md @@ -0,0 +1,28 @@ +# Coupang + +**Mode**: 🔐 Browser · **Domain**: `coupang.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli coupang search` | | +| `opencli coupang add-to-cart` | | + +## Usage Examples + +```bash +# Quick start +opencli coupang search --limit 5 + +# JSON output +opencli coupang search -f json + +# Verbose mode +opencli coupang search -v +``` + +## Prerequisites + +- Chrome running and **logged into** coupang.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/ctrip.md b/docs/adapters/browser/ctrip.md new file mode 100644 index 0000000..3f4080d --- /dev/null +++ b/docs/adapters/browser/ctrip.md @@ -0,0 +1,27 @@ +# Ctrip (携程) + +**Mode**: 🔐 Browser · **Domain**: `ctrip.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli ctrip search` | | + +## Usage Examples + +```bash +# Quick start +opencli ctrip search --limit 5 + +# JSON output +opencli ctrip search -f json + +# Verbose mode +opencli ctrip search -v +``` + +## Prerequisites + +- Chrome running and **logged into** ctrip.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/github.md b/docs/adapters/browser/github.md new file mode 100644 index 0000000..f64ef5e --- /dev/null +++ b/docs/adapters/browser/github.md @@ -0,0 +1,26 @@ +# GitHub + +**Mode**: 🌐 Public · **Domain**: `github.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli github search` | | + +## Usage Examples + +```bash +# Quick start +opencli github search --limit 5 + +# JSON output +opencli github search -f json + +# Verbose mode +opencli github search -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/hackernews.md b/docs/adapters/browser/hackernews.md new file mode 100644 index 0000000..f504a58 --- /dev/null +++ b/docs/adapters/browser/hackernews.md @@ -0,0 +1,26 @@ +# HackerNews + +**Mode**: 🌐 Public · **Domain**: `news.ycombinator.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli hackernews top` | | + +## Usage Examples + +```bash +# Quick start +opencli hackernews top --limit 5 + +# JSON output +opencli hackernews top -f json + +# Verbose mode +opencli hackernews top -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/linkedin.md b/docs/adapters/browser/linkedin.md new file mode 100644 index 0000000..f3658bc --- /dev/null +++ b/docs/adapters/browser/linkedin.md @@ -0,0 +1,27 @@ +# LinkedIn + +**Mode**: 🔐 Browser · **Domain**: `linkedin.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli linkedin search` | | + +## Usage Examples + +```bash +# Quick start +opencli linkedin search --limit 5 + +# JSON output +opencli linkedin search -f json + +# Verbose mode +opencli linkedin search -v +``` + +## Prerequisites + +- Chrome running and **logged into** linkedin.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/reddit.md b/docs/adapters/browser/reddit.md new file mode 100644 index 0000000..92b837d --- /dev/null +++ b/docs/adapters/browser/reddit.md @@ -0,0 +1,41 @@ +# Reddit + +**Mode**: 🔐 Browser · **Domain**: `reddit.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli reddit hot` | | +| `opencli reddit frontpage` | | +| `opencli reddit popular` | | +| `opencli reddit search` | | +| `opencli reddit subreddit` | | +| `opencli reddit read` | | +| `opencli reddit user` | | +| `opencli reddit user-posts` | | +| `opencli reddit user-comments` | | +| `opencli reddit upvote` | | +| `opencli reddit save` | | +| `opencli reddit comment` | | +| `opencli reddit subscribe` | | +| `opencli reddit saved` | | +| `opencli reddit upvoted` | | + +## Usage Examples + +```bash +# Quick start +opencli reddit hot --limit 5 + +# JSON output +opencli reddit hot -f json + +# Verbose mode +opencli reddit hot -v +``` + +## Prerequisites + +- Chrome running and **logged into** reddit.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/reuters.md b/docs/adapters/browser/reuters.md new file mode 100644 index 0000000..587bc3b --- /dev/null +++ b/docs/adapters/browser/reuters.md @@ -0,0 +1,27 @@ +# Reuters + +**Mode**: 🔐 Browser · **Domain**: `reuters.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli reuters search` | | + +## Usage Examples + +```bash +# Quick start +opencli reuters search --limit 5 + +# JSON output +opencli reuters search -f json + +# Verbose mode +opencli reuters search -v +``` + +## Prerequisites + +- Chrome running and **logged into** reuters.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/smzdm.md b/docs/adapters/browser/smzdm.md new file mode 100644 index 0000000..32e7b17 --- /dev/null +++ b/docs/adapters/browser/smzdm.md @@ -0,0 +1,27 @@ +# SMZDM (什么值得买) + +**Mode**: 🔐 Browser · **Domain**: `smzdm.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli smzdm search` | | + +## Usage Examples + +```bash +# Quick start +opencli smzdm search --limit 5 + +# JSON output +opencli smzdm search -f json + +# Verbose mode +opencli smzdm search -v +``` + +## Prerequisites + +- Chrome running and **logged into** smzdm.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/twitter.md b/docs/adapters/browser/twitter.md new file mode 100644 index 0000000..7bd3bfd --- /dev/null +++ b/docs/adapters/browser/twitter.md @@ -0,0 +1,47 @@ +# Twitter / X + +**Mode**: 🔐 Browser · **Domain**: `twitter.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli twitter trending` | | +| `opencli twitter bookmarks` | | +| `opencli twitter profile` | | +| `opencli twitter search` | | +| `opencli twitter timeline` | | +| `opencli twitter thread` | | +| `opencli twitter following` | | +| `opencli twitter followers` | | +| `opencli twitter notifications` | | +| `opencli twitter post` | | +| `opencli twitter reply` | | +| `opencli twitter delete` | | +| `opencli twitter like` | | +| `opencli twitter article` | | +| `opencli twitter follow` | | +| `opencli twitter unfollow` | | +| `opencli twitter bookmark` | | +| `opencli twitter unbookmark` | | +| `opencli twitter download` | | +| `opencli twitter accept` | | +| `opencli twitter reply-dm` | | + +## Usage Examples + +```bash +# Quick start +opencli twitter trending --limit 5 + +# JSON output +opencli twitter trending -f json + +# Verbose mode +opencli twitter trending -v +``` + +## Prerequisites + +- Chrome running and **logged into** twitter.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/v2ex.md b/docs/adapters/browser/v2ex.md new file mode 100644 index 0000000..85f1d72 --- /dev/null +++ b/docs/adapters/browser/v2ex.md @@ -0,0 +1,32 @@ +# V2EX + +**Mode**: 🌐 / 🔐 · **Domain**: `v2ex.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli v2ex hot` | | +| `opencli v2ex latest` | | +| `opencli v2ex topic` | | +| `opencli v2ex daily` | | +| `opencli v2ex me` | | +| `opencli v2ex notifications` | | + +## Usage Examples + +```bash +# Quick start +opencli v2ex hot --limit 5 + +# JSON output +opencli v2ex hot -f json + +# Verbose mode +opencli v2ex hot -v +``` + +## Prerequisites + +- Chrome running and **logged into** v2ex.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/weibo.md b/docs/adapters/browser/weibo.md new file mode 100644 index 0000000..eec3d6a --- /dev/null +++ b/docs/adapters/browser/weibo.md @@ -0,0 +1,27 @@ +# Weibo (微博) + +**Mode**: 🔐 Browser · **Domain**: `weibo.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli weibo hot` | | + +## Usage Examples + +```bash +# Quick start +opencli weibo hot --limit 5 + +# JSON output +opencli weibo hot -f json + +# Verbose mode +opencli weibo hot -v +``` + +## Prerequisites + +- Chrome running and **logged into** weibo.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/xiaohongshu.md b/docs/adapters/browser/xiaohongshu.md new file mode 100644 index 0000000..1ea7f85 --- /dev/null +++ b/docs/adapters/browser/xiaohongshu.md @@ -0,0 +1,32 @@ +# Xiaohongshu (小红书) + +**Mode**: 🔐 Browser · **Domain**: `xiaohongshu.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli xiaohongshu search` | | +| `opencli xiaohongshu notifications` | | +| `opencli xiaohongshu feed` | | +| `opencli xiaohongshu me` | | +| `opencli xiaohongshu user` | | +| `opencli xiaohongshu download` | | + +## Usage Examples + +```bash +# Quick start +opencli xiaohongshu search --limit 5 + +# JSON output +opencli xiaohongshu search -f json + +# Verbose mode +opencli xiaohongshu search -v +``` + +## Prerequisites + +- Chrome running and **logged into** xiaohongshu.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/xiaoyuzhou.md b/docs/adapters/browser/xiaoyuzhou.md new file mode 100644 index 0000000..60da790 --- /dev/null +++ b/docs/adapters/browser/xiaoyuzhou.md @@ -0,0 +1,28 @@ +# Xiaoyuzhou (小宇宙) + +**Mode**: 🌐 Public · **Domain**: `xiaoyuzhou.fm` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli xiaoyuzhou podcast` | | +| `opencli xiaoyuzhou podcast-episodes` | | +| `opencli xiaoyuzhou episode` | | + +## Usage Examples + +```bash +# Quick start +opencli xiaoyuzhou podcast --limit 5 + +# JSON output +opencli xiaoyuzhou podcast -f json + +# Verbose mode +opencli xiaoyuzhou podcast -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/xueqiu.md b/docs/adapters/browser/xueqiu.md new file mode 100644 index 0000000..cc32dc3 --- /dev/null +++ b/docs/adapters/browser/xueqiu.md @@ -0,0 +1,32 @@ +# Xueqiu (雪球) + +**Mode**: 🔐 Browser · **Domain**: `xueqiu.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli xueqiu feed` | | +| `opencli xueqiu hot-stock` | | +| `opencli xueqiu hot` | | +| `opencli xueqiu search` | | +| `opencli xueqiu stock` | | +| `opencli xueqiu watchlist` | | + +## Usage Examples + +```bash +# Quick start +opencli xueqiu feed --limit 5 + +# JSON output +opencli xueqiu feed -f json + +# Verbose mode +opencli xueqiu feed -v +``` + +## Prerequisites + +- Chrome running and **logged into** xueqiu.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/yahoo-finance.md b/docs/adapters/browser/yahoo-finance.md new file mode 100644 index 0000000..b1a51d4 --- /dev/null +++ b/docs/adapters/browser/yahoo-finance.md @@ -0,0 +1,26 @@ +# Yahoo Finance + +**Mode**: 🌐 Public · **Domain**: `finance.yahoo.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli yahoo-finance quote` | | + +## Usage Examples + +```bash +# Quick start +opencli yahoo-finance quote --limit 5 + +# JSON output +opencli yahoo-finance quote -f json + +# Verbose mode +opencli yahoo-finance quote -v +``` + +## Prerequisites + +- No browser required — uses public API diff --git a/docs/adapters/browser/youtube.md b/docs/adapters/browser/youtube.md new file mode 100644 index 0000000..dfa8e8f --- /dev/null +++ b/docs/adapters/browser/youtube.md @@ -0,0 +1,29 @@ +# YouTube + +**Mode**: 🔐 Browser · **Domain**: `youtube.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli youtube search` | | +| `opencli youtube video` | | +| `opencli youtube transcript` | | + +## Usage Examples + +```bash +# Quick start +opencli youtube search --limit 5 + +# JSON output +opencli youtube search -f json + +# Verbose mode +opencli youtube search -v +``` + +## Prerequisites + +- Chrome running and **logged into** youtube.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/browser/zhihu.md b/docs/adapters/browser/zhihu.md new file mode 100644 index 0000000..63e181b --- /dev/null +++ b/docs/adapters/browser/zhihu.md @@ -0,0 +1,30 @@ +# Zhihu + +**Mode**: 🔐 Browser · **Domain**: `zhihu.com` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli zhihu hot` | | +| `opencli zhihu search` | | +| `opencli zhihu question` | | +| `opencli zhihu download` | | + +## Usage Examples + +```bash +# Quick start +opencli zhihu hot --limit 5 + +# JSON output +opencli zhihu hot -f json + +# Verbose mode +opencli zhihu hot -v +``` + +## Prerequisites + +- Chrome running and **logged into** zhihu.com +- [Browser Bridge extension](/guide/browser-bridge) installed diff --git a/docs/adapters/desktop/antigravity.md b/docs/adapters/desktop/antigravity.md new file mode 100644 index 0000000..2808139 --- /dev/null +++ b/docs/adapters/desktop/antigravity.md @@ -0,0 +1,46 @@ +# Antigravity + +🔥 **CLI All Electron Apps! The Most Powerful Update Has Arrived!** 🔥 + +Turn your local Antigravity desktop application into a programmable AI node via Chrome DevTools Protocol (CDP). This allows you to compose complex LLM workflows entirely through the terminal by manipulating the actual UI natively, bypassing any API restrictions. + +## Prerequisites + +Start the Antigravity desktop app with the Chrome DevTools `remote-debugging-port` flag: + +```bash +# Start Antigravity in the background +/Applications/Antigravity.app/Contents/MacOS/Electron \ + --remote-debugging-port=9224 +``` + +> Depending on your installation, the executable might be named differently, e.g., `Antigravity` instead of `Electron`. + +Then set the target port: + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224" +``` + +## Commands + +### `opencli antigravity status` +Check the Chromium CDP connection. Returns the current window title and active internal URL. + +### `opencli antigravity send ` +Send a text prompt to the AI. Automatically locates the Lexical editor input box, types the prompt securely, and hits Enter. + +### `opencli antigravity read` +Scrape the entire current conversation history block as pure text. + +### `opencli antigravity new` +Click the "New Conversation" button to instantly clear the UI state and start fresh. + +### `opencli antigravity extract-code` +Extract any multi-line code blocks from the current conversation view. Ideal for automated script extraction (e.g. `opencli antigravity extract-code > script.sh`). + +### `opencli antigravity model ` +Quickly target and switch the active LLM engine. Example: `opencli antigravity model claude` or `opencli antigravity model gemini`. + +### `opencli antigravity watch` +A long-running, streaming process that continuously polls the Antigravity UI for chat updates and outputs them in real-time to standard output. diff --git a/docs/adapters/desktop/chatgpt.md b/docs/adapters/desktop/chatgpt.md new file mode 100644 index 0000000..8f20a9a --- /dev/null +++ b/docs/adapters/desktop/chatgpt.md @@ -0,0 +1,43 @@ +# ChatGPT + +Control the **ChatGPT macOS Desktop App** directly from the terminal. OpenCLI supports two automation approaches for ChatGPT. + +## Approach 1: AppleScript (Default, No Setup) + +The current built-in commands use native AppleScript automation — no extra launch flags needed. + +### Prerequisites +1. Install the official [ChatGPT Desktop App](https://openai.com/chatgpt/mac/) from OpenAI. +2. Grant **Accessibility permissions** to your terminal app in **System Settings → Privacy & Security → Accessibility**. + +### Commands +- `opencli chatgpt status`: Check if the ChatGPT app is currently running. +- `opencli chatgpt new`: Activate ChatGPT and press `Cmd+N` to start a new conversation. +- `opencli chatgpt send "message"`: Copy your message to clipboard, activate ChatGPT, paste, and submit. +- `opencli chatgpt read`: Copy the last AI response via `Cmd+Shift+C` and return it as text. + +## Approach 2: CDP (Advanced, Electron Debug Mode) + +ChatGPT Desktop is also an Electron app and can be launched with a remote debugging port: + +```bash +/Applications/ChatGPT.app/Contents/MacOS/ChatGPT \ + --remote-debugging-port=9224 +``` + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224" +``` + +> The CDP approach enables future advanced commands like DOM inspection, model switching, and code extraction. + +## How It Works + +- **AppleScript mode**: Uses `osascript` and `pbcopy`/`pbpaste` for clipboard-based text transfer. +- **CDP mode**: Connects via Chrome DevTools Protocol to the Electron renderer process. + +## Limitations + +- macOS only (AppleScript dependency) +- AppleScript mode requires Accessibility permissions +- `read` command copies the last response — earlier messages need manual scroll diff --git a/docs/adapters/desktop/chatwise.md b/docs/adapters/desktop/chatwise.md new file mode 100644 index 0000000..7d78d98 --- /dev/null +++ b/docs/adapters/desktop/chatwise.md @@ -0,0 +1,38 @@ +# ChatWise + +Control the **ChatWise Desktop App** from the terminal via Chrome DevTools Protocol (CDP). ChatWise is an Electron-based multi-LLM client supporting GPT-4, Claude, Gemini, and more. + +## Prerequisites + +1. Install [ChatWise](https://chatwise.app/). +2. Launch with remote debugging port: + ```bash + /Applications/ChatWise.app/Contents/MacOS/ChatWise \ + --remote-debugging-port=9228 + ``` + +## Setup + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9228" +``` + +## Commands + +### Diagnostics +- `opencli chatwise status`: Check CDP connection status. +- `opencli chatwise screenshot`: Export DOM + accessibility snapshot. + +### Chat +- `opencli chatwise new`: Start a new conversation (`Cmd+N`). +- `opencli chatwise send "message"`: Send a message to the active chat. +- `opencli chatwise read`: Read the current conversation. +- `opencli chatwise ask "prompt"`: Send + wait for response + return it (one-shot). + +### AI Features +- `opencli chatwise model`: Get the current AI model. +- `opencli chatwise model gpt-4`: Switch to a different model. + +### Organization +- `opencli chatwise history`: List conversations from the sidebar. +- `opencli chatwise export`: Export conversation as Markdown. diff --git a/docs/adapters/desktop/codex.md b/docs/adapters/desktop/codex.md new file mode 100644 index 0000000..9eec8c8 --- /dev/null +++ b/docs/adapters/desktop/codex.md @@ -0,0 +1,32 @@ +# Codex + +Control the **OpenAI Codex Desktop App** headless or headfully via Chrome DevTools Protocol (CDP). Because Codex is built on Electron, OpenCLI can directly drive its internal UI, automate slash commands, and manipulate its AI agent threads. + +## Prerequisites + +1. You must have the official OpenAI Codex app installed. +2. Launch it via the terminal and expose the remote debugging port: + ```bash + # macOS + /Applications/Codex.app/Contents/MacOS/Codex --remote-debugging-port=9222 + ``` + +## Setup + +```bash +export OPENCLI_CODEX_CDP_ENDPOINT="http://127.0.0.1:9222" +``` + +## Commands + +### Diagnostics +- `opencli codex status`: Checks connection and reads the current active window URL/title. +- `opencli codex dump`: Dumps the full UI DOM and Accessibility tree into `/tmp`. + +### Agent Manipulation +- `opencli codex new`: Simulates `Cmd+N` to start a completely fresh and isolated Git Worktree thread context. +- `opencli codex send "message"`: Robustly finds the active Thread Composer and injects your text. + - *Pro-tip*: You can trigger internal shortcuts, e.g., `opencli codex send "/review"`. +- `opencli codex read`: Extracts the entire current thread history and AI reasoning logs. +- `opencli codex extract-diff`: Automatically scrapes any visual Patch chunks and Code Diffs. +- `opencli codex model`: Get the currently active AI model. diff --git a/docs/adapters/desktop/cursor.md b/docs/adapters/desktop/cursor.md new file mode 100644 index 0000000..9ea6866 --- /dev/null +++ b/docs/adapters/desktop/cursor.md @@ -0,0 +1,33 @@ +# Cursor + +Control the **Cursor IDE** from the terminal via Chrome DevTools Protocol (CDP). Since Cursor is built on Electron (VS Code fork), OpenCLI can drive its internal UI, automate Composer interactions, and manipulate chat sessions. + +## Prerequisites + +1. Install [Cursor](https://cursor.sh/). +2. Launch it with the remote debugging port: + ```bash + /Applications/Cursor.app/Contents/MacOS/Cursor --remote-debugging-port=9226 + ``` + +## Setup + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9226" +``` + +## Commands + +### Diagnostics +- `opencli cursor status`: Check CDP connection status. +- `opencli cursor dump`: Dump the full DOM and Accessibility snapshot to `/tmp/cursor-dom.html` and `/tmp/cursor-snapshot.json`. + +### Chat Manipulation +- `opencli cursor new`: Press `Cmd+N` to start a new file/tab. +- `opencli cursor send "message"`: Inject text into the active Composer/Chat input and submit. +- `opencli cursor read`: Extract the full conversation history from the active chat panel. + +### AI Features +- `opencli cursor composer "prompt"`: Open the Composer panel (`Cmd+I`) and send a prompt for inline AI editing. +- `opencli cursor model`: Get the currently active AI model (e.g., `claude-4.5-sonnet`). +- `opencli cursor extract-code`: Extract all code blocks from the current conversation. diff --git a/docs/adapters/desktop/discord.md b/docs/adapters/desktop/discord.md new file mode 100644 index 0000000..302bc47 --- /dev/null +++ b/docs/adapters/desktop/discord.md @@ -0,0 +1,28 @@ +# Discord + +Control the **Discord Desktop App** from the terminal via Chrome DevTools Protocol (CDP). + +## Prerequisites + +Launch with remote debugging port: +```bash +/Applications/Discord.app/Contents/MacOS/Discord --remote-debugging-port=9232 +``` + +## Setup + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9232" +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli discord status` | Check CDP connection | +| `opencli discord send "message"` | Send a message in the active channel | +| `opencli discord read` | Read recent messages | +| `opencli discord channels` | List channels in the current server | +| `opencli discord servers` | List all joined servers | +| `opencli discord search "query"` | Search messages (Cmd+F) | +| `opencli discord members` | List online members | diff --git a/docs/adapters/desktop/feishu.md b/docs/adapters/desktop/feishu.md new file mode 100644 index 0000000..840f3d5 --- /dev/null +++ b/docs/adapters/desktop/feishu.md @@ -0,0 +1,20 @@ +# Feishu (飞书/Lark) + +Control **Feishu/Lark Desktop** from the terminal via AppleScript. + +> **Note:** Feishu uses a custom `Lark Framework` (Chromium-based but NOT Electron). CDP is not available, so this adapter uses AppleScript + clipboard. + +## Prerequisites + +1. Feishu/Lark must be running and logged in +2. Terminal must have **Accessibility permission** + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli feishu status` | Check if Feishu/Lark is running | +| `opencli feishu send "msg"` | Send message in active chat (paste + Enter) | +| `opencli feishu read` | Read current chat (Cmd+A → Cmd+C) | +| `opencli feishu search "query"` | Global search (Cmd+K) | +| `opencli feishu new` | New message/document (Cmd+N) | diff --git a/docs/adapters/desktop/neteasemusic.md b/docs/adapters/desktop/neteasemusic.md new file mode 100644 index 0000000..dd7cade --- /dev/null +++ b/docs/adapters/desktop/neteasemusic.md @@ -0,0 +1,31 @@ +# NeteaseMusic (网易云音乐) + +Control **NeteaseMusic** (网易云音乐) from the terminal via Chrome DevTools Protocol (CDP). The app uses Chromium Embedded Framework (CEF). + +## Prerequisites + +Launch with remote debugging port: +```bash +/Applications/NeteaseMusic.app/Contents/MacOS/NeteaseMusic --remote-debugging-port=9234 +``` + +## Setup + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9234" +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli neteasemusic status` | Check CDP connection | +| `opencli neteasemusic playing` | Current song info (title, artist, album) | +| `opencli neteasemusic play` | Play / Pause toggle | +| `opencli neteasemusic next` | Skip to next song | +| `opencli neteasemusic prev` | Go to previous song | +| `opencli neteasemusic search "query"` | Search songs, artists | +| `opencli neteasemusic playlist` | Show current playback queue | +| `opencli neteasemusic like` | Like / unlike current song | +| `opencli neteasemusic lyrics` | Get lyrics of current song | +| `opencli neteasemusic volume [0-100]` | Get or set volume | diff --git a/docs/adapters/desktop/notion.md b/docs/adapters/desktop/notion.md new file mode 100644 index 0000000..7ff21cd --- /dev/null +++ b/docs/adapters/desktop/notion.md @@ -0,0 +1,29 @@ +# Notion + +Control the **Notion Desktop App** from the terminal via Chrome DevTools Protocol (CDP). + +## Prerequisites + +Launch with remote debugging port: +```bash +/Applications/Notion.app/Contents/MacOS/Notion --remote-debugging-port=9230 +``` + +## Setup + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9230" +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli notion status` | Check CDP connection | +| `opencli notion search "query"` | Quick Find search (Cmd+P) | +| `opencli notion read` | Read the current page content | +| `opencli notion new "title"` | Create a new page (Cmd+N) | +| `opencli notion write "text"` | Append text to the current page | +| `opencli notion sidebar` | List pages from the sidebar | +| `opencli notion favorites` | List pages from the Favorites section | +| `opencli notion export` | Export page as Markdown | diff --git a/docs/adapters/desktop/wechat.md b/docs/adapters/desktop/wechat.md new file mode 100644 index 0000000..4b731e1 --- /dev/null +++ b/docs/adapters/desktop/wechat.md @@ -0,0 +1,28 @@ +# WeChat (微信) + +Control **WeChat Mac Desktop** from the terminal via AppleScript + Accessibility API. + +> **Note:** WeChat is a native macOS app (not Electron), so CDP is not available. This adapter uses AppleScript keyboard simulation and clipboard operations. + +## Prerequisites + +1. WeChat must be running and logged in +2. Terminal must have **Accessibility permission** (System Settings → Privacy & Security → Accessibility) + +## Commands + +| Command | Description | +|---------|-------------| +| `opencli wechat status` | Check if WeChat is running | +| `opencli wechat send "msg"` | Send message in the active chat (clipboard paste + Enter) | +| `opencli wechat read` | Read current chat content (Cmd+A → Cmd+C) | +| `opencli wechat search "keyword"` | Open search and type a query (Cmd+F) | +| `opencli wechat chats` | Switch to Chats tab (Cmd+1) | +| `opencli wechat contacts` | Switch to Contacts tab (Cmd+2) | + +## Limitations + +- **No CDP support** — WeChat is native Cocoa, not Electron +- `send` requires the correct conversation to be already open +- `read` captures whatever is visible via select-all + copy +- `search` types the query but cannot programmatically click results diff --git a/docs/adapters/index.md b/docs/adapters/index.md new file mode 100644 index 0000000..db589a4 --- /dev/null +++ b/docs/adapters/index.md @@ -0,0 +1,49 @@ +# All Adapters + +Run `opencli list` for the live registry. + +## Browser Adapters + +| Site | Commands | Mode | +|------|----------|------| +| **[twitter](/adapters/browser/twitter)** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` | 🔐 Browser | +| **[reddit](/adapters/browser/reddit)** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser | +| **[bilibili](/adapters/browser/bilibili)** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser | +| **[zhihu](/adapters/browser/zhihu)** | `hot` `search` `question` `download` | 🔐 Browser | +| **[xiaohongshu](/adapters/browser/xiaohongshu)** | `search` `notifications` `feed` `me` `user` `download` | 🔐 Browser | +| **[xueqiu](/adapters/browser/xueqiu)** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 🔐 Browser | +| **[youtube](/adapters/browser/youtube)** | `search` `video` `transcript` | 🔐 Browser | +| **[v2ex](/adapters/browser/v2ex)** | `hot` `latest` `topic` `daily` `me` `notifications` | 🌐 / 🔐 | +| **[weibo](/adapters/browser/weibo)** | `hot` | 🔐 Browser | +| **[linkedin](/adapters/browser/linkedin)** | `search` | 🔐 Browser | +| **[coupang](/adapters/browser/coupang)** | `search` `add-to-cart` | 🔐 Browser | +| **[boss](/adapters/browser/boss)** | `search` `detail` | 🔐 Browser | +| **[ctrip](/adapters/browser/ctrip)** | `search` | 🔐 Browser | +| **[reuters](/adapters/browser/reuters)** | `search` | 🔐 Browser | +| **[smzdm](/adapters/browser/smzdm)** | `search` | 🔐 Browser | + +## Public API Adapters + +| Site | Commands | Mode | +|------|----------|------| +| **[hackernews](/adapters/browser/hackernews)** | `top` | 🌐 Public | +| **[github](/adapters/browser/github)** | `search` | 🌐 Public | +| **[bbc](/adapters/browser/bbc)** | `news` | 🌐 Public | +| **[apple-podcasts](/adapters/browser/apple-podcasts)** | `search` `episodes` `top` | 🌐 Public | +| **[xiaoyuzhou](/adapters/browser/xiaoyuzhou)** | `podcast` `podcast-episodes` `episode` | 🌐 Public | +| **[yahoo-finance](/adapters/browser/yahoo-finance)** | `quote` | 🌐 Public | + +## Desktop Adapters + +| App | Description | Commands | +|-----|-------------|----------| +| **[Cursor](/adapters/desktop/cursor)** | Control Cursor IDE | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | +| **[Codex](/adapters/desktop/codex)** | Drive OpenAI Codex CLI agent | `status` `send` `read` `new` `extract-diff` `model` `ask` `screenshot` `history` `export` | +| **[Antigravity](/adapters/desktop/antigravity)** | Control Antigravity Ultra | `status` `send` `read` `new` `dump` `extract-code` `model` `watch` | +| **[ChatGPT](/adapters/desktop/chatgpt)** | Automate ChatGPT macOS app | `status` `new` `send` `read` `ask` | +| **[ChatWise](/adapters/desktop/chatwise)** | Multi-LLM client | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` | +| **[Notion](/adapters/desktop/notion)** | Search, read, write pages | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` | +| **[Discord](/adapters/desktop/discord)** | Desktop messages & channels | `status` `send` `read` `channels` `servers` `search` `members` | +| **[Feishu](/adapters/desktop/feishu)** | 飞书/Lark via AppleScript | `status` `send` `read` `search` `new` | +| **[WeChat](/adapters/desktop/wechat)** | 微信 via AppleScript | `status` `send` `read` `search` `chats` `contacts` | +| **[NeteaseMusic](/adapters/desktop/neteasemusic)** | 网易云音乐 via CDP | `status` `playing` `play` `next` `prev` `search` `playlist` `like` `lyrics` `volume` | diff --git a/docs/advanced/cdp.md b/docs/advanced/cdp.md new file mode 100644 index 0000000..09079f3 --- /dev/null +++ b/docs/advanced/cdp.md @@ -0,0 +1,103 @@ +# Connecting OpenCLI via CDP (Remote/Headless Servers) + +If you cannot use the opencli Browser Bridge extension (e.g., in a remote headless server environment without a UI), OpenCLI provides an alternative: connecting directly to Chrome via **CDP (Chrome DevTools Protocol)**. + +Because CDP binds to `localhost` by default for security reasons, accessing it from a remote server requires an additional networking tunnel. + +This guide is broken down into three phases: +1. **Preparation**: Start Chrome with CDP enabled locally. +2. **Network Tunnels**: Expose that CDP port to your remote server using either **SSH Tunnels** or **Reverse Proxies**. +3. **Execution**: Run OpenCLI on your server. + +--- + +## Phase 1: Preparation (Local Machine) + +First, you need to start a Chrome browser on your local machine with remote debugging enabled. + +**macOS:** +```bash +/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ + --remote-debugging-port=9222 \ + --user-data-dir="$HOME/chrome-debug-profile" \ + --remote-allow-origins="*" +``` + +**Linux:** +```bash +google-chrome \ + --remote-debugging-port=9222 \ + --user-data-dir="$HOME/chrome-debug-profile" \ + --remote-allow-origins="*" +``` + +**Windows:** +```cmd +"C:\Program Files\Google\Chrome\Application\chrome.exe" ^ + --remote-debugging-port=9222 ^ + --user-data-dir="%USERPROFILE%\chrome-debug-profile" ^ + --remote-allow-origins="*" +``` + +> **Note**: The `--remote-allow-origins="*"` flag is often required for modern Chrome versions to accept cross-origin CDP WebSocket connections (e.g. from reverse proxies like ngrok). + +Once this browser instance opens, **log into the target websites you want to use** (e.g., bilibili.com, zhihu.com) so that the session contains the correct cookies. + +--- + +## Phase 2: Remote Access Methods + +Once CDP is running locally on port `9222`, you must securely expose this port to your remote server. Choose one of the two methods below depending on your network conditions. + +### Method A: SSH Tunnel (Recommended) + +If your local machine has SSH access to the remote server, this is the most secure and straightforward method. + +Run this command on your **Local Machine** to forward the remote server's port `9222` back to your local port `9222`: + +```bash +ssh -R 9222:localhost:9222 your-server-user@your-server-ip +``` + +Leave this SSH session running in the background. + +### Method B: Reverse Proxy (ngrok / frp / socat) + +If you cannot establish a direct SSH connection (e.g., due to NAT or firewalls), you can use an intranet penetration tool like `ngrok`. + +Run this command on your **Local Machine** to expose your local port `9222` to the public internet securely via ngrok: + +```bash +ngrok http 9222 +``` + +This will print a forwarding URL, such as `https://abcdef.ngrok.app`. **Copy this URL**. + +--- + +## Phase 3: Execution (Remote Server) + +Now switch to your **Remote Server** where OpenCLI is installed. + +Depending on the network tunnel method you chose in Phase 2, set the `OPENCLI_CDP_ENDPOINT` environment variable and run your commands. + +### If you used Method A (SSH Tunnel): + +```bash +export OPENCLI_CDP_ENDPOINT="http://localhost:9222" +opencli doctor # Verify connection +opencli bilibili hot --limit 5 # Test a command +``` + +### If you used Method B (Reverse Proxy like ngrok): + +```bash +# Use the URL you copied from ngrok earlier +export OPENCLI_CDP_ENDPOINT="https://abcdef.ngrok.app" +opencli doctor # Verify connection +opencli bilibili hot --limit 5 # Test a command +``` + +> *Tip: If you provide a standard HTTP/HTTPS CDP endpoint, OpenCLI requests the `/json` target list and picks the most likely inspectable app/page target automatically. If multiple app targets exist, you can further narrow selection with `OPENCLI_CDP_TARGET` (for example `antigravity` or `codex`).* + +If you plan to use this setup frequently, you can persist the environment variable by adding the `export` line to your `~/.bashrc` or `~/.zshrc` on the server. diff --git a/docs/advanced/download.md b/docs/advanced/download.md new file mode 100644 index 0000000..ae717e1 --- /dev/null +++ b/docs/advanced/download.md @@ -0,0 +1,63 @@ +# Download Support + +OpenCLI supports downloading images, videos, and articles from supported platforms. + +## Supported Platforms + +| Platform | Content Types | Notes | +|----------|---------------|-------| +| **xiaohongshu** | Images, Videos | Downloads all media from a note | +| **bilibili** | Videos | Requires `yt-dlp` installed | +| **twitter** | Images, Videos | Downloads from user media tab or single tweet | +| **zhihu** | Articles (Markdown) | Exports articles with optional image download | + +## Prerequisites + +For video downloads from streaming platforms, install `yt-dlp`: + +```bash +# Install yt-dlp +pip install yt-dlp +# or +brew install yt-dlp +``` + +## Usage Examples + +```bash +# Download images/videos from Xiaohongshu note +opencli xiaohongshu download --note_id abc123 --output ./xhs + +# Download Bilibili video (requires yt-dlp) +opencli bilibili download --bvid BV1xxx --output ./bilibili +opencli bilibili download --bvid BV1xxx --quality 1080p + +# Download Twitter media from user +opencli twitter download --username elonmusk --limit 20 --output ./twitter + +# Download single tweet media +opencli twitter download --tweet-url "https://x.com/user/status/123" --output ./twitter + +# Export Zhihu article to Markdown +opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --output ./zhihu + +# Export with local images +opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --download-images +``` + +## Pipeline Step (YAML Adapters) + +The `download` step can be used in YAML pipelines: + +::: v-pre +```yaml +pipeline: + - fetch: https://api.example.com/media + - download: + url: ${{ item.imageUrl }} + dir: ./downloads + filename: ${{ item.title | sanitize }}.jpg + concurrency: 5 + skip_existing: true +``` +::: diff --git a/docs/advanced/electron.md b/docs/advanced/electron.md new file mode 100644 index 0000000..ec298b9 --- /dev/null +++ b/docs/advanced/electron.md @@ -0,0 +1,125 @@ +--- +description: How to CLI-ify and automate any Electron Desktop Application via CDP +--- + +# CLI-ifying Electron Applications (Skill Guide) + +Based on the successful automation of **Cursor**, **Codex**, **Antigravity**, **ChatWise**, **Notion**, and **Discord** desktop apps, this guide serves as the standard operating procedure (SOP) for adapting ANY Electron-based application into an OpenCLI adapter. + +## Core Concept + +Electron apps are essentially local Chromium browser instances. By exposing a debugging port (CDP — Chrome DevTools Protocol) at launch time, we can use the Browser Bridge to pierce through the UI layer, accessing and controlling all underlying state including React/Vue components and Shadow DOM. + +> **Note:** Not all desktop apps are Electron. WeChat (native Cocoa) and Feishu/Lark (custom Lark Framework) embed Chromium but do NOT expose CDP. For those apps, use the AppleScript + clipboard approach instead (see [Non-Electron Pattern](#non-electron-pattern-applescript)). + +### Launching the Target App +```bash +/Applications/AppName.app/Contents/MacOS/AppName --remote-debugging-port=9222 +``` + +### Verifying Electron +```bash +# Check for Electron Framework in the app bundle +ls /Applications/AppName.app/Contents/Frameworks/Electron\ Framework.framework +# If this directory exists → Electron → CDP works +# If not → check for libEGL.dylib (embedded Chromium/CEF, CDP may not work) +``` + +## The 5-Command Pattern (CDP / Electron) + +Every new Electron adapter should implement these 5 commands in `src/clis//`: + +### 1. `status.ts` — Connection Test +```typescript +export const statusCommand = cli({ + site: 'myapp', + name: 'status', + domain: 'localhost', + strategy: Strategy.UI, + browser: true, // Requires CDP connection + args: [], + columns: ['Status', 'Url', 'Title'], + func: async (page: IPage) => { + const url = await page.evaluate('window.location.href'); + const title = await page.evaluate('document.title'); + return [{ Status: 'Connected', Url: url, Title: title }]; + }, +}); +``` + +### 2. `dump.ts` — Reverse Engineering Core +Modern app DOMs are huge and obfuscated. **Never guess selectors.** Dump first, then extract precise class names with AI or `grep`: +```typescript +const dom = await page.evaluate('document.body.innerHTML'); +fs.writeFileSync('/tmp/app-dom.html', dom); +const snap = await page.snapshot({ interactive: false }); +fs.writeFileSync('/tmp/app-snapshot.json', JSON.stringify(snap, null, 2)); +``` + +### 3. `send.ts` — Advanced Text Injection +Electron apps often use complex rich-text editors (Monaco, Lexical, ProseMirror). Setting `.value` directly is ignored by React state. + +**Best practice:** Use `document.execCommand('insertText')` to perfectly simulate real user input, fully piercing React state: +```javascript +const composer = document.querySelector('[contenteditable="true"]'); +composer.focus(); +document.execCommand('insertText', false, 'Hello'); +``` +Then submit with `await page.pressKey('Enter')`. + +### 4. `read.ts` — Context Extraction +Don't extract the entire page text. Use `dump.ts` output to find the real "conversation container": +- Look for semantic selectors: `[role="log"]`, `[data-testid="conversation"]`, `[data-content-search-turn-key]` +- Format output as Markdown — readable by both humans and LLMs + +### 5. `new.ts` — Keyboard Shortcuts +Many GUI actions respond to native shortcuts rather than button clicks: +```typescript +const isMac = process.platform === 'darwin'; +await page.pressKey(isMac ? 'Meta+N' : 'Control+N'); +await page.wait(1); // Wait for re-render +``` + +## Environment Variable +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222" +``` + +## Non-Electron Pattern (AppleScript) + +For native macOS apps (WeChat, Feishu) that don't expose CDP: +```typescript +export const statusCommand = cli({ + site: 'myapp', + strategy: Strategy.PUBLIC, + browser: false, // No browser needed + func: async (page: IPage | null) => { + const output = execSync("osascript -e 'application \"MyApp\" is running'", { encoding: 'utf-8' }).trim(); + return [{ Status: output === 'true' ? 'Running' : 'Stopped' }]; + }, +}); +``` + +Core techniques: +- **status**: `osascript -e 'application "AppName" is running'` +- **send**: `pbcopy` → activate window → `Cmd+V` → `Enter` +- **read**: `Cmd+A` → `Cmd+C` → `pbpaste` +- **search**: Activate → `Cmd+F`/`Cmd+K` → `keystroke "query"` + +## Pitfalls & Gotchas + +1. **Port conflicts (EADDRINUSE)**: Only one app per port. Use unique ports: Codex=9222, ChatGPT=9224, Cursor=9226, ChatWise=9228, Notion=9230, Discord=9232 +2. **IPage abstraction**: OpenCLI wraps the browser page as `IPage` (`src/types.ts`). Use `page.pressKey()` and `page.evaluate()`, NOT direct DOM APIs +3. **Timing**: Always add `await page.wait(0.5)` to `1.0` after DOM mutations. Returning too early disconnects prematurely +4. **AppleScript requires Accessibility**: Terminal app must be granted permission in System Settings → Privacy & Security → Accessibility + +## Port Assignment Table + +| App | Port | Mode | +|-----|------|------| +| Codex | 9222 | CDP | +| ChatGPT | 9224 | CDP / AppleScript | +| Cursor | 9226 | CDP | +| ChatWise | 9228 | CDP | +| Notion | 9230 | CDP | +| Discord App | 9232 | CDP | diff --git a/docs/advanced/remote-chrome.md b/docs/advanced/remote-chrome.md new file mode 100644 index 0000000..e435d70 --- /dev/null +++ b/docs/advanced/remote-chrome.md @@ -0,0 +1,72 @@ +# Remote Chrome + +Run OpenCLI on a server or headless environment by connecting to a remote Chrome instance. + +## Use Cases + +- Running CLI commands on a remote server +- CI/CD automation with headed browser +- Shared team browser sessions + +## Setup + +### 1. Start Chrome on the Remote Machine + +```bash +# On the remote machine (or your Mac) +/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ + --remote-debugging-port=9222 +``` + +### 2. SSH Tunnel (If Needed) + +If the remote Chrome is on a different machine, create an SSH tunnel: + +```bash +# On your local machine or server +ssh -L 9222:127.0.0.1:9222 user@remote-host +``` + +::: warning +Use `127.0.0.1` instead of `localhost` in the SSH command to avoid IPv6 resolution issues that can cause timeouts. +::: + +### 3. Configure OpenCLI + +```bash +export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222" +``` + +### 4. Verify + +```bash +# Test the connection +curl http://127.0.0.1:9222/json/version + +# Run a diagnostic +opencli doctor +``` + +## CI/CD Integration + +For CI/CD environments, use a real Chrome instance with `xvfb`: + +::: v-pre +```yaml +steps: + - uses: browser-actions/setup-chrome@latest + id: setup-chrome + - run: | + xvfb-run --auto-servernum \ + ${{ steps.setup-chrome.outputs.chrome-path }} \ + --remote-debugging-port=9222 & +``` +::: + +Set the browser executable path: +::: v-pre +```yaml +env: + OPENCLI_BROWSER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} +``` +::: diff --git a/docs/developer/ai-workflow.md b/docs/developer/ai-workflow.md new file mode 100644 index 0000000..2eb4294 --- /dev/null +++ b/docs/developer/ai-workflow.md @@ -0,0 +1,66 @@ +# AI Workflow + +OpenCLI is designed with AI agents in mind. This guide covers the AI-native discovery and code generation tools. + +## Quick Mode (One-Shot) + +Generate a single command for a specific page URL — just a URL + one-line goal, 4 steps done: + +```bash +opencli generate https://example.com --goal "trending" +``` + +This runs: explore → synthesize → register in one shot. + +For the complete one-shot workflow details, see [CLI-ONESHOT.md](https://github.com/jackwener/opencli/blob/main/CLI-ONESHOT.md). + +## Full Mode (Explorer Workflow) + +### Step 1: Deep Explore + +Discover APIs, infer capabilities, and detect framework: + +```bash +opencli explore https://example.com --site mysite +``` + +Outputs to `.opencli/explore//`: +- `manifest.json` — Site metadata +- `endpoints.json` — Discovered API endpoints +- `capabilities.json` — Inferred capabilities +- `auth.json` — Authentication strategy details + +### Step 2: Synthesize + +Generate YAML adapters from explore artifacts: + +```bash +opencli synthesize mysite +``` + +### Step 3: Strategy Cascade + +Auto-probe authentication strategies: `PUBLIC → COOKIE → HEADER`: + +```bash +opencli cascade https://api.example.com/data +``` + +### Step 4: Validate & Test + +```bash +opencli validate # Validate generated YAML +opencli --limit 3 -f json # Test the command +``` + +## 5-Tier Authentication Strategy + +The explorer uses a decision tree to determine the best authentication approach: + +1. **PUBLIC** — No auth, direct API call +2. **COOKIE** — Reuse Chrome session cookies +3. **HEADER** — Custom auth headers +4. **BROWSER** — Full browser automation +5. **CDP** — Chrome DevTools Protocol for Electron apps + +For the complete browser exploration workflow and debugging guide, see [CLI-EXPLORER.md](https://github.com/jackwener/opencli/blob/main/CLI-EXPLORER.md). diff --git a/docs/developer/architecture.md b/docs/developer/architecture.md new file mode 100644 index 0000000..0937f4b --- /dev/null +++ b/docs/developer/architecture.md @@ -0,0 +1,90 @@ +# Architecture + +OpenCLI is built on a **Dual-Engine Architecture** that supports both declarative YAML pipelines and programmatic TypeScript adapters. + +## High-Level Architecture + +``` +┌─────────────────────────────────────────────────────┐ +│ opencli CLI │ +│ (Commander.js entry point) │ +├─────────────────────────────────────────────────────┤ +│ Engine Layer │ +│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │ +│ │ Registry │ │ Dynamic │ │ Output │ │ +│ │ (commands) │ │ Loader │ │ Formatter │ │ +│ └──────────────┘ └──────────────┘ └────────────┘ │ +├─────────────────────────────────────────────────────┤ +│ Adapter Layer │ +│ ┌─────────────────┐ ┌──────────────────────────┐ │ +│ │ YAML Pipeline │ │ TypeScript Adapters │ │ +│ │ (declarative) │ │ (browser/desktop/AI) │ │ +│ └─────────────────┘ └──────────────────────────┘ │ +├─────────────────────────────────────────────────────┤ +│ Connection Layer │ +│ ┌─────────────────┐ ┌──────────────────────────┐ │ +│ │ Browser Bridge │ │ CDP (Chrome DevTools) │ │ +│ │ (Extension+WS) │ │ (Electron apps) │ │ +│ └─────────────────┘ └──────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +## Core Modules + +### Registry (`src/registry.ts`) +Central command registry. All adapters register their commands via the `cli()` function with metadata: site, name, description, domain, strategy, args, columns. + +### Engine (`src/engine.ts`) +Command discovery and execution engine. Discovers commands from the registry, parses arguments, executes the appropriate adapter, and routes output through the formatter. + +### Browser (`src/browser.ts`) +Manages connections to Chrome via the Browser Bridge WebSocket daemon. Handles JSON-RPC messaging, tab management, and extension/standalone mode switching. + +### Pipeline (`src/pipeline/`) +The YAML pipeline engine. Processes declarative steps: +- **fetch** — HTTP requests with cookie/header strategies +- **map** — Data transformation with template expressions +- **limit** — Result truncation +- **filter** — Conditional filtering +- **download** — Media download support + +### Output (`src/output.ts`) +Unified output formatting: `table`, `json`, `yaml`, `md`, `csv`. + +## Authentication Strategies + +OpenCLI uses a 3-tier authentication strategy: + +| Strategy | How It Works | When to Use | +|----------|-------------|-------------| +| `public` | Direct HTTP fetch, no auth | Public APIs (HackerNews, BBC) | +| `cookie` | Reuse Chrome cookies via Browser Bridge | Logged-in sites (Bilibili, Zhihu) | +| `header` | Custom auth headers | API-key based services | + +## Directory Structure + +``` +src/ +├── main.ts # Entry point +├── engine.ts # Command execution engine +├── registry.ts # Command registry +├── browser.ts # Browser Bridge connection +├── output.ts # Output formatting +├── doctor.ts # Diagnostic tool +├── pipeline/ # YAML pipeline engine +│ ├── runner.ts +│ ├── template.ts +│ ├── transform.ts +│ └── steps/ +│ ├── fetch.ts +│ ├── map.ts +│ ├── limit.ts +│ ├── filter.ts +│ └── download.ts +└── clis/ # Site adapters + ├── twitter/ + ├── reddit/ + ├── bilibili/ + ├── cursor/ + └── ... +``` diff --git a/docs/developer/contributing.md b/docs/developer/contributing.md new file mode 100644 index 0000000..848345b --- /dev/null +++ b/docs/developer/contributing.md @@ -0,0 +1,136 @@ +# Contributing + +Thanks for your interest in contributing to OpenCLI. + +## Quick Start + +```bash +# 1. Fork & clone +git clone git@github.com:/opencli.git +cd opencli + +# 2. Install dependencies +npm install + +# 3. Build +npm run build + +# 4. Run a few checks +npx tsc --noEmit +npx vitest run src/ + +# 5. Link globally (optional, for testing `opencli` command) +npm link +``` + +## Adding a New Site Adapter + +This is the most common type of contribution. Start with YAML when possible, and use TypeScript only when you need browser-side logic or multi-step flows. + +### YAML Adapter (Recommended for data-fetching commands) + +Create a file like `src/clis//.yaml`: + +::: v-pre +```yaml +site: mysite +name: trending +description: Trending posts on MySite +domain: www.mysite.com +strategy: public # public | cookie | header +browser: false # true if browser session is needed + +args: + limit: + type: int + default: 20 + description: Number of items + +pipeline: + - fetch: + url: https://api.mysite.com/trending + + - map: + rank: ${{ index + 1 }} + title: ${{ item.title }} + score: ${{ item.score }} + url: ${{ item.url }} + + - limit: ${{ args.limit }} + +columns: [rank, title, score, url] +``` +::: + +See [`hackernews/top.yaml`](https://github.com/jackwener/opencli/blob/main/src/clis/hackernews/top.yaml) for a real example. + +### TypeScript Adapter (For complex browser interactions) + +Create a file like `src/clis//.ts`: + +```typescript +import { cli, Strategy } from '../../registry.js'; + +cli({ + site: 'mysite', + name: 'search', + description: 'Search MySite', + domain: 'www.mysite.com', + strategy: Strategy.COOKIE, + args: [ + { name: 'query', required: true, help: 'Search query' }, + { name: 'limit', type: 'int', default: 10, help: 'Max results' }, + ], + columns: ['title', 'url', 'date'], + + func: async (page, kwargs) => { + const { query, limit = 10 } = kwargs; + // ... browser automation logic + return data.slice(0, Number(limit)).map((item: any) => ({ + title: item.title, + url: item.url, + date: item.created_at, + })); + }, +}); +``` + +### Validate Your Adapter + +```bash +opencli validate # Validate YAML syntax and schema +opencli --limit 3 -f json # Test your command +opencli -v # Verbose mode for debugging +``` + +## Code Style + +- **TypeScript strict mode** — avoid `any` where possible. +- **ES Modules** — use `.js` extensions in imports (TypeScript output). +- **Naming**: `kebab-case` for files, `camelCase` for variables/functions, `PascalCase` for types/classes. +- **No default exports** — use named exports. + +## Commit Convention + +We use [Conventional Commits](https://www.conventionalcommits.org/): + +``` +feat(twitter): add thread command +fix(browser): handle CDP timeout gracefully +docs: update CONTRIBUTING.md +test(reddit): add e2e test for save command +chore: bump vitest to v4 +``` + +## Submitting a Pull Request + +1. Create a feature branch: `git checkout -b feat/mysite-trending` +2. Make your changes and add tests when relevant +3. Run the checks: + ```bash + npx tsc --noEmit # Type check + npx vitest run src/ # Unit tests + opencli validate # YAML validation (if applicable) + ``` +4. Commit using conventional commit format +5. Push and open a PR diff --git a/docs/developer/testing.md b/docs/developer/testing.md new file mode 100644 index 0000000..1bd17c9 --- /dev/null +++ b/docs/developer/testing.md @@ -0,0 +1,237 @@ +# Testing Guide + +> 面向开发者和 AI Agent 的测试参考手册。 + +## 目录 + +- [测试架构](#测试架构) +- [当前覆盖范围](#当前覆盖范围) +- [本地运行测试](#本地运行测试) +- [如何添加新测试](#如何添加新测试) +- [CI/CD 流水线](#cicd-流水线) +- [浏览器模式](#浏览器模式) +- [站点兼容性](#站点兼容性) + +--- + +## 测试架构 + +测试分为三层,全部使用 **vitest** 运行: + +``` +tests/ +├── e2e/ # E2E 集成测试(子进程运行真实 CLI) +│ ├── helpers.ts # runCli() 共享工具 +│ ├── public-commands.test.ts # 公开 API 命令(无需浏览器) +│ ├── browser-public.test.ts # 浏览器命令(公开数据) +│ ├── browser-auth.test.ts # 需登录命令(graceful failure 测试) +│ ├── management.test.ts # 管理命令(list, validate, verify, help) +│ └── output-formats.test.ts # 输出格式(json/yaml/csv/md) +├── smoke/ # 烟雾测试(仅定时 / 手动触发) +│ └── api-health.test.ts # 外部 API 可用性检测 +src/ +├── *.test.ts # 单元测试(已有 8 个) +``` + +| 层 | 位置 | 运行方式 | 用途 | +|---|---|---|---| +| 单元测试 | `src/**/*.test.ts` | `npx vitest run src/` | 内部模块逻辑 | +| E2E 测试 | `tests/e2e/*.test.ts` | `npx vitest run tests/e2e/` | 真实 CLI 命令执行 | +| 烟雾测试 | `tests/smoke/*.test.ts` | `npx vitest run tests/smoke/` | 外部 API 健康 | + +--- + +## 当前覆盖范围 + +### 单元测试(8 个文件) + +| 文件 | 覆盖内容 | +|---|---| +| `browser.test.ts` | JSON-RPC、tab 管理、extension/standalone 模式切换 | +| `engine.test.ts` | 命令发现与执行 | +| `registry.test.ts` | 命令注册与策略分配 | +| `output.test.ts` | 输出格式渲染 | +| `doctor.test.ts` | Token 诊断 | +| `coupang.test.ts` | 数据归一化 | +| `pipeline/template.test.ts` | 模板表达式求值 | +| `pipeline/transform.test.ts` | 数据变换步骤 | + +### E2E 测试(~52 个用例) + +| 文件 | 覆盖站点/功能 | 测试数 | +|---|---|---| +| `public-commands.test.ts` | hackernews/top, v2ex/hot, v2ex/latest, v2ex/topic | 5 | +| `browser-public.test.ts` | bbc, bilibili×3, weibo, zhihu×2, reddit×2, twitter, xueqiu×2, reuters, youtube, smzdm, boss, ctrip, coupang, xiaohongshu, yahoo-finance, v2ex/daily | 21 | +| `browser-auth.test.ts` | bilibili/me,dynamic,favorite,history,following + twitter/bookmarks,timeline,notifications + v2ex/me,notifications + xueqiu/feed,watchlist + xiaohongshu/feed,notifications | 14 | +| `management.test.ts` | list×5 格式, validate×3 级别, verify, --version, --help, unknown cmd | 12 | +| `output-formats.test.ts` | json, yaml, csv, md 格式验证 | 5 | + +### 烟雾测试 + +公开 API 可用性(hackernews, v2ex×2, v2ex/topic)+ 全站点注册完整性检查。 + +--- + +## 本地运行测试 + +### 前置条件 + +```bash +npm ci # 安装依赖 +npm run build # 编译(E2E 测试需要 dist/main.js) +``` + +### 运行命令 + +```bash +# 全部单元测试 +npx vitest run src/ + +# 全部 E2E 测试(会真实调用外部 API) +npx vitest run tests/e2e/ + +# 单个测试文件 +npx vitest run tests/e2e/management.test.ts + +# 全部测试(单元 + E2E) +npx vitest run + +# 烟雾测试 +npx vitest run tests/smoke/ + +# watch 模式(开发时推荐) +npx vitest src/ +``` + +### 浏览器命令本地测试须知 + +- opencli 通过 Browser Bridge 扩展连接已运行的 Chrome 浏览器 +- `browser-public.test.ts` 使用 `tryBrowserCommand()`,站点反爬导致空数据时 warn + pass +- `browser-auth.test.ts` 验证 **graceful failure**(不 crash 不 hang 即通过) +- 如需测试完整登录态,保持 Chrome 登录态并安装 Browser Bridge 扩展,手动跑对应测试 + +--- + +## 如何添加新测试 + +### 新增 YAML Adapter(如 `src/clis/producthunt/trending.yaml`) + +1. **无需额外操作**:`validate` 测试会自动覆盖 YAML 结构验证 +2. 根据 adapter 类型,在对应文件加一个 `it()` block: + +```typescript +// 如果 browser: false(公开 API)→ tests/e2e/public-commands.test.ts +it('producthunt trending returns data', async () => { + const { stdout, code } = await runCli(['producthunt', 'trending', '--limit', '3', '-f', 'json']); + expect(code).toBe(0); + const data = parseJsonOutput(stdout); + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBeGreaterThanOrEqual(1); + expect(data[0]).toHaveProperty('title'); +}, 30_000); +``` + +```typescript +// 如果 browser: true 但可公开访问 → tests/e2e/browser-public.test.ts +it('producthunt trending returns data', async () => { + const data = await tryBrowserCommand(['producthunt', 'trending', '--limit', '3', '-f', 'json']); + expectDataOrSkip(data, 'producthunt trending'); +}, 60_000); +``` + +```typescript +// 如果 browser: true 且需登录 → tests/e2e/browser-auth.test.ts +it('producthunt me fails gracefully without login', async () => { + await expectGracefulAuthFailure(['producthunt', 'me', '-f', 'json'], 'producthunt me'); +}, 60_000); +``` + +### 新增管理命令(如 `opencli export`) + +在 `tests/e2e/management.test.ts` 添加测试。 + +### 新增内部模块 + +在 `src/` 下对应位置创建 `*.test.ts`。 + +### 决策流程图 + +``` +新增功能 → 是内部模块? → 是 → src/ 下加 *.test.ts + ↓ 否 + 是 CLI 命令? → browser: false? → tests/e2e/public-commands.test.ts + ↓ true + 公开数据? → tests/e2e/browser-public.test.ts + ↓ 需登录 + tests/e2e/browser-auth.test.ts +``` + +--- + +## CI/CD 流水线 + +### ci.yml(主流水线) + +| Job | 触发条件 | 内容 | +|---|---|---| +| **build** | push/PR to main,dev | typecheck + build | +| **unit-test** | push/PR to main,dev | 单元测试,2 shard 并行 | +| **smoke-test** | 每周一 08:00 UTC / 手动 | xvfb + real Chrome,外部 API 健康检查 | + +### e2e-headed.yml(E2E 测试) + +| Job | 触发条件 | 内容 | +|---|---|---| +| **e2e-headed** | push/PR to main,dev | xvfb + real Chrome,全部 E2E 测试 | + +E2E 使用 `browser-actions/setup-chrome` 安装真实 Chrome,配合 `xvfb-run` 提供虚拟显示器,以 headed 模式运行浏览器。 + +### Sharding + +单元测试使用 vitest 内置 shard: + +::: v-pre +```yaml +strategy: + matrix: + shard: [1, 2] +steps: + - run: npx vitest run src/ --shard=${{ matrix.shard }}/2 +``` +::: + +--- + +## 浏览器模式 + +opencli 通过 Browser Bridge 扩展连接浏览器: + +| 条件 | 模式 | 使用场景 | +|---|---|---| +| 扩展已安装 | Extension 模式 | 本地用户,连接已登录的 Chrome | +| 扩展未安装 | CLI 报错提示安装 | 需要安装 Browser Bridge 扩展 | + +CI 中使用 `OPENCLI_BROWSER_EXECUTABLE_PATH` 指定真实 Chrome 路径: + +::: v-pre +```yaml +env: + OPENCLI_BROWSER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} +``` +::: + +--- + +## 站点兼容性 + +在 GitHub Actions 美国 runner 上,部分站点因地域限制或登录要求返回空数据。E2E 测试对这些站点使用 warn + pass 策略,不影响 CI 绿灯。 + +| 站点 | CI 状态 | 限制原因 | +|---|---|---| +| hackernews, bbc, v2ex | ✅ 返回数据 | 无限制 | +| yahoo-finance | ✅ 返回数据 | 无限制 | +| bilibili, zhihu, weibo, xiaohongshu | ⚠️ 空数据 | 地域限制(中国站点) | +| reddit, twitter, youtube | ⚠️ 空数据 | 需登录或 cookie | +| smzdm, boss, ctrip, coupang, xueqiu | ⚠️ 空数据 | 地域限制 / 需登录 | + +> 使用 self-hosted runner(国内服务器)可解决地域限制问题。 diff --git a/docs/developer/ts-adapter.md b/docs/developer/ts-adapter.md new file mode 100644 index 0000000..07a8a27 --- /dev/null +++ b/docs/developer/ts-adapter.md @@ -0,0 +1,87 @@ +# TypeScript Adapter Guide + +Use TypeScript adapters when you need browser-side logic, multi-step flows, DOM manipulation, or complex data extraction that goes beyond simple API fetching. + +## Basic Structure + +```typescript +import { cli, Strategy } from '../../registry.js'; + +cli({ + site: 'mysite', + name: 'search', + description: 'Search MySite', + domain: 'www.mysite.com', + strategy: Strategy.COOKIE, // PUBLIC | COOKIE | HEADER + args: [ + { name: 'query', required: true, help: 'Search query' }, + { name: 'limit', type: 'int', default: 10, help: 'Max results' }, + ], + columns: ['title', 'url', 'date'], + + func: async (page, kwargs) => { + const { query, limit = 10 } = kwargs; + + // Navigate and extract data + await page.goto('https://www.mysite.com'); + + const data = await page.evaluate(` + (async () => { + const res = await fetch('/api/search?q=${encodeURIComponent(String(query))}', { + credentials: 'include' + }); + return (await res.json()).results; + })() + `); + + return data.slice(0, Number(limit)).map((item: any) => ({ + title: item.title, + url: item.url, + date: item.created_at, + })); + }, +}); +``` + +## Strategy Types + +| Strategy | Constant | Use Case | +|----------|----------|----------| +| Public | `Strategy.PUBLIC` | No auth needed | +| Cookie | `Strategy.COOKIE` | Browser session cookies | +| Header | `Strategy.HEADER` | Custom headers/tokens | + +## The `page` Object + +The `page` parameter provides browser interaction methods: + +- `page.goto(url)` — Navigate to a URL +- `page.evaluate(script)` — Execute JavaScript in the page context +- `page.waitForSelector(selector)` — Wait for an element +- `page.click(selector)` — Click an element +- `page.type(selector, text)` — Type text into an input + +## The `kwargs` Object + +Contains parsed CLI arguments as key-value pairs. Always destructure with defaults: + +```typescript +const { query, limit = 10, format = 'json' } = kwargs; +``` + +## AI-Assisted Development + +Use the AI workflow tools to accelerate adapter creation: + +```bash +# Discover APIs and page structure +opencli explore https://example.com --site mysite + +# Auto-generate adapter from explore artifacts +opencli synthesize mysite + +# One-shot: explore → synthesize → register +opencli generate https://example.com --goal "trending" +``` + +See [AI Workflow](/developer/ai-workflow) for the complete guide. diff --git a/docs/developer/yaml-adapter.md b/docs/developer/yaml-adapter.md new file mode 100644 index 0000000..adfd861 --- /dev/null +++ b/docs/developer/yaml-adapter.md @@ -0,0 +1,108 @@ +# YAML Adapter Guide + +YAML adapters are the recommended way to add new commands when the site offers a straightforward API. They use a declarative pipeline approach — no TypeScript required. + +## Basic Structure + +::: v-pre +```yaml +site: mysite # Site identifier +name: trending # Command name (opencli mysite trending) +description: ... # Help text +domain: www.mysite.com +strategy: public # public | cookie | header +browser: false # true if browser session is needed + +args: # CLI arguments + limit: + type: int + default: 20 + description: Number of items + +pipeline: # Data processing steps + - fetch: + url: https://api.mysite.com/trending + + - map: + rank: ${{ index + 1 }} + title: ${{ item.title }} + + - limit: ${{ args.limit }} + +columns: [rank, title, score, url] +``` +::: + +## Pipeline Steps + +### `fetch` +Fetch data from a URL. Supports template expressions for dynamic URLs. + +::: v-pre +```yaml +- fetch: + url: https://api.example.com/search?q=${{ args.query }} + headers: + Accept: application/json +``` +::: + +### `map` + +::: v-pre +Transform each item in the result array. Use `${{ item.xxx }}` for field access and `${{ index }}` for position. + +```yaml +- map: + rank: ${{ index + 1 }} + title: ${{ item.title }} + url: https://example.com${{ item.path }} +``` +::: + +### `limit` +Truncate results to N items. + +::: v-pre +```yaml +- limit: ${{ args.limit }} +``` +::: + +### `filter` +Filter items by condition. + +::: v-pre +```yaml +- filter: ${{ item.score > 100 }} +``` +::: + +### `download` +Download media files. + +::: v-pre +```yaml +- download: + url: ${{ item.imageUrl }} + dir: ./downloads + filename: ${{ item.title | sanitize }}.jpg +``` +::: + +## Template Expressions + +::: v-pre +Use `${{ ... }}` for dynamic values: + +| Expression | Description | +|-----------|-------------| +| `${{ args.limit }}` | CLI argument | +| `${{ item.title }}` | Current item field | +| `${{ index }}` | Current index (0-based) | +| `${{ item.x \| sanitize }}` | Pipe filters | +::: + +## Real Example + +See [`src/clis/hackernews/top.yaml`](https://github.com/jackwener/opencli/blob/main/src/clis/hackernews/top.yaml). diff --git a/docs/guide/browser-bridge.md b/docs/guide/browser-bridge.md new file mode 100644 index 0000000..04b3e2d --- /dev/null +++ b/docs/guide/browser-bridge.md @@ -0,0 +1,38 @@ +# Browser Bridge Setup + +> **⚠️ Important**: Browser commands reuse your Chrome login session. You must be logged into the target website in Chrome before running commands. + +OpenCLI connects to your browser through a lightweight **Browser Bridge** Chrome Extension + micro-daemon (zero config, auto-start). + +## Extension Installation + +### Method 1: Download Pre-built Release (Recommended) + +1. Go to the GitHub [Releases page](https://github.com/jackwener/opencli/releases) and download the latest `opencli-extension.zip` or `opencli-extension.crx`. +2. Open `chrome://extensions` and enable **Developer mode** (top-right toggle). +3. Drag and drop the `.crx` file or the unzipped folder into the extensions page. + +### Method 2: Load Unpacked Source (For Developers) + +1. Open `chrome://extensions` and enable **Developer mode**. +2. Click **Load unpacked** and select the `extension/` directory from the repository. + +## Verification + +That's it! The daemon auto-starts when you run any browser command. No tokens, no manual configuration. + +```bash +opencli doctor # Check extension + daemon connectivity +opencli doctor --live # Also test live browser commands +``` + +## How It Works + +``` +┌─────────────┐ WebSocket ┌──────────────┐ Chrome API ┌─────────┐ +│ opencli │ ◄──────────────► │ micro-daemon │ ◄──────────────► │ Chrome │ +│ (Node.js) │ localhost:19825 │ (auto-start) │ Extension │ Browser │ +└─────────────┘ └──────────────┘ └─────────┘ +``` + +The daemon manages the WebSocket connection between your CLI commands and the Chrome extension. The extension executes JavaScript in the context of web pages, with access to the logged-in session. diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md new file mode 100644 index 0000000..7c2861c --- /dev/null +++ b/docs/guide/getting-started.md @@ -0,0 +1,56 @@ +# Getting Started + +> **Make any website or Electron App your CLI.** +> Zero risk · Reuse Chrome login · AI-powered discovery · Browser + Desktop automation + +[![npm](https://img.shields.io/npm/v/@jackwener/opencli?style=flat-square)](https://www.npmjs.com/package/@jackwener/opencli) +[![Node.js Version](https://img.shields.io/node/v/@jackwener/opencli?style=flat-square)](https://nodejs.org) +[![License](https://img.shields.io/npm/l/@jackwener/opencli?style=flat-square)](https://github.com/jackwener/opencli/blob/main/LICENSE) + +OpenCLI turns **any website** or **Electron app** into a command-line interface — Bilibili, Zhihu, 小红书, Twitter/X, Reddit, YouTube, Antigravity, and [many more](/adapters/) — powered by browser session reuse and AI-native discovery. + +## Highlights + +- **CLI All Electron** — CLI-ify apps like Antigravity Ultra! Now AI can control itself natively. +- **Account-safe** — Reuses Chrome's logged-in state; your credentials never leave the browser. +- **AI Agent ready** — `explore` discovers APIs, `synthesize` generates adapters, `cascade` finds auth strategies. +- **Self-healing setup** — `opencli setup` verifies Browser Bridge connectivity; `opencli doctor` diagnoses daemon, extension, and live browser connectivity. +- **Dynamic Loader** — Simply drop `.ts` or `.yaml` adapters into the `clis/` folder for auto-registration. +- **Dual-Engine Architecture** — Supports both YAML declarative data pipelines and robust browser runtime TypeScript injections. + +## Quick Start + +### Install via npm + +```bash +npm install -g @jackwener/opencli +``` + +### Basic Usage + +```bash +opencli list # See all commands +opencli hackernews top --limit 5 # Public API, no browser +opencli bilibili hot --limit 5 # Browser command +opencli zhihu hot -f json # JSON output +``` + +### Output Formats + +All built-in commands support `--format` / `-f`: + +```bash +opencli bilibili hot -f table # Default: rich terminal table +opencli bilibili hot -f json # JSON (pipe to jq or LLMs) +opencli bilibili hot -f yaml # YAML (human-readable) +opencli bilibili hot -f md # Markdown +opencli bilibili hot -f csv # CSV +opencli bilibili hot -v # Verbose: show pipeline debug +``` + +## Next Steps + +- [Installation details](/guide/installation) +- [Browser Bridge setup](/guide/browser-bridge) +- [All available adapters](/adapters/) +- [For developers / AI agents](/developer/contributing) diff --git a/docs/guide/installation.md b/docs/guide/installation.md new file mode 100644 index 0000000..5f948bd --- /dev/null +++ b/docs/guide/installation.md @@ -0,0 +1,37 @@ +# Installation + +## Requirements + +- **Node.js**: >= 20.0.0 +- **Chrome** running and logged into the target site (for browser commands) + +## Install via npm (Recommended) + +```bash +npm install -g @jackwener/opencli +``` + +## Install from Source + +```bash +git clone git@github.com:jackwener/opencli.git +cd opencli +npm install +npm run build +npm link # Link binary globally +opencli list # Now you can use it anywhere! +``` + +## Update + +```bash +npm install -g @jackwener/opencli@latest +``` + +## Verify Installation + +```bash +opencli --version # Check version +opencli list # List all commands +opencli doctor # Diagnose connectivity +``` diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md new file mode 100644 index 0000000..7ab5ae3 --- /dev/null +++ b/docs/guide/troubleshooting.md @@ -0,0 +1,56 @@ +# Troubleshooting + +## Common Issues + +### "Extension not connected" + +- Ensure the opencli Browser Bridge extension is installed and **enabled** in `chrome://extensions`. +- Run `opencli doctor` to diagnose connectivity. + +### Empty data or 'Unauthorized' error + +- Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page. +- Some sites have geographic restrictions (e.g., Bilibili, Zhihu from outside China). + +### Node API errors + +- Make sure you are using **Node.js >= 20**. Some dependencies require modern Node APIs. +- Run `node --version` to verify. + +### Daemon issues + +```bash +# Check daemon status +curl localhost:19825/status + +# View extension logs +curl localhost:19825/logs + +# Kill and restart daemon +pkill -f opencli-daemon +opencli doctor +``` + +### Desktop adapter connection issues + +For Electron/CDP-based adapters (Cursor, Codex, etc.): + +1. Make sure the app is launched with `--remote-debugging-port=XXXX` +2. Verify the endpoint is set: `echo $OPENCLI_CDP_ENDPOINT` +3. Test the endpoint: `curl http://127.0.0.1:XXXX/json/version` + +### Build errors + +```bash +# Clean rebuild +rm -rf dist/ +npm run build + +# Type check +npx tsc --noEmit +``` + +## Getting Help + +- [GitHub Issues](https://github.com/jackwener/opencli/issues) — Bug reports and feature requests +- Run `opencli doctor --live` for comprehensive diagnostics diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..41a960c --- /dev/null +++ b/docs/index.md @@ -0,0 +1,35 @@ +--- +layout: home + +hero: + name: OpenCLI + text: Make any website or Electron App your CLI + tagline: Zero risk · Reuse Chrome login · AI-powered discovery · Browser + Desktop automation + actions: + - theme: brand + text: Get Started + link: /guide/getting-started + - theme: alt + text: View on GitHub + link: https://github.com/jackwener/opencli + +features: + - icon: 🖥️ + title: CLI All Electron + details: Turn ANY Electron application into a CLI tool — Cursor, Codex, Antigravity, ChatGPT, Notion, and more. AI can control itself natively. + - icon: 🔐 + title: Account Safe + details: Reuses Chrome's logged-in state. Your credentials never leave the browser — no tokens, no exposed passwords. + - icon: 🤖 + title: AI Agent Ready + details: "explore discovers APIs, synthesize generates adapters, cascade finds auth strategies. Built for AI-first workflows." + - icon: ⚡ + title: Dual-Engine Architecture + details: Supports both YAML declarative data pipelines and robust browser runtime TypeScript injections for maximum flexibility. + - icon: 🔧 + title: Self-Healing Setup + details: "opencli setup verifies Browser Bridge connectivity. opencli doctor diagnoses daemon, extension, and live browser." + - icon: 📦 + title: Dynamic Loader + details: Simply drop .ts or .yaml adapters into the clis/ folder for auto-registration. Zero boilerplate. +--- diff --git a/docs/zh/adapters/index.md b/docs/zh/adapters/index.md new file mode 100644 index 0000000..00f3f19 --- /dev/null +++ b/docs/zh/adapters/index.md @@ -0,0 +1,5 @@ +# 所有适配器 + +运行 `opencli list` 查看完整命令列表。 + +详细文档请参考 [英文版本](/adapters/)。 diff --git a/docs/zh/advanced/cdp.md b/docs/zh/advanced/cdp.md new file mode 100644 index 0000000..bf57478 --- /dev/null +++ b/docs/zh/advanced/cdp.md @@ -0,0 +1,3 @@ +# Chrome DevTools Protocol + +详细文档请参考 [英文版本](/advanced/cdp)。 diff --git a/docs/zh/developer/contributing.md b/docs/zh/developer/contributing.md new file mode 100644 index 0000000..cb1b20d --- /dev/null +++ b/docs/zh/developer/contributing.md @@ -0,0 +1,24 @@ +# 贡献指南 + +详细贡献指南请参考 [英文版本](/developer/contributing)。 + +## 快速开始 + +```bash +git clone git@github.com:/opencli.git +cd opencli +npm install +npm run build +npx tsc --noEmit +npx vitest run src/ +``` + +## 提交规范 + +使用 [Conventional Commits](https://www.conventionalcommits.org/): + +``` +feat(twitter): add thread command +fix(browser): handle CDP timeout gracefully +docs: update CONTRIBUTING.md +``` diff --git a/docs/zh/guide/browser-bridge.md b/docs/zh/guide/browser-bridge.md new file mode 100644 index 0000000..1665989 --- /dev/null +++ b/docs/zh/guide/browser-bridge.md @@ -0,0 +1,25 @@ +# Browser Bridge 设置 + +> **⚠️ 重要**: 浏览器命令复用你的 Chrome 登录会话。运行命令前必须在 Chrome 中登录目标网站。 + +OpenCLI 通过轻量级 **Browser Bridge** Chrome 扩展 + 微守护进程连接浏览器(零配置,自动启动)。 + +## 扩展安装 + +### 方法 1:下载预构建版本(推荐) + +1. 前往 GitHub [Releases 页面](https://github.com/jackwener/opencli/releases) 下载最新的 `opencli-extension.zip` 或 `opencli-extension.crx`。 +2. 打开 `chrome://extensions`,启用**开发者模式**。 +3. 拖放 `.crx` 文件或解压后的文件夹到扩展页面。 + +### 方法 2:加载源码(开发者) + +1. 打开 `chrome://extensions`,启用**开发者模式**。 +2. 点击**加载已解压的扩展程序**,选择仓库中的 `extension/` 目录。 + +## 验证 + +```bash +opencli doctor # 检查扩展 + 守护进程连接 +opencli doctor --live # 同时测试实时浏览器命令 +``` diff --git a/docs/zh/guide/getting-started.md b/docs/zh/guide/getting-started.md new file mode 100644 index 0000000..c7dfe8f --- /dev/null +++ b/docs/zh/guide/getting-started.md @@ -0,0 +1,40 @@ +# 快速开始 + +> **让任何网站或 Electron 应用成为你的 CLI。** +> 零风险 · 复用 Chrome 登录态 · AI 驱动发现 · 浏览器 + 桌面自动化 + +OpenCLI 将**任何网站**或 **Electron 应用**变成命令行界面 — Bilibili、知乎、小红书、Twitter/X、Reddit、YouTube、Antigravity 等 — 基于浏览器会话复用和 AI 原生发现。 + +## 安装 + +```bash +npm install -g @jackwener/opencli +``` + +## 基本使用 + +```bash +opencli list # 查看所有命令 +opencli hackernews top --limit 5 # 公开 API,无需浏览器 +opencli bilibili hot --limit 5 # 浏览器命令 +opencli zhihu hot -f json # JSON 输出 +``` + +## 输出格式 + +所有命令支持 `--format` / `-f`: + +```bash +opencli bilibili hot -f table # 默认:终端表格 +opencli bilibili hot -f json # JSON +opencli bilibili hot -f yaml # YAML +opencli bilibili hot -f md # Markdown +opencli bilibili hot -f csv # CSV +``` + +## 下一步 + +- [安装详情](/zh/guide/installation) +- [Browser Bridge 设置](/zh/guide/browser-bridge) +- [所有适配器](/zh/adapters/) +- [开发者指南](/zh/developer/contributing) diff --git a/docs/zh/guide/installation.md b/docs/zh/guide/installation.md new file mode 100644 index 0000000..df38d0c --- /dev/null +++ b/docs/zh/guide/installation.md @@ -0,0 +1,37 @@ +# 安装 + +## 系统要求 + +- **Node.js**: >= 20.0.0 +- **Chrome** 已运行并登录目标网站(浏览器命令需要) + +## 通过 npm 安装(推荐) + +```bash +npm install -g @jackwener/opencli +``` + +## 从源码安装 + +```bash +git clone git@github.com:jackwener/opencli.git +cd opencli +npm install +npm run build +npm link +opencli list +``` + +## 更新 + +```bash +npm install -g @jackwener/opencli@latest +``` + +## 验证安装 + +```bash +opencli --version +opencli list +opencli doctor +``` diff --git a/docs/zh/index.md b/docs/zh/index.md new file mode 100644 index 0000000..6dcdeef --- /dev/null +++ b/docs/zh/index.md @@ -0,0 +1,29 @@ +--- +layout: home + +hero: + name: OpenCLI + text: 让任何网站或 Electron 应用成为你的 CLI + tagline: 零风险 · 复用 Chrome 登录态 · AI 驱动发现 · 浏览器 + 桌面自动化 + actions: + - theme: brand + text: 快速开始 + link: /zh/guide/getting-started + - theme: alt + text: 在 GitHub 查看 + link: https://github.com/jackwener/opencli + +features: + - icon: 🖥️ + title: CLI 所有 Electron 应用 + details: 将任何 Electron 应用变成 CLI 工具 — Cursor、Codex、Antigravity、ChatGPT、Notion 等。AI 可以原生控制自身。 + - icon: 🔐 + title: 账号安全 + details: 复用 Chrome 登录态,凭证永远不会离开浏览器 — 无 token,无密码泄露。 + - icon: 🤖 + title: AI Agent 就绪 + details: explore 发现 API,synthesize 生成适配器,cascade 查找认证策略。为 AI 优先工作流而生。 + - icon: ⚡ + title: 双引擎架构 + details: 同时支持 YAML 声明式数据管道和强大的浏览器运行时 TypeScript 注入。 +--- diff --git a/package-lock.json b/package-lock.json index ff94762..3e456d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,12 +25,321 @@ "@types/ws": "^8.5.13", "tsx": "^4.19.3", "typescript": "^5.8.2", + "vitepress": "^1.6.4", "vitest": "^4.1.0" }, "engines": { "node": ">=20.0.0" } }, + "node_modules/@algolia/abtesting": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.15.2.tgz", + "integrity": "sha512-rF7vRVE61E0QORw8e2NNdnttcl3jmFMWS9B4hhdga12COe+lMa26bQLfcBn/Nbp9/AF/8gXdaRCPsVns3CnjsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.49.2.tgz", + "integrity": "sha512-XyvKCm0RRmovMI/ChaAVjTwpZhXdbgt3iZofK914HeEHLqD1MUFFVLz7M0+Ou7F56UkHXwRbpHwb9xBDNopprQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.49.2.tgz", + "integrity": "sha512-jq/3qvtmj3NijZlhq7A1B0Cl41GfaBpjJxcwukGsYds6aMSCWrEAJ9pUqw/C9B3hAmILYKl7Ljz3N9SFvekD3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.49.2.tgz", + "integrity": "sha512-bn0biLequn3epobCfjUqCxlIlurLr4RHu7RaE4trgN+RDcUq6HCVC3/yqq1hwbNYpVtulnTOJzcaxYlSr1fnuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.49.2.tgz", + "integrity": "sha512-z14wfFs1T3eeYbCArC8pvntAWsPo9f6hnUGoj8IoRUJTwgJiiySECkm8bmmV47/x0oGHfsVn3kBdjMX0yq0sNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.49.2.tgz", + "integrity": "sha512-GpRf7yuuAX93+Qt0JGEJZwgtL0MFdjFO9n7dn8s2pA9mTjzl0Sc5+uTk1VPbIAuf7xhCP9Mve+URGb6J+EYxgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.49.2.tgz", + "integrity": "sha512-HZwApmNkp0DiAjZcLYdQLddcG4Agb88OkojiAHGgcm5DVXobT5uSZ9lmyrbw/tmQBJwgu2CNw4zTyXoIB7YbPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.49.2.tgz", + "integrity": "sha512-y1IOpG6OSmTpGg/CT0YBb/EAhR2nsC18QWp9Jy8HO9iGySpcwaTvs5kHa17daP3BMTwWyaX9/1tDTDQshZzXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.49.2", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.49.2.tgz", + "integrity": "sha512-YYJRjaZ2bqk923HxE4um7j/Cm3/xoSkF2HC2ZweOF8cXL3sqnlndSUYmCaxHFjNPWLaSHk2IfssX6J/tdKTULw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.49.2", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.49.2.tgz", + "integrity": "sha512-9WgH+Dha39EQQyGKCHlGYnxW/7W19DIrEbCEbnzwAMpGAv1yTWCHMPXHxYa+LcL3eCp2V/5idD1zHNlIKmHRHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.49.2.tgz", + "integrity": "sha512-K7Gp5u+JtVYgaVpBxF5rGiM+Ia8SsMdcAJMTDV93rwh00DKNllC19o1g+PwrDjDvyXNrnTEbofzbTs2GLfFyKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.49.2.tgz", + "integrity": "sha512-3UhYCcWX6fbtN8ABcxZlhaQEwXFh3CsFtARyyadQShHMPe3mJV9Wel4FpJTa+seugRkbezFz0tt6aPTZSYTBuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.49.2.tgz", + "integrity": "sha512-G94VKSGbsr+WjsDDOBe5QDQ82QYgxvpxRGJfCHZBnYKYsy/jv9qGIDb93biza+LJWizQBUtDj7bZzp3QZyzhPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.49.2.tgz", + "integrity": "sha512-UuihBGHafG/ENsrcTGAn5rsOffrCIRuHMOsD85fZGLEY92ate+BMTUqxz60dv5zerh8ZumN4bRm8eW2z9L11jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -41,6 +350,57 @@ "node": ">=0.1.90" } }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, "node_modules/@emnapi/core": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", @@ -517,6 +877,23 @@ "node": ">=18" } }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.74", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.74.tgz", + "integrity": "sha512-yqaohfY6jnYjTVpuTkaBQHrWbdUrQyWXhau0r/0EZiNWYXPX/P8WWwl1DoLH5CbvDjjcWQw5J0zADhgCUklOqA==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -823,6 +1200,443 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -866,6 +1680,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", @@ -873,6 +1697,41 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.19.15", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz", @@ -883,6 +1742,20 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -893,6 +1766,13 @@ "@types/node": "*" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, "node_modules/@vitest/expect": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz", @@ -1006,6 +1886,297 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vue/compiler-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "vue": "3.5.30" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/algoliasearch": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.49.2.tgz", + "integrity": "sha512-1K0wtDaRONwfhL4h8bbJ9qTjmY6rhGgRvvagXkMBsAOMNr+3Q2SffHECh9DIuNVrMA1JwA0zCwhyepgBZVakng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.15.2", + "@algolia/client-abtesting": "5.49.2", + "@algolia/client-analytics": "5.49.2", + "@algolia/client-common": "5.49.2", + "@algolia/client-insights": "5.49.2", + "@algolia/client-personalization": "5.49.2", + "@algolia/client-query-suggestions": "5.49.2", + "@algolia/client-search": "5.49.2", + "@algolia/ingestion": "1.49.2", + "@algolia/monitoring": "1.49.2", + "@algolia/recommend": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1031,6 +2202,27 @@ "node": ">=12" } }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -1053,6 +2245,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/cli-table3": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", @@ -1068,6 +2282,17 @@ "@colors/colors": "1.5.0" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", @@ -1084,6 +2309,39 @@ "dev": true, "license": "MIT" }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1094,12 +2352,46 @@ "node": ">=8" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-module-lexer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", @@ -1187,6 +2479,16 @@ } } }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tabbable": "^6.4.0" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1215,6 +2517,62 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -1224,6 +2582,19 @@ "node": ">=8" } }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -1507,6 +2878,143 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true, + "license": "MIT" + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1537,6 +3045,18 @@ ], "license": "MIT" }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -1544,6 +3064,13 @@ "dev": true, "license": "MIT" }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1557,7 +3084,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -1594,6 +3120,55 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.29.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", + "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -1604,6 +3179,13 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/rolldown": { "version": "1.0.0-rc.9", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", @@ -1638,6 +3220,76 @@ "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" } }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -1655,6 +3307,27 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -1683,6 +3356,21 @@ "node": ">=8" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1695,6 +3383,26 @@ "node": ">=8" } }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -1739,6 +3447,17 @@ "node": ">=14.0.0" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1753,7 +3472,6 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -1789,13 +3507,115 @@ "dev": true, "license": "MIT" }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@oxc-project/runtime": "0.115.0", "lightningcss": "^1.32.0", @@ -1869,6 +3689,552 @@ } } }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vitepress/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitepress/node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/vitepress/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitepress/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz", @@ -1951,6 +4317,28 @@ } } }, + "node_modules/vue": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -1988,6 +4376,17 @@ "optional": true } } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index b35faa6..d17fb56 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,10 @@ "prepublishOnly": "npm run build", "test": "vitest run", "test:site": "node scripts/test-site.mjs", - "test:watch": "vitest" + "test:watch": "vitest", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" }, "keywords": [ "cli", @@ -49,10 +52,11 @@ }, "devDependencies": { "@types/js-yaml": "^4.0.9", - "@types/ws": "^8.5.13", "@types/node": "^22.13.10", + "@types/ws": "^8.5.13", "tsx": "^4.19.3", "typescript": "^5.8.2", + "vitepress": "^1.6.4", "vitest": "^4.1.0" } }