{"_id":"@app-public/weaverbird-debug","_rev":"6-0d369ef8ee6294c6c4b4e9c931235d61","name":"@app-public/weaverbird-debug","dist-tags":{"latest":"1.0.5"},"versions":{"1.0.0":{"name":"@app-public/weaverbird-debug","version":"1.0.0","keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","_id":"@app-public/weaverbird-debug@1.0.0","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"bin":{"weaverbird-debug":"bin/weaverbird-debug.js"},"dist":{"shasum":"379b415a696712d501a8d50cc7b504da80667aa2","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.0.tgz","fileCount":14,"integrity":"sha512-tNA9nngAIH+ciTKzRb4PK0XA6lAr0fzcynZao5kbeLQOX0kzscQoKjS9aIbGd6LJ1l9F0ZF3DycSu+sT0IKlgQ==","signatures":[{"sig":"MEUCIBkD0AMinRXXOY5U77LmDKtgGl1eX+ZEd9s4J1U/C5YjAiEA45rQF2u77BiqJHpdLDvoeVWryIApMbTgXql7hjsTTUs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":29106},"main":"index.js","engines":{"node":">=16"},"gitHead":"2c68f164e89e2997bf55698616de332f3b8ef453","scripts":{"test":"node --test test/*.test.js","build":"node scripts/run-build.js","config":"node scripts/build-config.js","config:test":"node scripts/build-config.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test","config:debug":"node scripts/build-config.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:debug":"node scripts/run-publish.js --env=debug","config:release":"node scripts/build-config.js --env=release","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release"},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"_npmVersion":"11.12.1","description":"WeaverBird CI 开放 CLI — 本地调试环境","directories":{},"_nodeVersion":"25.9.0","dependencies":{"open":"^8.4.2","yargs":"^17.7.2","express":"^4.18.2","cross-fetch":"^4.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/weaverbird-debug_1.0.0_1782286127542_0.13567484353922898","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@app-public/weaverbird-debug","version":"1.0.1","keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","_id":"@app-public/weaverbird-debug@1.0.1","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"bin":{"weaverbird-debug":"bin/weaverbird-debug.js"},"dist":{"shasum":"67b3538a8658b30e313efa8abd5a1ec61a3fb792","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.1.tgz","fileCount":17,"integrity":"sha512-alNJaTdzl8XwLN9sfbHSo/wdFhUdFkyCfX+YmKwRBml+P6tefDO+W+vYCJKA8Qrdcytq9yAq8Sy9WOGf6JAP1Q==","signatures":[{"sig":"MEUCIQCTQILXlMzhgPaqfYtFuiHOKf5l05aD3B7oH9UKaBcw0AIgaQrdABEEix9rRaEMTeheCEbrIcQFcG5KMRY/+97wqjg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33397},"main":"index.js","engines":{"node":">=16"},"gitHead":"44dbcf0753b3cd73f178e9384757a7f89e014ab9","scripts":{"test":"node --test test/*.test.js","build":"node scripts/run-build.js","config":"node scripts/build-config.js","config:test":"node scripts/build-config.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test","config:debug":"node scripts/build-config.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:debug":"node scripts/run-publish.js --env=debug","config:release":"node scripts/build-config.js --env=release","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release"},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"_npmVersion":"11.12.1","description":"WeaverBird CI 开放 CLI — 本地调试环境","directories":{},"_nodeVersion":"25.9.0","dependencies":{"open":"^8.4.2","yargs":"^17.7.2","express":"^4.18.2","cross-fetch":"^4.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/weaverbird-debug_1.0.1_1782291484364_0.93479049600638","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@app-public/weaverbird-debug","version":"1.0.2","keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","_id":"@app-public/weaverbird-debug@1.0.2","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"bin":{"weaverbird-debug":"bin/weaverbird-debug.js"},"dist":{"shasum":"a895c4b4bcd62395fd0235958955604b031c67f3","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.2.tgz","fileCount":18,"integrity":"sha512-Ducsk3NpBAlB6gu+LkguRSr6qMXA7HhBL6/RF19+736yK+Uo95JJcV9vcBtC3ZjsGZulypkT2HB3Ed4h1qw1IQ==","signatures":[{"sig":"MEUCIQDL/2c6F+nNxEXYVoUOWiOUAhLlnvTjSiOk9RJkx6wzVgIgHTZddZmXwhkcR/L0/7ucI81DPKAbkh86LvRnLh8hmD8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35442},"main":"index.js","engines":{"node":">=16"},"gitHead":"44dbcf0753b3cd73f178e9384757a7f89e014ab9","scripts":{"test":"node --test test/*.test.js","build":"node scripts/run-build.js","config":"node scripts/build-config.js","config:test":"node scripts/build-config.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test","config:debug":"node scripts/build-config.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:debug":"node scripts/run-publish.js --env=debug","config:release":"node scripts/build-config.js --env=release","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release"},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"_npmVersion":"11.12.1","description":"WeaverBird CI 开放 CLI — 本地调试环境","directories":{},"_nodeVersion":"25.9.0","dependencies":{"open":"^8.4.2","yargs":"^17.7.2","express":"^4.18.2","cross-fetch":"^4.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/weaverbird-debug_1.0.2_1782297814505_0.8920458022878504","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@app-public/weaverbird-debug","version":"1.0.3","keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","_id":"@app-public/weaverbird-debug@1.0.3","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"bin":{"weaverbird-debug":"bin/weaverbird-debug.js"},"dist":{"shasum":"61a84a266e02952628df2e209216eacc965eef75","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.3.tgz","fileCount":18,"integrity":"sha512-ATPaEKA4iGxlCpa/f0ZJMwCMBTQpcingVEZj8f9zCp8p1MSqx57xu9khX4yLdbNuWyPcxGmkI+I0f9LqAuCwLg==","signatures":[{"sig":"MEQCIDn9BbaaCn66vbG3VrmgFBBFmTuSSrLsEXAhsQFydWiRAiAv8sUAFsCoJ459Kblm0XAkC9+M5Zwy+x5dKag3emgYSg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35675},"main":"index.js","engines":{"node":">=16"},"gitHead":"44dbcf0753b3cd73f178e9384757a7f89e014ab9","scripts":{"test":"node --test test/*.test.js","build":"node scripts/run-build.js","config":"node scripts/build-config.js","config:test":"node scripts/build-config.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test","config:debug":"node scripts/build-config.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:debug":"node scripts/run-publish.js --env=debug","config:release":"node scripts/build-config.js --env=release","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release"},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"_npmVersion":"11.12.1","description":"WeaverBird CI 开放 CLI — 本地调试环境","directories":{},"_nodeVersion":"25.9.0","dependencies":{"open":"^8.4.2","yargs":"^17.7.2","express":"^4.18.2","cross-fetch":"^4.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/weaverbird-debug_1.0.3_1782302164886_0.23434412772713786","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@app-public/weaverbird-debug","version":"1.0.4","keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","_id":"@app-public/weaverbird-debug@1.0.4","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"bin":{"weaverbird-debug":"index.js"},"dist":{"shasum":"e0f2f45d05ce029477b3795b39f821ca100fea0f","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.4.tgz","fileCount":16,"integrity":"sha512-Iqq0bTjkzXhWPGn5fBgOCFu2YfDfZ9PMkbYG41yWE9DmzsLcl2FpO0qCDOdGozuhKVO7j8JCwymh1OSVXMnVag==","signatures":[{"sig":"MEUCID9gaSDxbpNhDCHphLNg4JVeius6hosLNT4lZG7mbPxkAiEAswGGZ/S0c9N3rItQKa2/MwVIF0h487ETj87Wuv+C7Qg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36799},"main":"index.js","engines":{"node":">=16"},"gitHead":"6d884ce862f66189b8519d42a3f19dbddadd1dfd","scripts":{"test":"node --test test/*.test.js","build":"node scripts/run-build.js","config":"node scripts/build-config.js","config:test":"node scripts/build-config.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test","config:debug":"node scripts/build-config.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:debug":"node scripts/run-publish.js --env=debug","config:release":"node scripts/build-config.js --env=release","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release"},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"_npmVersion":"11.12.1","description":"WeaverBird CI 开放 CLI — 本地调试环境","directories":{},"_nodeVersion":"25.9.0","dependencies":{"open":"^8.4.2","yargs":"^17.7.2","express":"^4.18.2","cross-fetch":"^4.0.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/weaverbird-debug_1.0.4_1782356083372_0.7183606514238441","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@app-public/weaverbird-debug","description":"WeaverBird CI 开放 CLI — 本地调试环境","bin":{"weaverbird-debug":"index.js"},"main":"index.js","scripts":{"config":"node scripts/build-config.js","config:debug":"node scripts/build-config.js --env=debug","config:test":"node scripts/build-config.js --env=test","config:release":"node scripts/build-config.js --env=release","build":"node scripts/run-build.js","test":"node --test test/*.test.js","prepublishOnly":"node scripts/run-build.js","publish:release":"node scripts/run-publish.js --env=release","publish:debug":"node scripts/run-publish.js --env=debug","publish:test":"node scripts/run-publish.js --env=test","publish:all":"npm run publish:release && npm run publish:debug && npm run publish:test"},"engines":{"node":">=16"},"dependencies":{"cross-fetch":"^4.0.0","express":"^4.18.2","open":"^8.4.2","yargs":"^17.7.2"},"keywords":["weaverbird","ci","vesync"],"license":"UNLICENSED","version":"1.0.5","gitHead":"8b0924b6701c883cf28bcbd65f2e1fb251c26846","_id":"@app-public/weaverbird-debug@1.0.5","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-fQmV4Pl1hh9b2eMwqyx0q2SjVFvRrKe/viyMBIBCTidJRy20F0Ut4s9ekk4vH/lEQMSSOhKdjok6Yd/kJlGXtA==","shasum":"1cb7fe15aab72a149a5fa88e5e90fb18fd1c53c0","tarball":"https://registry.npmjs.org/@app-public/weaverbird-debug/-/weaverbird-debug-1.0.5.tgz","fileCount":16,"unpackedSize":40192,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICUfEOA4kSeKb6eQf7+FPljrCxtkflIz4JObET0yV2/ZAiBZ6hvaeOZgp1rFYlH5N6O34fJCyffcxdoSiSwiQo9PXQ=="}]},"_npmUser":{"name":"app-public","email":"app-public@vesync.com"},"directories":{},"maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/weaverbird-debug_1.0.5_1782453831894_0.52400985650941"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-24T07:28:47.360Z","modified":"2026-06-26T06:03:52.131Z","1.0.0":"2026-06-24T07:28:47.682Z","1.0.1":"2026-06-24T08:58:04.511Z","1.0.2":"2026-06-24T10:43:34.642Z","1.0.3":"2026-06-24T11:56:05.033Z","1.0.4":"2026-06-25T02:54:43.504Z","1.0.5":"2026-06-26T06:03:52.031Z"},"license":"UNLICENSED","keywords":["weaverbird","ci","vesync"],"description":"WeaverBird CI 开放 CLI — 本地调试环境","maintainers":[{"name":"app-public","email":"app-public@vesync.com"}],"readme":"# WeaverBird CLI\r\n\r\nWeaverBird CI 开放 CLI，通过 OAuth 2.0 登录后访问 CI 平台 API。与 CI 流水线共用同一 OAuth 应用，凭证按环境配置在 `config/profiles/` 中。\r\n\r\n设计说明见飞书文档：[CI 系统 2.5 版本方案设计 — CI 开放 Cli 认证](https://vesync.feishu.cn/wiki/EJRjwbQJki7ozXkJOIZcvmppngd)\r\n\r\n## 环境要求\r\n\r\n- Node.js >= 16\r\n\r\n## 安装\r\n\r\n```bash\r\ncd cli\r\nnpm install\r\n```\r\n\r\n全局联调（可选）：\r\n\r\n```bash\r\nnpm link\r\n```\r\n\r\n或从 npm 安装（发布后，按环境选择包，scope 为 `@app-public`）：\r\n\r\n```bash\r\nnpm install -g @app-public/weaverbird          # 线上（命令仍为 weaverbird）\r\nnpm install -g @app-public/weaverbird-debug    # 本地调试\r\nnpm install -g @app-public/weaverbird-test     # 测试环境\r\n```\r\n\r\n> scoped 包 `@app-public/weaverbird` 与公共 npm 上无 scope 的 `weaverbird`（Vue 查询构建器）是**不同包**，不会冲突。\r\n\r\n## CLI 命令\r\n\r\n| 操作 | 命令 |\r\n|------|------|\r\n| 顶层帮助 | `weaverbird --help` |\r\n| cli 子命令帮助 | `weaverbird cli --help` |\r\n| token 帮助 | `weaverbird cli token --help` |\r\n| token set 参数 | `weaverbird cli token set --help` |\r\n| 版本 | `weaverbird --version` |\r\n| OAuth 登录 | `weaverbird cli login` |\r\n| 退出登录 | `weaverbird cli logout` |\r\n| 登录状态 | `weaverbird cli status` |\r\n| 自更新 | `weaverbird update` |\r\n| 设置 Figma token | `weaverbird cli token set --type figma <token>` |\r\n\r\n`update` 可在顶层或 `cli` 下执行，二者等价。`token set` 的 `<token>` 是**位置参数**，放在命令最后；`--type figma` 必填。\r\n\r\n### token set 示例\r\n\r\n```bash\r\nweaverbird cli token set --type figma figd_xxxxxxxxxxxxxxxx\r\nweaverbird cli token set -t figma figd_xxxxxxxxxxxxxxxx\r\n```\r\n\r\n需先 `weaverbird cli login`。Figma token：Settings → Security → Personal access tokens。\r\n\r\n### login 流程\r\n\r\n1. 本地启动 `http://localhost:3333/callback` 回调服务\r\n2. CLI 调用 `POST /v1/api/ci/oauth/createAuthorizeSession` 创建**一次性、5 分钟有效**的授权会话\r\n3. 自动打开浏览器访问 `{WEAVERBIRD_URL}/weaverbird/oauth/authorize?session=...`（链接不可复制复用）\r\n4. 用户授权后回调带 `code`，CLI 调用 `POST /v1/api/ci/oauth/token` 换取 token\r\n5. token 写入 `~/.weaverbird/token.{env}.json`（如 `token.release.json`）\r\n\r\n### status 输出示例\r\n\r\n已登录：\r\n\r\n```json\r\n{\r\n  \"logged_in\": true,\r\n  \"env\": \"debug\",\r\n  \"ci_base_url\": \"http://10.25.72.141:16644\",\r\n  \"token_path\": \"C:\\\\Users\\\\xxx\\\\.weaverbird\\\\token.debug.json\",\r\n  \"user_id\": \"abc123\",\r\n  \"user_name\": \"张三\",\r\n  \"token\": {\r\n    \"access_token\": \"eyJxxx\",\r\n    \"token_type\": \"Bearer\",\r\n    \"expires_in\": 7200,\r\n    \"refresh_token\": \"xxx\",\r\n    \"user\": {\r\n      \"id\": \"abc123\",\r\n      \"name\": \"zhangsan\",\r\n      \"realname\": \"张三\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n未登录：\r\n\r\n```json\r\n{\r\n  \"logged_in\": false,\r\n  \"env\": \"debug\",\r\n  \"ci_base_url\": \"http://10.25.72.141:16644\",\r\n  \"token_path\": \"C:\\\\Users\\\\xxx\\\\.weaverbird\\\\token.debug.json\",\r\n  \"user_id\": null,\r\n  \"user_name\": null,\r\n  \"token\": null\r\n}\r\n```\r\n\r\n## 多环境配置\r\n\r\nCLI 通过**命令名**区分环境（`weaverbird` / `weaverbird-debug` / `weaverbird-test`），配置与后端 `core/config/config.py` 对齐，位于 `config/profiles/`：\r\n\r\n| 命令 | 环境 | `CI_BASE_URL`（SERVER_HOST） | `WEAVERBIRD_URL` |\r\n|------|------|------------------------------|------------------|\r\n| `weaverbird` | `release` | `https://apphost.vesync.cn` | `https://apphost.vesync.cn` |\r\n| `weaverbird-debug` | `debug` | `http://10.25.72.141:16644` | `http://10.25.72.141:18833` |\r\n| `weaverbird-test` | `test` | `http://192.168.10.191:16644` | `http://192.168.10.191:18833` |\r\n\r\n### 校验 profile\r\n\r\n```bash\r\nnpm run config -- --env=release\r\nnpm run config:debug\r\nnpm run config:test\r\nnpm run config:release\r\n```\r\n\r\n### 构建（profile 校验 + 语法检查 + 单元测试）\r\n\r\n```bash\r\nnpm run build\r\n```\r\n\r\n### 发布\r\n\r\n发布前自动执行 `prepublishOnly`（构建与测试）。按环境发布为 **`@app-public` scope 下的独立包**（自动 `--access public`）：\r\n\r\n| 脚本 | npm 包名 | 全局命令 |\r\n|------|----------|----------|\r\n| `npm run publish:release` | `@app-public/weaverbird` | `weaverbird` |\r\n| `npm run publish:debug` | `@app-public/weaverbird-debug` | `weaverbird-debug` |\r\n| `npm run publish:test` | `@app-public/weaverbird-test` | `weaverbird-test` |\r\n| `npm run publish:all` | 依次发布以上三个包 | — |\r\n\r\n```bash\r\nnpm run publish:release              # 发布线上包\r\nnpm run publish:debug              # 发布调试包\r\nnpm run publish:test               # 发布测试包\r\nnpm run publish:all                # 一次性发布三个包（版本号需一致）\r\n\r\n# 透传 npm publish 参数\r\nnpm run publish:release -- --dry-run\r\nnpm run publish:test -- --tag beta\r\n```\r\n\r\n> 本地 `package.json` 为私有工作区包（`weaverbird-cli`，`private: true`），**不可直接 `npm publish`**。`publish:*` 脚本会临时改写为对应环境的独立包名与 bin，发布完成后自动还原。\r\n\r\n三个环境对应**三个不同的 scoped 包名**，互不影响、可独立发版：\r\n\r\n| 环境 | npm 包名 |\r\n|------|----------|\r\n| 线上 | `@app-public/weaverbird` |\r\n| 调试 | `@app-public/weaverbird-debug` |\r\n| 测试 | `@app-public/weaverbird-test` |\r\n\r\n## 运行时环境变量覆盖\r\n\r\n生成 `config.js` 在运行时按命令名加载 profile；仍可通过环境变量覆盖部分配置（便于本地调试）：\r\n\r\n| 变量 | 说明 |\r\n|------|------|\r\n| `WEAVERBIRD_ENV` | 环境标识（debug / test / release） |\r\n| `WEAVERBIRD_CI_URL` | CI API 根地址 |\r\n| `WEAVERBIRD_URL` | WeaverBird 前端地址 |\r\n| `WEAVERBIRD_CLIENT_ID` | OAuth 应用 ID |\r\n| `WEAVERBIRD_CLIENT_SECRET` | OAuth 应用密钥 |\r\n| `WEAVERBIRD_REDIRECT_URI` | OAuth 回调地址，默认 `http://localhost:3333/callback` |\r\n| `WEAVERBIRD_CALLBACK_PORT` | 本地回调端口，默认 `3333` |\r\n| `WEAVERBIRD_SCOPE` | OAuth scope，默认 `read write` |\r\n\r\n## OAuth 凭证配置\r\n\r\n凭证由服务端 **`oauth_client` 表**统一生成与管理（每个 PocketBase 库各一条应用记录）。环境不写在表里，而是通过 `core/config` 连接不同数据库（debug / test / release）自然隔离。\r\n\r\nCLI 侧在 `config/profiles/{debug,test,release}.js` 中配置各环境 API 地址，并从**对应环境数据库**初始化脚本输出的 `CLIENT_ID` / `CLIENT_SECRET` 填入 profile。\r\n\r\n### 初始化 WeaverBird CLI 应用\r\n\r\n在目标环境的 PocketBase 建好 `oauth_client` 表后，用对应环境启动脚本执行（与后端一致，如 `python main.py test` 或 `release`）：\r\n\r\n```bash\r\npython util/data_server_update/maintain_260615/main.py\r\n```\r\n\r\n每个数据库只会创建一条 `name=WeaverBird CLI` 的记录；首次创建时打印明文 `clientSecret`，写入该环境对应的 `cli/config/profiles/*.js`。\r\n\r\n**注意：** 不要将真实 `CLIENT_SECRET` 提交到公开仓库；CI/CD 发布时建议通过环境变量注入。\r\n\r\n## OAuth 客户端应用表（`oauth_client`）\r\n\r\nPocketBase 集合名：`oauth_client`\r\n\r\n| 字段 | 类型 | 必填 | 说明 |\r\n|------|------|------|------|\r\n| `name` | text | 是 | 应用名称，如 `WeaverBird CLI` |\r\n| `clientId` | text | 是 | OAuth `CLIENT_ID`，格式 `cli_` + 32 位 hex，**全局唯一** |\r\n| `clientSecret` | text | 是 | AES 加密存储的 `CLIENT_SECRET`，**不可明文回显** |\r\n| `redirectUris` | json | 是 | 允许的回调地址列表，默认 `[\"http://localhost:3333/callback\"]` |\r\n| `scopes` | text | 是 | 授权范围，默认 `read write` |\r\n| `grantTypes` | json | 是 | 默认 `[\"authorization_code\",\"refresh_token\"]` |\r\n| `isInvalid` | bool | 否 | 是否禁用，默认 `false` |\r\n| `description` | text | 否 | 备注 |\r\n\r\n> **环境隔离**：不在表中存 `env` / `key`。debug、test、release 各自连独立 PocketBase（见 `core/config/config.py` 的 `POCKETBASE_BASE_URL`），各库维护各自的 `oauth_client` 记录。\r\n\r\n### 凭证生成规则\r\n\r\n后端 `OAuthClientExtLogic`（`logic/ext/oauth_client.py`）：\r\n\r\n| 方法 | 说明 |\r\n|------|------|\r\n| `generate_client_id()` | `cli_{secrets.token_hex(16)}` |\r\n| `generate_client_secret()` | `secrets.token_urlsafe(32)` |\r\n| `create_oauth_client(name, ...)` | 创建应用，**仅返回时展示一次**明文 secret |\r\n| `create_or_get_weaverbird_cli()` | 若已有 `WeaverBird CLI` 则返回首条，否则新建 |\r\n| `get_by_client_id` | 按 clientId 查询（唯一键） |\r\n| `verify_client(client_id, secret)` | OAuth token 端校验客户端 |\r\n\r\n`clientSecret` 使用 `Encrypt.encrypt_with_salt` 加密，`salt` 为 `clientId`。\r\n\r\n### 与 CLI profile 的关系\r\n\r\n| 后端环境（core/config） | PocketBase | CLI profile |\r\n|-------------------------|------------|-------------|\r\n| debug | `10.25.72.141:17760` | `config/profiles/debug.js` |\r\n| test | `192.168.10.191:17760` | `config/profiles/test.js` |\r\n| release | `apphost.vesync.cn` | `config/profiles/release.js` |\r\n\r\n各环境分别在对应库执行初始化脚本，将输出的凭证填入同名 profile 即可。\r\n\r\n### 关联表（OAuth 完整链路，后续实现）\r\n\r\n| 表名 | 用途 |\r\n|------|------|\r\n| `oauth_authorization_code` | 授权码：`code`、`clientId`、`userId`、`redirectUri`、`scope`、`expiresTime`（兑换后删除） |\r\n| `oauth_access_token` | 访问令牌：可复用现有 `token` 表扩展，或独立存储 `accessToken`、`refreshToken`、`clientId`、`userId`、`expiresAt` |\r\n\r\n## 目录结构\r\n\r\n```\r\ncli/\r\n├── index.js              # CLI 入口（bin: weaverbird / weaverbird-debug / weaverbird-test）\r\n├── config.js             # 运行时按命令名加载 profile\r\n├── config/\r\n│   └── profiles/         # 各环境 profile（与 core/config 对齐）\r\n├── login.js              # OAuth 登录逻辑\r\n├── tokenStore.js         # ~/.weaverbird/token.json 读写\r\n├── api.js                # Bearer 请求与 refresh_token 刷新\r\n├── scripts/\r\n│   ├── build-config.js   # 校验 profile\r\n│   ├── run-build.js      # build 入口\r\n│   └── run-publish.js    # 按环境发布 npm 包\r\n├── test/\r\n└── package.json\r\n```\r\n\r\n## 开发\r\n\r\n```bash\r\nnpm run build             # 完整构建\r\nnpm run publish:release   # 发布线上包（示例）\r\n```\r\n\r\n## 后端依赖\r\n\r\nCLI 依赖服务端 OAuth 接口（均为 POST JSON，响应格式与项目统一 `{ code, msg, data }`）：\r\n\r\n| 接口 | 说明 |\r\n|------|------|\r\n| `/v1/api/ci/oauth/createOauthClient` | 管理员创建 OAuth 应用（header `token`） |\r\n| `/v1/api/ci/oauth/createAuthorizeSession` | CLI 创建授权页一次性会话（需 client_secret） |\r\n| `/v1/api/ci/oauth/getAuthorizeSession` | Web 查询授权会话状态（pending/expired/invalid） |\r\n| `/v1/api/ci/oauth/authorize` | 签发 authorization code（需 session_token + header `token`） |\r\n| `/v1/api/ci/oauth/token` | 换取/刷新 access_token |\r\n| `/v1/api/ci/open/setToken` | CLI 设置第三方 token（如 figma），需 `cli_token` header |\r\n\r\n授权页由前端 `{WEAVERBIRD_URL}/weaverbird/oauth/authorize?session=...` 实现；会话 **5 分钟过期、一次性使用**，过期或已用后 Web 会拦截并提示重新执行 `weaverbird cli login`。\r\n\r\n业务 API 请求头：`cli_token` header（OAuth 换取的 access_token，与网页 `token` 独立）。\r\n\r\n### PocketBase 需创建的表\r\n\r\n- `oauth_client` — OAuth 应用\r\n- `oauth_authorize_session` — 授权页会话（字段：sessionToken, clientId, redirectUri, responseType, scope, state, expiresTime；使用后删除）\r\n- `oauth_authorization_code` — 授权码（字段：code, clientId, userId, redirectUri, scope, expiresTime；兑换后删除）\r\n- `oauth_refresh_token` — 刷新令牌（字段：refreshToken, clientId, userId, scope, expiresTime, isInvalid）\r\n","readmeFilename":"README.md"}