{"_id":"@daiyu-5577/buildsystem","_rev":"6-a4653789b38e7c3520f496074a717a4d","name":"@daiyu-5577/buildsystem","dist-tags":{"latest":"1.3.1"},"versions":{"1.0.0":{"name":"@daiyu-5577/buildsystem","version":"1.0.0","author":{"name":"daiyu"},"license":"MIT","_id":"@daiyu-5577/buildsystem@1.0.0","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"bin":{"buildSystem":"dist/cli.js"},"dist":{"shasum":"b79ba7e62f1d68dc03b49828110b48900b112dde","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.0.0.tgz","fileCount":50,"integrity":"sha512-h/T8Rxurb7OxSgQC6sq6mSaEbpkCc06Jv90kGKUMdi1W5Pbr57M4bFYCU1oXjEucXjGgfNSAFo5+MSnnFs47bQ==","signatures":[{"sig":"MEYCIQCgygY7weCVwAB0HuckWihl24PUcihO3lFkHk1JjJPcEwIhAKQmVZWwFwD+4JWrP0gkwv+yGaBtmkVUrct2Y8yZXJQ7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1109845},"main":"dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"bcdaf2ed02f4d2d58f45b57936922726e1533be6","scripts":{"cli":"node ./dist/cli.js","build":"tsc && cd web && npm run build","server":"node ./dist/server/index.js","dev:web":"cd web && npm run dev","release":"release-it","xpublish":"npm publish --access public","build:web":"cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web"},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"_npmVersion":"11.6.1","description":"CLI tool to build projects based on git changes","directories":{},"_nodeVersion":"24.11.0","dependencies":{"cors":"^2.8.5","cron":"^4.1.0","glob":"^11.0.1","axios":"^1.7.9","chalk":"^5.4.1","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","winston":"^3.17.0","fs-extra":"^11.3.0","commander":"^13.0.0","socket.io":"^4.8.1","release-it":"^20.0.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston-daily-rotate-file":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","cross-env":"^7.0.3","typescript":"^5.7.3","@types/cors":"^2.8.17","@types/node":"^22.10.7","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8"},"_npmOperationalInternal":{"tmp":"tmp/buildsystem_1.0.0_1779335915760_0.053167977534900324","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@daiyu-5577/buildsystem","version":"1.0.1","author":{"name":"daiyu"},"license":"MIT","_id":"@daiyu-5577/buildsystem@1.0.1","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"bin":{"buildsystem":"dist/cli.js"},"dist":{"shasum":"76d36c78fe0d867e2bb3fa72caa8757e4f4af2d0","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.0.1.tgz","fileCount":50,"integrity":"sha512-/j3bLSbeumKnRk73s0jQeMN4rc/5eotrTylqtA9LlnsyqA8MolCUEyrBeJuvBIbhU/M14rxsxo2D1WNafz+F+g==","signatures":[{"sig":"MEUCIGB41PsoIXujyuvtLSda9NFpUi6pv3IkhRzRotj7Nj/VAiEA2SvhHw06wXmuHUG2X5Y5CKST+rhoNnlrYXL2nTfA1ZE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1109846},"main":"dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"83b1d95e1074a5a5a45c2e6bd0d59f96d06fdd5d","scripts":{"cli":"node ./dist/cli.js","build":"tsc && cd web && npm run build","server":"node ./dist/server/index.js","dev:web":"cd web && npm run dev","release":"release-it","xpublish":"npm publish --access public","build:web":"cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web"},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"_npmVersion":"11.6.1","description":"CLI tool to build projects based on git changes","directories":{},"_nodeVersion":"24.11.0","dependencies":{"cors":"^2.8.5","cron":"^4.1.0","glob":"^11.0.1","axios":"^1.7.9","chalk":"^5.4.1","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","winston":"^3.17.0","fs-extra":"^11.3.0","commander":"^13.0.0","socket.io":"^4.8.1","release-it":"^20.0.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston-daily-rotate-file":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","cross-env":"^7.0.3","typescript":"^5.7.3","@types/cors":"^2.8.17","@types/node":"^22.10.7","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8"},"_npmOperationalInternal":{"tmp":"tmp/buildsystem_1.0.1_1779342648825_0.5334190759734383","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@daiyu-5577/buildsystem","version":"1.1.0","author":{"name":"daiyu"},"license":"MIT","_id":"@daiyu-5577/buildsystem@1.1.0","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"bin":{"buildsystem":"dist/cli.js"},"dist":{"shasum":"05e86c101d371d1b17d9d00b0927c7a22e7e4fd2","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.1.0.tgz","fileCount":50,"integrity":"sha512-zGCC2Bm9KCUqTQZx9gKVBNHUIgqx0dwOUshk++Vg+oMB21Zuf8EDbC1/VCwh5aed5+Pb3CINpphRW90lCH8V1Q==","signatures":[{"sig":"MEQCIG0WC93/pNc2Cl5XO9X+IzvLTPT9HmEX3R8n9HAKs/DlAiBfG+CRhTOOB3t6IEwOEkyUf1YT598cyDuXhvYXcXZAfA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1110695},"main":"dist/cli.js","type":"module","engines":{"node":">=23.5.0"},"gitHead":"6699f438b4332833f9c41be8fa72da4b276b2d00","scripts":{"cli":"node ./dist/cli.js","build":"tsc && cd web && npm run build","server":"node ./dist/server/index.js","dev:web":"cd web && npm run dev","release":"release-it","xpublish":"npm publish --access public","build:web":"cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web"},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"_npmVersion":"11.6.1","description":"CLI tool to build projects based on git changes","directories":{},"_nodeVersion":"24.11.0","dependencies":{"cors":"^2.8.5","cron":"^4.1.0","glob":"^11.0.1","axios":"^1.7.9","chalk":"^5.4.1","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","winston":"^3.17.0","fs-extra":"^11.3.0","commander":"^13.0.0","socket.io":"^4.8.1","release-it":"^20.0.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston-daily-rotate-file":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","cross-env":"^7.0.3","typescript":"^5.7.3","@types/cors":"^2.8.17","@types/node":"^22.10.7","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8"},"_npmOperationalInternal":{"tmp":"tmp/buildsystem_1.1.0_1779354253328_0.5671350090437259","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@daiyu-5577/buildsystem","version":"1.2.0","author":{"name":"daiyu"},"license":"MIT","_id":"@daiyu-5577/buildsystem@1.2.0","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"bin":{"buildsystem":"dist/cli.js"},"dist":{"shasum":"8bc517f0af0b500945c4bad59d3491b6b1677ea7","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.2.0.tgz","fileCount":50,"integrity":"sha512-ARmkd4Giui1uVR7x1dJjjQFbJmcjrdsP2DaI/BPAf9FKJNWQeZpguFsEehjKzM3VypaY9k5e0wQLarBczdAijw==","signatures":[{"sig":"MEYCIQCbmuSMVRt0zIfqUdTVc5XMGl4i5CiufB8XRR5FknltAQIhAN4t+N9xHQUBDlASdw9DEIRgydyHgRreKx54DgfN2n4O","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1114829},"main":"dist/cli.js","type":"module","engines":{"node":">=16.0.0"},"gitHead":"ed713c8e8c4708fc0f43b35daf5e60245d144eeb","scripts":{"cli":"node ./dist/cli.js","build":"tsc && cd web && npm run build","server":"node ./dist/server/index.js","dev:web":"cd web && npm run dev","release":"release-it","xpublish":"npm publish --access public","build:web":"cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web"},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"_npmVersion":"11.6.1","description":"CLI tool to build projects based on git changes","directories":{},"_nodeVersion":"24.11.0","dependencies":{"cors":"^2.8.5","cron":"^4.1.0","glob":"^10.5.0","axios":"^1.7.9","chalk":"^5.4.1","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","winston":"^3.17.0","fs-extra":"^11.3.0","commander":"^13.0.0","socket.io":"^4.8.1","release-it":"^20.0.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston-daily-rotate-file":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","cross-env":"^7.0.3","typescript":"^5.7.3","@types/cors":"^2.8.17","@types/node":"^22.10.7","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8"},"_npmOperationalInternal":{"tmp":"tmp/buildsystem_1.2.0_1779682638359_0.22087540989406618","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@daiyu-5577/buildsystem","version":"1.3.0","author":{"name":"daiyu"},"license":"MIT","_id":"@daiyu-5577/buildsystem@1.3.0","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"bin":{"buildsystem":"dist/cli.js"},"dist":{"shasum":"a089328bc0e631a08146c7f07a6552e43cad8700","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.3.0.tgz","fileCount":50,"integrity":"sha512-AJyeOyGXOwoZQR3ZmsqJNRb2u0Mr+OBlEm37LZobkSI4daJQAa75cc69/YD/lIgVrtfYApXpANMAL/5XSfRQ4Q==","signatures":[{"sig":"MEUCIQCC3O5JE0Iux1/lUi+djjBJKbkrU5f3GwZcCafopSaNawIgYxSpb5WekCCikavDN0Tzfe9ubUkt5fY1XC5TTfD/CeI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1117409},"main":"dist/cli.js","type":"module","engines":{"node":">=16.0.0"},"gitHead":"d335e10f1ec2999f5c12df7f7678e9fba012a410","scripts":{"cli":"node ./dist/cli.js","build":"tsc && cd web && npm run build","server":"node ./dist/server/index.js","dev:web":"cd web && npm run dev","release":"release-it","xpublish":"npm publish --access public","build:web":"cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web"},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"_npmVersion":"11.6.1","description":"CLI tool to build projects based on git changes","directories":{},"_nodeVersion":"24.11.0","dependencies":{"cors":"^2.8.5","cron":"^4.1.0","glob":"^10.5.0","axios":"^1.7.9","chalk":"^5.4.1","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","winston":"^3.17.0","fs-extra":"^11.3.0","commander":"^13.0.0","socket.io":"^4.8.1","release-it":"^20.0.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston-daily-rotate-file":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","cross-env":"^7.0.3","typescript":"^5.7.3","@types/cors":"^2.8.17","@types/node":"^22.10.7","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8"},"_npmOperationalInternal":{"tmp":"tmp/buildsystem_1.3.0_1779693290846_0.9266989987887029","host":"s3://npm-registry-packages-npm-production"}},"1.3.1":{"name":"@daiyu-5577/buildsystem","version":"1.3.1","description":"CLI tool to build projects based on git changes","main":"dist/cli.js","type":"module","bin":{"buildsystem":"dist/cli.js"},"scripts":{"build":"tsc && cd web && npm run build","dev:build":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts build -b dev -p . -n http://localhost:3000/api/notify","dev:server":"cross-env NODE_ENV=development nodemon --signal SIGHUP -e .ts --exec node --loader ts-node/esm src/cli.ts server --website-root ./web --website-path /web","dev:web":"cd web && npm run dev","build:web":"cd web && npm run build","cli":"node ./dist/cli.js","server":"node ./dist/server/index.js","release":"release-it","xpublish":"npm publish --access public"},"author":{"name":"daiyu"},"license":"MIT","engines":{"node":">=16.0.0"},"dependencies":{"axios":"^1.7.9","chalk":"^5.4.1","commander":"^13.0.0","cors":"^2.8.5","cron":"^4.1.0","dayjs":"^1.11.13","dotenv":"^17.4.2","express":"^5.1.0","fs-extra":"^11.3.0","glob":"^10.5.0","release-it":"^20.0.1","socket.io":"^4.8.1","swagger-jsdoc":"^6.2.8","swagger-ui-express":"^5.0.1","winston":"^3.17.0","winston-daily-rotate-file":"^5.0.0"},"devDependencies":{"@types/cors":"^2.8.17","@types/express":"^5.0.0","@types/fs-extra":"^11.0.4","@types/node":"^22.10.7","@types/swagger-jsdoc":"^6.0.4","@types/swagger-ui-express":"^4.1.8","cross-env":"^7.0.3","esbuild":"^0.24.2","nodemon":"^3.1.9","ts-node":"^10.9.2","typescript":"^5.7.3"},"gitHead":"407c866d956ab9ec2b9b28144ff965a16f39ebba","_id":"@daiyu-5577/buildsystem@1.3.1","_nodeVersion":"24.11.0","_npmVersion":"11.6.1","dist":{"integrity":"sha512-qpA5QAcs3R8nZOrxeJ166xcPlfbbNTGOdhURn2lvIvtyGXxSra9i+3t5HfxXBvG39jlgkkeOvCToFurUw2QnXg==","shasum":"cdf697c99a65b9204a80418efb2fb2d069b22693","tarball":"https://registry.npmjs.org/@daiyu-5577/buildsystem/-/buildsystem-1.3.1.tgz","fileCount":50,"unpackedSize":1117670,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG96nIx0Oft8Y98xz8GV64BLIrsfnmPheMVgLy6uB8x9AiEAqr8HR5aXo/G/qh9qjA+ObPSZ69ECVxBTLcKMhsHMcy8="}]},"_npmUser":{"name":"daiyu5577","email":"843355724@qq.com"},"directories":{},"maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/buildsystem_1.3.1_1779694727536_0.0169795126601604"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-21T03:58:35.603Z","modified":"2026-05-25T07:38:47.837Z","1.0.0":"2026-05-21T03:58:35.955Z","1.0.1":"2026-05-21T05:50:48.988Z","1.1.0":"2026-05-21T09:04:13.511Z","1.2.0":"2026-05-25T04:17:18.540Z","1.3.0":"2026-05-25T07:14:51.006Z","1.3.1":"2026-05-25T07:38:47.727Z"},"author":{"name":"daiyu"},"license":"MIT","description":"CLI tool to build projects based on git changes","maintainers":[{"name":"daiyu5577","email":"843355724@qq.com"}],"readme":"# BuildSystem\n\n基于 Git 变更的自动化构建系统，提供 CLI 构建命令和 Web 可视化构建管理界面，支持增量构建、并发控制、实时消息推送、版本回退、Webhook 通知和多用户权限管理。\n\n## 功能概览\n\n- **CLI 构建** — 命令行一键触发构建，支持指定分支、目录、commit 区间\n- **Web 管理界面** — 实时构建状态监控、聊天室、日志查看、版本回退、用户权限管理\n- **增量构建** — 通过 `git diff` 识别变更项目，仅构建受影响的包\n- **并发控制** — 可配置最大并发构建数（`MAX_CONCURRENCY`）\n- **实时推送** — Socket.IO 双向通信，构建日志实时流式推送\n- **Webhook 通知** — 构建完成自动通知外部系统\n- **版本回退** — 构建前自动备份，支持一键回退\n- **定时清理** — Cron 定时清理旧日志和备份\n- **多用户认证** — Token 加密鉴权，支持邀请注册\n- **角色权限** — 三级角色体系（Super / Admin / User），细粒度权限控制\n\n## 目录结构\n\n```\nbuildSystem/\n├── src/                          # 后端（Node.js + TypeScript + ESM）\n│   ├── cli.ts                    # CLI 入口（commander）\n│   ├── commands/\n│   │   ├── build.ts              # build 命令：纯 CLI 构建\n│   │   └── server.ts             # server 命令：启动 Web 服务\n│   ├── server/\n│   │   ├── index.ts              # Express + Socket.IO 服务主类\n│   │   ├── routes.ts             # REST API 路由（含用户管理接口）\n│   │   └── websocket.ts          # WebSocket 处理器 & 命令系统\n│   ├── queue.ts                  # 构建任务队列（并发控制、增量构建）\n│   ├── git.ts                    # Git 异步操作（checkout/pull/diff/clean）\n│   ├── pm.ts                     # 包管理器检测（npm/yarn/pnpm）\n│   ├── artifact.ts               # 构建产物备份与复制\n│   ├── notifier.ts               # 通知系统（Socket.IO + Webhook）\n│   ├── cron.ts                   # Cron 定时任务\n│   ├── crypto.ts                 # AES-256-CBC 加解密\n│   ├── database/\n│   │   ├── index.ts              # JSON 文件数据库\n│   │   └── types.ts              # 数据库类型（User/Message/Invite）\n│   ├── config.ts                 # 集中配置（环境变量 + 路径）\n│   ├── types.ts                  # 公共类型定义\n│   ├── logger.ts                 # Winston 日志（http / socket 分离）\n│   ├── fsHelpers.ts              # 文件系统工具\n│   ├── utils.ts                  # 通用工具函数\n│   └── custError.ts              # 自定义错误\n│\n├── web/                          # 前端（React + Vite + Less）\n│   ├── src/\n│   │   ├── main.tsx              # 入口（Router + AuthGuard）\n│   │   ├── pages/\n│   │   │   ├── Home.tsx          # 主页（构建面板 + 聊天室 + 用户操作）\n│   │   │   ├── Login.tsx         # 登录/注册页\n│   │   │   ├── InviteModal.tsx   # 邀请码弹窗\n│   │   │   ├── PermissionModal.tsx # 权限管理弹窗\n│   │   │   ├── UserInfoModal.tsx   # 用户信息弹窗\n│   │   │   └── *.module.less     # 页面级样式\n│   │   ├── components/\n│   │   │   ├── Modal/            # 模态框体系（StackModal/Toast/Confirm/ImagePreview）\n│   │   │   ├── Select/           # 下拉选择器\n│   │   │   ├── SuggestMenu/      # 命令建议菜单\n│   │   │   └── UserAvatar/       # 用户头像下拉组件\n│   │   ├── hooks/\n│   │   │   ├── useSocket.ts      # Socket.IO 连接 + 消息管理\n│   │   │   └── useScrollToBottom.ts\n│   │   ├── utils/\n│   │   │   └── api.ts            # API 封装（带 token）\n│   │   └── index.css             # 全局样式 & CSS 变量\n│   └── vite.config.ts\n│\n├── .buildsystemCatch/            # 运行时缓存（自动创建）\n│   ├── webBackup/                # 构建产物备份\n│   ├── buildLog/                 # 构建日志\n│   ├── database/                 # JSON 数据库\n│   ├── log/                      # HTTP 日志\n│   └── images/                   # 聊天图片\n│\n├── .env.example                  # 环境变量模板\n├── package.json\n└── tsconfig.json\n```\n\n## 架构\n\n```\n┌──────────────────────────────────────────────────────────────┐\n│                    Browser                                    │\n│  ┌──────────┐  ┌──────────┐  ┌───────────────────────────┐  │\n│  │ Login    │  │ Home     │  │ Modal/Select/UserAvatar   │  │\n│  │ (React)  │  │ (React)  │  │ (React Components)        │  │\n│  └────┬─────┘  └────┬─────┘  └─────────────┬─────────────┘  │\n│       │              │                       │                │\n│       └──────┬───────┴───────────────────────┘                │\n│              │ REST API + Socket.IO                           │\n└──────────────┼────────────────────────────────────────────────┘\n               │\n┌──────────────┼────────────────────────────────────────────────┐\n│         BuildServer (Express)                                 │\n│  ┌───────────┴───────────┐                                    │\n│  │  routes.ts (REST API) │  websocket.ts (Socket.IO)          │\n│  │  - 构建任务管理        │  - 实时消息推送                     │\n│  │  - 用户与权限管理      │  - 聊天室 & 快捷命令               │\n│  │  - 邀请码管理          │  - 构建日志订阅                    │\n│  └───────────┬───────────┘──────────┬─────────────────────────┘\n│              │                       │                         │\n│  ┌───────────┴───────────────────────┴────────────────────────┐ │\n│  │              BuildTaskQueue                                │ │\n│  │  ┌─────────┐  ┌──────────┐  ┌───────────────────────────┐ │ │\n│  │  │  git.ts  │  │  pm.ts   │  │   artifact.ts             │ │ │\n│  │  │ checkout │  │ npm ci   │  │  backup / copy / restore  │ │ │\n│  │  │ pull     │  │ yarn     │  │                           │ │ │\n│  │  │ diff     │  │ pnpm     │  └───────────────────────────┘ │ │\n│  │  └─────────┘  └──────────┘                                │ │\n│  └───────────────────────────────────────────────────────────┘ │\n│  ┌─────────────┐  ┌───────────┐  ┌──────────────────────────┐  │\n│  │ notifier.ts │  │  cron.ts  │  │  database/               │  │\n│  │ webhook     │  │ 定时清理  │  │  User / Message / Invite │  │\n│  └─────────────┘  └───────────┘  └──────────────────────────┘  │\n└────────────────────────────────────────────────────────────────┘\n```\n\n## 快速开始\n\n### 前置要求\n\n- Node.js >= 16\n- 项目根目录包含 `package.json`（含 `build` 脚本）\n\n### 使用方式\n\nbuildSystem 支持两种使用场景：作为全局 CLI 工具直接使用，或从源码开发。\n\n#### 全局安装\n\n```bash\nnpm install @daiyu-5577/buildsystem -g\n```\n\n```bash\n# 构建项目，指定分支为 master\nbuildsystem build -b master\n\n# 启动 Web 服务\n# 启动后访问 `http://localhost:3000/buildsystem` 进入后台 Web 界面\n# 账号/密码：root/123456\nbuildsystem server --port 3000\n\n# 启动 Web 服务，并托管网站。静态文件根路径为 /path/to/dist，网站路由前缀为 /page\n# 启动后访问 `http://localhost:3000/page/app` 进入静态托管的 Web 界面\nbuildsystem server --port 3000 --website /path/to/dist --website-prefix /page\n```\n\n#### CLI 命令参考\n\n**`build` 命令** — 纯 CLI 构建，不启动 Web 服务\n\n```bash\nbuildsystem build -b <branch> [-p <paths...>] [-c <commit>] [-n <notify>]\n```\n\n| 参数 | 说明 | 示例 |\n|------|------|------|\n| `-b, --branch` | 目标分支（必填） | `master` |\n| `-p, --packagePaths` | 指定构建目录 | `packages/app1 packages/app2` |\n| `-c, --commit` | commit 区间，增量构建 | `abc123..def456` |\n| `-n, --notify` | 构建通知地址 | `https://hooks.example.com/notify` |\n\n**`server` 命令** — 启动 Web 管理界面 + REST API + Socket.IO\n\n```bash\nbuildsystem server [--port <number>] [--website <path>] [--website-prefix <prefix>]\n```\n\n| 参数 | 说明 | 默认值 |\n|------|------|--------|\n| `--port` | 端口号 | `3000` |\n| `--website` | 托管的网站静态文件路径 | 空 |\n| `--website-prefix` | 网站路由前缀（挂载点） | `/page` |\n\n### Nginx 反向代理配置\n\n当自定义了 `BASE_ROUTE` 环境变量，并通过nginx匹配该路径`location BASE_ROUTE`，需要通过反向代理将所有匹配的路径统一转发到后端服务：\n\n```nginx\nserver {\n    listen 80;\n    server_name example.com;\n\n    # 匹配自定义 BASE_ROUTE 路径下的所有请求，全部转发到后端\n    location /$BASE_ROUTE/ {\n        proxy_pass http://127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    }\n\n    # 匹配 /buildsystem 路径下的所有请求，全部转发到后端\n    # 启动后访问 `http://localhost:3000/buildsystem` 进入后台 Web 界面\n    location /buildsystem/ {\n        proxy_pass http://127.0.0.1:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n```\n\n如果使用 `--website-prefix /page` 托管另一个站点，则需添加对应的 location block：\n\n```nginx\nlocation /page/ {\n    proxy_pass http://127.0.0.1:3000;\n    # ... 同上 header\n}\n```\n\n这样无论前端如何路由，所有请求都会到达 Express，由 `findIndexHtml` 或 `express.static` 正确处理 SPA 的 fallback 逻辑。\n\n\n### 网站托管（`--website` / `--website-prefix`）\n\n通过 `server --website <path> --website-prefix <prefix>` 可在指定 URL 路径下托管任意静态网站：\n\n```bash\nbuildsystem server \\\n  --website /data/sites/app \\\n  --website-prefix /app\n```\n\n| 参数 | 作用 | 示例 |\n|------|------|------|\n| `--website` | 静态文件实际所在的**绝对路径** | `/data/sites/app` |\n| `--website-prefix` | URL 匹配前缀（挂载点） | `/app` |\n\n访问 `http://example.com/app` → 返回 `/data/sites/app/index.html`\n访问 `http://example.com/app/login` → 返回 `/data/sites/app/login/index.html`\n\n#### 多层级目录结构\n\n假设 `website-root` 目录如下：\n\n```\n/data/sites/app/\n├── index.html              # /app → 命中\n├── login/index.html        # /app/login → 命中\n├── vue/index.html     # /app/vue → 命中\n│   └── assets/\n└── react/index.html   # /app/react → 命中\n    └── assets/\n```\n\n只需启动一次服务，所有子路径自动生效。无需为每个站点单独配置 `--website-path`。\n\n| 客户端访问 | 查找逻辑 | 结果 |\n|-----------|---------|------|\n| `/app` | `/data/sites/app/index.html` | ✅ |\n| `/app/login` | `/data/sites/app/login/index.html` | ✅ |\n| `/app/vue/assets/logo.png` | `express.static` 直接提供静态资源 | ✅ |\n| `/app/vue/non-existent` | 逐级 fallback 查找 `index.html` | 找到最近的父级或根 |\n\n#### `findIndexHtml` 逐级查找算法\n\n当请求无文件扩展名（SPA History 模式）时，服务端从长到短逐级尝试匹配：\n\n```\n请求路径: /app/vue/deep/page\n匹配路径: /app\nwebsiteRoot: /data/sites/app\n\n1. /data/sites/app + /vue/deep/page + /index.html  → 不存在\n2.            /vue/deep + /index.html               → 不存在\n3.                  /vue + /index.html              → ✅ 命中\n```\n\n- `--website-prefix` 仅作为 Express 的 `use` 前缀过滤，不参与最终文件路径拼接\n- 拼接公式：`websiteRoot + 请求路径的前缀 + /index.html`\n- 逐级向上 fallback 直到根目录的 `index.html`\n\n### 注意事项\n\n| 要点 | 说明 |\n|------|------|\n| 位置顺序 | `location` 按**前缀匹配优先级**从高到低排列，较长前缀应放在较之前，否则短前缀会先匹配拦截请求 |\n| `/buildsystem/` | 这是前端 Vite 构建产物所在的路径，对应代码中 `base: '/buildsystem'` |\n| `/app/vue/`、`/app/react/` | 通过 `server --website-prefix /app` 启动后，所有 `/app/**` 请求都会被 Express 代理处理 |\n| WebSocket 头 | Socket.IO 依赖 `Upgrade` + `Connection` 头部做协议升级，务必添加这两行 |\n\n## Vite 配置详解\n\n前端使用 Vite 6 开发，配置文件位于 `web/vite.config.ts`：\n\n```ts\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-react'\n\nexport default defineConfig({\n  base: '/buildsystem',       // ① 前端资源路径前缀，与 Nginx 的 location 和 Express 的静态文件路径对应\n  plugins: [react()],          // ② React JSX 转换插件\n  server: {\n    port: 5173,                // ③ 开发服务器端口\n    proxy: {                   // ④ 开发环境代理：将 /api、/ws 请求转发到后端 :3000\n      '/api': {                //    - /api → Express REST API（用户认证、任务管理等）\n        target: 'http://localhost:3000',\n        changeOrigin: true,    //    - 修改 Host 头为目标地址，避免 CORS 问题\n      },\n      '/ws': {                 //    - /ws → Socket.IO 实时通信端点\n        target: 'http://localhost:3000',\n        ws: true,              //    - 启用 WebSocket 代理\n      },\n    },\n  },\n  build: {\n    outDir: '../dist/web',     // ⑤ 生产构建输出目录（相对于 web/ 即项目根目录的 dist/web）\n    emptyOutDir: true,         // ⑥ 构建前先清空输出目录，避免残留旧文件\n  },\n})\n```\n\n| 字段 | 作用 | 注意事项 |\n|------|------|----------|\n| `base` | 定义前端资源（JS/CSS/HTML）访问路径的前缀 | 设为 `/buildsystem` 表示所有请求 URL 以 `/buildsystem/` 开头；若改为 `/` 则表示直接部署在域名根路径下 |\n| `server.proxy` | 仅开发环境生效，解决前后端同源策略 | 生产环境需通过 Nginx 反向代理或后端统一端口解决 |\n| `build.outDir` | 指定编译产出放置位置 | 默认会覆盖整个目录，配合 `emptyOutDir` 保证干净构建 |\n| `build.emptyOutDir` | 确保每次构建都是全新产物 | 如果希望保留某些文件可设为 `false`，但通常建议开启 |\n\n\n## 环境变量\n\n| 变量 | 说明 | 默认值 |\n|------|------|--------|\n| `NODE_ENV` | 运行环境 | `development` |\n| `BASE_ROUTE` | REST API 路由前缀（即 express 中 `/api/...` 的前缀） | 空 |\n| `CATCH_ROOT` | 缓存根目录 | `.buildsystemCatch` |\n| `DIST_ROOT` | 构建产物目录 | `dist` |\n| `MAX_CONCURRENCY` | 最大并发构建数 | `1` |\n| `CRYPTO_SALT` | AES 加密 salt | 生产环境必须设置 |\n| `CRYPTO_SECRET` | AES 加密 secret | 生产环境必须设置 |\n| `WEBHOOK_URL` | Webhook 通知地址 | 空 |\n\n## 用户权限体系\n\n系统采用三级角色体系：\n\n| 角色 | 权限 |\n|------|------|\n| **Super** | 全部权限：可以分配 Super/Admin/User 角色、生成邀请码 |\n| **Admin** | 管理权限：可以分配 Admin/User 角色、查看所有构建 |\n| **User** | 普通用户：仅可查看构建状态、发送聊天消息 |\n\n### 邀请注册流程\n\n1. 管理员（Super/Admin）生成邀请码\n2. 将邀请码分享给新用户\n3. 用户在登录页切换至\"注册\"Tab，输入用户名、密码和邀请码完成注册\n\n### 权限管理\n\n- 点击右上角头像打开下拉菜单，选择\"权限管理\"（需 Admin 或以上角色）\n- 搜索用户后通过下拉框修改其角色\n- Admin 不能降级或提升 Super 角色的用户\n\n## API\n\n启动 Server 后，主要接口位于 `/api/` 路径下（若设置了 `BASE_ROUTE`，则为 `<BASE_ROUTE>/api/...`）：\n\n| 方法 | 路径 | 说明 |\n|------|------|------|\n| POST | `/api/login` | 用户登录 |\n| POST | `/api/register` | 用户注册（需邀请码） |\n| POST | `/api/addTask` | 添加构建任务 |\n| POST | `/api/cancelTask` | 取消构建任务 |\n| GET | `/api/getAllTask` | 获取任务列表 |\n| GET | `/api/getAllPackage` | 获取可构建项目列表 |\n| GET | `/api/refreshPackages` | 刷新可构建项目列表（Admin/Super） |\n| GET | `/api/getAllLog` | 获取日志列表 |\n| GET | `/api/getAllBackup` | 获取备份列表 |\n| POST | `/api/restore` | 版本回退 |\n| GET | `/api/getNoticeList` | 获取通知配置 |\n| POST | `/api/notify` | Webhook 回调（构建通知） |\n| GET | `/api/getUserInfo` | 获取当前/指定用户信息 |\n| GET | `/api/getAllUsers` | 获取所有用户列表（Admin/Super） |\n| POST | `/api/updateUserRole` | 更新用户角色（Admin/Super） |\n| GET | `/api/inviteCodes` | 获取当前用户的邀请码列表（Super） |\n| POST | `/api/generateInviteCode` | 生成新邀请码（Super） |\n\n## 构建流程\n\n```\n添加任务 → 入队列 → 并发调度 → 执行：\n  1. git checkout <branch> + git pull\n  2. 检测包管理器 → npm ci / yarn install / pnpm install\n  3. npm run build\n  4. 备份旧产物 → 复制新产物到 dist/\n  5. git clean（还原工作区）\n  → 成功/失败 → Webhook 通知 + Socket.IO 推送\n```\n\n## 技术栈\n\n**后端**：Node.js · TypeScript · ESM · Express 5 · Socket.IO · Commander · Winston · dayjs · fs-extra\n\n**前端**：React 19 · Vite 6 · TypeScript · React Router 6 · Socket.IO Client · Less (CSS Modules)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}