Forráskód Böngészése

feat(dist): wheel 发行包 + 修 editable 安装 bug + 源码保护说明

发行不再把整个源码树 editable 送人:
- setup.sh 新增 --build(构建 lambdagent/agentpaas wheel→dist/)
  和 --package(组装 release/,仅含 wheel+启动脚本+前端产物+文档,无任何 src/.git/内部文档)
- install_deps 自动判定:dist/*.whl 存在→发行模式从 wheel 装;
  否则源码目录→开发模式 editable 装
- 修历史 bug:原 `pip install -e ".[all]"`(root 无 pyproject 实际失败),
  lambdagent 真实路径是 ./lambdagent
- 构建走 PEP 517 隔离,不再依赖 .venv

验证:wheel 内含 98+83 模块;clean venv 从 release/ 装上,
agentpaas/lambdagent/FastAPI app 均从 site-packages 导入,release 无源码树。

文档:DESKTOP_MANUAL_zh §3 加发行包模式说明 + 「源码保护」边界
(wheel≠混淆,防逆向强度阶梯 .py<wheel<Nuitka<核心上云;当前定位靠 BSL 协议威慑);
QUICK_START 补 --build/--package;.gitignore 忽略 release/。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kenny67nju 2 hónapja
szülő
commit
0e0d46abba
4 módosított fájl, 168 hozzáadás és 12 törlés
  1. 3 0
      .gitignore
  2. 6 0
      QUICK_START.md
  3. 29 0
      docs/DESKTOP_MANUAL_zh.md
  4. 130 12
      setup.sh

+ 3 - 0
.gitignore

@@ -261,3 +261,6 @@ review_comments*.md
 review_comments*.pdf
 review_result*.json
 *商业计划书*
+
+# 发行包组装产物(setup.sh --package 生成,含 wheel,勿入库)
+/release/

+ 6 - 0
QUICK_START.md

@@ -138,6 +138,12 @@ chmod +x setup.sh
 # 使用 Docker 启动
 ./setup.sh --docker
 
+# 构建 wheel 发行包(开发者:打包发布用,产出 dist/*.whl)
+./setup.sh --build
+
+# 组装「不含源码」的发行包 release/(再 zip 后发给用户)
+./setup.sh --package
+
 # 查看帮助
 ./setup.sh --help
 ```

+ 29 - 0
docs/DESKTOP_MANUAL_zh.md

@@ -77,6 +77,11 @@ chmod +x setup.sh
 ./setup.sh --help       # 查看帮助
 ```
 
+> **两种安装模式自动识别**:`setup.sh` 会先看同目录下有没有 `dist/*.whl`。
+> 拿到**发行包**(解压后含 `dist/` 里两个 `.whl`、无源码)→ 从预编译 wheel 安装;
+> 在**源码树**里(有 `lambdagent/`、`agentpaas/` 目录)→ editable 安装源码。
+> 终端用户走前者,开发者走后者,命令都是 `./setup.sh`,无需关心区别。
+
 ### 方式二:手动安装(pip)
 
 ```bash
@@ -105,6 +110,30 @@ curl http://127.0.0.1:8000/health
 # 期望输出: {"status":"ok","version":"1.3.0"}
 ```
 
+### 打包发布给他人(开发者)
+
+要把产品发给别人,**不要**直接拷贝整个源码目录或让对方 `git clone`——那等于把全部源码、
+测试、内部文档一并送出。正确做法是构建 wheel 发行包:
+
+```bash
+./setup.sh --build      # ① 构建 wheel:lambdagent / agentpaas → dist/*.whl
+./setup.sh --package    # ② 组装发行包:release/(只含 wheel + 启动脚本 + 前端产物 + 文档)
+zip -r lambdagent-paas-1.3.0.zip release/   # ③ 压缩后分发
+```
+
+对方拿到压缩包后:解压 → `cd release` → `./setup.sh`,脚本检测到 `dist/*.whl` 即按发行模式安装。
+`release/` 里**不含** `lambdagent/src`、`agentpaas/src` 源码树,也不含 `.git`、测试、内部文档。
+
+> **关于源码保护(重要,请如实理解)**
+> Python 是解释型语言,代码要在用户机器上运行,因此**任何纯本地分发都无法做到真正不可逆**——
+> 这是语言层面的客观限制,不是本产品的缺陷。上面的 wheel 发行包解决的是最严重的问题:
+> 不再把整个 git 仓库 editable 送人。但要清楚它的边界:
+> - **wheel 仍是 `.py` 源文件的打包**——用 `unzip` 解开 `.whl` 仍能读到源码,它**不混淆、不加密**;
+> - 它的价值在于:① 不泄露仓库历史/测试/内部文档;② 安装件落在 `site-packages`,普通用户不会去翻;③ 配合授权协议形成「合规约束」。
+> 防护强度由弱到强可选:`.py` 源码(最弱)< wheel(当前默认)< PyInstaller/Nuitka 编译为原生二进制 < 核心逻辑放服务端(唯一在数学上成立)。
+> **本产品当前定位为面向高校老师的单机产品 + BSL 1.1 协议**,真正的威慑来自授权条款而非技术混淆;
+> 如未来出现付费客户与盗版风险,再引入 Nuitka 编译或核心上云。详见 `RELEASE_NOTES.md` 与 BSL 协议。
+
 ---
 
 ## 4. 首次启动与设置向导

+ 130 - 12
setup.sh

@@ -3,9 +3,15 @@
 # LambdAgent PaaS 一键安装启动脚本
 # 用法:
 #   chmod +x setup.sh
-#   ./setup.sh              # 安装并启动(开发模式)
+#   ./setup.sh              # 安装并启动(自动识别 发行包/源码 两种模式)
+#   ./setup.sh --build      # 构建发行 wheel 包到 dist/
+#   ./setup.sh --package    # 打出「不含源码」的发行包 release/
 #   ./setup.sh --docker     # 使用 Docker 启动
 #   ./setup.sh --help       # 查看帮助
+#
+# 安装模式(install_deps 自动判定):
+#   发行模式  dist/*.whl 存在 → 从预编译 wheel 安装(终端用户拿到的包用这种)
+#   开发模式  无 wheel 但有源码目录 → editable 安装(开发者本机)
 # ============================================================
 
 set -e
@@ -32,12 +38,19 @@ show_help() {
     echo "LambdAgent PaaS 一键安装启动脚本"
     echo ""
     echo "用法:"
-    echo "  ./setup.sh              安装依赖并启动服务(开发模式)"
+    echo "  ./setup.sh              安装依赖并启动服务(自动识别发行/源码模式)"
+    echo "  ./setup.sh --build      构建发行 wheel 包 → dist/*.whl"
+    echo "  ./setup.sh --package    打出不含源码的发行包 → release/"
     echo "  ./setup.sh --docker     使用 Docker Compose 启动"
     echo "  ./setup.sh --install    仅安装依赖,不启动服务"
     echo "  ./setup.sh --launch     安装并一键启动 Agent 对话"
     echo "  ./setup.sh --help       显示此帮助信息"
     echo ""
+    echo "发布给终端用户的流程(开发者执行):"
+    echo "  ./setup.sh --build      # 在源码树里先构建 wheel"
+    echo "  ./setup.sh --package    # 组装 release/,里面只有 wheel + 启动脚本,无源码"
+    echo "  然后把 release/ 压缩发给用户;用户解压后跑 ./setup.sh 即可"
+    echo ""
     echo "环境要求:"
     echo "  Python 方式: Python 3.10+"
     echo "  Docker 方式: Docker + Docker Compose"
@@ -120,7 +133,93 @@ setup_env() {
     fi
 }
 
+# ── 构建发行 wheel 包 ─────────────────────────────────────
+# 把 lambdagent / agentpaas 两个子包构建成 .whl 放进 dist/。
+# wheel 是「打包后的安装件」——发给用户的不再是整个源码树(含 .git、
+# 测试、商业计划书等),而是这两个 whl。注意:普通 wheel 内部仍是 .py
+# 源文件,它解决的是「别再把整个仓库 editable 送人」,不是代码混淆;
+# 真要防逆向需要 Nuitka 编译,见 docs/DESKTOP_MANUAL_zh.md「源码保护」一节。
+build_wheels() {
+    check_python
+
+    if [ ! -d lambdagent ] || [ ! -d agentpaas ]; then
+        fail "未找到源码目录(lambdagent/ agentpaas/)。--build 只能在源码树里执行。"
+    fi
+
+    # 构建 wheel 走 PEP 517 构建隔离,不依赖 .venv —— 直接用 $PYTHON 即可。
+    info "构建 wheel 包 → dist/ ..."
+    mkdir -p dist
+    rm -f dist/lambdagent-*.whl dist/agentpaas-*.whl
+
+    $PYTHON -m pip wheel --no-deps ./lambdagent -w dist/ --quiet
+    $PYTHON -m pip wheel --no-deps ./agentpaas  -w dist/ --quiet
+
+    echo ""
+    ok "wheel 构建完成:"
+    ls -1 dist/lambdagent-*.whl dist/agentpaas-*.whl 2>/dev/null | sed 's/^/    /'
+    echo ""
+    echo "  下一步: ./setup.sh --package  组装不含源码的发行包"
+    echo ""
+}
+
+# ── 组装「不含源码」的发行包 ──────────────────────────────
+# 产出 release/:只含 wheel + 启动脚本 + 前端静态产物 + 配置样例 + 文档,
+# 不含 lambdagent/src、agentpaas/src、tests、.git、商业计划书等。
+# 把 release/ 压缩后发给终端用户即可。
+package_release() {
+    if ! ls dist/lambdagent-*.whl >/dev/null 2>&1 || ! ls dist/agentpaas-*.whl >/dev/null 2>&1; then
+        warn "未找到 dist/*.whl,先执行构建..."
+        build_wheels
+    fi
+
+    # 从 agentpaas/pyproject.toml 取版本号(兼容无源码时回退到 wheel 文件名)
+    local VER
+    if [ -f agentpaas/pyproject.toml ]; then
+        VER=$(grep -m1 '^version' agentpaas/pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
+    else
+        VER=$(ls dist/agentpaas-*.whl 2>/dev/null | sed -E 's/.*agentpaas-([0-9][^-]*)-.*/\1/' | head -1)
+    fi
+    [ -z "$VER" ] && VER="dev"
+
+    info "组装发行包 → release/ ..."
+    rm -rf release
+    mkdir -p release/dist
+
+    cp dist/lambdagent-*.whl dist/agentpaas-*.whl release/dist/
+    cp setup.sh release/
+    chmod +x release/setup.sh
+
+    # 前端静态产物(已编译,无源码)
+    [ -d webui-dist ] && cp -R webui-dist release/
+
+    # 用户需要的配置样例 / 编排文件 / 文档(均非核心源码)
+    [ -f .env.example ]        && cp .env.example release/
+    [ -f docker-compose.yml ]  && cp docker-compose.yml release/
+    [ -f Dockerfile ]          && cp Dockerfile release/ 2>/dev/null || true
+    [ -d agentexample ]        && cp -R agentexample release/
+    mkdir -p release/docs
+    [ -f docs/DESKTOP_MANUAL_zh.md ] && cp docs/DESKTOP_MANUAL_zh.md release/docs/
+    [ -f QUICK_START.md ]      && cp QUICK_START.md release/
+    [ -f README.md ]           && cp README.md release/
+    [ -f LICENSE ]             && cp LICENSE release/
+
+    # 清掉 macOS 垃圾文件
+    find release -name '.DS_Store' -delete 2>/dev/null || true
+
+    echo ""
+    ok "发行包已生成: release/"
+    echo "  内容(不含任何 src 源码 / .git / 内部文档):"
+    (cd release && find . -maxdepth 2 -type f | sed 's/^/    /' | head -30)
+    echo ""
+    echo "  压缩发布:  zip -r lambdagent-paas-${VER}.zip release/"
+    echo "  用户使用:  解压 → cd release → ./setup.sh"
+    echo ""
+}
+
 # ── 创建虚拟环境并安装依赖 ────────────────────────────────
