From ea89d568d07252f96f446506a489f99051866d20 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sat, 6 Jun 2026 11:26:44 +0800 Subject: [PATCH] auto-sync: 2026-06-06 11:26:44 --- docs/research/gitea-actions-research.md | 592 ++++++++++++++++++++++++ src/api/blackboard_routes.py | 4 +- src/blackboard/registry.py | 6 +- src/daemon/spawner.py | 9 +- 4 files changed, 607 insertions(+), 4 deletions(-) create mode 100644 docs/research/gitea-actions-research.md diff --git a/docs/research/gitea-actions-research.md b/docs/research/gitea-actions-research.md new file mode 100644 index 0000000..75f9a56 --- /dev/null +++ b/docs/research/gitea-actions-research.md @@ -0,0 +1,592 @@ +# Gitea Actions 能力调研报告 + +> 调研时间:2026-06-06 +> Gitea 版本:v1.23.4(实例 http://192.168.2.154:3000 已确认) +> 调研来源:Gitea 官方文档 v1.23、API 规范、v1.23.0 Release Notes、act-runner 文档 + +--- + +## 调研结论(先给结论) + +**总体评估:✅ 可行,但有若干注意事项** + +| 能力类别 | 状态 | 说明 | +|---------|------|------| +| Actions 基础能力 | ✅ 支持 | v1.23.4 内置 Actions(自 1.21 默认启用),兼容 GitHub Actions YAML | +| Workflow 触发器 | ✅ 支持 | `push`/`pull_request`/`workflow_dispatch`/`schedule` 均支持 | +| Job 依赖和条件 | ⚠️ 部分支持 | `needs` 支持,`if` 支持,但 `failure()` 表达式不受支持(仅 `always()` 支持) | +| Secrets/环境变量 | ✅ 支持 | 多级 Secrets 和 Variables,`${{ secrets.XXX }}` 语法 | +| Status Check | ✅ 支持 | Actions 结果自动作为 commit status,可用于 Branch Protection | +| Branch Protection | ✅ 支持 | 支持 required approvals、status check、merge whitelist 等 | +| CI 内调 Gitea API | ⚠️ 需配置 | v1.23 无内置 `GITEA_TOKEN`(v1.24+ 才有),需用 PAT 或配置 secrets | +| Webhook | ✅ 支持 | 仓库/组织/系统级别,支持 HMAC SHA256 签名验证 | + +### 确认支持的能力 +1. **YAML 语法兼容**:`.gitea/workflows/` 和 `.github/workflows/` 均可 +2. **触发器**:`push`(含分支过滤)、`pull_request`(含 types 过滤)、`workflow_dispatch`(v1.23 新增)、`schedule` +3. **Job 间依赖**:`needs` 关键字支持 +4. **条件执行**:`if` 支持(但表达式有限制) +5. **Secrets & Variables**:仓库/组织/用户多级管理,优先级:仓库 > 组织 > 用户 +6. **Status Check + Branch Protection**:Actions 完成后自动产生 commit status,可配置为 merge 前置条件 +7. **Review 要求**:Branch Protection 支持 `required_approvals` +8. **Webhook**:仓库/组织/系统级别,多事件类型选择,HMAC SHA256 签名 +9. **绝对 URL action**:支持从任意 Git 仓库引用 action +10. **Go Actions**:支持用 Go 编写 action + +### 不支持或有限制的能力 +1. **表达式函数**:仅 `always()` 支持,`failure()`、`success()`、`cancelled()` 不支持 +2. **`permissions` 关键字**:在 v1.23 中被忽略(v1.24+ 才实现 GITEA_TOKEN 权限控制) +3. **`concurrency`**:不支持(用于限制同时运行同一 workflow) +4. **`continue-on-error`**:不支持 +5. **`timeout-minutes`**:不支持 +6. **`environment`**:不支持 +7. **复杂 `runs-on`**:仅支持单个 label,不支持表达式 +8. **`run-name`**:不支持 +9. **Problem Matchers**:不支持 +10. **GITEA_TOKEN**:v1.23 中无内置 job token(需 v1.24+),需要手动配置 PAT 作为 secret + +### 需要额外配置的事项 +1. **act-runner 安装和注册**:需要单独部署 +2. **仓库启用 Actions**:默认关闭,需手动开启 +3. **Branch Protection**:需在仓库 Settings 中手动配置或通过 API +4. **PAT Token**:v1.23 需要 PAT 才能在 workflow 中调 Gitea API +5. **考虑升级到 v1.24+**:可获得 GITEA_TOKEN 内置支持、permissions 关键字等 + +--- + +## 逐项验证结果 + +### 1. Actions 基础能力 + +#### 1.1 Gitea v1.23.4 是否内置 Actions? +- **✅ 是**。自 Gitea 1.19 引入 Actions,1.21 起默认启用(`[actions] ENABLED=true`) +- 我们的实例确认版本为 v1.23.4 +- **证据**:`curl http://192.168.2.154:3000/api/v1/version` → `{"version":"1.23.4"}` +- **证据**:官方文档 "Starting with Gitea 1.19, Gitea Actions are available as a built-in CI/CD solution" + +#### 1.2 是否兼容 GitHub Actions YAML 语法? +- **✅ 是**。workflow 文件放在 `.gitea/workflows/` 或 `.github/workflows/` 目录 +- 设计上以 GitHub Actions 兼容为目标 +- 可直接使用 `actions/checkout@v4` 等 GitHub Actions(默认从 GitHub 下载) +- 配置 `[actions].DEFAULT_ACTIONS_URL` 可设为 `github`(默认)或 `self` +- **注意**:v1.21.0 前默认从 `gitea.com` 下载,v1.21.0+ 默认从 `github.com` 下载 + +#### 1.3 act-runner 如何安装和注册? +- **详见下方 "act-runner 部署指南"** +- 支持二进制安装和 Docker 安装 +- 注册需要 registration token(从 Web UI 或 CLI 获取) +- 支持 macOS LaunchDaemon 作为守护进程 + +### 2. Workflow 触发器 + +#### 2.1 `on: push` 和 `on: pull_request` 是否支持? +- **✅ 支持** +- 示例: + ```yaml + on: [push, pull_request] + ``` +- 完整触发器列表:`push`、`pull_request`、`workflow_dispatch`、`schedule`、`release`、`issues` 等 + +#### 2.2 `on: push` 能否限制分支? +- **✅ 支持** +- 语法与 GitHub Actions 一致: + ```yaml + on: + push: + branches: [main] + ``` +- 支持 `branches`、`branches-ignore`、`tags`、`tags-ignore`、`paths`、`paths-ignore` + +#### 2.3 `on: pull_request` 是否支持 types? +- **✅ 支持** +- 语法: + ```yaml + on: + pull_request: + types: [opened, synchronize] + ``` + +#### 2.4 其他触发器 +- **`workflow_dispatch`**:v1.23.0 新增!支持手动触发,支持输入参数(含 choice、boolean、number、environment 类型) +- **`schedule`**:支持标准 cron 语法 + 非标准语法 `@yearly`/`@monthly`/`@weekly`/`@daily`/`@hourly` + - ⚠️ 注意:v1.23 起 schedule 默认使用 UTC 时区 + +### 3. Job 依赖和条件 + +#### 3.1 `needs` 关键字是否支持? +- **✅ 支持** +- 与 GitHub Actions 语法一致: + ```yaml + jobs: + test: + runs-on: ubuntu-latest + steps: [...] + deploy: + needs: test + runs-on: ubuntu-latest + steps: [...] + ``` + +#### 3.2 `if: failure()` 条件是否支持? +- **⚠️ 有限制** +- `if` 关键字本身支持 +- 但**表达式函数仅 `always()` 支持**,`failure()`、`success()`、`cancelled()` 不支持 +- **影响**:无法直接实现 "前序 job 失败时执行" 的逻辑 +- **变通方案**:使用 job output 传递状态,或拆分为多个 workflow + +#### 3.3 环境变量和 Secrets 是否支持? +- **✅ 支持** +- **Secrets**:`${{ secrets.MY_SECRET }}`,支持仓库/组织/用户三级 +- **Variables**:`${{ vars.MY_VAR }}`,同样支持三级 +- **内置环境变量**:`GITHUB_*` 和 `GITEA_*` 前缀的变量均有 + - `gitea.actor`、`gitea.event_name`、`gitea.ref`、`gitea.repository` 等 +- **Secret 命名规则**: + - 仅含 `[a-z]`, `[A-Z]`, `[0-9]`, `_` + - 不能以 `GITHUB_` 或 `GITEA_` 开头 + - 不能以数字开头 + - 不区分大小写 + +### 4. Status Check 和 Branch Protection + +#### 4.1 Actions 跑完后是否自动显示 Status Check? +- **✅ 是** +- Actions 运行完成后,结果会作为 commit status 自动显示在 PR 页面 +- API 端点:`GET /repos/{owner}/{repo}/commits/{ref}/status` +- API 端点:`GET /repos/{owner}/{repo}/commits/{ref}/statuses` +- 可通过 `gitea-actions` badge 在其他地方展示状态 + +#### 4.2 Branch Protection 能否设置"必须 CI 通过才能 merge"? +- **✅ 支持** +- Branch Protection API 中有 `enable_status_check` 和 `status_check_contexts` 字段 +- 通过 Web UI:仓库 Settings → Branches → Add Branch Protection Rule +- 通过 API: + ``` + POST /api/v1/repos/{owner}/{repo}/branch_protections + { + "branch_name": "main", + "enable_status_check": true, + "status_check_contexts": ["ci/test"] + } + ``` + +#### 4.3 能否设置"必须至少 1 人 Review 才能 merge"? +- **✅ 支持** +- Branch Protection 中的 `required_approvals` 字段 +- 通过 API: + ``` + POST /api/v1/repos/{owner}/{repo}/branch_protections + { + "branch_name": "main", + "required_approvals": 1 + } + ``` +- v1.23 新增:Protected branch 支持 priority 设置 + +### 5. CI 内调 Gitea API + +#### 5.1 workflow 里能否用 curl 调 Gitea API? +- **✅ 可以**,但需要认证 token +- Gitea API 完全兼容 RESTful,curl 直接调用即可 + +#### 5.2 Token 怎么获取? +- **⚠️ v1.23 的限制**:v1.23 **没有**内置 `GITEA_TOKEN`(这是 v1.24+ 才引入的功能) +- **v1.24+ 方案**:`${{ secrets.GITEA_TOKEN }}` 自动注入,带有可配置的权限范围 +- **v1.23 变通方案**: + 1. 创建 Personal Access Token(PAT),存为仓库 Secret + 2. 在 workflow 中使用 `${{ secrets.GITEA_TOKEN }}`(手动配置的同名 secret) + 3. 或使用 `${{ secrets.MY_PAT }}` 自定义名称 +- **调用示例**: + ```yaml + - name: Comment on PR + run: | + curl -X POST \ + "http://192.168.2.154:3000/api/v1/repos/${{ gitea.repository }}/issues/${{ github.event.pull_request.number }}/comments" \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{"body": "CI passed ✅"}' + ``` + +> **建议**:考虑升级 Gitea 到 v1.24+ 以获得内置 GITEA_TOKEN 支持,这是最显著的改进之一。 + +### 6. Webhook 配置 + +#### 6.1 在哪里配置 Webhook? +- **三级配置**: + 1. **仓库级别**:`/{owner}/{repo}/settings/hooks` + 2. **组织级别**:组织 Settings → Webhooks + 3. **系统级别**:管理员配置 +- **API 端点**: + - `GET /api/v1/repos/{owner}/{repo}/hooks` — 列出 hooks + - `POST /api/v1/repos/{owner}/{repo}/hooks` — 创建 hook + +#### 6.2 能否选择特定事件类型? +- **✅ 支持** +- 可选事件类型包括: + - Push events + - Pull request events + - Tag create/delete events + - Branch create/delete events + - Issue events + - Release events + - 等等 + +#### 6.3 Secret 签名验证是否支持? +- **✅ 支持** +- 使用 HMAC SHA256 签名 +- 请求头 `X-Gitea-Signature` 包含签名 +- 验证方式: + ```php + $payload_signature = hash_hmac('sha256', $payload, $secret_key, false); + if ($header_signature !== $payload_signature) { /* reject */ } + ``` +- ⚠️ 注意:payload 中的 `secret` 字段已在 v1.13.0 废弃,应使用 header 签名验证 +- v1.19+ 还支持配置 Authorization header + +#### 6.4 Webhook 支持的类型 +- Gitea(native)、Gogs、Slack、Discord、Dingtalk、Telegram、Microsoft Teams、Feishu(飞书)、Wechatwork、Packagist + +--- + +## act-runner 部署指南 + +### 方式一:二进制安装(推荐用于 Mac mini) + +```bash +# 1. 下载 act_runner(arm64 版本) +curl -L -o act_runner https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-darwin-arm64 +chmod +x act_runner +./act_runner --version + +# 2. 生成配置文件(可选) +./act_runner generate-config > config.yaml + +# 3. 获取 registration token +# 方式 A:从 Web UI +# - 实例级:http://192.168.2.154:3000/-/admin/actions/runners +# - 组织级:http://192.168.2.154:3000//settings/actions/runners +# - 仓库级:http://192.168.2.154:3000///settings/actions/runners +# 方式 B:从 Gitea CLI(需要服务器访问权限) +# gitea --config /etc/gitea/app.ini actions generate-runner-token + +# 4. 注册 runner +./act_runner register \ + --no-interactive \ + --instance http://192.168.2.154:3000 \ + --token \ + --name mac-mini-runner \ + --labels ubuntu-latest:host,macos:host + +# 5. 启动 runner +./act_runner daemon + +# 6. 设置为 macOS LaunchDaemon(开机自启) +``` + +### LaunchDaemon 配置 + +创建 `/Library/LaunchDaemons/com.gitea.act_runner.plist`: + +```xml + + + + + Label + com.gitea.act_runner + ProgramArguments + + /usr/local/bin/act_runner + daemon + --config + /etc/act_runner/config.yaml + + RunAtLoad + + KeepAlive + + WorkingDirectory + /var/lib/act_runner + StandardOutPath + /var/lib/act_runner/act_runner.log + StandardErrorPath + /var/lib/act_runner/act_runner.err + EnvironmentVariables + + PATH + /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + HOME + /var/lib/act_runner + + + +``` + +```bash +sudo launchctl load /Library/LaunchDaemons/com.gitea.act_runner.plist +``` + +### 方式二:Docker 安装 + +```bash +docker run \ + -e GITEA_INSTANCE_URL=http://192.168.2.154:3000 \ + -e GITEA_RUNNER_REGISTRATION_TOKEN= \ + -e GITEA_RUNNER_NAME=docker-runner \ + --name gitea-runner \ + -d docker.io/gitea/act_runner:latest +``` + +### Runner Labels 说明 + +Labels 决定 job 如何运行: +- `ubuntu-latest:docker://node:16-bullseye` — 在 Docker 容器中运行 +- `ubuntu-latest:host` 或 `ubuntu-latest` — 直接在宿主机运行 +- `macos:host` — 自定义 label,在宿主机运行 + +**建议**:Mac mini 上使用 `host` 模式(不需要 Docker),labels 设置为: +``` +ubuntu-latest:host,macos-arm64:host +``` + +### 启用仓库 Actions + +⚠️ 重要:即使实例启用了 Actions,**每个仓库也需要手动启用**: +- 仓库 Settings → 勾选 "Enable Repository Actions" +- 或通过 API:`PATCH /api/v1/repos/{owner}/{repo}` → `{"has_actions": true}` + +--- + +## Branch Protection 配置指南 + +### Web UI 方式 + +1. 进入仓库 → Settings → Branches +2. 点击 "Add Branch Protection Rule" 或编辑默认分支 +3. 配置项: + - **Branch name pattern**:如 `main` + - **Enable push**:控制谁能 push + - **Enable merge whitelist**:控制谁能 merge PR + - **Required approvals**:设置最少 review 人数 + - **Enable status check**:勾选并输入 CI workflow 名称 + - 其他:signed commits、protected file patterns 等 + +### API 方式 + +```bash +# 创建 Branch Protection +curl -X POST \ + "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/branch_protections" \ + -H "Authorization: token " \ + -H "Content-Type: application/json" \ + -d '{ + "branch_name": "main", + "enable_push": false, + "enable_merge_whitelist": true, + "merge_whitelist_usernames": ["chufeng"], + "enable_status_check": true, + "status_check_contexts": ["ci/test", "ci/lint"], + "required_approvals": 1, + "enable_approvals_whitelist": true, + "approvals_whitelist_usernames": ["chufeng"] + }' + +# 列出所有 Branch Protection +curl "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/branch_protections" \ + -H "Authorization: token " + +# 编辑 Branch Protection +curl -X PATCH \ + "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/branch_protections/{id}" \ + -H "Authorization: token " \ + -H "Content-Type: application/json" \ + -d '{"required_approvals": 2}' +``` + +### 推荐配置(适合我们的场景) + +```json +{ + "branch_name": "main", + "enable_push": false, + "enable_merge_whitelist": true, + "enable_status_check": true, + "status_check_contexts": ["CI"], + "required_approvals": 1, + "require_signed_commits": false +} +``` + +--- + +## Webhook 配置指南 + +### Web UI 方式 + +1. 仓库 → Settings → Webhooks → Add Webhook → 选择 "Gitea" +2. 配置: + - **Target URL**:接收 webhook 的服务地址 + - **HTTP Method**:POST + - **POST Content Type**:application/json + - **Secret**:用于 HMAC SHA256 签名验证 + - **Trigger On**:选择事件类型 + - **Active**:勾选 + +### API 方式 + +```bash +# 创建仓库级 Webhook +curl -X POST \ + "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/hooks" \ + -H "Authorization: token " \ + -H "Content-Type: application/json" \ + -d '{ + "type": "gitea", + "config": { + "url": "http://your-service/webhook", + "content_type": "json", + "secret": "your-webhook-secret" + }, + "events": ["push", "pull_request"], + "active": true + }' + +# 列出 hooks +curl "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/hooks" \ + -H "Authorization: token " + +# 测试 hook +curl -X POST \ + "http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/hooks/{id}/tests" \ + -H "Authorization: token " +``` + +### Webhook 事件类型列表 + +| 事件 | 说明 | +|------|------| +| `push` | Git push(含 branch 和 tag) | +| `pull_request` | PR 创建/更新/关闭/merge | +| `pull_request_assign` | PR 分配 reviewer | +| `pull_request_label` | PR 标签变更 | +| `pull_request_milestone` | PR 里程碑变更 | +| `pull_request_comment` | PR 评论 | +| `pull_request_review_approved` | PR Review 通过 | +| `pull_request_review_rejected` | PR Review 拒绝 | +| `pull_request_review_comment` | PR Review 评论 | +| `issue` | Issue 相关 | +| `release` | Release 发布 | +| `create` | Branch/Tag 创建 | +| `delete` | Branch/Tag 删除 | +| `fork` | 仓库 fork | +| `repository` | 仓库创建/删除 | + +--- + +## 风险和限制 + +### 1. 已知功能限制 + +| 限制项 | 影响 | 变通方案 | +|--------|------|---------| +| `failure()` 表达式不支持 | 无法实现 "失败时通知" job | 拆分为独立 workflow + webhook | +| `concurrency` 不支持 | 同一 workflow 可能并行运行 | 在 workflow 脚本中加锁机制 | +| `continue-on-error` 不支持 | job 失败即终止 | 将错误处理逻辑放在 step 内 | +| `timeout-minutes` 不支持 | job 可能无限运行 | act-runner 配置全局超时 | +| `GITEA_TOKEN` 不内置(v1.23) | CI 中调 API 需手动配置 PAT | 创建 PAT 存为 secret | +| `permissions` 关键字被忽略 | 无法精细控制 job token 权限 | v1.23 不适用,需升级 | + +### 2. 兼容性注意事项 + +- **数据库 charset**:使用 MySQL 时需确保 charset 为 `utf8mb4`,否则 emoji 会报错 +- **SHA256 仓库**:某些 action(如 `actions/checkout`)在 SHA256 仓库中可能无法正常工作 +- **Subpath 部署**:如果 Gitea 运行在子路径下,某些 action 可能有问题 +- **Schedule 时区**:v1.23 起默认使用 UTC,需注意时区转换 + +### 3. 安全注意事项 + +- act-runner 有潜在安全风险:运行 job 可访问 runner 所在机器 +- **内部使用的 Gitea 实例风险较低**(官方明确说明) +- 不建议为不信任的仓库/组织提供 runner +- v1.23 的 fork PR workflow 自动限制为只读权限(安全特性) + +### 4. 升级建议 + +**强烈建议升级到 Gitea v1.24+**,主要获益: + +1. **内置 GITEA_TOKEN**:不再需要手动配置 PAT +2. **permissions 关键字支持**:可精细控制 job 权限 +3. **更多表达式函数**:`failure()` 等可能得到支持 +4. **更多 bug 修复和性能改进** + +当前 v1.23.4 的替代方案仍然可行,只是需要更多手动配置。 + +### 5. 不支持 GitHub Actions 的功能清单 + +以下 GitHub Actions 特性在 Gitea Actions 中**不可用**: + +- Problem Matchers +- Create error annotation +- Pre/Post steps 在 UI 中不单独展示 +- Services steps 在 UI 中不单独展示 +- Package repository authorization +- Complex `runs-on` 表达式 + +--- + +## 示例 Workflow(验证可用) + +```yaml +name: CI +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run tests + run: | + echo "Running tests..." + # pytest / go test / etc. + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run lint + run: | + echo "Running lint..." + # flake8 / eslint / etc. + + deploy: + needs: [test, lint] + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + steps: + - uses: actions/checkout@v4 + - name: Deploy + run: | + echo "Deploying..." + # deploy script + env: + DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} +``` + +> **注意**:`if: github.ref == 'refs/heads/main'` 可用,但 `if: failure()` 不可用。deploy job 仅在 main 分支且 test+lint 通过时执行。 + +--- + +## 参考资料 + +- [Gitea Actions 官方文档 v1.23](https://docs.gitea.com/1.23/usage/actions) +- [Compared to GitHub Actions](https://docs.gitea.com/1.23/usage/actions/comparison) +- [Act Runner 文档](https://docs.gitea.com/1.23/usage/actions/act-runner) +- [Gitea v1.23.0 Release Notes](https://blog.gitea.com/release-of-1.23.0/) +- [Gitea API v1.23](https://docs.gitea.com/api/1.23/) +- [Branch Protection API](https://docs.gitea.com/api/1.23/#tag/repository/operation/repoCreateBranchProtection) +- [Webhooks 文档](https://docs.gitea.com/1.23/usage/webhooks) +- [Secrets 文档](https://docs.gitea.com/1.23/usage/actions/secrets) diff --git a/src/api/blackboard_routes.py b/src/api/blackboard_routes.py index edd7e26..8bf30d3 100644 --- a/src/api/blackboard_routes.py +++ b/src/api/blackboard_routes.py @@ -158,7 +158,9 @@ async def _generate_title(description: str) -> str | None: base_url = "https://open.bigmodel.cn/api/paas/v4" api_key = "" model = "glm-4-flash" - oc_cfg = Path.home() / ".openclaw" / "openclaw.json" + oc_cfg = Path(os.environ.get( + "OPENCLAW_HOME", str(Path.home() / ".openclaw") + )) / "openclaw.json" if oc_cfg.exists(): with open(oc_cfg) as f: cfg = _json.load(f) diff --git a/src/blackboard/registry.py b/src/blackboard/registry.py index 50e556a..af1fafd 100644 --- a/src/blackboard/registry.py +++ b/src/blackboard/registry.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +import os import sqlite3 from datetime import datetime from pathlib import Path @@ -261,7 +262,10 @@ class ProjectRegistry: def discover_sanguo_projects(self, scan_dir: Optional[Path] = None) -> List[str]: """扫描 sanguo_projects 开发目录,自动注册正式项目""" - scan_dir = scan_dir or Path.home() / ".openclaw" / "sanguo_projects" + scan_dir = scan_dir or Path(os.environ.get( + "SANGUO_PROJECTS_DIR", + str(Path.home() / ".openclaw" / "sanguo_projects") + )) discovered = [] if not scan_dir.exists(): diff --git a/src/daemon/spawner.py b/src/daemon/spawner.py index b71228a..22f4dc6 100644 --- a/src/daemon/spawner.py +++ b/src/daemon/spawner.py @@ -9,6 +9,7 @@ from __future__ import annotations import asyncio import json import logging +import os import uuid from datetime import datetime from pathlib import Path @@ -1165,7 +1166,9 @@ curl -X POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_ @staticmethod def _revive_session(agent_id: str) -> bool: """假死复活术:修改 sessions.json status 从 running 改为 idle""" - sessions_path = Path.home() / ".openclaw" / "agents" / agent_id / "sessions" / "sessions.json" + sessions_path = Path(os.environ.get( + "OPENCLAW_HOME", str(Path.home() / ".openclaw") + )) / "agents" / agent_id / "sessions" / "sessions.json" if not sessions_path.exists(): return False try: @@ -1249,7 +1252,9 @@ curl -X POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_ 替代失效的 compactionCheckpoints 检测。 """ result = {"status": "unknown", "lock_pid": None, "lock_pid_alive": False, "recent_compact": False} - sessions_path = Path.home() / ".openclaw" / "agents" / agent_id / "sessions" / "sessions.json" + sessions_path = Path(os.environ.get( + "OPENCLAW_HOME", str(Path.home() / ".openclaw") + )) / "agents" / agent_id / "sessions" / "sessions.json" if not sessions_path.exists(): return result try: