diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a957d12..1d11b70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: run: cd server && go test ./... web: - name: Web + core packages + name: Desktop UI runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -33,12 +33,10 @@ jobs: cache: npm - name: Install dependencies run: npm ci - - name: Build web - run: npm run build:web - - name: Test core - run: npm run test:core + - name: Build desktop UI + run: npm run build:ui - name: Test UI - run: npm run test:ui --if-present + run: npm test rust: name: Desktop (Tauri) cargo check @@ -58,5 +56,10 @@ jobs: libgtk-3-dev \ libxdo-dev - uses: dtolnay/rust-toolchain@stable + - uses: actions/setup-go@v5 + with: + go-version: '1.25' + - name: Prepare native sidecar + run: bash ./run.sh prepare - name: Cargo check run: cd src-tauri && cargo check diff --git a/AGENTS.md b/AGENTS.md index 3ec144b..0e6a491 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,26 +7,26 @@ ```text 浏览器 → 只看官网 + 文档(Gin :8788) 操作 → 只走桌面 Tauri(./run.sh gui) -apps/web (:5174) → 仅桌面 Vite 源 / 打包 frontendDist,不是浏览器产品 +src (:5174) → 仅桌面 Vite 源 / 打包 frontendDist,不是浏览器产品 ``` - **不要**把工作台做成浏览器 SaaS,或把 `:5174` 当对外入口。 -- Gin(`apps/server`)= 官网 / docs / health / 驱动相关 API;**不是**「远程多人协作后端」。 +- Gin(`server`)= 官网 / docs / health / 驱动相关 API;**不是**「远程多人协作后端」。 - 连接与查询数据默认在本机;密钥与连接串按现有桌面安全实践处理。 -同族:`opsxapi` 同形态;`opsxshell` 同样「浏览器=官网/docs,操作=桌面」(Gin 在 `apps/server`,**无**操作 API,原生全在 Rust)。 +同族:`opsxapi` 同形态;`opsxshell` 同样「浏览器=官网/docs,操作=桌面」(Gin 在 `server`,**无**操作 API,原生全在 Rust)。 ## 架构 ```text -packages/ui + apps/web → packages/transport(tauri-native | gin) → 桌面 / 本机 Gin -apps/desktop → Tauri 2 壳 -apps/server → Gin 官网 + docs + 驱动 API +src/ → React 桌面 UI / 本机 API +src-tauri/ → Tauri 2 壳 +server/ → Gin 官网 + docs + 驱动 API connection-types/ → 引擎注册表(ready / verified / notes) -agents/ → JDBC agent 桥(Java 单文件桥 + 协议文档;Go 侧在 apps/server/internal/db/agent.go) +agents/ → JDBC agent 桥(Java 单文件桥 + 协议文档;Go 侧在 server/internal/db/agent.go) ``` -改驱动能力:先动注册表与 server/desktop 对应路径,再补 UI;未 `ready` 的引擎界面须灰态,勿标成可用。 +改驱动能力:先动注册表与 server/src-tauri 对应路径,再补 UI;未 `ready` 的引擎界面须灰态,勿标成可用。 ## 怎么跑 @@ -37,10 +37,10 @@ npm install ./run.sh stop | status | restart ``` -改 `apps/server` 后需重编(`./run.sh restart`)。清单与验收见 `docs/BACKLOG.md`。 +改 `server` 后需重编(`./run.sh restart`)。清单与验收见 `docs/BACKLOG.md`。 ## 给 AI -- 跟现有 monorepo 分包,勿平行造第二套客户端。 +- 沿用根级 src / src-tauri / server 架构,勿重建 apps 或第二套客户端;homepage 保持独立。 - 需求清楚就直接改;细节以邻近代码与 BACKLOG 为准,不必先扩写长规范。 - 少加「仅 AI 可读」的重复文档;用户可见文案与 docs 内容保持同步即可。 diff --git a/CLAUDE.md b/CLAUDE.md index 57fab9d..35990c4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,7 @@ 请使用中文。规则以 [AGENTS.md](./AGENTS.md) 为准。 -**浏览器 = Gin 官网 + `/docs`(:8788);操作只走桌面 Tauri。** `apps/web` 只是桌面打包源。 +**浏览器 = Gin 官网 + `/docs`(:8788);操作只走桌面 Tauri。** `src` 只是桌面打包源。 ```bash ./run.sh web # 官网/文档 diff --git a/Makefile b/Makefile index 15efe71..343d1ca 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ install: npm install - npm --prefix apps/desktop install web: ./run.sh web @@ -26,7 +25,7 @@ desktop: ./run.sh desktop build-web: - npm run build:web + npm run build:ui # test = Go 后端用例 + UI 回归 test: @@ -37,4 +36,4 @@ test-go: cd server && go test ./... test-ui: - npm run test:ui --if-present + npm test diff --git a/agents/README.md b/agents/README.md index 9f13793..4ec5347 100644 --- a/agents/README.md +++ b/agents/README.md @@ -3,7 +3,7 @@ 纯 JDK + gson 的通用 JDBC 桥:Go 服务端通过 stdin/stdout 的 JSON Lines 协议驱动一个 本机 JVM 进程,由它加载**官方 JDBC 驱动**(用户自备 jar,许可合规)连接数据库。 设计对标 DBX 的 agent 模式;v1 先接达梦,新增驱动在 -`apps/server/internal/db/agent.go` 的 `agentDriverSpecs` 登记一行即可。 +`server/internal/db/agent.go` 的 `agentDriverSpecs` 登记一行即可。 ## 组成 @@ -11,9 +11,9 @@ agents/jdbc/OpsxJdbcAgent.java JDBC 通用桥(达梦等官方 JDBC 驱动) agents/jdbc/OpsxZkAgent.java ZooKeeper 专属桥(官方客户端,NIO socket 免 netty 全家桶之外还需 6 个 netty jar 供 SSL 类初始化) agents/jdbc/OpsxMongoAgent.java MongoDB 专属桥(官方 sync driver + 迷你 DSL) -apps/server/internal/db/agent.go Go 侧:进程池 / 协议客户端 / 元数据与执行入口(注册表 agentDriverSpecs) -apps/server/internal/db/es.go Elasticsearch 原生接入(HTTP + SQL API) -apps/server/internal/db/influx.go InfluxDB 2.x 原生接入(HTTP + Flux) +server/internal/db/agent.go Go 侧:进程池 / 协议客户端 / 元数据与执行入口(注册表 agentDriverSpecs) +server/internal/db/es.go Elasticsearch 原生接入(HTTP + SQL API) +server/internal/db/influx.go InfluxDB 2.x 原生接入(HTTP + Flux) ``` > Elasticsearch 曾评估走 agent + x-pack-sql-jdbc,实测 basic 许可报 diff --git a/apps/desktop/package-lock.json b/apps/desktop/package-lock.json deleted file mode 100644 index 5031bd6..0000000 --- a/apps/desktop/package-lock.json +++ /dev/null @@ -1,220 +0,0 @@ -{ - "name": "@opsxdb/desktop", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@opsxdb/desktop", - "version": "0.1.0", - "devDependencies": { - "@tauri-apps/cli": "^2.4.0" - } - }, - "node_modules/@tauri-apps/cli": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", - "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", - "dev": true, - "bin": { - "tauri": "tauri.js" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/tauri" - }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.11.4", - "@tauri-apps/cli-darwin-x64": "2.11.4", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", - "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", - "@tauri-apps/cli-linux-arm64-musl": "2.11.4", - "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", - "@tauri-apps/cli-linux-x64-gnu": "2.11.4", - "@tauri-apps/cli-linux-x64-musl": "2.11.4", - "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", - "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", - "@tauri-apps/cli-win32-x64-msvc": "2.11.4" - } - }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", - "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", - "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", - "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", - "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", - "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", - "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", - "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", - "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", - "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", - "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", - "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - } - } -} diff --git a/apps/desktop/package.json b/apps/desktop/package.json deleted file mode 100644 index 8a6d833..0000000 --- a/apps/desktop/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@opsxdb/desktop", - "version": "0.1.0", - "private": true, - "scripts": { - "tauri": "tauri" - }, - "devDependencies": { - "@tauri-apps/cli": "^2.4.0" - } -} diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml deleted file mode 100644 index 9270a8d..0000000 --- a/apps/desktop/src-tauri/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "opsxdb-desktop" -version = "0.1.0" -description = "OpsxDB Tauri desktop shell" -authors = ["OpsxDB"] -edition = "2021" -default-run = "OpsxDB" - -[lib] -name = "opsxdb_desktop_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[[bin]] -name = "OpsxDB" -path = "src/main.rs" - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -tauri = { version = "2", features = [] } # path via Manager -tauri-plugin-single-instance = "2" # 二次启动聚焦已有窗口 -serde = { version = "1", features = ["derive"] } -serde_json = "1" -reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json", "blocking"] } -tokio = { version = "1", features = ["time"] } -url = "2" -rand = "0.8" -tauri-plugin-window-state = "2" diff --git a/apps/desktop/src-tauri/build.rs b/apps/desktop/src-tauri/build.rs deleted file mode 100644 index d860e1e..0000000 --- a/apps/desktop/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build() -} diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json deleted file mode 100644 index ab248a4..0000000 --- a/apps/desktop/src-tauri/capabilities/default.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "Default capabilities for the OpsxDB main window", - "windows": [ - "main" - ], - "permissions": [ - "core:default", - "window-state:default" - ] -} diff --git a/apps/desktop/src-tauri/icons/128x128.png b/apps/desktop/src-tauri/icons/128x128.png deleted file mode 100644 index dd5d5a5..0000000 Binary files a/apps/desktop/src-tauri/icons/128x128.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/128x128@2x.png b/apps/desktop/src-tauri/icons/128x128@2x.png deleted file mode 100644 index 3d58e3e..0000000 Binary files a/apps/desktop/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/32x32.png b/apps/desktop/src-tauri/icons/32x32.png deleted file mode 100644 index c400508..0000000 Binary files a/apps/desktop/src-tauri/icons/32x32.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/64x64.png b/apps/desktop/src-tauri/icons/64x64.png deleted file mode 100644 index 518db93..0000000 Binary files a/apps/desktop/src-tauri/icons/64x64.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square107x107Logo.png b/apps/desktop/src-tauri/icons/Square107x107Logo.png deleted file mode 100644 index ce0c62a..0000000 Binary files a/apps/desktop/src-tauri/icons/Square107x107Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square142x142Logo.png b/apps/desktop/src-tauri/icons/Square142x142Logo.png deleted file mode 100644 index d3209c2..0000000 Binary files a/apps/desktop/src-tauri/icons/Square142x142Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square150x150Logo.png b/apps/desktop/src-tauri/icons/Square150x150Logo.png deleted file mode 100644 index dbb1c82..0000000 Binary files a/apps/desktop/src-tauri/icons/Square150x150Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square284x284Logo.png b/apps/desktop/src-tauri/icons/Square284x284Logo.png deleted file mode 100644 index 8078d1d..0000000 Binary files a/apps/desktop/src-tauri/icons/Square284x284Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square30x30Logo.png b/apps/desktop/src-tauri/icons/Square30x30Logo.png deleted file mode 100644 index 0a73e00..0000000 Binary files a/apps/desktop/src-tauri/icons/Square30x30Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square310x310Logo.png b/apps/desktop/src-tauri/icons/Square310x310Logo.png deleted file mode 100644 index 1b1b8c2..0000000 Binary files a/apps/desktop/src-tauri/icons/Square310x310Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square44x44Logo.png b/apps/desktop/src-tauri/icons/Square44x44Logo.png deleted file mode 100644 index 2cd5e2b..0000000 Binary files a/apps/desktop/src-tauri/icons/Square44x44Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square71x71Logo.png b/apps/desktop/src-tauri/icons/Square71x71Logo.png deleted file mode 100644 index 01015a9..0000000 Binary files a/apps/desktop/src-tauri/icons/Square71x71Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/Square89x89Logo.png b/apps/desktop/src-tauri/icons/Square89x89Logo.png deleted file mode 100644 index a8250c6..0000000 Binary files a/apps/desktop/src-tauri/icons/Square89x89Logo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/StoreLogo.png b/apps/desktop/src-tauri/icons/StoreLogo.png deleted file mode 100644 index 70abd6b..0000000 Binary files a/apps/desktop/src-tauri/icons/StoreLogo.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml b/apps/desktop/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 2ffbf24..0000000 --- a/apps/desktop/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index ec23ae9..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 7afb752..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index 38a17e0..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 2fb0fe7..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 9fcd5d6..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index e37aa7f..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 1d93418..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 23d33e0..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index bdf6a4b..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 28c4417..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 543a3c0..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index 70f66f0..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 2404cb4..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 63134f3..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index f4fdb65..0000000 Binary files a/apps/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/android/values/ic_launcher_background.xml b/apps/desktop/src-tauri/icons/android/values/ic_launcher_background.xml deleted file mode 100644 index ea9c223..0000000 --- a/apps/desktop/src-tauri/icons/android/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #fff - \ No newline at end of file diff --git a/apps/desktop/src-tauri/icons/icon.icns b/apps/desktop/src-tauri/icons/icon.icns deleted file mode 100644 index 73fcf19..0000000 Binary files a/apps/desktop/src-tauri/icons/icon.icns and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/icon.ico b/apps/desktop/src-tauri/icons/icon.ico deleted file mode 100644 index 240a49e..0000000 Binary files a/apps/desktop/src-tauri/icons/icon.ico and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/icon.png b/apps/desktop/src-tauri/icons/icon.png deleted file mode 100644 index 03b7766..0000000 Binary files a/apps/desktop/src-tauri/icons/icon.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/icon.svg b/apps/desktop/src-tauri/icons/icon.svg deleted file mode 100644 index 8accdbc..0000000 --- a/apps/desktop/src-tauri/icons/icon.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png deleted file mode 100644 index b32b5ce..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png deleted file mode 100644 index ceeee7f..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png deleted file mode 100644 index ceeee7f..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png deleted file mode 100644 index b64c721..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png deleted file mode 100644 index dded63b..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png deleted file mode 100644 index d3b6745..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png deleted file mode 100644 index d3b6745..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png deleted file mode 100644 index f4e1b0a..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png deleted file mode 100644 index ceeee7f..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png deleted file mode 100644 index 9dc1641..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png deleted file mode 100644 index 9dc1641..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png deleted file mode 100644 index 1851a00..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png deleted file mode 100644 index ae96588..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-512@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png deleted file mode 100644 index 1851a00..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png deleted file mode 100644 index c8ee8b4..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png deleted file mode 100644 index 7351eb1..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png deleted file mode 100644 index 1be910b..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png deleted file mode 100644 index bf53b2e..0000000 Binary files a/apps/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/options/cylinder.png b/apps/desktop/src-tauri/icons/options/cylinder.png deleted file mode 100644 index eb72235..0000000 Binary files a/apps/desktop/src-tauri/icons/options/cylinder.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/options/cylinder.svg b/apps/desktop/src-tauri/icons/options/cylinder.svg deleted file mode 100644 index 8f30d42..0000000 --- a/apps/desktop/src-tauri/icons/options/cylinder.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/apps/desktop/src-tauri/icons/options/star.png b/apps/desktop/src-tauri/icons/options/star.png deleted file mode 100644 index 169cacf..0000000 Binary files a/apps/desktop/src-tauri/icons/options/star.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/options/star.svg b/apps/desktop/src-tauri/icons/options/star.svg deleted file mode 100644 index a5a4b2d..0000000 --- a/apps/desktop/src-tauri/icons/options/star.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/apps/desktop/src-tauri/icons/options/tilt.png b/apps/desktop/src-tauri/icons/options/tilt.png deleted file mode 100644 index 6e9af19..0000000 Binary files a/apps/desktop/src-tauri/icons/options/tilt.png and /dev/null differ diff --git a/apps/desktop/src-tauri/icons/options/tilt.svg b/apps/desktop/src-tauri/icons/options/tilt.svg deleted file mode 100644 index 1c23a36..0000000 --- a/apps/desktop/src-tauri/icons/options/tilt.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs deleted file mode 100644 index f25f3e2..0000000 --- a/apps/desktop/src-tauri/src/lib.rs +++ /dev/null @@ -1,170 +0,0 @@ -mod sidecar; - -use tauri::Manager; - -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::time::{Duration, Instant}; - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct BodySpec { - mode: String, - raw: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct HttpSpec { - method: String, - url: String, - #[serde(default)] - headers: HashMap, - query: Option>, - body: Option, - timeout_ms: Option, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct HttpResult { - status: u16, - headers: HashMap, - body: String, - time_ms: u128, - size: usize, -} - -#[derive(Debug, Deserialize)] -struct WsSpec { - url: String, - protocols: Option>, - headers: Option>, -} - -fn validate_http_url(raw: &str) -> Result { - let parsed = url::Url::parse(raw).map_err(|e| format!("invalid URL: {e}"))?; - match parsed.scheme() { - "http" | "https" => {} - _ => return Err("only http/https schemes are allowed".into()), - } - match parsed.host_str().unwrap_or("").to_ascii_lowercase().as_str() { - "169.254.169.254" | "metadata.google.internal" => { - return Err("blocked metadata host".into()) - } - _ => {} - } - Ok(parsed) -} - -#[tauri::command] -async fn http_send(spec: HttpSpec) -> Result { - let mut url = validate_http_url(&spec.url)?; - if let Some(query) = &spec.query { - let mut pairs = url.query_pairs_mut(); - for (key, value) in query { - pairs.append_pair(key, value); - } - } - - let method = reqwest::Method::from_bytes(spec.method.as_bytes()) - .map_err(|e| format!("invalid method: {e}"))?; - let timeout = Duration::from_millis(spec.timeout_ms.unwrap_or(30_000)); - let client = reqwest::Client::builder() - .timeout(timeout) - .build() - .map_err(|e| e.to_string())?; - let mut request = client.request(method, url); - for (key, value) in spec.headers { - request = request.header(&key, &value); - } - if let Some(body) = spec.body { - if body.mode != "none" { - request = request.body(body.raw.unwrap_or_default()); - } - } - - let started = Instant::now(); - let response = request.send().await.map_err(|e| e.to_string())?; - let status = response.status().as_u16(); - let headers = response - .headers() - .iter() - .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())) - .collect(); - let bytes = response.bytes().await.map_err(|e| e.to_string())?; - let size = bytes.len(); - let body = String::from_utf8_lossy(&bytes).into_owned(); - Ok(HttpResult { - status, - headers, - body, - time_ms: started.elapsed().as_millis(), - size, - }) -} - -#[tauri::command] -async fn ws_connect(spec: WsSpec) -> Result { - let _ = (&spec.protocols, &spec.headers); - // TODO(week2): hold WebSocket sessions in managed state and emit messages. - Err(format!( - "WebSocket native tunnel is not implemented yet for {} (use browser WS in MVP)", - spec.url - )) -} - -#[tauri::command] -async fn ws_send(session_id: String, data: String) -> Result<(), String> { - let _ = (session_id, data); - Err("WebSocket native send is a Week 2 stub".into()) -} - -#[tauri::command] -async fn ws_close(session_id: String) -> Result<(), String> { - let _ = session_id; - Ok(()) -} - -/// 前端启动时拉取后端地址与 token(注入 window.__OPSXDB_API__/__OPSXDB_TOKEN__)。 -#[tauri::command] -fn get_backend_config( - state: tauri::State<'_, sidecar::SidecarState>, -) -> Result { - state - .backend_config() - .ok_or_else(|| "后端尚未就绪".to_string()) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { - // 二次启动聚焦已有窗口 - if let Some(w) = app.get_webview_window("main") { - let _ = w.show(); - let _ = w.unminimize(); - let _ = w.set_focus(); - } - })) - .plugin(tauri_plugin_window_state::Builder::default().build()) - .manage(sidecar::SidecarState::default()) - .setup(|app| { - let state = app.state::(); - sidecar::ensure_backend(app.handle(), &state); - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - http_send, - ws_connect, - ws_send, - ws_close, - get_backend_config - ]) - .build(tauri::generate_context!()) - .expect("error while building OpsxDB desktop") - .run(|app, event| { - let state = app.state::(); - sidecar::on_run_event(app, &event, &state); - }); -} diff --git a/apps/desktop/src-tauri/src/main.rs b/apps/desktop/src-tauri/src/main.rs deleted file mode 100644 index a5f036e..0000000 --- a/apps/desktop/src-tauri/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - opsxdb_desktop_lib::run(); -} diff --git a/apps/desktop/src-tauri/src/sidecar.rs b/apps/desktop/src-tauri/src/sidecar.rs deleted file mode 100644 index d5084b6..0000000 --- a/apps/desktop/src-tauri/src/sidecar.rs +++ /dev/null @@ -1,212 +0,0 @@ -//! 桌面启动时拉起本机 OpsxDB Gin 后端。 -//! - 动态端口:TcpListener 绑 127.0.0.1:0 选空闲端口,OPSXDB_ADDR 传子进程; -//! - 每次自起生成随机 token,OPSXDB_TOKEN 传子进程,与 addr 一起经 get_backend_config 注入前端; -//! - 复用 8788 上已运行后端前先比对 /health 版本主版本,不匹配则换端口自起; -//! - 失败时 emit "opsxdb://backend-failed",后端 stdout/stderr 重定向到 app_log_dir/opsxdb-server.log。 -use std::path::PathBuf; -use std::process::{Child, Command, Stdio}; -use std::sync::Mutex; -use std::thread; -use std::time::Duration; -use tauri::{AppHandle, Emitter, Manager, RunEvent}; - -const DEFAULT_ADDR: &str = "127.0.0.1:8788"; -/// 与服务端 cmd/opsxdb main.go Version 保持一致,复用前比对主版本。 -const BACKEND_VERSION: &str = "0.1.0"; -const EVENT_BACKEND_FAILED: &str = "opsxdb://backend-failed"; - -#[derive(Clone, serde::Serialize)] -#[serde(rename_all = "camelCase")] -pub struct BackendConfig { - pub addr: String, - pub token: String, -} - -pub struct SidecarState { - child: Mutex>, - config: Mutex>, -} - -impl Default for SidecarState { - fn default() -> Self { - Self { - child: Mutex::new(None), - config: Mutex::new(None), - } - } -} - -impl SidecarState { - fn set_config(&self, cfg: BackendConfig) { - if let Ok(mut g) = self.config.lock() { - *g = Some(cfg); - } - } - - pub fn backend_config(&self) -> Option { - self.config.lock().ok().and_then(|g| g.clone()) - } -} - -fn version_major(v: &str) -> &str { - v.split('.').next().unwrap_or("") -} - -/// GET /health 并解析版本;失败或非 200 返回 None。 -fn health_version(addr: &str) -> Option { - let resp = reqwest::blocking::Client::builder() - .timeout(Duration::from_secs(1)) - .build() - .ok()? - .get(format!("http://{addr}/health")) - .send() - .ok()?; - if !resp.status().is_success() { - return None; - } - let v: serde_json::Value = resp.json().ok()?; - v.get("version")?.as_str().map(|s| s.to_string()) -} - -fn health_ok(addr: &str) -> bool { - health_version(addr).is_some() -} - -/// 尝试复用 8788 上已在运行的后端:仅当主版本一致才复用, -/// 否则换端口自起而非静默连上旧版本。 -fn try_reuse_existing(state: &SidecarState) -> bool { - match health_version(DEFAULT_ADDR) { - Some(v) if version_major(&v) == version_major(BACKEND_VERSION) => { - // 复用路径拿不到对方 token,按本机 dev 无鉴权处理 - state.set_config(BackendConfig { - addr: format!("http://{DEFAULT_ADDR}"), - token: String::new(), - }); - true - } - Some(v) => { - eprintln!( - "opsxdb: 已有后端版本 {v} 与期望 {BACKEND_VERSION} 主版本不匹配,改自动态端口自起" - ); - false - } - None => false, - } -} - -/// 绑 127.0.0.1:0 选一个空闲端口(立即释放,交给子进程绑定)。 -fn pick_free_port() -> Option { - let ln = std::net::TcpListener::bind("127.0.0.1:0").ok()?; - ln.local_addr().ok().map(|a| a.port()) -} - -fn gen_token() -> String { - use rand::RngCore; - let mut b = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut b); - b.iter().map(|x| format!("{x:02x}")).collect() -} - -fn candidate_bins(app: &AppHandle) -> Vec { - // Windows 产物为 opsxdb-server.exe - let bin = format!("opsxdb-server{}", std::env::consts::EXE_EXTENSION); - let mut out = Vec::new(); - // 打包资源:externalBin → 与可执行文件同级的 binaries 或 resource - if let Ok(dir) = app.path().resource_dir() { - out.push(dir.join(&bin)); - out.push(dir.join("binaries").join(&bin)); - } - if let Ok(exe) = app.path().executable_dir() { - out.push(exe.join(&bin)); - out.push(exe.join("binaries").join(&bin)); - } - // 开发态:仓库 apps/server/bin - out.push(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../server/bin").join(&bin)); - out.push(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../apps/server/bin").join(&bin)); - out -} - -/// 后端 stdout/stderr 重定向到 app_log_dir/opsxdb-server.log。 -fn server_log_file(app: &AppHandle) -> Option { - let dir = app.path().app_log_dir().ok()?; - std::fs::create_dir_all(&dir).ok()?; - std::fs::File::create(dir.join("opsxdb-server.log")).ok() -} - -fn spawn_server( - bin: &PathBuf, - addr: &str, - token: &str, - log_file: Option<&std::fs::File>, -) -> std::io::Result { - let mut cmd = Command::new(bin); - cmd.env("OPSXDB_ADDR", addr) - .env("OPSXDB_TOKEN", token) - .env("GIN_MODE", "release"); - match log_file { - Some(f) => { - let err_f = f.try_clone()?; - cmd.stdout(Stdio::from(f.try_clone()?)).stderr(Stdio::from(err_f)); - } - None => { - cmd.stdout(Stdio::null()).stderr(Stdio::null()); - } - } - cmd.spawn() -} - -pub fn ensure_backend(app: &AppHandle, state: &SidecarState) { - if try_reuse_existing(state) { - return; - } - let Some(port) = pick_free_port() else { - let _ = app.emit(EVENT_BACKEND_FAILED, "无法分配空闲端口"); - return; - }; - let addr = format!("127.0.0.1:{port}"); - let token = gen_token(); - let log_file = server_log_file(app); - let mut last_err = String::from("未找到后端二进制"); - for bin in candidate_bins(app) { - if !bin.exists() { - continue; - } - match spawn_server(&bin, &addr, &token, log_file.as_ref()) { - Ok(child) => { - *state.child.lock().unwrap() = Some(child); - for _ in 0..30 { - if health_ok(&addr) { - state.set_config(BackendConfig { - addr: format!("http://{addr}"), - token: token.clone(), - }); - return; - } - thread::sleep(Duration::from_millis(100)); - } - last_err = format!("后端启动后健康检查超时({})", bin.display()); - } - Err(e) => { - last_err = format!("启动 {} 失败: {e}", bin.display()); - continue; - } - } - } - let _ = app.emit(EVENT_BACKEND_FAILED, last_err); -} - -pub fn stop_backend(state: &SidecarState) { - if let Ok(mut g) = state.child.lock() { - if let Some(mut child) = g.take() { - let _ = child.kill(); - let _ = child.wait(); - } - } -} - -pub fn on_run_event(app: &AppHandle, event: &RunEvent, state: &SidecarState) { - if matches!(event, RunEvent::Exit | RunEvent::ExitRequested { .. }) { - stop_backend(state); - let _ = app; - } -} diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json deleted file mode 100644 index e1c1df2..0000000 --- a/apps/desktop/src-tauri/tauri.conf.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "OpsxDB", - "version": "0.1.0", - "identifier": "com.opsx.db", - "build": { - "beforeDevCommand": "bash -lc 'curl -fsS http://127.0.0.1:5174 >/dev/null 2>&1 || npm --prefix ../.. run dev:web'", - "devUrl": "http://127.0.0.1:5174", - "beforeBuildCommand": "bash -lc 'cd ../.. && npm run build:web'", - "frontendDist": "../../web/dist" - }, - "app": { - "windows": [ - { - "title": "OpsxDB", - "width": 1280, - "height": 800, - "minWidth": 960, - "minHeight": 640, - "resizable": true, - "fullscreen": false, - "label": "main" - } - ], - "security": { - "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:* ipc://localhost; object-src 'none'; base-uri 'self'" - } - }, - "bundle": { - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "externalBin": [ - "binaries/opsxdb-server" - ] - } -} diff --git a/apps/web/index.html b/apps/web/index.html deleted file mode 100644 index da0ae42..0000000 --- a/apps/web/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - OpsxDB - - -
- - - diff --git a/apps/web/package.json b/apps/web/package.json deleted file mode 100644 index 15a1a13..0000000 --- a/apps/web/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@opsxdb/web", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --host 127.0.0.1 --port 5174", - "build": "tsc -b && vite build", - "preview": "vite preview --host 127.0.0.1 --port 5174" - }, - "dependencies": { - "@opsxdb/ui": "*", - "@tauri-apps/api": "^2.5.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@types/node": "^22.20.3", - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", - "@vitejs/plugin-react": "^4.4.1", - "autoprefixer": "^10.4.21", - "postcss": "^8.5.3", - "tailwindcss": "^3.4.17", - "typescript": "^5.8.2", - "vite": "^6.2.2" - } -} diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js deleted file mode 100644 index 2aa7205..0000000 --- a/apps/web/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg deleted file mode 100644 index 8accdbc..0000000 --- a/apps/web/public/favicon.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/apps/web/public/icons/databases/dameng.svg b/apps/web/public/icons/databases/dameng.svg deleted file mode 100644 index 5315156..0000000 --- a/apps/web/public/icons/databases/dameng.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/elasticsearch.svg b/apps/web/public/icons/databases/elasticsearch.svg deleted file mode 100644 index 0da0d70..0000000 --- a/apps/web/public/icons/databases/elasticsearch.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/gaussdb.svg b/apps/web/public/icons/databases/gaussdb.svg deleted file mode 100644 index f115a85..0000000 --- a/apps/web/public/icons/databases/gaussdb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/influxdb.svg b/apps/web/public/icons/databases/influxdb.svg deleted file mode 100644 index a6ed507..0000000 --- a/apps/web/public/icons/databases/influxdb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/kingbase.svg b/apps/web/public/icons/databases/kingbase.svg deleted file mode 100644 index 9d7f076..0000000 --- a/apps/web/public/icons/databases/kingbase.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/mariadb.svg b/apps/web/public/icons/databases/mariadb.svg deleted file mode 100644 index 33794b1..0000000 --- a/apps/web/public/icons/databases/mariadb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/mongodb.svg b/apps/web/public/icons/databases/mongodb.svg deleted file mode 100644 index 8660ced..0000000 --- a/apps/web/public/icons/databases/mongodb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/mysql.svg b/apps/web/public/icons/databases/mysql.svg deleted file mode 100644 index 853c55f..0000000 --- a/apps/web/public/icons/databases/mysql.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/oceanbase.svg b/apps/web/public/icons/databases/oceanbase.svg deleted file mode 100644 index 2ace405..0000000 --- a/apps/web/public/icons/databases/oceanbase.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/opengauss.svg b/apps/web/public/icons/databases/opengauss.svg deleted file mode 100644 index 6f46971..0000000 --- a/apps/web/public/icons/databases/opengauss.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/oracle.svg b/apps/web/public/icons/databases/oracle.svg deleted file mode 100644 index f5449b2..0000000 --- a/apps/web/public/icons/databases/oracle.svg +++ /dev/null @@ -1 +0,0 @@ -Oracle \ No newline at end of file diff --git a/apps/web/public/icons/databases/polardb.png b/apps/web/public/icons/databases/polardb.png deleted file mode 100644 index 197ba75..0000000 Binary files a/apps/web/public/icons/databases/polardb.png and /dev/null differ diff --git a/apps/web/public/icons/databases/postgresql.svg b/apps/web/public/icons/databases/postgresql.svg deleted file mode 100644 index abacb8f..0000000 --- a/apps/web/public/icons/databases/postgresql.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/redis.svg b/apps/web/public/icons/databases/redis.svg deleted file mode 100644 index 1981b34..0000000 --- a/apps/web/public/icons/databases/redis.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/sqlite.svg b/apps/web/public/icons/databases/sqlite.svg deleted file mode 100644 index dde0558..0000000 --- a/apps/web/public/icons/databases/sqlite.svg +++ /dev/null @@ -1,7 +0,0 @@ - - SQLite - - - - - diff --git a/apps/web/public/icons/databases/sqlserver.svg b/apps/web/public/icons/databases/sqlserver.svg deleted file mode 100644 index b23e83d..0000000 --- a/apps/web/public/icons/databases/sqlserver.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/tdsql.svg b/apps/web/public/icons/databases/tdsql.svg deleted file mode 100644 index 65627ff..0000000 --- a/apps/web/public/icons/databases/tdsql.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Tencent Cloud - - - - - - - - diff --git a/apps/web/public/icons/databases/tidb.svg b/apps/web/public/icons/databases/tidb.svg deleted file mode 100644 index ee0b723..0000000 --- a/apps/web/public/icons/databases/tidb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/databases/zookeeper.svg b/apps/web/public/icons/databases/zookeeper.svg deleted file mode 100644 index a281bab..0000000 --- a/apps/web/public/icons/databases/zookeeper.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/icons/icon-512.png b/apps/web/public/icons/icon-512.png deleted file mode 100644 index 165a23b..0000000 Binary files a/apps/web/public/icons/icon-512.png and /dev/null differ diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx deleted file mode 100644 index 5f42dc1..0000000 --- a/apps/web/src/main.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import { OpsxWorkspace } from "@opsxdb/ui"; -import "./styles.css"; - -const root = document.getElementById("root")!; -const isTauri = - typeof window !== "undefined" && - Boolean((window as unknown as { __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__); - -// 产品唯一形态是桌面 Tauri:生产构建被浏览器打开时展示导引页,不渲染工作台。 -// (开发态的 Vite 浏览器访问保留,仅供 UI 调试。) -if (!isTauri && import.meta.env.PROD) { - ReactDOM.createRoot(root).render( -
-
-
🗄️
-

OpsxDB 请在桌面应用中打开

-

- 客户端唯一形态是桌面 App(Tauri 2),本页面仅为桌面端构建产物。 -
- 官网与文档由本地后端提供: - 官网 ·{" "} - 文档 -

-
-
, - ); -} else { - ReactDOM.createRoot(root).render( - - - , - ); -} diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css deleted file mode 100644 index 61deba2..0000000 --- a/apps/web/src/styles.css +++ /dev/null @@ -1,553 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - /* Design tokens v2 — 亮暗双套同色相,4 级字号,间距/圆角/阴影/层级全令牌化 */ - color-scheme: dark; - /* 背景层级:三档,编辑器不再另起第四档深色(修 V7) */ - --ops-bg: #0e1116; - --ops-surface: #151a21; - --ops-surface-2: #1a212b; - --ops-editor-bg: #10151c; /* 介于 bg 与 surface 之间,取代 #070b11 "黑洞" */ - /* 边框 / 文本 */ - --ops-border: #2a3340; - --ops-border-soft: #1f2733; - --ops-text: #e8edf5; - --ops-muted: #8b95a5; - /* 语义色:亮暗同色相,仅调明度(修 V3) */ - --ops-accent: #3b82f6; - --ops-accent-strong: #2563eb; - --ops-accent-soft: color-mix(in srgb, var(--ops-accent) 16%, transparent); /* 补齐 V1 */ - --ops-danger: #ef4444; - --ops-warning: #f59e0b; /* 统一命名,已删除 --ops-warn 别名(修 V1,引用侧由 WS-C 收敛) */ - --ops-success: #10b981; - /* 兼容别名:--ops-fg 是历史误引用,统一收敛为 --ops-text(修 V1) */ - --ops-fg: var(--ops-text); - --ops-input-bg: var(--ops-surface-2); /* 补齐 V1 */ - --ops-row-alt: rgba(26, 33, 43, 0.65); - --ops-bg-active: var(--ops-accent-soft); - /* 字号:收敛为 4 级(修 V4,废除 10/11.5/12.5px) */ - --ops-text-xs: 11px; /* 徽章、分组标签、状态栏 */ - --ops-text-sm: 12px; /* 网格、树、次要文本 */ - --ops-text-md: 13px; /* 正文、模态、表单 */ - --ops-text-lg: 15px; /* 模态标题、空态标题 */ - /* v1 字号别名:映射到 4 级新令牌,WS-C 收敛引用后删除 */ - --ops-font-xs: var(--ops-text-xs); - --ops-font-sm: var(--ops-text-sm); - --ops-font-md: var(--ops-text-md); - /* 间距:4 的倍数 */ - --ops-space-1: 4px; --ops-space-2: 8px; --ops-space-3: 12px; - --ops-space-4: 16px; --ops-space-5: 24px; --ops-space-6: 32px; - /* 圆角:3 级(修 V5) */ - --ops-radius-sm: 4px; /* 按钮、输入框、标签 */ - --ops-radius-md: 6px; /* 卡片、右键菜单 */ - --ops-radius-lg: 10px; /* 模态、Toast */ - /* 阴影:2 级 */ - --ops-shadow-pop: 0 8px 24px rgb(0 0 0 / .35); - --ops-shadow-modal: 0 16px 48px rgb(0 0 0 / .45); - /* 层级 */ - --ops-z-banner: 40; /* 断连/后端未就绪横幅 */ - --ops-z-ctx: 80; /* 右键菜单 */ - --ops-z-toast: 90; - --ops-z-modal: 100; - --ops-z-confirm: 110; - /* 尺寸(保留 v1) */ - --ops-toolbar-h: 36px; --ops-tab-h: 32px; --ops-row-h: 28px; - --ops-statusbar-h: 24px; --ops-sidebar-w: 260px; - /* 滚动条走令牌(修 V11) */ - --ops-scrollbar: #334155; - } - html.light { - /* 亮色:同色相,仅调明度 */ - color-scheme: light; - --ops-bg: #f1f5f9; --ops-surface: #ffffff; --ops-surface-2: #f8fafc; - --ops-editor-bg: #f1f5f9; - --ops-border: #e2e8f0; --ops-border-soft: #eef2f7; - --ops-text: #1e293b; --ops-muted: #64748b; - --ops-accent: #2563eb; /* 蓝色系,不再切换青色(修 V3) */ - --ops-accent-strong: #1d4ed8; - --ops-danger: #dc2626; --ops-warning: #d97706; --ops-success: #059669; - --ops-row-alt: #f8fafc; - --ops-scrollbar: #cbd5e1; - } - * { scrollbar-color: var(--ops-scrollbar) transparent; scrollbar-width: thin; } - body { - @apply m-0 font-sans antialiased; - background: var(--ops-bg); - color: var(--ops-text); - } - button, input, select, textarea { font: inherit; } - /* 全局焦点环:覆盖按钮/树项/Tab(02-P2-3) */ - :focus-visible { - outline: 2px solid var(--ops-accent); - outline-offset: 1px; - } -} - -@layer components { - .ops-shell { - background: var(--ops-bg); - color: var(--ops-text); - } - - .ops-input { - @apply rounded border px-2 py-1 outline-none transition; - font-size: var(--ops-text-sm); - border-color: var(--ops-border); - background: var(--ops-input-bg); - color: var(--ops-text); - } - .ops-input::placeholder { color: var(--ops-muted); opacity: 0.7; } - .ops-input:focus { - border-color: var(--ops-accent); - box-shadow: 0 0 0 1px color-mix(in srgb, var(--ops-accent) 35%, transparent); - } - - .ops-btn-primary { - @apply inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded px-2.5 font-semibold text-white shadow-sm transition disabled:cursor-not-allowed disabled:opacity-50; - height: var(--ops-row-h); - font-size: var(--ops-text-sm); - background: var(--ops-accent-strong); - } - .ops-btn-primary:hover:not(:disabled) { background: var(--ops-accent); } - - /* 危险主按钮:删除/截断/无 WHERE 更新等确认场景统一红钮(修 C2/C3、G5) */ - .ops-btn-danger { - @apply inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded px-2.5 font-semibold text-white shadow-sm transition disabled:cursor-not-allowed disabled:opacity-50; - height: var(--ops-row-h); - font-size: var(--ops-text-sm); - background: var(--ops-danger); - } - .ops-btn-danger:hover:not(:disabled) { - background: color-mix(in srgb, var(--ops-danger) 85%, #fff); - } - - .ops-btn-secondary { - @apply inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded border px-2 transition; - height: var(--ops-row-h); - font-size: var(--ops-text-sm); - border-color: var(--ops-border); - background: var(--ops-surface-2); - color: var(--ops-text); - } - .ops-btn-secondary:hover { - border-color: color-mix(in srgb, var(--ops-accent) 45%, var(--ops-border)); - background: color-mix(in srgb, var(--ops-accent) 8%, var(--ops-surface-2)); - } - - .ops-btn-ghost { - @apply inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded px-1.5 transition; - height: var(--ops-row-h); - font-size: var(--ops-text-sm); - color: var(--ops-muted); - } - .ops-btn-ghost:hover { - color: var(--ops-text); - background: color-mix(in srgb, var(--ops-accent) 10%, transparent); - } - - .ops-btn-ai { - @apply rounded border px-1.5 py-0.5 font-medium transition; - font-size: var(--ops-text-xs); - border-color: var(--ops-border); - background: var(--ops-surface-2); - color: var(--ops-text); - } - .ops-btn-ai:hover:not(:disabled) { - border-color: color-mix(in srgb, var(--ops-accent) 50%, var(--ops-border)); - color: var(--ops-accent); - } - .ops-btn-ai:disabled { opacity: 0.5; cursor: not-allowed; } - - .ops-tabbar { - @apply flex shrink-0 items-stretch gap-0.5 overflow-x-auto border-b px-1; - height: var(--ops-tab-h); - border-color: var(--ops-border); - background: var(--ops-surface-2); - } - .ops-empty { - @apply flex flex-1 flex-col items-center justify-center gap-3 px-6 text-center; - color: var(--ops-muted); - background: var(--ops-bg); - } - .ops-empty h2 { - @apply m-0 font-semibold; - font-size: var(--ops-text-lg); - color: var(--ops-text); - } - .ops-empty p { - @apply m-0 max-w-sm; - font-size: var(--ops-text-sm); - } - .ops-conn-row { - @apply flex w-full items-center gap-3 border-b px-3 text-left transition; - min-height: 44px; - border-color: var(--ops-border-soft); - background: var(--ops-surface); - } - .ops-conn-row:hover { - background: color-mix(in srgb, var(--ops-accent) 8%, var(--ops-surface)); - } - .ops-section-card { - @apply space-y-2 rounded border p-3; - border-color: var(--ops-border); - background: var(--ops-surface); - } - .ops-section-title { - @apply mb-1 font-semibold uppercase; - font-size: var(--ops-text-xs); - color: var(--ops-muted); - letter-spacing: 0.04em; - } - .ops-tab { - @apply border-b-2 border-transparent px-2.5 py-1.5 font-medium transition; - font-size: var(--ops-text-sm); - color: var(--ops-muted); - } - .ops-tab:hover { color: var(--ops-text); } - .ops-tab-active { - border-color: var(--ops-accent); - color: var(--ops-accent); - } - - /* 编辑器:背景走 --ops-editor-bg,不再另起深色档(修 V7) */ - .ops-code { - @apply font-mono leading-[1.45] outline-none; - font-size: var(--ops-text-sm); - background: var(--ops-editor-bg); - color: var(--ops-text); - border-color: var(--ops-border); - } - - .ops-panel { - background: var(--ops-surface); - border-color: var(--ops-border); - } - - .ops-chrome-header { - @apply flex shrink-0 items-center gap-1.5 border-b px-2.5; - height: var(--ops-toolbar-h); - border-color: var(--ops-border); - background: color-mix(in srgb, var(--ops-surface) 92%, #000); - } - html.light .ops-chrome-header { - background: var(--ops-surface); - } - - .ops-section-label { - @apply flex h-7 shrink-0 items-center px-2.5 font-semibold uppercase tracking-[0.06em]; - font-size: var(--ops-text-xs); - color: var(--ops-muted); - border-color: var(--ops-border); - background: var(--ops-surface-2); - } - - .ops-statusbar { - @apply flex shrink-0 items-center gap-2.5 border-t px-2.5; - font-size: var(--ops-text-xs); - height: var(--ops-statusbar-h); - border-color: var(--ops-border); - background: var(--ops-surface-2); - color: var(--ops-muted); - } - - .ops-tree-item { - @apply flex w-full items-center gap-1 truncate rounded px-1.5 text-left leading-tight transition; - min-height: var(--ops-row-h); - font-size: var(--ops-text-sm); - color: color-mix(in srgb, var(--ops-text) 78%, var(--ops-muted)); - } - .ops-tree-item:hover { - background: color-mix(in srgb, var(--ops-accent) 10%, transparent); - color: var(--ops-accent); - } - .ops-tree-item-active { - background: color-mix(in srgb, var(--ops-accent) 14%, transparent); - color: var(--ops-accent); - } - - .ops-grid { - @apply w-full border-collapse text-left; - font-size: var(--ops-text-sm); - } - .ops-grid th { - @apply sticky top-0 border-b px-1.5 py-[3px] font-semibold whitespace-nowrap; - border-color: var(--ops-border); - background: var(--ops-surface-2); - color: var(--ops-muted); - } - .ops-grid td { - @apply border-b px-1.5 py-[2px] font-mono whitespace-nowrap; - border-color: var(--ops-border-soft); - color: var(--ops-text); - } - .ops-grid tbody tr:nth-child(even) td { - background: var(--ops-row-alt); - } - .ops-grid tbody tr:hover td { - background: color-mix(in srgb, var(--ops-accent) 8%, transparent); - } - .ops-grid tbody tr.ops-row-selected td { - background: var(--ops-bg-active) !important; - } - .ops-grid th { - position: relative; - user-select: none; - } - .ops-grid th .ops-col-resize { - position: absolute; - right: 0; - top: 0; - width: 5px; - height: 100%; - cursor: col-resize; - } - .ops-grid th.ops-sortable { - cursor: pointer; - } - .ops-driver-row { - display: flex; - align-items: center; - gap: 10px; - width: 100%; - min-height: var(--ops-row-h); - padding: 0 10px; - border-bottom: 1px solid var(--ops-border-soft); - text-align: left; - background: transparent; - color: var(--ops-text); - font-size: var(--ops-text-sm); - transition: background 0.1s; - } - .ops-driver-row:hover { - background: var(--ops-bg-active); - } - .ops-driver-row .ops-driver-meta { - margin-left: auto; - font-size: var(--ops-text-xs); - color: var(--ops-muted); - } - .ops-tab-dirty::before { - content: "●"; - margin-right: 4px; - font-size: 8px; - color: var(--ops-accent); - } - .ops-grid .ops-null { - color: var(--ops-muted); - font-style: italic; - } - .ops-grid .ops-rownum { - @apply w-7 min-w-[1.75rem] text-right select-none; - color: var(--ops-muted); - background: var(--ops-surface-2) !important; - } - - /* 统一模态基件样式:圆角/阴影/字级全走令牌,页脚右对齐 */ - .ops-modal-overlay { - position: fixed; - inset: 0; - display: flex; - align-items: center; - justify-content: center; - padding: var(--ops-space-4); - background: rgb(0 0 0 / .55); - backdrop-filter: blur(2px); - } - .ops-modal { - @apply overflow-hidden border; - border-radius: var(--ops-radius-lg); - border-color: var(--ops-border); - background: var(--ops-surface); - color: var(--ops-text); - box-shadow: var(--ops-shadow-modal); - font-size: var(--ops-text-md); - } - .ops-modal-header { - @apply border-b px-3.5 py-2 font-semibold; - font-size: var(--ops-text-md); - border-color: var(--ops-border); - background: var(--ops-surface-2); - } - .ops-modal-body { - @apply px-3.5 py-2.5 leading-relaxed; - font-size: var(--ops-text-md); - color: color-mix(in srgb, var(--ops-text) 90%, var(--ops-muted)); - } - .ops-modal-footer { - @apply flex justify-end gap-2 border-t px-3.5 py-2; - border-color: var(--ops-border); - } - /* 危险确认语句清单(前 3 条 + 折叠,修 C2) */ - .ops-modal-items { - @apply mt-2 space-y-1 rounded border px-2.5 py-2 font-mono whitespace-pre-wrap break-all; - font-size: var(--ops-text-xs); - border-color: var(--ops-border-soft); - background: var(--ops-editor-bg); - color: var(--ops-muted); - } - - /* Toast:圆角/阴影走令牌,分级色由调用侧以 var(--ops-*) 注入 */ - .ops-toast { - pointer-events: auto; - display: flex; - width: 360px; - max-width: calc(100vw - 2rem); - align-items: flex-start; - gap: var(--ops-space-3); - padding: var(--ops-space-3) var(--ops-space-4); - border: 1px solid var(--ops-border); - border-radius: var(--ops-radius-lg); - background: var(--ops-surface); - box-shadow: var(--ops-shadow-pop); - } - - .ops-card { - @apply flex flex-col items-center gap-1.5 rounded-md border p-2.5 transition; - border-color: var(--ops-border); - background: color-mix(in srgb, var(--ops-surface-2) 80%, transparent); - } - .ops-card:hover { - border-color: color-mix(in srgb, var(--ops-accent) 55%, var(--ops-border)); - background: color-mix(in srgb, var(--ops-accent) 8%, var(--ops-surface-2)); - } - - /* 结果区分段控件(02-§4.2-5,供 ResultPane 内部 Tab 使用) */ - .ops-seg { - @apply inline-flex items-center gap-0.5 rounded border p-0.5; - border-color: var(--ops-border); - background: var(--ops-surface-2); - } - .ops-seg button { - @apply rounded px-2 py-0.5 transition; - font-size: var(--ops-text-xs); - color: var(--ops-muted); - background: transparent; - } - .ops-seg button:hover { color: var(--ops-text); } - .ops-seg button.ops-seg-active { - background: var(--ops-surface); - color: var(--ops-text); - box-shadow: 0 1px 2px rgb(0 0 0 / .25); - } - - /* 骨架屏基类(备用):低饱和呼吸动画 */ - .ops-skel { - border-radius: var(--ops-radius-sm); - background: color-mix(in srgb, var(--ops-muted) 18%, transparent); - animation: ops-skel-pulse 1.6s ease-in-out infinite; - } - @keyframes ops-skel-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.45; } - } - - details > summary .ops-tree-chevron { - display: inline-block; - transition: transform 0.12s ease; - } - details[open] > summary .ops-tree-chevron { - transform: rotate(90deg); - } -} - - - .ops-drop-line { - height: 2px; - margin: 1px 4px; - border-radius: 1px; - background: var(--ops-accent); - } - .ops-drop-slot { - border: 1px dashed var(--ops-border); - } - .ops-drop-slot-active { - border-color: var(--ops-accent); - background: color-mix(in srgb, var(--ops-accent) 12%, transparent); - } - - .ops-split-x { - width: 5px; - cursor: col-resize; - flex-shrink: 0; - background: transparent; - } - .ops-split-x:hover, - .ops-split-x:active { - background: color-mix(in srgb, var(--ops-accent) 45%, transparent); - } - .ops-split-y { - height: 5px; - cursor: row-resize; - flex-shrink: 0; - background: transparent; - } - .ops-split-y:hover, - .ops-split-y:active { - background: color-mix(in srgb, var(--ops-accent) 45%, transparent); - } - .cm-editor { - height: 100%; - outline: none; - background: transparent; - } - - /* Tab 关闭按钮:固定 18px 占位,透明度切换消除横向抖动(修 T1) */ - .ops-close-faint { - display: inline-flex; - align-items: center; - justify-content: center; - flex: none; - width: 18px; - height: 18px; - border-radius: 3px; - font-size: 12px; - line-height: 1; - color: color-mix(in srgb, var(--ops-muted) 55%, transparent); - background: transparent; - } - .ops-close-faint:hover { - color: var(--ops-text); - background: color-mix(in srgb, var(--ops-muted) 18%, transparent); - } - /* 右键菜单:z-index/阴影/圆角走令牌 */ - .ops-ctx { - position: fixed; - z-index: var(--ops-z-ctx); - min-width: 140px; - padding: var(--ops-space-1); - border-radius: var(--ops-radius-md); - border: 1px solid var(--ops-border); - background: var(--ops-surface); - box-shadow: var(--ops-shadow-pop); - } - .ops-ctx button { - display: block; - width: 100%; - text-align: left; - padding: 6px 10px; - border-radius: var(--ops-radius-sm); - font-size: var(--ops-text-sm); - color: var(--ops-text); - background: transparent; - } - .ops-ctx button:hover:not(:disabled) { - background: var(--ops-bg-active); - } - .ops-ctx button:disabled { - opacity: 0.4; - cursor: not-allowed; - } - .ops-ctx-sep { - height: 1px; - margin: 4px 6px; - background: var(--ops-border); - } - .ops-tree-group { - font-size: var(--ops-text-xs); - font-weight: 600; - letter-spacing: 0.04em; - color: var(--ops-muted); - } diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts deleted file mode 100644 index db2c1dd..0000000 --- a/apps/web/tailwind.config.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { Config } from "tailwindcss"; - -/** - * 设计令牌 v2 映射:与 apps/web/src/styles.css 的 :root 令牌同源, - * 新增组件样式优先使用 ops-* utility,避免散落硬编码色值。 - */ -export default { - content: [ - "./index.html", - "./src/**/*.{ts,tsx}", - "../../packages/ui/src/**/*.{ts,tsx}", - ], - theme: { - extend: { - colors: { - ops: { - bg: "var(--ops-bg)", - surface: "var(--ops-surface)", - "surface-2": "var(--ops-surface-2)", - "editor-bg": "var(--ops-editor-bg)", - border: "var(--ops-border)", - "border-soft": "var(--ops-border-soft)", - text: "var(--ops-text)", - muted: "var(--ops-muted)", - accent: "var(--ops-accent)", - "accent-strong": "var(--ops-accent-strong)", - "accent-soft": "var(--ops-accent-soft)", - danger: "var(--ops-danger)", - warning: "var(--ops-warning)", - success: "var(--ops-success)", - "input-bg": "var(--ops-input-bg)", - "row-alt": "var(--ops-row-alt)", - "bg-active": "var(--ops-bg-active)", - }, - }, - fontSize: { - "ops-xs": "var(--ops-text-xs)", - "ops-sm": "var(--ops-text-sm)", - "ops-md": "var(--ops-text-md)", - "ops-lg": "var(--ops-text-lg)", - }, - spacing: { - "ops-1": "var(--ops-space-1)", - "ops-2": "var(--ops-space-2)", - "ops-3": "var(--ops-space-3)", - "ops-4": "var(--ops-space-4)", - "ops-5": "var(--ops-space-5)", - "ops-6": "var(--ops-space-6)", - }, - borderRadius: { - "ops-sm": "var(--ops-radius-sm)", - "ops-md": "var(--ops-radius-md)", - "ops-lg": "var(--ops-radius-lg)", - }, - boxShadow: { - "ops-pop": "var(--ops-shadow-pop)", - "ops-modal": "var(--ops-shadow-modal)", - }, - zIndex: { - "ops-banner": "var(--ops-z-banner)", - "ops-ctx": "var(--ops-z-ctx)", - "ops-toast": "var(--ops-z-toast)", - "ops-modal": "var(--ops-z-modal)", - "ops-confirm": "var(--ops-z-confirm)", - }, - // 修 V6:删除 JetBrains Mono 声明,等宽栈与 SqlEditor 统一为系统栈 - fontFamily: { - mono: ["ui-monospace", "SFMono-Regular", "Menlo", "Consolas", "monospace"], - }, - }, - }, - plugins: [], -} satisfies Config; diff --git a/apps/web/tsconfig.app.json b/apps/web/tsconfig.app.json deleted file mode 100644 index 7a3d8ce..0000000 --- a/apps/web/tsconfig.app.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "noEmit": true, - "allowImportingTsExtensions": true, - "types": [ - "vite/client" - ] - }, - "include": [ - "src", - "../../packages/ui/src", - "../../packages/core/src", - "../../packages/transport/src" - ] -} diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json deleted file mode 100644 index ea9d0cd..0000000 --- a/apps/web/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "files": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.node.json" - } - ] -} diff --git a/apps/web/tsconfig.node.json b/apps/web/tsconfig.node.json deleted file mode 100644 index d8ff2ca..0000000 --- a/apps/web/tsconfig.node.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "noEmit": true, - "composite": true, - "types": [ - "node" - ] - }, - "include": [ - "vite.config.ts" - ] -} diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts deleted file mode 100644 index 696f6b6..0000000 --- a/apps/web/vite.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; -import path from "node:path"; - -export default defineConfig({ - plugins: [react()], - resolve: { - alias: { "@opsxdb/ui": path.resolve(__dirname, "../../packages/ui/src/index.ts"), - }, - }, - server: { - host: "127.0.0.1", - port: 5174, - strictPort: true, - proxy: { - "/api": { - target: "http://127.0.0.1:8788", - changeOrigin: true, - }, - "/health": { - target: "http://127.0.0.1:8788", - changeOrigin: true, - }, - }, - }, -}); diff --git a/connection-types/NOTICE.md b/connection-types/NOTICE.md index eaed60b..3725e0c 100644 --- a/connection-types/NOTICE.md +++ b/connection-types/NOTICE.md @@ -4,8 +4,8 @@ | 数据 | 来源 | |---|---| -| `id` / `label` / `category` / `defaultPort` / `color` / `icon` / `mysqlCompat` / `ready` / `form` / `hints` | `packages/ui/src/catalog.ts` 的 `DRIVERS` 数组(注册表顺序 = 该数组顺序) | -| `driverFamily` / `runtime` | `apps/server/internal/db/open.go` 的服务端驱动分发 | +| `id` / `label` / `category` / `defaultPort` / `color` / `icon` / `mysqlCompat` / `ready` / `form` / `hints` | `src/catalog.ts` 的 `DRIVERS` 数组(注册表顺序 = 该数组顺序) | +| `driverFamily` / `runtime` | `server/internal/db/open.go` 的服务端驱动分发 | | `verified` / `notes` | `tests/README.md` 驱动验收表 | | 默认端口、产品名、品牌色等产品事实 | 各数据库官方公开文档(MySQL 3306、PostgreSQL 5432、SQL Server 1433、Oracle 1521、Redis 6379、MongoDB 27017、达梦 DM8 5236 等),属不受著作权保护的技术事实 | diff --git a/connection-types/README.md b/connection-types/README.md index 1a7aae4..b69db95 100644 --- a/connection-types/README.md +++ b/connection-types/README.md @@ -1,7 +1,7 @@ # opsxdb 连接类型注册表(connection-types.json,schema v1) -`connection-types.json` 是 opsxdb 驱动目录的**单一事实来源**(规划中):`packages/ui/src/catalog.ts` -的 `DRIVERS` 与服务端 `apps/server/internal/db/open.go` 的驱动分发,最终都应从本注册表生成。 +`connection-types.json` 是 opsxdb 驱动目录的**单一事实来源**(规划中):`src/catalog.ts` +的 `DRIVERS` 与服务端 `server/internal/db/open.go` 的驱动分发,最终都应从本注册表生成。 当前阶段注册表与代码手工保持一致,生成器接入前以代码为准。 数据来源说明见 `NOTICE.md`。 @@ -33,7 +33,7 @@ ## 纪律 -- `fields` 必须与 `apps/server/internal/db/types.go` 的 `ConnReq` 实际消费字段一致 +- `fields` 必须与 `server/internal/db/types.go` 的 `ConnReq` 实际消费字段一致 (审计记录:Oracle 的 `oracleRole`/`oracleIdKind`、SQL Server 的 `authMode`、 Redis 的 `keySeparator`/`redisMode` 为已知的死参数,不得回流)。 - 新增驱动时同步更新 `tests/README.md` 验收表与 `catalog.ts`,并保持注册表与 diff --git a/docs/15-AI-MCP-Agent.md b/docs/15-AI-MCP-Agent.md index 9721302..c8e5f37 100644 --- a/docs/15-AI-MCP-Agent.md +++ b/docs/15-AI-MCP-Agent.md @@ -1,5 +1,7 @@ # OpsxDB AI / MCP / Agent 任务书 +> 当前行为(2026-10-15 更新):新配置默认启用读写与危险 SQL,连接仍需明确授权;旧配置沿用原权限,设置 → MCP 可一次性「使用默认权限」。设置页移除权限开关,改为紧凑状态展示。Agent 生成写命令后弹出确认框,展示连接、数据库和完整命令;仅确认当前一条,模型不能代确认。下文 P0 只读默认的描述属于历史阶段规划。 + > 更新:2026-10-15 · 用户拍板:**先 MCP,再内部会话,最后 GUI 联动** > 对标:优先 [DBX MCP](https://github.com/t8y2/dbx)(`packages/mcp-server` / `crates/dbx-mcp`);架构思路参考 oh-my-pi;可选对照 Google MCP Toolbox for Databases、DBHub、官方 MCP SDK。 @@ -199,8 +201,8 @@ go build -o ../bin/opsxdb-mcp ./cmd/opsxdb-mcp |----|------| | Ask | 侧栏分段 **Ask**:走既有 `/api/ai/chat`,不调工具(生成/解释/优化) | | Agent | 分段 **Agent**:`POST /api/ai/agent` → `ai.RunAgent` → 进程内 `aitools.Runtime.Call`(与 MCP 同源) | -| 协议 | Agent tool calling 目前仅 **openai-chat**(DeepSeek / OpenAI 兼容) | -| 安全 | P0 只读;ConfirmDanger 永不 true;白名单 / 审计同 MCP | +| 协议 | Agent tool calling 支持 openai-chat、Anthropic 与 OpenAI Responses;云模型真链路仍需实测 | +| 安全 | 默认只读;工具限定当前连接/库,模型不能自行确认写入;白名单 / 审计同 MCP | | UI | 输入框上 Ask\|Agent;回复下可折叠步骤时间线(默认最近 3 步) | | 单测 | `go test ./internal/ai/ ./internal/aitools/`(含 mock tool loop) | | 真库冒烟 | `cd server && go run ./cmd/opsxdb-agent-accept/`(需 `~/.opsxdb/ai.json` 真 key) | @@ -211,6 +213,19 @@ go build -o ../bin/opsxdb-mcp ./cmd/opsxdb-mcp MySQL 3306 demo + Redis 6379:`go run ./cmd/opsxdb-mcp-accept/` 全过。实践文档:`~/Downloads/AI-Agent接入GUI工具开发实践.md`。 +### 本地回归 2026-10-15(当前隔离执行环境) + +| 路径 | 结果 | +| --- | --- | +| `go test ./internal/ai/ ./internal/aitools/ ./internal/server/ -count=1` | 通过;补测 Ask 不强制生成 SQL、MySQL Agent 越界连接/库拒绝、Redis DB1 GET 与 SET 需确认 | +| stdio MCP `initialize` / `tools/list` / `tools/call` | 7 个工具可列出;MySQL `DROP` 与 Redis `FLUSHDB` 均按只读策略拒绝 | +| `opsxdb-mcp-accept` | 连接列表通过;MySQL `127.0.0.1:3306` 遇 `operation not permitted`,后续真库调用未运行 | +| `opsxdb-crud-accept` | 只读拒写通过;MySQL 预检同样被本地连接权限拦截,未进入真实写操作;命令已改为预检失败立即停止并显示原因 | +| `opsxdb-agent-accept` | 真模型请求在解析 `api.deepseek.com` 时失败(`no such host`),未得到模型与真库结果 | +| 桌面交互 | Computer Use 自动审批拒绝访问 OpsxDB;未验证桌面按钮、视觉和真库操作 | + +上述限制只影响本次环境的真库/云模型回归;不可将失败命令记为产品功能验收通过。实际真库重测仍执行本节 P0 命令,并核对唯一标记的数据写入与清理。 + ## 会话产品层(阶段 5,2026-10-15) diff --git a/docs/16-AI-Session-Harness.md b/docs/16-AI-Session-Harness.md index 9b66b6b..95264de 100644 --- a/docs/16-AI-Session-Harness.md +++ b/docs/16-AI-Session-Harness.md @@ -244,11 +244,11 @@ confirm_bind = sha256(connection_id + "\n" + normalize(sql_or_command)) ## 9. 验收(会话层) -- [ ] `go test ./internal/ai/ ./internal/aitools/` 通过(含 outcome / trim / redact / bind) -- [ ] 触顶轮次:响应 `run_outcome=incomplete`,`incomplete_reason=max_steps` -- [ ] 审计行含 `run_id`(Agent 路径) -- [ ] confirm:改 SQL 后旧 bind 拒绝 -- [ ] (P1)关窗再开:同 session 注入 prior 能继续调工具 +- [x] `go test ./internal/ai/ ./internal/aitools/ ./internal/server/ -count=1` 通过(含 outcome / trim / redact / bind) +- [x] 触顶轮次:单测响应 `run_outcome=incomplete`,`incomplete_reason=max_steps` +- [x] 单测 Agent 审计行含 `run_id`;真库审计仍待复验 +- [x] confirm:单测修改 SQL、连接或数据库后旧 bind 拒绝 +- [ ] (P1)桌面关窗再开:同 session 注入 prior 能继续调工具(会话层单测已覆盖,桌面操作待验) --- diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 2298351..d4ab942 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -140,8 +140,10 @@ | 右侧 AI 面板可开关 | 已收 | — | | 真模型接入(生成/解释/优化) | **已接**(2026-10-14:Provider 预设 + 三协议,见 §23 补记) | 桌面接真实云端 key 验收;流式输出后置 | | MCP 最小工具集 + 安全策略(**P0 纯只读**) | **本轮落地** | `aitools` + `opsxdb-mcp` stdio;白名单/审计/connections.json 双写;写+确认=P1;验收盯 MySQL/PG/Redis | -| 内部 Agent 会话(共用 tool runtime) | 未做(P1) | Ask \| Agent UI(设计阶段 2 先只记文档);多轮 + 步骤展示 | -| GUI 联动(插入编辑器 / 结果网格) | 未做(P1) | 设置页 MCP 配置片段 | +| 内部 Agent 会话(共用 tool runtime) | 已有 Ask / Agent 流式会话、步骤、停止与单槽排队;模式下拉默认 Ask;Agent 工具限制当前连接与库,写入确认绑定库 | 桌面真实模型、多连接切换、跨库限定与写入确认回归;SQL 显式跨库引用仍由数据库权限管控 | +| GUI 联动(插入编辑器 / 结果网格) | Ask 生成 SQL 仅在回复中建议,需手动「复制到 SQL 窗口」;Agent 结果可在结果区打开;当前连接和库显示在输入区 | 桌面端跨方言、Redis DB 与结果网格联动回归 | +| 大模型设置 | 设置分类改为「大模型 · AI 供应商」;参照 opsxshell 的字段层级整理当前单供应商配置 | 多供应商保存/切换属后续能力,现有后端只保存一个配置 | +| AI 验收(2026-10-15) | Ask 自由提问修正为聊天提示词,不再强制生成 SQL;stdio MCP 初始化/7 工具列举及危险命令拒绝通过;Go 单测覆盖 MySQL/Redis Agent 当前库、确认写 | 本次隔离环境禁止连本机 3306/6379、云模型 DNS 不通;桌面 Computer Use 自动审批拒绝 OpsxDB,真库 CRUD 与模型/视觉实测待复验(细节见 15-AI-MCP-Agent) | --- @@ -322,6 +324,8 @@ 详见 [DATABASE-OPERATIONS-AUDIT.md](DATABASE-OPERATIONS-AUDIT.md)。右侧结构页已复用对象树的 MySQL/PG/SQLite 元数据查询,查询失败单组提示并可重试;AI 晚到 SQL 的原标签/未保存状态和切库保护已有回归。下一步真库核对与树节点定位 → 字段/索引设计及 DDL 预览 → CSV 导入 → 表级导出完善 → 逻辑备份与恢复。规划项未标为已完成。 +2026-10-15 的 [OpsxDB / DBX / DBeaver 高频操作评审](DB-CLIENT-REVIEW.md)按关系库工作流重新评分,并复核了源码。优先补表数据新增行、明确 NULL 与改动/部分失败反馈,以及 CSV 导入向导;手动事务须先做绑定查询标签的独占物理连接与生命周期,不能只在现有连接池上发 `BEGIN`。随后处理整表导出截断提示、MySQL/PG 手动备份与恢复演练、结构漂移校验和只读比较。AI/Redis 优势单列,不以视觉旧分替代功能分;规划能力不得显示为已完成。 + ### 主题随系统 + AI 真模型接入(2026-10-14 · 参考 opsxshell) | 项 | 状态 | diff --git a/docs/DATABASE-OPERATIONS-AUDIT.md b/docs/DATABASE-OPERATIONS-AUDIT.md new file mode 100644 index 0000000..6c234c5 --- /dev/null +++ b/docs/DATABASE-OPERATIONS-AUDIT.md @@ -0,0 +1,94 @@ +# 库、表与数据迁移功能缺项盘点 + +更新:2026-10-14(同日复核一轮:右键与复制主路径已落地,本文相关条目同步;代码现状以根级 `src` / `src-tauri` / `server` 布局核查)。依据当前 OpsxDB 代码以及 DBFlux、dbx、RustGrid 本地源码/文档静态核查;未运行参考项目,能力存在不等于所有引擎已验证。本文优先于早期「整表导出尚未实现」等笼统表述。 + +## 已确认的现状 + +- 按用户要求移除工作台「执行计划」按钮、结果「计划」页签及其前端执行处理。底层 API 保留兼容,不列入近期开发。 +- 表/视图节点下有字段分组(对象树自带);表节点另有索引、外键、触发器分组(`TableMetadataTree`,按驱动 DDL 能力挂载)。目录查询覆盖 MySQL 系列、PG 系列、SQLite,未适配引擎明确提示而非伪装空列表,尚待真库验证。 +- 右侧/结果区「结构」页有字段列表,索引/外键/触发器区块已复用对象树的目录查询,覆盖 MySQL 系列、PG 系列和 SQLite;每组单独显示加载、失败重试、空态与截断。编辑入口在表右键「设计表」,MySQL 普通索引可编辑,外键/触发器仍只读;真实数据库兼容性待验收。 +- 已有当前结果 CSV/JSON/INSERT 导出及服务端整表、完整查询导出入口;表右键已有 CSV/JSON 导出与 SQL 三态转储。这些有行数上限的导出不等于数据库备份。 +- 编辑器/结果/对象树右键主路径已于 2026-10-14 补齐一轮(格式化、注释、查找替换、定义跳转、复制与导出、SELECT/INSERT 模板、新建查询带库),验收状态以 BACKLOG §3 为准;本文只保留与结构、表设计、迁移相关的条目。AI 晚到 SQL 的原标签、未保存状态和切库保护已补回归。 +- Redis 键浏览/编辑已有独立面板(`RedisKeyPane`),非本盘点的关系对象迁移范畴。 + +## 库与 Schema + +| 操作 | OpsxDB 状态 | 缺口与优先级 | +|---|---|---| +| 新建查询、刷新、复制名称/连接地址 | 已有(另含设为默认库、删除库、限定名与主机端口复制) | 菜单键盘、焦点、视口约束已统一实现(2026-10-14),待桌面验收;剩余为禁用项说明的一致性 | +| 默认库切换 | 部分 | P1:PG Schema/search_path 与会话隔离验证;显示实际生效目标 | +| 新建数据库 / Schema | 缺少可视化流程 | P1:库名、字符集/排序规则或 owner 按方言开放,预览 SQL | +| 删除数据库 | 有能力裁剪入口 | P1:验收目标确认、权限失败、删除后连接与标签刷新 | +| 查看/修改库属性 | 缺少 | P2:编码、排序规则、大小、注释;可修改项按引擎限制 | +| 批量选择表 | 缺少 | P1:为多表导出/备份提供选择,不优先批量删除 | +| 视图、过程、函数定义管理 | 列表 + 视图可展开字段、复制建表/视图 SQL | P2:查看/复制定义已部分具备,新建/修改/删除、参数调用仍缺;按引擎支持 | +| 用户/权限、服务器管理 | 缺少 | 后置:不挤占表设计和迁移优先级 | + +## 表与表设计 + +| 操作 | OpsxDB 状态 | 缺口与验收要求 | +|---|---|---| +| 查看数据、前 N 行、查看结构/DDL | 已有 | 右侧结构已统一字段及三组目录;P1:点击树中索引定位对应详情,并以真库验证权限、方言差异与刷新行为 | +| 新建表 | 设计器 v1 已落地(2026-10-14):库右键「新建表…」/表右键「设计表…」,字段网格 + 方言化 CREATE 预览 + 应用 | P0:真库验收新建→改字段→改主键全流程;表选项(引擎/字符集)后置 | +| 新增/修改/删除字段 | 设计器 v1 支持列级 diff ALTER(MySQL 族 ADD/DROP/MODIFY/CHANGE、PG 族 TYPE/NOT NULL/DEFAULT/RENAME;SQLite 仅 ADD) | P0:真库各方言验收;结构漂移重校验(执行前被外部修改)后置 | +| 主键管理 | 设计器 v1 支持主键组变更(ADD/DROP PRIMARY KEY) | P0:复合主键真库验收;不把普通索引当主键 | +| 创建/修改/删除索引 | MySQL 系列设计器可编辑普通 BTREE/唯一及复合索引,实时预览 DROP/ADD;前缀、FULLTEXT、SPATIAL、降序等特殊索引只读。PG/SQLite 仍只读 | P0:MySQL 真库验证索引重建与外部结构漂移;PG 并发索引等高级项后置 | +| 外键管理 | 仅查看 | P1:多列映射、引用表列、ON DELETE/UPDATE;依赖检查 | +| 检查约束 | 未接入树/设计器 | P2:读取/创建/删除,按引擎版本裁剪 | +| 触发器 | 主要是查看 | P2:源码查看/编辑与 DDL 预览;避免假定支持原地 ALTER | +| 重命名表、修改表注释 | 缺少专用操作 | P1:方言转义、名称冲突、成功后刷新和旧标签提示 | +| 克隆为新表 | 缺少 | P1:仅结构/结构+数据;明确索引、外键、触发器是否复制 | +| 清空/截断、删除表 | 已有危险确认入口 | P1:区分 DELETE 与 TRUNCATE,事务/自增/外键语义及失败反馈 | +| 生成 SQL | 表右键「生成 SQL」折叠组提供 SELECT/INSERT/UPDATE/DELETE/DDL;新开带库查询,更新/删除有主键时填 WHERE 占位,不自动执行 | P1:复合主键、生成列/自增列和各方言参数占位符真库校验 | +| 表数据新增/修改/删除 | 部分内联修改、粘贴和删除 | P1:新增行、待提交变更、明确 NULL 编辑、多行部分失败反馈,避免并发回滚覆盖 | +| 表关系图、结构比较、数据比较 | 缺少 | 结构比较 P1(只读差异,目标选择和过滤);数据比较 P2(主键、同构、分页/限量);关系图后置 | + +设计器现状:字段、索引、外键、触发器、SQL 预览分区;大弹窗、紧凑密度、MySQL 表注释、普通索引编辑,外键/触发器只读。应用前展示 DDL 并确认,读取元数据失败或存在不支持的修改时禁止应用。未含:外键/触发器图形编辑、引擎/字符集选项、草稿保留(关闭即丢)、结构漂移重校验、SQLite 重建表流程;这些仍是后续项。 + +## 导出、导入、备份与恢复 + +| 能力 | OpsxDB 状态 | 必须补齐的闭环 | +|---|---|---| +| 当前结果 CSV/JSON/INSERT | 已有 | P1:范围、编码、NULL/换行/大整数、取消/保存失败回归 | +| 整表 / 完整查询导出 | 表右键可导出 CSV/JSON,输入 1–500000 行上限(默认 100000);服务端流式取数,不受前端结果分页限制。右键还可转储 SQL 三态(仅结构/仅数据/结构和数据) | P1:上限命中时服务端给出明确截断标志、列与条件选择、进度/取消、大表内存验证;目前文件达到上限不能判定是否完整,不可当备份 | +| 表结构 SQL 导出 | 表右键转储「仅结构/结构和数据」已可保存 .sql | P1:多表选择、对象依赖顺序;视图/过程/函数纳入 | +| CSV 导入 | 缺少向导 | P0:文件预览、编码/分隔符、表头、字段映射、类型/NULL、批次、事务策略、错误行报告 | +| SQL 文件执行/导入 | 缺少完整流程 | P1:大文件流式读取、方言分隔符、进度/取消、失败位置;不是简单按分号切开 | +| JSON/Excel 导入导出 | JSON 结果导出已有,其他缺少 | P2:先 CSV;Excel 为可选扩展,不先堆格式 | +| 单表 / 多表逻辑备份 | 缺少 | P1:结构+数据、索引/约束/触发器范围、快照一致性说明、产物清单 | +| 整库逻辑备份 | 缺少 | P1:MySQL/PG 优先,评估原生 dump 工具依赖或自有导出;凭据不放命令行/日志 | +| 备份恢复 | 缺少 | P1:目标库确认、冲突策略、对象顺序、失败报告,完成后实际验证可恢复性 | +| 定时备份/保留策略/历史 | 缺少 | P2:手动备份恢复验收后再做;桌面退出时不承诺继续运行 | +| 物理备份、PITR、binlog/WAL 归档 | 无 | 不纳入近期桌面客户端范围;逻辑 SQL 导出不能冒充灾备 | + +## 三个参考项目取舍与证据 + +| 参考 | 静态证据 | 借鉴内容 | +|---|---|---| +| dbx | `docs/content/docs/table-structure.cn.mdx`;`crates/dbx-core/src/table_structure_sql/` 的 columns/indexes/foreign_keys/sqlite_rebuild/validation;结构编辑器并发与元数据重校验测试 | 字段/索引设计、能力裁剪、DDL 预览、草稿与结构漂移校验,作为表设计主要参考 | +| dbx | `crates/dbx-web/src/routes/table_export.rs`(CSV/JSON/XLSX/SQL、进度、取消)、`docs/content/docs/database-backup.cn.mdx`、`crates/dbx-core/src/sql_file_import/table_restore.rs` | 借鉴导出任务反馈、立即备份与恢复;XLSX 按真实需求后置,不把有限行导出称为备份 | +| navop | `crates/db_view/src/compare/`、`import_export/table_import_view.rs` | 比较目标、差异预览、失败状态与导入映射。优先只读结构差异,再做按主键的数据比较;同步执行需独立确认与回滚策略 | +| AnotherRedisDesktopManager | `src/components/OperateItem.vue`、`MemoryAnalysis.vue`、`src/redisClient.js` | 搜索输入、取消/分批 SCAN 与集群节点处理;不引入会阻塞服务器的 KEYS 全量搜索 | +| DBFlux | `crates/dbflux_ui_document/src/import_wizard/column_mapping.rs`、`export_wizard/`、`crates/dbflux_export/src/streaming.rs`、`dbflux_ui_sidebar/src/operations/export_tables.rs` | 导入映射、按对象直达导出、步骤层级与流式任务。不能仅凭 schema_alter policy 推断完整设计器已成熟 | +| RustGrid | `README_zh.md`、`crates/rustgrid-backup/src/lib.rs`、`crates/rustgrid-app/src/app/backup.rs`、`crates/rustgrid-postgresql/src/backup.rs` | 中文导入导出向导、备份/还原成对入口;不优先复制专有 .rgbak 格式,先通用 SQL/CSV | + +上述 dbx/navop/dbflux/rustgrid 路径相对 `/Users/logan/devops/demo/db-gui/`,Redis 参考项目位于 `/Users/logan/devops/demo/db-client/`。本文不因参考项目声明功能就宣称其全部驱动均通过验收。 + +Navicat 截图的数据库/表/视图与工具图标用于辨识和层级参考;OpsxDB 保留自有 SVG 图标与紧凑桌面工具栏,不复制其图形资产或将比较、备份按钮提前摆在主工具栏。结构比较 P1 先只读展示字段、索引、约束差异;数据比较 P2 要求同构表、明确主键、限量取样与差异统计,跨库同步和无主键全表比较后置。导入以 CSV 预览→字段映射→批量执行→错误报告为 P0;导出优先 CSV/JSON/SQL INSERT/结构 SQL,XLSX 为 P2,整库逻辑备份必须能恢复验证。 + +## 推荐开发顺序 + +1. **结构查看验收**:目录查询与错误/空态已复用;补树节点定位结构详情,并用 MySQL、PG、SQLite 真库核对索引、复合外键和触发器。 +2. **表设计器验收**:字段网格、MySQL 普通索引、结构只读页签与 DDL 确认已落地;MySQL 3306 旧版建表/转储验收不覆盖本轮索引改造。下一步真库验收索引重建与结构漂移重校验。 +3. **日常迁移**:CSV 导入 + 表右键导出 + SQL 文件执行;有进度、取消与错误报告。 +4. **备份恢复**:先手动单库逻辑备份并完成恢复演练,再多库/定时。 +5. **按需扩展**:外键/触发器编辑、克隆、关系图/比较,不把整个管理平台塞入默认右键菜单。 + +验收矩阵应覆盖:空表/大表/复合主键/无主键/权限不足/断连/取消/名称特殊字符/跨标签切换/结构被外部修改;每种方言单独记录。规划项未实现前不在产品中放置伪可用入口。 + +## 本地质量复核 + +- 前端构建/类型检查通过,60 项前端测试通过;Go 编译和 2 项无监听的 Redis 扫描预算测试通过,差异空白检查通过。homepage 未改动。 +- 复核修正:结构页不再把索引等目录查询报错显示为「无」,三组分别加载、报错重试;AI 异步生成 SQL 保留原标签与未保存标记,用户修改 SQL 或切库后不覆盖。 +- 2026-10-14 晚补充:设计器 v1(tableDdl 11 项单测,前端合计 75 项全绿)、`/api/db/dump` 三态转储、`⌘/` 注释快捷键修正(帮助改 `⌘⇧/`);MySQL 3306 真库端到端验证建表、插数与三种转储输出后已清理测试库。 +- 尚未完成:真实 MySQL/PG/SQLite 的结构目录校验、桌面视觉/右键/剪贴板验收、表设计与导入备份闭环。完整 Go 集成测试中的本地监听用例在当前受限环境不能运行;这不等于真实数据库验收通过。 diff --git a/docs/DB-CLIENT-REVIEW.md b/docs/DB-CLIENT-REVIEW.md new file mode 100644 index 0000000..51a688b --- /dev/null +++ b/docs/DB-CLIENT-REVIEW.md @@ -0,0 +1,42 @@ +# 高频数据库操作评审:OpsxDB / DBX / DBeaver + +更新:2026-10-15。依据当前工作区的 OpsxDB 根级 `src/`、`server/`,以及 `/Users/logan/devops/demo/db-gui/dbx`、`/Users/logan/devops/demo/db-client/dbeaver` 的源码和随库文档。**这是静态代码评审与产品取舍,不是三个桌面程序的同机实测,也不是所有驱动的兼容性认证。** 分数只针对日常关系数据库工作流;AI/MCP、Redis 等差异化能力在下文单列,不靠第三方插件数量加分。参考项目自身的文档陈述若未在本轮实测,以“源码中有路径”评价。 + +## 评分口径 + +每项满分是该列权重;一条功能只存在入口或说明但缺执行、错误恢复和验证时扣分。结果集“筛选已加载行”不等于数据库服务端过滤;限量 SQL 导出不等于可恢复备份。下表为评审判断值,允许在真库与桌面验收后修订,不能与 2026-10-14 的 [GUI 布局评分](GUI-COMPARISON.md)混用。 + +| 维度(满分) | OpsxDB | DBX | DBeaver | 主要判断 | +|---|---:|---:|---:|---| +| 连接、对象树与上下文(15) | 12 | 14 | 14 | OpsxDB 已有多连接、库/表/列及索引/外键/触发器目录和带库标签;PG Schema 与真实驱动目录仍需验收;两参照项目对象导航与目标上下文更完整 | +| SQL 编辑、会话与事务(20) | 11 | 18 | 18 | OpsxDB 有选区/当前语句执行、格式化、历史、切库、取消与危险确认;尚无可靠跨请求手动事务;DBX 有标签专用事务会话,DBeaver 有自动提交切换和事务监视 | +| 表设计与数据编辑(20) | 12 | 18 | 19 | OpsxDB 有字段/主键、MySQL 普通索引设计及有主键的单元格改/删;缺新增行、批量暂存提交、外键编辑,PG/SQLite 索引只读;参照项目有更完整的编辑持久化路径 | +| 导入、导出与恢复(20) | 7 | 18 | 18 | OpsxDB 有结果与整表导出、单表 SQL 三态转储,缺 CSV 导入、完整备份与恢复;DBX 有表导入、数据传输和 MySQL/PG 备份,DBeaver 有数据传输向导与 MySQL/PG 原生备份向导 | +| 结果集高频交互与大数据(15) | 11 | 13 | 13 | OpsxDB 有复制/右键、局部筛选排序、分页与继续显示,但服务端按 offset 丢弃前面行;两参照项目有更丰富的过滤、行状态与任务反馈 | +| 失败反馈、回归证据与操作安全(10) | 5 | 7 | 9 | OpsxDB 有危险确认与部分单测,桌面及真库矩阵尚未闭环;DBX 有事务/导入/比较专门回归,DBeaver 的持久化器含行标识校验、部分提交与回滚处理。此项不代表本轮运行了第三方测试 | +| **合计 / 100** | **58** | **88** | **91** | 能力覆盖与闭环成熟度的当前估计,不是视觉评分或性能基准 | + +OpsxDB 的优势是轻量的连接→对象→查询主路径、Redis 键操作、Ask/Agent 与 MCP 同一会话工具边界;后两项没有纳入上述关系库同口径打分。DBeaver 覆盖广而操作层级多;DBX 的步骤式迁移和上下文入口值得借鉴。OpsxDB 应保持日常操作短路径,复杂任务才进入向导。 + +## 对照后最值得补的能力 + +| 频率 / 优先级 | OpsxDB 当前缺口与影响 | 参考代码证据 | 适合 OpsxDB 的实现范围 | +|---|---|---|---| +| 高频 P0:新增/修改/删除一批数据 | `src/ResultPane.tsx` 有主键写回和删除,空输入转 NULL,单元格写入立即提交;没有新增行与可查看的待提交改动。粘贴多格失败时需明确哪些已写入,不能用旧结果覆盖后来的成功写回 | DBX `apps/desktop/src/lib/dataGrid/dataGridContextMenu.ts` 有 clone/restore/delete、NULL/筛选操作;DBeaver `plugins/org.jkiss.dbeaver.ui.editors.data/.../ResultSetPersister.java` 区分 insert/update/delete,并对缺少唯一行标识拒绝删除 | 先做“新增行、显式 NULL、改动预览、保存/撤销”;事务支持前明示逐行立即生效和部分失败。限制表来源与主键,避免任意 JOIN 结果写回 | +| 高频 P0:导入 CSV 到已有表 | 无数据导入向导;手工写 INSERT 成本高,易错 | DBX `crates/dbx-core/src/data/table_import.rs`、`crates/dbx-web/src/routes/table_import.rs` 与 `docs/content/docs/table-import.cn.mdx`;DBeaver `plugins/org.jkiss.dbeaver.data.transfer.ui/.../DataTransferWizard.java` | 从表右键进入,文件预览→编码/表头/分隔符→字段映射与 NULL→目标复核→分批写入/进度/取消/错误行;先支持 MySQL/PG/SQLite 的 CSV,测试事务及失败行语义 | +| 高频 P0:可控事务 | `server/internal/db/session.go` 按库缓存 `*sql.DB` 连接池,`server/internal/db/ops.go` 每次通过池执行;连发 `BEGIN`、DML、`ROLLBACK` 不能保证同一物理连接。前端没有会话绑定的提交/回滚状态 | DBX `crates/dbx-core/tests/live_manual_transaction.rs`、`apps/desktop/src/components/layout/EditorToolbar.vue`;DBeaver `plugins/org.jkiss.dbeaver.core/.../DataSourceTransactionModeContributor.java` 与 `.../TransactionMonitorToolbar.java` | 先设计每查询标签独占 `*sql.Conn`/`*sql.Tx` 的本机事务句柄,再开放手动模式和提交/回滚。连接/库切换、关闭标签、超时、取消、断连与提交响应未知均有状态处理;事务内不隐式重试。MySQL DDL 的隐式提交单独提示。不能先只加按钮或直接发送 BEGIN | +| 高频 P1:备份与恢复 | `server/internal/db/dump.go` 仅单表 SQL 转储;整表 CSV/JSON 上限 500000 行,达到上限未明确是否截断;没有整库一致性备份、依赖顺序或恢复验证 | DBX `docs/content/docs/database-backup.cn.mdx`、`crates/dbx-core/src/scheduled_backup/engine.rs`;DBeaver `plugins/org.jkiss.dbeaver.ext.mysql.ui/.../MySQLExportWizard.java`、`plugins/org.jkiss.dbeaver.ext.postgresql.ui/.../PostgreBackupWizard.java` | 先 MySQL/PG 手动逻辑备份,列出范围、对象与输出文件并做空库恢复演练;查询导出达到上限明确标注不完整。定时与保留策略后置,桌面退出不承诺继续运行 | +| 中频 P1:表设计变更可靠性 | 设计器有 DDL 预览,但读取后到应用前未重新校验结构;MySQL 索引支持常见类型,PG/SQLite 索引与外键只读 | DBX `crates/dbx-sql-schema/src/table_structure_sql/`、结构编辑器的验证与 SQLite 重建路径;DBeaver 对象属性编辑路径 | 先校验元数据版本/快照与实际目标,处理复合主键和默认值;PG 普通索引、外键在真库验收后分方言开放。危险 DDL 展示影响与失败后的状态,不追求一次支持所有约束 | +| 中频 P1:服务端筛选和高效翻页 | `src/ResultPane.tsx` 的筛选/排序作用于已加载行;`server/internal/db/ops.go` 的 offset 在结果扫描中逐行跳过,深页成本增长,重跑查询可能读到变化后的数据 | DBX `apps/desktop/src/lib/dataGrid/dataGridContextMenu.ts` 的筛选菜单与数据网格;DBeaver 结果集查看/编辑组件 | 表数据增加列条件筛选与稳定排序,清楚标示“当前页”或“全表”;按方言生成带 LIMIT/OFFSET 的安全查询,深页考虑主键游标。不将任意 SQL 重写成服务端过滤 | +| 中频 P1–P2:比较/迁移 | OpsxDB 无结构比较/数据比较、跨连接传输;SQL 文件导入也未形成完整解析和进度路径 | DBX `crates/dbx-core/src/data/data_compare.rs`、`apps/desktop/src/components/diff/DataCompareDialog.vue`、`crates/dbx-core/src/data/transfer.rs`;DBeaver `plugins/org.jkiss.dbeaver.cmp.simple.ui/.../CompareObjectsWizard.java` | 先做只读结构差异;数据比较限定同构、唯一键、行数上限并展示样本;跨库传输与同步等 CSV 导入/备份闭环后再排期 | + +路径中 `...` 表示相应插件包内的 `src/org/jkiss/dbeaver/` 前缀,并非 OpsxDB 文件。完整库/表缺项及现有功能参阅 [DATABASE-OPERATIONS-AUDIT.md](DATABASE-OPERATIONS-AUDIT.md)。DBX 表导入文档与核心实现对应,但其 SQL 导入限定字面量 INSERT,不能据此推断任意 SQL 脚本恢复已经通用可用;“可导出 SQL”也不能推断“已验证可恢复”。 + +## 项目决策与验收门槛 + +1. **先补可信的数据操作**:表网格新增行和明确 NULL;校验主键、唯一行定位、并发变化与多行部分失败。若暂存/批量保存需依赖事务,先把服务器独占连接与标签生命周期打通,再显示“保存/撤销”;与普通 SQL 的手动事务可以共用句柄层,UI 保持简单。 +2. **CSV 导入做一条完整路径**:从表右键进预填目标的向导,不加额外主工具栏按钮。测试 UTF-8/GBK、引号换行、空串与 NULL、自增/默认字段、重复键、取消、断连和错误行定位;明确每批是否已提交,输出成功/跳过/失败行数。 +3. **加固现有出口**:整表导出区分“达到行上限”与“完整”;导出失败/取消不留下貌似成功的文件。随后再做 MySQL/PG 的单次整库备份与空库恢复演练,备份内容与对象范围可核对。 +4. **依赖真库的结构工作随后做**:MySQL 8.4/MariaDB 11/PG 16/SQLite 的新建→改字段/主键/索引→刷新/重连、并发结构变动、无权限和特殊标识符。结构比较先只读;数据比较、XLSX、跨连接复制、定时任务为后续选项。 + +本次只读核查三份本地源码,未运行 DBX、DBeaver;未将 OpsxDB 桌面视觉/右键或 MySQL/Redis Agent 真库测试记为通过。当前 Computer Use 访问 OpsxDB 曾被自动审批拒绝,且此前隔离环境不能连接本机数据库;这些验收应在可访问的本机桌面环境补做。此评审不改变 `homepage/` 或产品形态:官网与文档在浏览器,数据库操作仍只走 Tauri 桌面。 diff --git a/docs/GUI-COMPARISON.md b/docs/GUI-COMPARISON.md new file mode 100644 index 0000000..bf8ede0 --- /dev/null +++ b/docs/GUI-COMPARISON.md @@ -0,0 +1,56 @@ +# 数据库桌面 GUI 对比与优化依据 + +日期:2026-10-14。参考目录:`/Users/logan/devops/demo/db-gui` 下的 DBFlux、DBX、RustGrid;目标为 OpsxDB 当前工作区。 + +产品取舍(用户确认):以 DBFlux 的布局层级与上下文操作为主要参考;DBX 只借鉴实用功能与细致回归。常用操作一两步可达,按目标显示相关菜单,不堆全量管理能力,不为追求功能数量增加学习负担。 + +## 方法与评分 + +依据本地仓库截图、用户文档、菜单/编辑器/结果表实现及已有测试进行静态评审。未运行三个参考项目,未测启动速度、内存、海量结果性能或逐引擎兼容性;README 宣称的驱动数量不作为已验证能力。截图可能早于代码。下列分数是相同桌面数据库日常任务下的设计评审分,不是性能或质量认证;OpsxDB 55 分为 2026-10-14 右键与复制补齐**前**的基线,当日一轮「操作闭环」已落地(见 BACKLOG §3)但尚未桌面验收,本文不因此自动上调分数,验收后重评。 + +每项 10 分:0–3 缺失或断链,4–6 主路径具备但存在明显缺口,7–8 较完整且有边界处理,9–10 系统化实现及回归证据。总分按权重换算为 100 分。 + +| 维度 | 权重 | DBFlux | DBX | RustGrid | OpsxDB | +|---|---:|---:|---:|---:|---:| +| 布局层级、空间利用、信息密度 | 20% | 9 | 8 | 8 | 6 | +| 视觉一致性、主题、可读性 | 15% | 9 | 8 | 7 | 6 | +| 编辑器、右键与键盘交互完整度 | 20% | 9 | 9 | 7 | 5 | +| 结果浏览、复制、编辑与导出 | 20% | 9 | 9 | 8 | 5 | +| 功能组织与对象上下文 | 15% | 9 | 9 | 7 | 6 | +| 错误反馈、安全与回归证据 | 10% | 8 | 8 | 6 | 5 | +| **加权总分** | **100%** | **89** | **85.5** | **73** | **55** | + +## 布局与设计对比 + +| 项目 | 布局与设计 | 适合借鉴 | 详细不足与取舍 | +|---|---|---|---| +| DBFlux | 连接树 + 文档标签 + 数据区 + 右侧检查器;深浅主题统一;底部状态与任务分离 | 面包屑显示对象上下文、复制/编辑按目标与能力启用、单元格详情、键盘操作 | 三栏同时展开时数据区受挤压;图表、Dashboard、脚本、任务、审计增加学习成本;截图字号偏小,高密度不是所有用户的最佳默认。GPUI 实现不能直接移植进 Tauri | +| DBX | 顶部全局操作、连接/库/Schema 树、多标签、结果工具条与 AI 侧栏;类型信息进表头 | 菜单的目标同步、列操作、复制格式、SQL 编辑器边界测试、连接/库/Schema 分层 | 同屏工具条和图标入口较多;AI 展开后宽表横向空间不足;多数据库/云/CLI/浏览器形态使产品复杂,OpsxDB 不应照搬浏览器操作模式;大量能力不等于每个驱动同等成熟 | +| RustGrid | Navicat 式大图标工具条、左树、中间对象/查询标签、下方结果与分页 | 清晰的对象类别、显式运行/停止、筛选/排序/导出紧邻数据、中文可发现性 | 大图标顶栏与多排工具条占用垂直空间;截图存在标签截断;界面更传统、设置与细节组织不如前两者统一;README 明示早期迭代,不应按文档能力视为稳定验收 | +| OpsxDB | 紧凑顶栏、左侧连接/对象树、编辑器与结果上下分割、可开关 AI;底部状态栏样式存在但未挂载,状态实际经结果工具条与 toast 呈现 | 保留紧凑桌面结构与现有主题;使用已有能力补齐交互 | 图标/文字密度不统一;树、编辑器和结果菜单各自实现;右键主路径已补齐一轮(编辑器/结果/树,2026-10-14 落地待桌面验收);库上下文已随新建查询与模板补齐,PG Schema 语义未完;结果分批 500 行增量显示,仍非真正虚拟滚动;持久化密码是混淆而非钥匙串加密 | + +## 功能对比与证据 + +| 能力 | DBFlux | DBX | RustGrid | OpsxDB 缺口 | +|---|---|---|---|---| +| 编辑器 | 文档工作区、历史、保存查询、键盘命令 | CodeMirror 编辑与上下文菜单、目标同步回归测试 | 高亮、补全、美化、命名查询 | 右键已接入:执行选中/当前、格式化(选区/全文)、注释/取消注释、查找替换、按光标标识符跳 DDL(支持 库.表 限定名);CodeMirror 6 + 库表列补全 + DataGrip 风高亮 + 历史面板。剩余:定义跳转仅限已加载元数据中的明确标识符,别名/CTE/未加载对象后置 | +| 结果网格 | 虚拟表格、检查器、过滤、分页、Copy as Query | 复制格式、列冻结/隐藏、筛选/排序、详情、结果上下文工具 | 分页、编辑、筛选、导入导出 | 右键已接入:复制单元格/行/列(TSV)、列名、排序、列宽、行 JSON/INSERT、筛选结果复制、导出当前结果 CSV/JSON;首批 500 行可增量「继续显示」。剩余:非虚拟滚动;TSV 不含表头;桌面剪贴板与保存文件待验收 | +| 对象操作 | 驱动能力决定菜单,Schema 层级 | 多 Schema 与连接/查询上下文区分 | 对象类别、表/视图/例程与备份 | SELECT/INSERT 模板已入菜单并新开带库查询(UPDATE/DELETE 函数就绪未开放);新建查询携带所点库并持久化;限定名复制、设为默认库、删除库已有。剩余:PG Schema 语义与 search_path;库节点断开/重连归属;表右键直达导出 | +| 设置/安全 | 设置、配置/秘密存储说明、审计与错误关联 | 设置、驱动管理与回归测试较全面 | 主题/语言,XChaCha20-Poly1305 本地密钥存储 | 设置左导航 + 搜索已重构,安全页明示混淆非加密;主题已支持深/浅/随系统(2026-10-14 补齐)。剩余:国际化未实现(无 i18n,文案硬编码中文);凭据仍 Base64 混淆,Keychain 迁移需独立设计 | +| 扩展能力 | 图表、Dashboard、可视化查询、脚本/MCP | 数据传输、ER、AI、多引擎与多部署形态 | 导入导出、备份还原、账户与例程 | 主路径优先,不在此轮加入 BI、权限系统、远程协作或第二套客户端 | + +本地证据(相对各参考项目根目录): + +- DBFlux:`resources/dbflux.png`、`docs/USAGE.md`、`crates/dbflux_ui_sidebar/src/context_menu.rs`、`crates/dbflux_ui_document/src/data_grid_panel/context_menu/items.rs`、`data_grid_panel/row_inspector.rs`。 +- DBX:`docs/screenshot-dark.png`、`docs/screenshot-light.png`、`apps/desktop/src/lib/dataGrid/dataGridContextMenu.ts`、`components/editor/__tests__/QueryEditorContextMenu.spec.ts`、`lib/sql/newQueryContext.ts`(后两项相对 `apps/desktop/src`)。 +- RustGrid:`docs/img/img2_cn.png`、`docs/img/img4_cn.png`、`crates/rustgrid-app/src/app/grid_menu.rs`、`app/query_editor.rs`(相对同一 src)、`crates/rustgrid-config/src/secrets.rs`、`README_zh.md`。 +- OpsxDB:`src/Workspace.tsx`、`src/SqlEditor.tsx`、`src/ObjectTree.tsx`、`src/ResultPane.tsx`、`src/store.ts`、`src/secrets.ts`、`src/SettingsModal.tsx`、`src/contextActions.ts`(右键复用工具)、`src/tableMetadata.ts`(表元数据目录查询)。 + +## 结合 BACKLOG 的优化路线 + +1. **操作闭环(2026-10-14 已落地,待桌面验收)。** 对应 BACKLOG §3:编辑器格式化/注释/查找替换/复制信息与光标标识符定位,库查询上下文,表 SQL 模板与限定名,结果集复制与导出右键;统一菜单的键盘、视口边界与焦点处理。逐项验收清单与剩余边界见 BACKLOG §3,菜单均调用既有逻辑,无仅补文案的占位项。 +2. **可理解性(已随上项落地)。** 菜单按目标对象与能力裁剪;复制连接信息不带凭据,INSERT 缺少可靠来源时禁用;保留当前浅深主题和桌面产品边界。 +3. **后续专项:数据层与性能。** PG Schema 默认路径的连接池隔离、真正虚拟滚动、整表导出与导入任务进度;需数据库环境与规模数据实测后验收。 +4. **后续专项:安全与完整设计系统。** OS Keychain 凭据迁移、统一 SVG 图标、系统主题/语言、统一错误诊断与测试;不能将 Base64 混淆宣传为加密。 + +本轮完成情况与未验项回写 `BACKLOG.md`,不因菜单增加直接提升评分;优化后需以桌面任务验收重新评估。 diff --git a/package-lock.json b/package-lock.json index 4f6e7ac..3232091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,31 @@ { "name": "opsxdb", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opsxdb", - "workspaces": [ - "apps/web", - "packages/*" - ], - "engines": { - "node": ">=20" - } - }, - "apps/web": { - "name": "@opsxdb/web", "version": "0.1.0", "dependencies": { - "@opsxdb/ui": "*", + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.11.1", + "@codemirror/lang-sql": "^6.10.0", + "@codemirror/language": "^6.12.4", + "@codemirror/search": "^6.7.2", + "@codemirror/state": "^6.7.5", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.43.12", "@tauri-apps/api": "^2.5.0", + "@tauri-apps/plugin-opener": "^2.7.1", + "lucide-react": "^0.511.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "sql-formatter": "^15.8.2", + "zustand": "^5.0.3" }, "devDependencies": { + "@tauri-apps/cli": "^2.4.0", "@types/node": "^22.20.3", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", @@ -31,7 +34,11 @@ "postcss": "^8.5.3", "tailwindcss": "^3.4.17", "typescript": "^5.8.2", - "vite": "^6.2.2" + "vite": "^6.2.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=20" } }, "node_modules/@alloc/quick-lru": { @@ -361,6 +368,17 @@ "style-mod": "^4.0.0" } }, + "node_modules/@codemirror/search": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.2.tgz", + "integrity": "sha512-gUYkYhT2+n/+VGZ+8EzE5WFkYZUZYm1VOKDudIsNqh42uRVQJ0a6Yss9sdKT3MeOYfuL1N6AZA57oza0Oyr0LA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.37.0", + "crelt": "^1.0.5" + } + }, "node_modules/@codemirror/state": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.5.tgz", @@ -936,14 +954,6 @@ "node": ">= 8" } }, - "node_modules/@opsxdb/ui": { - "resolved": "packages/ui", - "link": true - }, - "node_modules/@opsxdb/web": { - "resolved": "apps/web", - "link": true - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1276,14 +1286,229 @@ ] }, "node_modules/@tauri-apps/api": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", - "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", + "version": "2.12.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.12.3.tgz", + "integrity": "sha512-9s0PKw0p4r3kFq92jhpivYSp+cSht15o0gXpZxuQd0+dV9KCexEVkNaLELVoLdJWyoH4KlfQo5h3W2LIM8siJg==", + "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/tauri" } }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "dev": true, + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-opener": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.7.1.tgz", + "integrity": "sha512-XkXdt30rontti9TII/gBBxFRXWfj8DiprFW7RgBFRBj1OhdfjBNVcFqSEWkkZ4hXafHnuEnB7F1sFsmu6uyywQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.12.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2165,6 +2390,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.511.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.511.0.tgz", + "integrity": "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -3289,31 +3523,6 @@ "optional": true } } - }, - "packages/ui": { - "name": "@opsxdb/ui", - "version": "0.1.0", - "dependencies": { - "@codemirror/autocomplete": "^6.20.3", - "@codemirror/commands": "^6.11.1", - "@codemirror/lang-sql": "^6.10.0", - "@codemirror/language": "^6.12.4", - "@codemirror/state": "^6.7.5", - "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.43.12", - "sql-formatter": "^15.8.2", - "zustand": "^5.0.3" - }, - "devDependencies": { - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", - "typescript": "^5.8.2", - "vitest": "^3.0.9" - }, - "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0" - } } } } diff --git a/package.json b/package.json index afcf2bd..244d0bc 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,15 @@ "version": "0.1.0", "type": "module", "scripts": { - "dev": "vite --host 127.0.0.1 --port 5174", - "build": "tsc -b && vite build", + "dev": "bash ./run.sh prepare && tauri dev", + "build": "bash ./run.sh package", "preview": "vite preview --host 127.0.0.1 --port 5174", "test": "vitest run", "test:watch": "vitest", - "tauri": "tauri" + "tauri": "tauri", + "dev:ui": "vite --host 127.0.0.1 --port 5174", + "build:ui": "tsc -b && vite build", + "typecheck": "tsc --noEmit" }, "engines": { "node": ">=20" @@ -24,6 +27,8 @@ "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.43.12", "@tauri-apps/api": "^2.5.0", + "@tauri-apps/plugin-opener": "^2.7.1", + "lucide-react": "^0.511.0", "react": "^19.0.0", "react-dom": "^19.0.0", "sql-formatter": "^15.8.2", @@ -42,4 +47,4 @@ "vite": "^6.2.2", "vitest": "^3.0.9" } -} \ No newline at end of file +} diff --git a/packages/opsxdb-mcp/package-lock.json b/packages/opsxdb-mcp/package-lock.json new file mode 100644 index 0000000..0dc5584 --- /dev/null +++ b/packages/opsxdb-mcp/package-lock.json @@ -0,0 +1,4572 @@ +{ + "name": "@rlwj-lab/opsxdb-mcp", + "version": "0.1.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@rlwj-lab/opsxdb-mcp", + "version": "0.1.1", + "license": "MIT", + "dependencies": { + "npx": "^10.2.2" + }, + "bin": { + "opsxdb-mcp": "bin/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npx": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/npx/-/npx-10.2.2.tgz", + "integrity": "sha512-eImmySusyeWphzs5iNh791XbZnZG0FSNvM4KSah34pdQQIDsdTDhIwg1sjN3AIVcjGLpbQ/YcfqHPshKZQK1fA==", + "bundleDependencies": [ + "npm", + "libnpx" + ], + "deprecated": "This package is now part of the npm CLI.", + "license": "ISC", + "dependencies": { + "libnpx": "10.2.2", + "npm": "5.1.0" + }, + "bin": { + "npx": "index.js" + } + }, + "node_modules/npx/node_modules/ansi-align": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^2.0.0" + } + }, + "node_modules/npx/node_modules/ansi-regex": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/ansi-styles": { + "version": "3.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/balanced-match": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/boxen": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/brace-expansion": { + "version": "1.1.11", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npx/node_modules/builtins": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/camelcase": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/capture-stack-trace": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/chalk": { + "version": "2.4.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/ci-info": { + "version": "1.6.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/cli-boxes": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/cliui": { + "version": "4.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/npx/node_modules/code-point-at": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/color-convert": { + "version": "1.9.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npx/node_modules/color-name": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/configstore": { + "version": "3.1.2", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/create-error-class": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "capture-stack-trace": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/cross-spawn": { + "version": "5.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/npx/node_modules/crypto-random-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/decamelize": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/deep-extend": { + "version": "0.6.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/npx/node_modules/dot-prop": { + "version": "4.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/dotenv": { + "version": "5.0.1", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.6.0" + } + }, + "node_modules/npx/node_modules/duplexer3": { + "version": "0.1.4", + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npx/node_modules/end-of-stream": { + "version": "1.4.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/npx/node_modules/escape-string-regexp": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npx/node_modules/execa": { + "version": "0.7.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/find-up": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/fs.realpath": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/get-caller-file": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/get-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/glob": { + "version": "7.1.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npx/node_modules/global-dirs": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/got": { + "version": "6.7.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/graceful-fs": { + "version": "4.2.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/has-flag": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/hosted-git-info": { + "version": "2.8.5", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/import-lazy": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npx/node_modules/inflight": { + "version": "1.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/inherits": { + "version": "2.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/ini": { + "version": "1.3.5", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/invert-kv": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/is-ci": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/npx/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/is-installed-globally": { + "version": "0.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/is-npm": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/is-obj": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/is-path-inside": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/is-redirect": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/is-retry-allowed": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/is-stream": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/isexe": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/latest-version": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "package-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/lcid": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "invert-kv": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/libnpx": { + "version": "10.2.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^11.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/locate-path": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/lowercase-keys": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/lru-cache": { + "version": "4.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/npx/node_modules/make-dir": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/map-age-cleaner": { + "version": "0.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/mem": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/mimic-fn": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/minimatch": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/minimist": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/nice-try": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm": { + "version": "5.1.0", + "bundleDependencies": [ + "abbrev", + "ansi-regex", + "ansicolors", + "ansistyles", + "aproba", + "archy", + "cacache", + "call-limit", + "bluebird", + "chownr", + "cmd-shim", + "columnify", + "config-chain", + "debuglog", + "detect-indent", + "dezalgo", + "editor", + "fs-vacuum", + "fs-write-stream-atomic", + "fstream", + "fstream-npm", + "glob", + "graceful-fs", + "has-unicode", + "hosted-git-info", + "iferr", + "imurmurhash", + "inflight", + "inherits", + "ini", + "init-package-json", + "JSONStream", + "lazy-property", + "lockfile", + "lodash._baseindexof", + "lodash._baseuniq", + "lodash._bindcallback", + "lodash._cacheindexof", + "lodash._createcache", + "lodash._getnative", + "lodash.clonedeep", + "lodash.restparam", + "lodash.union", + "lodash.uniq", + "lodash.without", + "lru-cache", + "mkdirp", + "mississippi", + "move-concurrently", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-cache-filename", + "npm-install-checks", + "npm-package-arg", + "npm-registry-client", + "npm-user-validate", + "npmlog", + "once", + "opener", + "osenv", + "pacote", + "path-is-inside", + "promise-inflight", + "read", + "read-cmd-shim", + "read-installed", + "read-package-json", + "read-package-tree", + "readable-stream", + "readdir-scoped-modules", + "request", + "retry", + "rimraf", + "semver", + "sha", + "slide", + "sorted-object", + "sorted-union-stream", + "ssri", + "strip-ansi", + "tar", + "text-table", + "uid-number", + "umask", + "unique-filename", + "unpipe", + "update-notifier", + "uuid", + "validate-npm-package-license", + "validate-npm-package-name", + "which", + "wrappy", + "write-file-atomic", + "safe-buffer", + "worker-farm" + ], + "inBundle": true, + "license": "Artistic-2.0", + "dependencies": { + "abbrev": "~1.1.0", + "ansi-regex": "~3.0.0", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.1.2", + "archy": "~1.0.0", + "bluebird": "~3.5.0", + "cacache": "~9.2.9", + "call-limit": "~1.1.0", + "chownr": "~1.0.1", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "fstream": "~1.0.11", + "fstream-npm": "~1.2.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "~2.5.0", + "iferr": "~0.1.5", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "~1.3.4", + "init-package-json": "~1.10.1", + "JSONStream": "~1.3.1", + "lazy-property": "~1.0.0", + "lockfile": "~1.0.3", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "~4.1.1", + "mississippi": "~1.3.0", + "mkdirp": "~0.5.1", + "move-concurrently": "~1.0.1", + "node-gyp": "~3.6.2", + "nopt": "~4.0.1", + "normalize-package-data": "~2.4.0", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-package-arg": "~5.1.2", + "npm-registry-client": "~8.4.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "~1.4.3", + "osenv": "~0.1.4", + "pacote": "~2.7.38", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "~2.0.9", + "read-package-tree": "~5.1.6", + "readable-stream": "~2.3.2", + "readdir-scoped-modules": "*", + "request": "~2.81.0", + "retry": "~0.10.1", + "rimraf": "~2.6.1", + "safe-buffer": "~5.1.1", + "semver": "~5.3.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "~4.1.6", + "strip-ansi": "~4.0.0", + "tar": "~2.2.1", + "text-table": "~0.2.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "~1.1.0", + "unpipe": "~1.0.0", + "update-notifier": "~2.2.0", + "uuid": "~3.1.0", + "validate-npm-package-license": "*", + "validate-npm-package-name": "~3.0.0", + "which": "~1.2.14", + "worker-farm": "~1.3.1", + "wrappy": "~1.0.2", + "write-file-atomic": "~2.1.0" + }, + "bin": { + "npm": "bin/npm-cli.js" + } + }, + "node_modules/npx/node_modules/npm-package-arg": { + "version": "6.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npx/node_modules/npm-run-path": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/abbrev": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/ansi-regex": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/ansicolors": { + "version": "0.3.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/ansistyles": { + "version": "0.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/aproba": { + "version": "1.1.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/bluebird": { + "version": "3.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/cacache": { + "version": "9.2.9", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "bluebird": "^3.5.0", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^1.3.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.1", + "ssri": "^4.1.6", + "unique-filename": "^1.1.0", + "y18n": "^3.2.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/cacache/node_modules/lru-cache": { + "version": "4.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/cacache/node_modules/lru-cache/node_modules/pseudomap": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/cacache/node_modules/lru-cache/node_modules/yallist": { + "version": "2.1.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/cacache/node_modules/y18n": { + "version": "3.2.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/call-limit": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/chownr": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/cmd-shim": { + "version": "2.0.2", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify": { + "version": "1.5.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify/node_modules/wcwidth": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify/node_modules/wcwidth/node_modules/defaults": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/columnify/node_modules/wcwidth/node_modules/defaults/node_modules/clone": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/config-chain": { + "version": "1.1.11", + "inBundle": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/config-chain/node_modules/proto-list": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/debuglog": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/detect-indent": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/dezalgo": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/dezalgo/node_modules/asap": { + "version": "2.0.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/editor": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/fs-vacuum": { + "version": "1.2.10", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream": { + "version": "1.0.11", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm": { + "version": "1.2.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fstream-ignore": "^1.0.0", + "inherits": "2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm/node_modules/fstream-ignore": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm/node_modules/fstream-ignore/node_modules/minimatch": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm/node_modules/fstream-ignore/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm/node_modules/fstream-ignore/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/fstream-npm/node_modules/fstream-ignore/node_modules/minimatch/node_modules/brace-expansion/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/glob": { + "version": "7.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/fs.realpath": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/minimatch": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/minimatch/node_modules/brace-expansion/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/glob/node_modules/path-is-absolute": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/graceful-fs": { + "version": "4.1.11", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/hosted-git-info": { + "version": "2.5.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/iferr": { + "version": "0.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npx/node_modules/npm/node_modules/inflight": { + "version": "1.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/inherits": { + "version": "2.0.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/ini": { + "version": "1.3.4", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/init-package-json": { + "version": "1.10.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/init-package-json/node_modules/promzard": { + "version": "0.3.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/JSONStream": { + "version": "1.3.1", + "inBundle": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "index.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/JSONStream/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/JSONStream/node_modules/through": { + "version": "2.3.8", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lazy-property": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lockfile": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._baseindexof": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._baseuniq": { + "version": "4.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._baseuniq/node_modules/lodash._createset": { + "version": "4.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._baseuniq/node_modules/lodash._root": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._bindcallback": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._cacheindexof": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._createcache": { + "version": "3.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lodash._getnative": "^3.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/lodash._getnative": { + "version": "3.9.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash.clonedeep": { + "version": "4.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash.restparam": { + "version": "3.6.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash.union": { + "version": "4.6.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash.uniq": { + "version": "4.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lodash.without": { + "version": "4.4.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/lru-cache": { + "version": "4.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/lru-cache/node_modules/pseudomap": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/lru-cache/node_modules/yallist": { + "version": "2.1.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi": { + "version": "1.3.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^1.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/concat-stream": { + "version": "1.6.0", + "engines": [ + "node >= 0.8" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/concat-stream/node_modules/typedarray": { + "version": "0.0.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/duplexify": { + "version": "3.5.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/duplexify/node_modules/end-of-stream": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "~1.3.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/duplexify/node_modules/end-of-stream/node_modules/once": { + "version": "1.3.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/duplexify/node_modules/stream-shift": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/end-of-stream": { + "version": "1.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/flush-write-stream": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/from2": { + "version": "2.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/parallel-transform": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/parallel-transform/node_modules/cyclist": { + "version": "0.2.2", + "inBundle": true + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/pump": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/pumpify": { + "version": "1.3.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.1.2", + "inherits": "^2.0.1", + "pump": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/stream-each": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/stream-each/node_modules/stream-shift": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/through2": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mississippi/node_modules/through2/node_modules/xtend": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mkdirp": { + "version": "0.5.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/mkdirp/node_modules/minimist": { + "version": "0.0.8", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/move-concurrently": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/move-concurrently/node_modules/copy-concurrently": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/move-concurrently/node_modules/run-queue": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp": { + "version": "3.6.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp/node_modules/minimatch/node_modules/brace-expansion/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/node-gyp/node_modules/nopt": { + "version": "3.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/nopt": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/normalize-package-data": { + "version": "2.4.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/normalize-package-data/node_modules/is-builtin-module": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/normalize-package-data/node_modules/is-builtin-module/node_modules/builtin-modules": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npm-cache-filename": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/npm-install-checks": { + "version": "3.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npm-package-arg": { + "version": "5.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^2.4.2", + "osenv": "^0.1.4", + "semver": "^5.1.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npm-registry-client": { + "version": "8.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^4.1.2" + }, + "optionalDependencies": { + "npmlog": "2 || ^3.1.0 || ^4.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npm-registry-client/node_modules/concat-stream": { + "version": "1.6.0", + "engines": [ + "node >= 0.8" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npm-registry-client/node_modules/concat-stream/node_modules/typedarray": { + "version": "0.0.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/npm-user-validate": { + "version": "1.0.0", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog": { + "version": "4.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet/node_modules/delegates": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/console-control-strings": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge": { + "version": "2.7.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/object-assign": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/string-width/node_modules/code-point-at": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/string-width/node_modules/is-fullwidth-code-point/node_modules/number-is-nan": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/gauge/node_modules/wide-align": { + "version": "1.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/npmlog/node_modules/set-blocking": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/once": { + "version": "1.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/opener": { + "version": "1.4.3", + "inBundle": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "opener.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/osenv": { + "version": "0.1.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/osenv/node_modules/os-homedir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/osenv/node_modules/os-tmpdir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote": { + "version": "2.7.38", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "bluebird": "^3.5.0", + "cacache": "^9.2.9", + "glob": "^7.1.2", + "lru-cache": "^4.1.1", + "make-fetch-happen": "^2.4.13", + "minimatch": "^3.0.4", + "mississippi": "^1.2.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^5.1.2", + "npm-pick-manifest": "^1.0.4", + "osenv": "^0.1.4", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^4.0.0", + "safe-buffer": "^5.1.1", + "semver": "^5.3.0", + "ssri": "^4.1.6", + "tar-fs": "^1.15.3", + "tar-stream": "^1.5.4", + "unique-filename": "^1.1.0", + "which": "^1.2.12" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen": { + "version": "2.4.13", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "agentkeepalive": "^3.3.0", + "cacache": "^9.2.9", + "http-cache-semantics": "^3.7.3", + "http-proxy-agent": "^2.0.0", + "https-proxy-agent": "^2.0.0", + "lru-cache": "^4.1.1", + "mississippi": "^1.2.0", + "node-fetch-npm": "^2.0.1", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.0", + "ssri": "^4.1.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/agentkeepalive": { + "version": "3.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/agentkeepalive/node_modules/humanize-ms": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/agentkeepalive/node_modules/humanize-ms/node_modules/ms": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-cache-semantics": { + "version": "3.7.3", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "4", + "debug": "2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent/node_modules/agent-base/node_modules/es6-promisify": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent/node_modules/agent-base/node_modules/es6-promisify/node_modules/es6-promise": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent/node_modules/debug": { + "version": "2.6.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/http-proxy-agent/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.1.0", + "debug": "^2.4.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent/node_modules/agent-base": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent/node_modules/agent-base/node_modules/es6-promisify": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent/node_modules/agent-base/node_modules/es6-promisify/node_modules/es6-promise": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent/node_modules/debug": { + "version": "2.6.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/https-proxy-agent/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/node-fetch-npm": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "encoding": "^0.1.11", + "json-parse-helpfulerror": "^1.0.3", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/node-fetch-npm/node_modules/encoding": { + "version": "0.1.12", + "inBundle": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "~0.4.13" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/node-fetch-npm/node_modules/encoding/node_modules/iconv-lite": { + "version": "0.4.18", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/node-fetch-npm/node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jju": "^1.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/node-fetch-npm/node_modules/json-parse-helpfulerror/node_modules/jju": { + "version": "1.3.0", + "inBundle": true, + "license": "WTFPL" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.0.1", + "socks": "^1.1.10" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/agent-base/node_modules/es6-promisify": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/agent-base/node_modules/es6-promisify/node_modules/es6-promise": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/socks": { + "version": "1.1.10", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + }, + "engines": { + "node": ">= 0.10.0", + "npm": ">= 1.3.5" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/socks/node_modules/ip": { + "version": "1.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/make-fetch-happen/node_modules/socks-proxy-agent/node_modules/socks/node_modules/smart-buffer": { + "version": "1.1.15", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.10.15", + "npm": ">= 1.3.5" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/minimatch": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/minimatch/node_modules/brace-expansion/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/npm-pick-manifest": { + "version": "1.0.4", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "npm-package-arg": "^5.1.2", + "semver": "^5.3.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/promise-retry": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/promise-retry/node_modules/err-code": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/protoduck": { + "version": "4.0.0", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "genfun": "^4.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/protoduck/node_modules/genfun": { + "version": "4.0.1", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-fs": { + "version": "1.15.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-fs/node_modules/pump": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-fs/node_modules/pump/node_modules/end-of-stream": { + "version": "1.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-stream": { + "version": "1.5.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bl": "^1.0.0", + "end-of-stream": "^1.0.0", + "readable-stream": "^2.0.0", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-stream/node_modules/bl": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-stream/node_modules/end-of-stream": { + "version": "1.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/pacote/node_modules/tar-stream/node_modules/xtend": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/path-is-inside": { + "version": "1.0.2", + "inBundle": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/npx/node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/read": { + "version": "1.0.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read-cmd-shim": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read-installed": { + "version": "4.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read-installed/node_modules/util-extend": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/read-package-json": { + "version": "2.0.9", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read-package-json/node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jju": "^1.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read-package-json/node_modules/json-parse-helpfulerror/node_modules/jju": { + "version": "1.3.0", + "inBundle": true, + "license": "WTFPL" + }, + "node_modules/npx/node_modules/npm/node_modules/read-package-tree": { + "version": "5.1.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/read/node_modules/mute-stream": { + "version": "0.0.7", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream": { + "version": "2.3.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.0", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream/node_modules/core-util-is": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream/node_modules/process-nextick-args": { + "version": "1.0.7", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/readable-stream/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/readdir-scoped-modules": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request": { + "version": "2.81.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/aws-sign2": { + "version": "0.6.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/aws4": { + "version": "1.6.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/caseless": { + "version": "0.12.0", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/combined-stream": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/combined-stream/node_modules/delayed-stream": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/extend": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/forever-agent": { + "version": "0.6.1", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/form-data": { + "version": "2.1.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/form-data/node_modules/asynckit": { + "version": "0.4.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator": { + "version": "4.2.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator/node_modules/ajv": { + "version": "4.11.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator/node_modules/ajv/node_modules/co": { + "version": "4.6.0", + "inBundle": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator/node_modules/ajv/node_modules/json-stable-stringify": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator/node_modules/ajv/node_modules/json-stable-stringify/node_modules/jsonify": { + "version": "0.0.0", + "inBundle": true, + "license": "Public Domain", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/har-validator/node_modules/har-schema": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/hawk": { + "version": "3.1.3", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/hawk/node_modules/boom": { + "version": "2.10.1", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/hawk/node_modules/cryptiles": { + "version": "2.0.5", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "boom": "2.x.x" + }, + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/hawk/node_modules/hoek": { + "version": "2.16.3", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.40" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/hawk/node_modules/sntp": { + "version": "1.0.9", + "inBundle": true, + "dependencies": { + "hoek": "2.x.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/assert-plus": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim": { + "version": "1.4.0", + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/assert-plus": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/extsprintf": { + "version": "1.0.2", + "engines": [ + "node >=0.6.0" + ], + "inBundle": true + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/json-schema": { + "version": "0.2.3", + "inBundle": true + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror": { + "version": "1.3.6", + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "dependencies": { + "extsprintf": "1.0.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk": { + "version": "1.13.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "dashdash": "^1.12.0", + "getpass": "^0.1.1" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + }, + "optionalDependencies": { + "bcrypt-pbkdf": "^1.0.0", + "ecc-jsbn": "~0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/asn1": { + "version": "0.2.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/assert-plus": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/bcrypt-pbkdf": { + "version": "1.0.1", + "inBundle": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/dashdash": { + "version": "1.14.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/ecc-jsbn": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/getpass": { + "version": "0.1.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "inBundle": true, + "license": "Unlicense", + "optional": true + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/is-typedarray": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/isstream": { + "version": "0.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/json-stringify-safe": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/mime-types": { + "version": "2.1.15", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "~1.27.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/mime-types/node_modules/mime-db": { + "version": "1.27.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/oauth-sign": { + "version": "0.8.2", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/performance-now": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/qs": { + "version": "6.4.0", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/stringstream": { + "version": "0.0.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/tough-cookie": { + "version": "2.3.2", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/tough-cookie/node_modules/punycode": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/request/node_modules/tunnel-agent": { + "version": "0.6.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/retry": { + "version": "0.10.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/rimraf": { + "version": "2.6.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.0.5" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/safe-buffer": { + "version": "5.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/semver": { + "version": "5.3.0", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sha": { + "version": "2.0.1", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT)", + "dependencies": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/slide": { + "version": "1.1.6", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-object": { + "version": "2.0.1", + "inBundle": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/from2": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/from2/node_modules/readable-stream": { + "version": "1.1.14", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/from2/node_modules/readable-stream/node_modules/core-util-is": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/from2/node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/from2/node_modules/readable-stream/node_modules/string_decoder": { + "version": "0.10.31", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/stream-iterate": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/sorted-union-stream/node_modules/stream-iterate/node_modules/stream-shift": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/ssri": { + "version": "4.1.6", + "inBundle": true, + "license": "CC0-1.0", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/strip-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/tar": { + "version": "2.2.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/tar/node_modules/block-stream": { + "version": "0.0.9", + "inBundle": true, + "license": "ISC", + "dependencies": { + "inherits": "~2.0.0" + }, + "engines": { + "node": "0.4 || >=0.5.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/uid-number": { + "version": "0.0.6", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npx/node_modules/npm/node_modules/umask": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/unique-filename": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/unique-filename/node_modules/unique-slug": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/unpipe": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier": { + "version": "2.2.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^1.0.0", + "chalk": "^1.0.0", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^1.1.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^0.1.0", + "widest-line": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/ansi-align": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^2.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/camelcase": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/cli-boxes": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/string-width": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "execa": "^0.4.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa": { + "version": "0.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cross-spawn-async": "^2.1.1", + "is-stream": "^1.1.0", + "npm-run-path": "^1.0.0", + "object-assign": "^4.0.1", + "path-key": "^1.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/cross-spawn-async": { + "version": "2.2.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.0", + "which": "^1.2.8" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/is-stream": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/npm-run-path": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/object-assign": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/path-key": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/term-size/node_modules/execa/node_modules/strip-eof": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width/node_modules/code-point-at": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width/node_modules/is-fullwidth-code-point/node_modules/number-is-nan": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/boxen/node_modules/widest-line/node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/ansi-styles": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/has-ansi": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore": { + "version": "3.1.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/dot-prop": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/dot-prop/node_modules/is-obj": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/make-dir": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/make-dir/node_modules/pify": { + "version": "2.3.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/unique-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/configstore/node_modules/unique-string/node_modules/crypto-random-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/import-lazy": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/is-npm": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "package-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got": { + "version": "6.7.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/create-error-class": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "capture-stack-trace": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/create-error-class/node_modules/capture-stack-trace": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/duplexer3": { + "version": "0.1.4", + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/get-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/is-redirect": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/is-retry-allowed": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/is-stream": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/lowercase-keys": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/timed-out": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/unzip-response": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/url-parse-lax": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/got/node_modules/url-parse-lax/node_modules/prepend-http": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-auth-token": { + "version": "3.3.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-auth-token/node_modules/rc": { + "version": "1.2.1", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "index.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-auth-token/node_modules/rc/node_modules/deep-extend": { + "version": "0.4.2", + "inBundle": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.12.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-auth-token/node_modules/rc/node_modules/minimist": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-auth-token/node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-url": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-url/node_modules/rc": { + "version": "1.2.1", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "index.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-url/node_modules/rc/node_modules/deep-extend": { + "version": "0.4.2", + "inBundle": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.12.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-url/node_modules/rc/node_modules/minimist": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/latest-version/node_modules/package-json/node_modules/registry-url/node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/semver-diff": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^5.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/update-notifier/node_modules/xdg-basedir": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/uuid": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-correct": { + "version": "1.0.2", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-license-ids": "^1.0.2" + } + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-correct/node_modules/spdx-license-ids": { + "version": "1.2.2", + "inBundle": true, + "license": "Unlicense" + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "1.0.4", + "inBundle": true, + "license": "(MIT AND CC-BY-3.0)" + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/npx/node_modules/npm/node_modules/validate-npm-package-name/node_modules/builtins": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/which": { + "version": "1.2.14", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npx/node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/worker-farm": { + "version": "1.3.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "errno": ">=0.1.1 <0.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "node_modules/npx/node_modules/npm/node_modules/worker-farm/node_modules/errno": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "prr": "~0.0.0" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/npx/node_modules/npm/node_modules/worker-farm/node_modules/errno/node_modules/prr": { + "version": "0.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/npm/node_modules/worker-farm/node_modules/xtend": { + "version": "4.0.1", + "inBundle": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/npx/node_modules/npm/node_modules/wrappy": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/npm/node_modules/write-file-atomic": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + }, + "node_modules/npx/node_modules/number-is-nan": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/once": { + "version": "1.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npx/node_modules/os-homedir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/os-locale": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/os-locale/node_modules/cross-spawn": { + "version": "6.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npx/node_modules/os-locale/node_modules/execa": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/os-locale/node_modules/get-stream": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/os-tmpdir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/osenv": { + "version": "0.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/npx/node_modules/p-defer": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/p-finally": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/p-is-promise": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npx/node_modules/p-limit": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/p-locate": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/p-try": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/package-json": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/path-exists": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/path-is-absolute": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/path-is-inside": { + "version": "1.0.2", + "inBundle": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/npx/node_modules/path-key": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/pify": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/prepend-http": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/pseudomap": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/pump": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/npx/node_modules/rc": { + "version": "1.2.8", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/npx/node_modules/registry-auth-token": { + "version": "3.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/npx/node_modules/registry-url": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/require-directory": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/require-main-filename": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/rimraf": { + "version": "2.7.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/npx/node_modules/safe-buffer": { + "version": "5.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npx/node_modules/semver": { + "version": "5.7.1", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npx/node_modules/semver-diff": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^5.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/set-blocking": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/shebang-command": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/shebang-regex": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/signal-exit": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/string-width": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/strip-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/strip-eof": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/strip-json-comments": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/supports-color": { + "version": "5.5.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/term-size": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "execa": "^0.7.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/timed-out": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/unique-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/unzip-response": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/update-notifier": { + "version": "2.5.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/url-parse-lax": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/npx/node_modules/which": { + "version": "1.3.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npx/node_modules/which-module": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/widest-line": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/wrap-ansi": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/wrap-ansi/node_modules/string-width": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npx/node_modules/wrappy": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/write-file-atomic": { + "version": "2.4.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/npx/node_modules/xdg-basedir": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npx/node_modules/y18n": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/yallist": { + "version": "2.1.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npx/node_modules/yargs": { + "version": "11.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "node_modules/npx/node_modules/yargs-parser": { + "version": "9.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "camelcase": "^4.1.0" + } + }, + "node_modules/npx/node_modules/yargs/node_modules/y18n": { + "version": "3.2.1", + "inBundle": true, + "license": "ISC" + } + } +} diff --git a/packages/opsxdb-mcp/package.json b/packages/opsxdb-mcp/package.json index 560b07c..ef6127c 100644 --- a/packages/opsxdb-mcp/package.json +++ b/packages/opsxdb-mcp/package.json @@ -26,4 +26,5 @@ "publishConfig": { "access": "public" } + } diff --git a/packages/ui/assets/databases/dameng.svg b/packages/ui/assets/databases/dameng.svg deleted file mode 100644 index 5315156..0000000 --- a/packages/ui/assets/databases/dameng.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/elasticsearch.svg b/packages/ui/assets/databases/elasticsearch.svg deleted file mode 100644 index 0da0d70..0000000 --- a/packages/ui/assets/databases/elasticsearch.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/gaussdb.svg b/packages/ui/assets/databases/gaussdb.svg deleted file mode 100644 index f115a85..0000000 --- a/packages/ui/assets/databases/gaussdb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/influxdb.svg b/packages/ui/assets/databases/influxdb.svg deleted file mode 100644 index a6ed507..0000000 --- a/packages/ui/assets/databases/influxdb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/kingbase.svg b/packages/ui/assets/databases/kingbase.svg deleted file mode 100644 index 9d7f076..0000000 --- a/packages/ui/assets/databases/kingbase.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/mariadb.svg b/packages/ui/assets/databases/mariadb.svg deleted file mode 100644 index 33794b1..0000000 --- a/packages/ui/assets/databases/mariadb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/mongodb.svg b/packages/ui/assets/databases/mongodb.svg deleted file mode 100644 index 8660ced..0000000 --- a/packages/ui/assets/databases/mongodb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/mysql.svg b/packages/ui/assets/databases/mysql.svg deleted file mode 100644 index 853c55f..0000000 --- a/packages/ui/assets/databases/mysql.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/oceanbase.svg b/packages/ui/assets/databases/oceanbase.svg deleted file mode 100644 index 2ace405..0000000 --- a/packages/ui/assets/databases/oceanbase.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/opengauss.svg b/packages/ui/assets/databases/opengauss.svg deleted file mode 100644 index 6f46971..0000000 --- a/packages/ui/assets/databases/opengauss.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/oracle.svg b/packages/ui/assets/databases/oracle.svg deleted file mode 100644 index f5449b2..0000000 --- a/packages/ui/assets/databases/oracle.svg +++ /dev/null @@ -1 +0,0 @@ -Oracle \ No newline at end of file diff --git a/packages/ui/assets/databases/polardb.png b/packages/ui/assets/databases/polardb.png deleted file mode 100644 index 197ba75..0000000 Binary files a/packages/ui/assets/databases/polardb.png and /dev/null differ diff --git a/packages/ui/assets/databases/postgresql.svg b/packages/ui/assets/databases/postgresql.svg deleted file mode 100644 index abacb8f..0000000 --- a/packages/ui/assets/databases/postgresql.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/redis.svg b/packages/ui/assets/databases/redis.svg deleted file mode 100644 index 1981b34..0000000 --- a/packages/ui/assets/databases/redis.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/sqlite.svg b/packages/ui/assets/databases/sqlite.svg deleted file mode 100644 index dde0558..0000000 --- a/packages/ui/assets/databases/sqlite.svg +++ /dev/null @@ -1,7 +0,0 @@ - - SQLite - - - - - diff --git a/packages/ui/assets/databases/sqlserver.svg b/packages/ui/assets/databases/sqlserver.svg deleted file mode 100644 index b23e83d..0000000 --- a/packages/ui/assets/databases/sqlserver.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/tdsql.svg b/packages/ui/assets/databases/tdsql.svg deleted file mode 100644 index 65627ff..0000000 --- a/packages/ui/assets/databases/tdsql.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Tencent Cloud - - - - - - - - diff --git a/packages/ui/assets/databases/tidb.svg b/packages/ui/assets/databases/tidb.svg deleted file mode 100644 index ee0b723..0000000 --- a/packages/ui/assets/databases/tidb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/assets/databases/zookeeper.svg b/packages/ui/assets/databases/zookeeper.svg deleted file mode 100644 index a281bab..0000000 --- a/packages/ui/assets/databases/zookeeper.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/package.json b/packages/ui/package.json deleted file mode 100644 index ad67c57..0000000 --- a/packages/ui/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@opsxdb/ui", - "version": "0.1.0", - "private": true, - "type": "module", - "main": "./src/index.ts", - "types": "./src/index.ts", - "exports": { - ".": "./src/index.ts" - }, - "dependencies": { - "@codemirror/autocomplete": "^6.20.3", - "@codemirror/commands": "^6.11.1", - "@codemirror/lang-sql": "^6.10.0", - "@codemirror/language": "^6.12.4", - "@codemirror/state": "^6.7.5", - "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.43.12", - "sql-formatter": "^15.8.2", - "zustand": "^5.0.3" - }, - "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "scripts": { - "test": "vitest run", - "test:watch": "vitest" - }, - "devDependencies": { - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", - "typescript": "^5.8.2", - "vitest": "^3.0.9" - } -} diff --git a/packages/ui/src/AiPanel.tsx b/packages/ui/src/AiPanel.tsx deleted file mode 100644 index 06c2235..0000000 --- a/packages/ui/src/AiPanel.tsx +++ /dev/null @@ -1,425 +0,0 @@ -import { useEffect, useState } from "react"; -import { callAi, getAiConfig, saveAiConfig, schemaContextFor, type AiAction } from "./api"; -import { useWorkspaceStore } from "./store"; - -const ACTIONS: { id: AiAction; label: string }[] = [ - { id: "generate", label: "生成" }, - { id: "explain", label: "解释" }, - { id: "optimize", label: "优化" }, - { id: "fix", label: "修复" }, - { id: "dialect", label: "方言" }, - { id: "sample", label: "样例" }, -]; - -type ContentSeg = { kind: "text" | "code"; text: string }; - -/** R2-F7:拆分 AI 回复中的 ``` 代码块(通常 sql);块外文本维持纯文本 */ -function splitContent(content: string): ContentSeg[] { - const segs: ContentSeg[] = []; - const re = /```[a-zA-Z]*\r?\n?([\s\S]*?)```/g; - let last = 0; - let m: RegExpExecArray | null; - while ((m = re.exec(content))) { - if (m.index > last) segs.push({ kind: "text", text: content.slice(last, m.index) }); - segs.push({ kind: "code", text: m[1].replace(/\n$/, "") }); - last = m.index + m[0].length; - } - if (last < content.length) segs.push({ kind: "text", text: content.slice(last) }); - return segs.length ? segs : [{ kind: "text", text: content }]; -} - -/** R2-F7:等宽代码块 + 顶部「复制」「插入编辑器」小按钮 */ -function CodeBlock({ code }: { code: string }) { - const notify = useWorkspaceStore((s) => s.notify); - const copy = async () => { - await navigator.clipboard.writeText(code); - notify({ kind: "success", title: "已复制", message: "SQL 已复制", mode: "toast", durationMs: 1200 }); - }; - const insertToEditor = () => { - const st = useWorkspaceStore.getState(); - const tab = st.tabs.find((t) => t.id === st.activeTabId); - const cur = tab?.sql ?? ""; - st.updateActiveSql(cur.trim() ? `${cur.replace(/\s+$/, "")}\n\n${code}` : code); - notify({ kind: "success", title: "已插入编辑器", message: "SQL 已追加到当前查询", mode: "toast", durationMs: 1400 }); - }; - return ( -
-
- - -
-
-        {code}
-      
-
- ); -} - -/** R2-F7:AI 消息渲染 —— 代码块走等宽块,其余纯文本(无代码块时整体不变) */ -function MessageContent({ content }: { content: string }) { - const segs = splitContent(content); - if (segs.length === 1 && segs[0].kind === "text") return <>{content}; - return ( - <> - {segs.map((s, i) => - s.kind === "code" ? : {s.text}, - )} - - ); -} - -/** C4:AI 设置(baseURL / API Key / model + 保存/测试),配置持久化在服务端 ~/.opsxdb/ai.json */ -function AiSettings({ onClose }: { onClose: () => void }) { - const notify = useWorkspaceStore((s) => s.notify); - const set = useWorkspaceStore((s) => s.set); - const [provider, setProvider] = useState("openai"); - const [baseURL, setBaseURL] = useState(""); - const [apiKey, setApiKey] = useState(""); - const [model, setModel] = useState(""); - const [hasKey, setHasKey] = useState(false); - const [busy, setBusy] = useState(false); - - useEffect(() => { - let alive = true; - getAiConfig() - .then((cfg) => { - if (!alive) return; - setProvider(cfg.provider || "stub"); - setBaseURL(cfg.baseURL || ""); - setModel(cfg.model || ""); - setHasKey(!!cfg.hasKey); - }) - .catch(() => {}); - return () => { - alive = false; - }; - }, []); - - const save = async () => { - setBusy(true); - try { - await saveAiConfig({ - provider, - baseURL: baseURL.trim(), - // 留空表示不改动已保存的 key(服务端掩码不回传明文) - apiKey: apiKey.trim() || undefined, - model: model.trim(), - }); - if (model.trim()) set("aiModel", model.trim()); - setHasKey(hasKey || !!apiKey.trim()); - notify({ kind: "success", title: "AI 配置", message: "已保存", mode: "toast", durationMs: 1400 }); - return true; - } catch (e) { - notify({ kind: "error", title: "AI 配置", message: e instanceof Error ? e.message : String(e), mode: "modal" }); - return false; - } finally { - setBusy(false); - } - }; - - const test = async () => { - if (!(await save())) return; - setBusy(true); - try { - const res = await callAi({ action: "ask", prompt: "用一句话回答:连接正常", model: model.trim() || undefined }); - notify({ - kind: "success", - title: "AI 连接正常", - message: res.content.slice(0, 120) || "(空响应)", - mode: "toast", - durationMs: 4000, - }); - } catch (e) { - notify({ kind: "error", title: "AI 连接失败", message: e instanceof Error ? e.message : String(e), mode: "modal" }); - } finally { - setBusy(false); - } - }; - - return ( -
-
- - setModel(e.target.value)} - aria-label="模型" - /> -
- setBaseURL(e.target.value)} - aria-label="Base URL" - /> - setApiKey(e.target.value)} - aria-label="API Key" - /> -
- - - -
-
- ); -} - -export function AiPanel() { - const messages = useWorkspaceStore((s) => s.aiMessages); - const ask = useWorkspaceStore((s) => s.aiAsk); - const model = useWorkspaceStore((s) => s.aiModel); - const busy = useWorkspaceStore((s) => s.aiBusy); - const connections = useWorkspaceStore((s) => s.connections); - const activeConnectionId = useWorkspaceStore((s) => s.activeConnectionId); - const tabs = useWorkspaceStore((s) => s.tabs); - const activeTabId = useWorkspaceStore((s) => s.activeTabId); - const result = useWorkspaceStore((s) => s.result); - const set = useWorkspaceStore((s) => s.set); - const pushAi = useWorkspaceStore((s) => s.pushAi); - const updateActiveSql = useWorkspaceStore((s) => s.updateActiveSql); - const [showSettings, setShowSettings] = useState(false); - /** C4:真实配置的模型清单(来自 /api/ai/config) */ - const [cfgModel, setCfgModel] = useState(""); - - useEffect(() => { - let alive = true; - getAiConfig() - .then((cfg) => { - if (!alive) return; - if (cfg.model) { - setCfgModel(cfg.model); - const cur = useWorkspaceStore.getState().aiModel; - if (!cur || cur === "opsxdb-stub") set("aiModel", cfg.model); - } - }) - .catch(() => {}); - return () => { - alive = false; - }; - }, [set]); - - const conn = connections.find((c) => c.id === activeConnectionId); - const tab = tabs.find((t) => t.id === activeTabId); - const sql = tab?.sql ?? ""; - - const run = async (action: AiAction, prompt?: string) => { - const text = (prompt ?? ask).trim(); - if (action === "ask" && !text) return; - set("aiBusy", true); - if (action === "ask" || action === "generate") { - pushAi("user", text || ACTIONS.find((a) => a.id === action)?.label || action); - } else { - pushAi("user", `${ACTIONS.find((a) => a.id === action)?.label || action}`); - } - try { - // C8:注入当前连接的库表列上下文(按 connId 隔离,截断 4000 字符,见 api.ts) - const schema = schemaContextFor(conn?.id, conn?.database || tab?.database); - const res = await callAi({ - action, - prompt: text, - sql, - driver: conn?.driver, - database: conn?.database || tab?.database, - error: result?.error, - schema: schema || undefined, - model: model && model !== "opsxdb-stub" ? model : undefined, - }); - pushAi("assistant", res.content); - if (res.sql) updateActiveSql(res.sql); - if (action === "ask" || action === "generate") set("aiAsk", ""); - } catch (e) { - pushAi("assistant", `失败:${e instanceof Error ? e.message : String(e)}`); - } finally { - set("aiBusy", false); - } - }; - - const modelOptions = Array.from(new Set([cfgModel, model, "opsxdb-stub"].filter(Boolean))); - - return ( - - ); -} diff --git a/packages/ui/src/ConnectionForm.tsx b/packages/ui/src/ConnectionForm.tsx deleted file mode 100644 index 5e6af8c..0000000 --- a/packages/ui/src/ConnectionForm.tsx +++ /dev/null @@ -1,558 +0,0 @@ -import { useState, type ReactNode } from "react"; -import { formKindOf, type DriverDef } from "./catalog"; -import type { SavedConnection } from "./store"; - -const COLORS = ["#3b82f6", "#22c55e", "#f59e0b", "#ef4444", "#8b5cf6", "#64748b"]; - -type TabId = "general" | "advanced" | "ssl" | "ssh"; - -const TABS: { id: TabId; label: string }[] = [ - { id: "general", label: "常规" }, - { id: "advanced", label: "高级" }, - { id: "ssl", label: "SSL" }, - { id: "ssh", label: "SSH" }, -]; - -function cx(...xs: Array) { - return xs.filter(Boolean).join(" "); -} - -function Row({ label, children }: { label: string; children: ReactNode }) { - return ( -
-
- {label} -
-
{children}
-
- ); -} - -function PasswordInput({ - value, - placeholder, - onChange, -}: { - value: string; - placeholder?: string; - onChange: (v: string) => void; -}) { - const [show, setShow] = useState(false); - return ( -
- onChange(e.target.value)} - autoComplete="off" - /> - -
- ); -} - -export type ConnectionFormProps = { - selected: DriverDef; - form: Partial; - setForm: (next: Partial) => void; - dsn: string; - setDsn: (v: string) => void; - onApplyDsn: () => void; -}; - -export function ConnectionForm({ selected, form, setForm, dsn, setDsn, onApplyDsn }: ConnectionFormProps) { - const [tab, setTab] = useState("general"); - const kind = formKindOf(selected.id); - const patch = (p: Partial) => setForm({ ...form, ...p }); - - const text = (key: keyof SavedConnection, ph = "") => ( - patch({ [key]: e.target.value } as Partial)} - /> - ); - - const portInput = ( - patch({ port: Number(e.target.value) || 0 })} - /> - ); - - const general = () => { - if (kind === "file") { - return ( - <> - {text("name", "我的数据库")} - - patch({ database: e.target.value })} - /> - - - ); - } - - if (kind === "redis") { - const mode = form.redisMode ?? "standalone"; - return ( - <> - {text("name", "Redis 连接")} - -
- {( - [ - ["standalone", "单机"], - ["sentinel", "Sentinel"], - ["cluster", "Cluster"], - ] as const - ).map(([v, label]) => ( - - ))} -
-
- {mode === "standalone" && ( - <> - {text("host", selected.hints?.host ?? "127.0.0.1")} - {portInput} - - )} - {mode === "sentinel" && ( - <> - -