+# 自动判定两种模式:
+#   发行模式: 同目录 dist/*.whl 存在 → 从预编译 wheel 安装(终端用户)
+#   开发模式: 无 wheel 但有源码目录 → editable 安装(开发者本机)
 install_deps() {
     info "创建 Python 虚拟环境..."
 
@@ -133,16 +232,29 @@ install_deps() {
 
     # 激活虚拟环境
     source .venv/bin/activate
-
-    info "安装依赖..."
-
-    # 安装 lambdagent(核心库)
-    pip install -e ".[all]" --quiet 2>&1 | tail -1
-    ok "lambdagent 已安装"
-
-    # 安装 agentpaas(服务层)
-    pip install -e "./agentpaas[dev]" --quiet 2>&1 | tail -1
-    ok "agentpaas 已安装"
+    pip install --quiet --upgrade pip >/dev/null 2>&1
+
+    if ls dist/lambdagent-*.whl >/dev/null 2>&1 && ls dist/agentpaas-*.whl >/dev/null 2>&1; then
+        # ── 发行模式: 从 wheel 安装 ──
+        info "检测到预编译 wheel,按【发行模式】安装..."
+        # 先装 lambdagent(agentpaas 依赖它),再装 agentpaas;
+        # 第三方依赖(fastapi 等)由 pip 从 PyPI 拉取。
+        pip install --quiet --upgrade dist/lambdagent-*.whl
+        ok "lambdagent 已从 wheel 安装"
+        pip install --quiet --upgrade dist/agentpaas-*.whl
+        ok "agentpaas 已从 wheel 安装"
+    elif [ -d lambdagent ] && [ -d agentpaas ]; then
+        # ── 开发模式: editable 源码安装 ──
+        info "未检测到 wheel,按【开发模式】editable 安装源码..."
+        # 修复历史 bug: 原为 `pip install -e ".[all]"`(root 无 pyproject,
+        # 实际安装失败),lambdagent 真实路径是 ./lambdagent。
+        pip install -e "./lambdagent[all]" --quiet 2>&1 | tail -1
+        ok "lambdagent 已安装(editable)"
+        pip install -e "./agentpaas[dev]" --quiet 2>&1 | tail -1
+        ok "agentpaas 已安装(editable)"
+    else
+        fail "既无 dist/*.whl 也无源码目录(lambdagent/ agentpaas/),无法安装。"
+    fi
 
     echo ""
     ok "所有依赖安装完成!"
@@ -226,6 +338,12 @@ main() {
             show_help
             exit 0
             ;;
+        --build)
+            build_wheels
+            ;;
+        --package)
+            package_release
+            ;;
         --docker)
             start_docker
             ;;