@yyy9527/openclaw-manager 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +37 -0
- package/README.md +195 -0
- package/config/agents.yaml +22 -0
- package/config/channels.yaml +14 -0
- package/config/clawhub-skills.txt +6 -0
- package/config/model-env-templates/README.md +25 -0
- package/config/model-env-templates/dev.env.example +10 -0
- package/config/model-env-templates/master.env.example +10 -0
- package/config/model-env-templates/test.env.example +10 -0
- package/config/openclaw.env +20 -0
- package/config/openclaw.env.example +49 -0
- package/config/versions.lock +9 -0
- package/docker-compose.yml +24 -0
- package/package.json +47 -0
- package/scripts/apply_config.sh +33 -0
- package/scripts/bootstrap_models.sh +133 -0
- package/scripts/check_env.sh +55 -0
- package/scripts/health_check.sh +108 -0
- package/scripts/install_openclaw.sh +119 -0
- package/scripts/openclaw_ctl.sh +323 -0
- package/scripts/set_qwen_vendor_model.sh +142 -0
- package/scripts/setup_env.sh +156 -0
- package/scripts/skills_sync.sh +154 -0
- package/scripts/sync_model_configs.sh +217 -0
- package/src/integrations/feishu/notifier.js +46 -0
- package/src/orchestrator/index.js +30 -0
- package/src/tui/index.js +74 -0
package/.env.example
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# 敏感变量模板(复制为 .env 后填入真实值)
|
|
2
|
+
|
|
3
|
+
# Git 访问令牌(必填)
|
|
4
|
+
# 用途:Issue/PR 创建、认领、状态更新、PR 审查
|
|
5
|
+
# 获取路径(Gitee):个人设置 -> 私人令牌(Personal Access Tokens)
|
|
6
|
+
# 如使用 GitHub:Settings -> Developer settings -> Personal access tokens
|
|
7
|
+
GIT_TOKEN=
|
|
8
|
+
|
|
9
|
+
# 飞书机器人 Webhook(可选,启用通知时必填)
|
|
10
|
+
# 用途:任务状态、PR 结果、积分变更通知
|
|
11
|
+
# 获取路径:飞书群 -> 机器人 -> 自定义机器人 -> Webhook URL
|
|
12
|
+
FEISHU_WEBHOOK_URL=
|
|
13
|
+
|
|
14
|
+
# 飞书签名密钥(可选)
|
|
15
|
+
# 用途:Webhook 签名校验
|
|
16
|
+
# 获取路径:与 Webhook 同页面查看签名密钥
|
|
17
|
+
FEISHU_SIGNING_SECRET=
|
|
18
|
+
|
|
19
|
+
# npm 发布令牌(最后发布阶段使用)
|
|
20
|
+
# 用途:npm publish 鉴权
|
|
21
|
+
# 获取路径:npm 官网 -> Access Tokens
|
|
22
|
+
NPM_TOKEN=
|
|
23
|
+
|
|
24
|
+
# Ollama provider 注册占位键(非敏感)
|
|
25
|
+
# 用途:让 OpenClaw 将 Ollama 识别为已注册 provider
|
|
26
|
+
# 建议值:ollama-local
|
|
27
|
+
OLLAMA_API_KEY=ollama-local
|
|
28
|
+
|
|
29
|
+
# 厂商 Qwen(DashScope)非交互切换参数(可选)
|
|
30
|
+
# 用途:`npm run set-model:qwen` 自动写入每个实例模型配置
|
|
31
|
+
# 二选一即可(建议填 DASHSCOPE_API_KEY)
|
|
32
|
+
DASHSCOPE_API_KEY=
|
|
33
|
+
QWEN_API_KEY=
|
|
34
|
+
# 默认值:qwen-max
|
|
35
|
+
QWEN_MODEL=qwen-max
|
|
36
|
+
# 默认值:https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
37
|
+
QWEN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# OpenClaw Manager
|
|
2
|
+
|
|
3
|
+
面向 macOS 的 OpenClaw 多实例部署与协作编排脚手架,支持:
|
|
4
|
+
|
|
5
|
+
- 一键环境初始化与非交互安装
|
|
6
|
+
- `npm run` 统一管理
|
|
7
|
+
- TUI 交互
|
|
8
|
+
- 飞书通知适配
|
|
9
|
+
- 多实例隔离与统一命名规范
|
|
10
|
+
- 里程碑提交、自测记录、问题闭环沉淀
|
|
11
|
+
|
|
12
|
+
> 职责边界:脚本只负责安装、启停、重启、健康检查、日志和配置校验;任务拆分/认领/PR 协作/积分结算由 OpenClaw Skills 执行。
|
|
13
|
+
|
|
14
|
+
## 1. 前置准备
|
|
15
|
+
|
|
16
|
+
1. macOS(Apple Silicon / Intel)
|
|
17
|
+
2. 安装并启动 Docker Desktop
|
|
18
|
+
3. 准备 `.env` 中的敏感变量(Git Token、飞书 webhook 等)
|
|
19
|
+
|
|
20
|
+
## 2. 快速开始
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cp config/openclaw.env.example config/openclaw.env
|
|
24
|
+
cp .env.example .env
|
|
25
|
+
npm run setup
|
|
26
|
+
npm run install
|
|
27
|
+
npm run status
|
|
28
|
+
npm run help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> 首次执行 `npm run install` 需要拉取官方镜像,可能耗时较长(取决于网络)。
|
|
32
|
+
> clawhub 在 macOS 安装后,只有把 skills 安装到 `OPENCLAW_HOME_ROOT` 可见目录并挂载到容器,才能持久化并在容器内生效。
|
|
33
|
+
|
|
34
|
+
## 3. 常用命令
|
|
35
|
+
|
|
36
|
+
- `npm run help`:查看友好的 CLI 帮助
|
|
37
|
+
- `npm run setup`:初始化环境(幂等)
|
|
38
|
+
- `npm run install`:按配置启动全部实例
|
|
39
|
+
- `npm run start` / `npm run stop` / `npm run restart`
|
|
40
|
+
- `npm run status`:查看实例状态
|
|
41
|
+
- `npm run list:claw`:列出当前配置的 claw 名称
|
|
42
|
+
- `npm run start:claw -- <name>`:启动指定实例
|
|
43
|
+
- `npm run stop:claw -- <name>`:停止指定实例
|
|
44
|
+
- `npm run status:claw -- <name>`:查看指定实例状态
|
|
45
|
+
- `npm run logs:claw -- <name>`:查看指定实例日志
|
|
46
|
+
- `npm run logs`:查看日志
|
|
47
|
+
- `npm run tui`:进入终端交互界面
|
|
48
|
+
- `npm run tui:claw -- <name>`:进入指定容器内 OpenClaw 的对话 TUI
|
|
49
|
+
- `npm run clawhub:login`:登录 clawhub,避免匿名限流影响 skills 安装
|
|
50
|
+
- `npm run check-env`:检查你是否已补齐关键 `.env` 变量
|
|
51
|
+
- `npm run sync-skills`:创建共享/专属 skills 目录,并优先通过 clawhub 搜索安装
|
|
52
|
+
- `npm run sync-model-configs`:将各实例家目录的 `model.env` 同步到各自 `openclaw.json`
|
|
53
|
+
- `npm run apply-config`:配置变更后统一生效(先同步模型配置,再重启)
|
|
54
|
+
- `npm run bootstrap-models`:显式覆盖为 Ollama(需先开启覆盖开关)
|
|
55
|
+
- `npm run set-model:qwen`:非交互切换到厂商 Qwen(DashScope/OpenAI 兼容)
|
|
56
|
+
- `npm run health-check`:检查 Docker / Gitee 令牌与仓库 / 飞书配置可用性
|
|
57
|
+
- `npm run self-test`:执行基础自测
|
|
58
|
+
|
|
59
|
+
## 3.1 `--help` 与配置文件切换
|
|
60
|
+
|
|
61
|
+
脚本入口支持统一全局参数:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bash ./scripts/openclaw_ctl.sh --help
|
|
65
|
+
bash ./scripts/openclaw_ctl.sh --config ./config/openclaw.dev.env status
|
|
66
|
+
bash ./scripts/openclaw_ctl.sh --config ./config/openclaw.prod.env --env-file ./.env.prod apply-config
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
如果通过 `npm run` 使用,也可以把参数透传给底层脚本(注意 `--`):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run ctl -- --config ./config/openclaw.dev.env status
|
|
73
|
+
npm run ctl -- --config ./config/openclaw.prod.env --env-file ./.env.prod apply-config
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> 这个体验与你提到的 `webpack --config` 思路一致,适合 dev/staging/prod 多套配置并行维护。
|
|
77
|
+
|
|
78
|
+
## 3.2 Git 平台切换(当前默认 Gitee)
|
|
79
|
+
|
|
80
|
+
- 默认配置位于 `config/openclaw.env`(可通过 `--config` 指向其他文件):
|
|
81
|
+
- `GIT_PLATFORM=gitee`
|
|
82
|
+
- `GIT_API_BASE=https://gitee.com/api/v5`
|
|
83
|
+
- `GIT_REPO=你的命名空间/仓库名`
|
|
84
|
+
- 访问令牌放到 `.env`(或 `--env-file` 指定文件)的 `GIT_TOKEN`
|
|
85
|
+
|
|
86
|
+
## 3.3 Skills 协作入口
|
|
87
|
+
|
|
88
|
+
- 共享 skills 目录:`${OPENCLAW_HOME_ROOT}/shared/skills`
|
|
89
|
+
- 实例专属 skills 目录:`${OPENCLAW_HOME_ROOT}/{instance}/skills`
|
|
90
|
+
- clawhub 清单:`config/clawhub-skills.txt`
|
|
91
|
+
- 容器挂载路径:
|
|
92
|
+
- `${OPENCLAW_HOME_ROOT}/{instance}` -> `/home/node/.openclaw`
|
|
93
|
+
- `${OPENCLAW_HOME_ROOT}/shared/skills` -> `/home/node/.openclaw/shared/skills`
|
|
94
|
+
- 协作边界:
|
|
95
|
+
- 运维动作由脚本执行
|
|
96
|
+
- 需求拆分、任务认领、PR 审查、积分结算由 OpenClaw Skills 执行
|
|
97
|
+
|
|
98
|
+
> `clawhub` 通过 `pnpm` 安装(`pnpm add -g clawhub`)。
|
|
99
|
+
> `sync-skills` 会先尝试安装 `find-skills`,再按检索词搜索最佳匹配并安装;遇到超时会自动重试。
|
|
100
|
+
> 若出现 `Rate limit exceeded`,请先执行 `npm run clawhub:login` 再重试 `npm run sync-skills`。
|
|
101
|
+
> 如果 TUI 报 `No API key found for provider "anthropic"`,先执行 `npm run apply-config`。该命令会重启容器并引导默认模型到 `ollama/qwen3.5:27b`。
|
|
102
|
+
> 如果 TUI 报 `not connected to gateway`,通常是网关刚重启尚未就绪;`tui:claw` 现已内置等待逻辑,超时可执行 `npm run apply-config` 后重试。
|
|
103
|
+
|
|
104
|
+
### 非交互切换到厂商 Qwen
|
|
105
|
+
|
|
106
|
+
1. 在 `.env` 配置:
|
|
107
|
+
- `DASHSCOPE_API_KEY`(或 `QWEN_API_KEY`)
|
|
108
|
+
- 可选:`QWEN_MODEL`(默认 `qwen-max`)
|
|
109
|
+
- 可选:`QWEN_BASE_URL`(默认 DashScope OpenAI 兼容地址)
|
|
110
|
+
2. 执行:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm run set-model:qwen
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
该命令会自动为每个实例写入 `~/openclaws/{instance}/model.env`,再同步到家目录 `openclaw.json`。
|
|
117
|
+
最终通过 `npm run apply-config` 重启生效,无需交互式 `openclaw configure`。
|
|
118
|
+
|
|
119
|
+
你也可以按实例准备模板(可选):
|
|
120
|
+
|
|
121
|
+
- `config/model-env-templates/master.env(.example)`
|
|
122
|
+
- `config/model-env-templates/dev.env(.example)`
|
|
123
|
+
- `config/model-env-templates/test.env(.example)`
|
|
124
|
+
|
|
125
|
+
`set-model:qwen` 与 `sync-model-configs` 只会更新受控键,不会整文件覆盖你在 `model.env` 中新增的自定义键。
|
|
126
|
+
|
|
127
|
+
> `apply-config` 默认不会强制回写 Ollama 模型,避免覆盖实例家目录中的厂商模型配置。
|
|
128
|
+
> 如需在 `apply-config` 后强制回写 Ollama,需同时设置:
|
|
129
|
+
> - `OPENCLAW_FORCE_OLLAMA_AFTER_APPLY=true`
|
|
130
|
+
> - `OPENCLAW_ALLOW_OLLAMA_OVERRIDE=true`
|
|
131
|
+
>
|
|
132
|
+
> `bootstrap-models` 会覆盖当前模型主配置,默认关闭,必须显式开启才会执行。
|
|
133
|
+
|
|
134
|
+
## 4. 多实例统一命名规范
|
|
135
|
+
|
|
136
|
+
当前架构是 **单镜像多容器**(你的判断是正确的):每个 OpenClaw 一个独立容器,统一复用同一镜像版本。
|
|
137
|
+
|
|
138
|
+
- `agent_id`: `master|dev|test|...`
|
|
139
|
+
- `container_name`: `${OPENCLAW_NAME_PREFIX}-${agent_id}`
|
|
140
|
+
- `instance_name`: 来自 `OPENCLAW_INSTANCE_IDS`(例如 `master`、`dev`)
|
|
141
|
+
- `data_dir`: `${OPENCLAW_HOME_ROOT}/${instance_name}`(每个实例独立“家目录”)
|
|
142
|
+
- `log_dir`: `./logs/${OPENCLAW_NAME_PREFIX}-${agent_id}`
|
|
143
|
+
- `port_http`: `OPENCLAW_BASE_HTTP_PORT + ordinal`
|
|
144
|
+
- `container_port`: `OPENCLAW_CONTAINER_PORT`(默认 `18789`)
|
|
145
|
+
- `issue_label`: `agent:${agent_id}` / `task:*` / `status:*`
|
|
146
|
+
|
|
147
|
+
示例:
|
|
148
|
+
|
|
149
|
+
- 实例 `master` -> `openclaw-master` / `~/openclaws/master` / `3100`
|
|
150
|
+
- 实例 `dev` -> `openclaw-dev` / `~/openclaws/dev` / `3101`
|
|
151
|
+
|
|
152
|
+
## 5. 固定版本策略
|
|
153
|
+
|
|
154
|
+
- 当前固定版本记录在 `config/versions.lock`
|
|
155
|
+
- 更新版本时需同步修改:
|
|
156
|
+
- `config/versions.lock`
|
|
157
|
+
- `config/openclaw.env`(`OPENCLAW_VERSION`)
|
|
158
|
+
- 变更说明与里程碑记录
|
|
159
|
+
|
|
160
|
+
## 6. 里程碑与验收记录规范
|
|
161
|
+
|
|
162
|
+
- 里程碑记录:`docs/milestones/`
|
|
163
|
+
- 每步自测记录:`docs/validation/`
|
|
164
|
+
- 问题与解决路径:`docs/incidents/`
|
|
165
|
+
|
|
166
|
+
每个里程碑必须至少一个 Git 提交,提交信息使用中文并包含:
|
|
167
|
+
|
|
168
|
+
1. 目的(为什么)
|
|
169
|
+
2. 变更(做了什么)
|
|
170
|
+
3. 验证(如何确认)
|
|
171
|
+
|
|
172
|
+
示例提交:
|
|
173
|
+
|
|
174
|
+
`feat(里程碑01): 完成多实例安装脚本与端口冲突校验,补充自测记录`
|
|
175
|
+
|
|
176
|
+
## 7. 作为 npm 包使用与发布
|
|
177
|
+
|
|
178
|
+
本项目已具备 CLI 包基础结构(`bin` 指向 `scripts/openclaw_ctl.sh`)。
|
|
179
|
+
|
|
180
|
+
本地验证:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npm pack
|
|
184
|
+
npx openclaw-manager --help
|
|
185
|
+
npx clawctl --help
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
发布前建议:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm login
|
|
192
|
+
npm publish --access public
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> 当前建议包名:`@yyy9527/openclaw-manager`。若需组织统一命名,可改为你的团队 scope。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
agents:
|
|
2
|
+
- id: master
|
|
3
|
+
role: "主 OpenClaw"
|
|
4
|
+
duty: "需求理解、任务拆分、Issue 下发、PR 审查、积分结算"
|
|
5
|
+
score_rules:
|
|
6
|
+
issue_created: 5
|
|
7
|
+
review_completed: 10
|
|
8
|
+
|
|
9
|
+
- id: dev
|
|
10
|
+
role: "开发 OpenClaw"
|
|
11
|
+
duty: "认领任务、实现需求、提交 PR"
|
|
12
|
+
score_rules:
|
|
13
|
+
issue_claimed: 3
|
|
14
|
+
pr_merged: 20
|
|
15
|
+
pr_rejected: -5
|
|
16
|
+
|
|
17
|
+
- id: test
|
|
18
|
+
role: "测试 OpenClaw"
|
|
19
|
+
duty: "执行验证、提交测试结论、反馈风险"
|
|
20
|
+
score_rules:
|
|
21
|
+
validation_completed: 8
|
|
22
|
+
defect_found: 5
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 实例模型模板(可选)
|
|
2
|
+
|
|
3
|
+
用于为不同实例提供不同的模型默认值。脚本会按实例名读取:
|
|
4
|
+
|
|
5
|
+
- `config/model-env-templates/<instance>.env`
|
|
6
|
+
- 若不存在,再尝试 `config/model-env-templates/<instance>.env.example`
|
|
7
|
+
|
|
8
|
+
## 使用方式
|
|
9
|
+
|
|
10
|
+
1. 复制示例模板并改名为 `.env`(可选):
|
|
11
|
+
- `master.env.example -> master.env`
|
|
12
|
+
- `dev.env.example -> dev.env`
|
|
13
|
+
- `test.env.example -> test.env`
|
|
14
|
+
2. 修改你希望按实例区分的键值。
|
|
15
|
+
3. 执行:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run set-model:qwen
|
|
19
|
+
npm run apply-config
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 安全更新说明
|
|
23
|
+
|
|
24
|
+
- `set-model:qwen` 与 `sync-model-configs` 只更新受控键(`MODEL_*` 核心字段)。
|
|
25
|
+
- `~/openclaws/<instance>/model.env` 中的其他自定义键会被保留,不会整文件覆盖。
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# dev:成本优先,可用于日常迭代
|
|
2
|
+
MODEL_PROVIDER_ID="openai"
|
|
3
|
+
MODEL_PRIMARY="openai/qwen-plus"
|
|
4
|
+
MODEL_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
5
|
+
MODEL_API_KEY_ENV="DASHSCOPE_API_KEY"
|
|
6
|
+
MODEL_API="openai-completions"
|
|
7
|
+
MODEL_ID="qwen-plus"
|
|
8
|
+
MODEL_NAME="Qwen Dev"
|
|
9
|
+
MODEL_CONTEXT_WINDOW=131072
|
|
10
|
+
MODEL_MAX_TOKENS=8192
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# master:稳定主模型
|
|
2
|
+
MODEL_PROVIDER_ID="openai"
|
|
3
|
+
MODEL_PRIMARY="openai/qwen-max"
|
|
4
|
+
MODEL_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
5
|
+
MODEL_API_KEY_ENV="DASHSCOPE_API_KEY"
|
|
6
|
+
MODEL_API="openai-completions"
|
|
7
|
+
MODEL_ID="qwen-max"
|
|
8
|
+
MODEL_NAME="Qwen Master"
|
|
9
|
+
MODEL_CONTEXT_WINDOW=131072
|
|
10
|
+
MODEL_MAX_TOKENS=8192
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# test:快速反馈,可用于回归验证
|
|
2
|
+
MODEL_PROVIDER_ID="openai"
|
|
3
|
+
MODEL_PRIMARY="openai/qwen-turbo"
|
|
4
|
+
MODEL_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
5
|
+
MODEL_API_KEY_ENV="DASHSCOPE_API_KEY"
|
|
6
|
+
MODEL_API="openai-completions"
|
|
7
|
+
MODEL_ID="qwen-turbo"
|
|
8
|
+
MODEL_NAME="Qwen Test"
|
|
9
|
+
MODEL_CONTEXT_WINDOW=131072
|
|
10
|
+
MODEL_MAX_TOKENS=8192
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 从 openclaw.env.example 复制而来,可按需修改。
|
|
2
|
+
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw
|
|
3
|
+
OPENCLAW_VERSION=latest
|
|
4
|
+
OPENCLAW_INSTANCE_IDS=master,dev,test
|
|
5
|
+
OPENCLAW_NAME_PREFIX=openclaw
|
|
6
|
+
OPENCLAW_BASE_HTTP_PORT=3100
|
|
7
|
+
OPENCLAW_CONTAINER_PORT=18789
|
|
8
|
+
OPENCLAW_HOME_ROOT=${HOME}/openclaws
|
|
9
|
+
OPENCLAW_SHARED_SKILLS_DIR=${OPENCLAW_HOME_ROOT}/shared/skills
|
|
10
|
+
OPENCLAW_ENABLE_CLAWHUB_SKILLS=true
|
|
11
|
+
OPENCLAW_CLAWHUB_INSTALL_RETRIES=8
|
|
12
|
+
OPENCLAW_FORCE_OLLAMA_AFTER_APPLY=false
|
|
13
|
+
OPENCLAW_ALLOW_OLLAMA_OVERRIDE=false
|
|
14
|
+
OLLAMA_BASE_URL=http://host.docker.internal:11434
|
|
15
|
+
OLLAMA_MODEL=qwen3.5:27b
|
|
16
|
+
OLLAMA_API_KEY=ollama-local
|
|
17
|
+
GIT_PLATFORM=gitee
|
|
18
|
+
GIT_REPO=yangyiyuan0825/openclaws
|
|
19
|
+
GIT_API_BASE=https://gitee.com/api/v5
|
|
20
|
+
FEISHU_ENABLED=true
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# OpenClaw 运行配置(非敏感)
|
|
2
|
+
|
|
3
|
+
# 镜像仓库名称(当前使用官方 GHCR)
|
|
4
|
+
OPENCLAW_IMAGE=ghcr.io/openclaw/openclaw
|
|
5
|
+
|
|
6
|
+
# 固定版本(当前固定 latest,可按需锁定具体 tag)
|
|
7
|
+
OPENCLAW_VERSION=latest
|
|
8
|
+
|
|
9
|
+
# 多实例名称(逗号分隔)。每个名称都会成为一个独立实例名。
|
|
10
|
+
OPENCLAW_INSTANCE_IDS=master,dev,test
|
|
11
|
+
|
|
12
|
+
# 命名规范前缀
|
|
13
|
+
OPENCLAW_NAME_PREFIX=openclaw
|
|
14
|
+
|
|
15
|
+
# 端口策略:按实例序号递增,避免冲突
|
|
16
|
+
# master: 3100, dev: 3101, test: 3102
|
|
17
|
+
OPENCLAW_BASE_HTTP_PORT=3100
|
|
18
|
+
OPENCLAW_CONTAINER_PORT=18789
|
|
19
|
+
|
|
20
|
+
# 本地家目录根路径(每个实例会自动创建 `${OPENCLAW_HOME_ROOT}/${实例名}`)
|
|
21
|
+
OPENCLAW_HOME_ROOT=${HOME}/openclaws
|
|
22
|
+
|
|
23
|
+
# 共享技能目录(所有实例共用)
|
|
24
|
+
OPENCLAW_SHARED_SKILLS_DIR=${OPENCLAW_HOME_ROOT}/shared/skills
|
|
25
|
+
|
|
26
|
+
# 是否优先通过 clawhub 搜索并安装技能
|
|
27
|
+
OPENCLAW_ENABLE_CLAWHUB_SKILLS=true
|
|
28
|
+
# clawhub 安装重试次数(网络超时时自动重试)
|
|
29
|
+
OPENCLAW_CLAWHUB_INSTALL_RETRIES=8
|
|
30
|
+
# 是否在 apply-config 后强制回写 Ollama 模型(默认 false)
|
|
31
|
+
OPENCLAW_FORCE_OLLAMA_AFTER_APPLY=false
|
|
32
|
+
# 是否允许执行 bootstrap-models 覆盖当前主模型(默认 false)
|
|
33
|
+
OPENCLAW_ALLOW_OLLAMA_OVERRIDE=false
|
|
34
|
+
|
|
35
|
+
# 默认 Ollama 连接
|
|
36
|
+
OLLAMA_BASE_URL=http://host.docker.internal:11434
|
|
37
|
+
OLLAMA_MODEL=qwen3.5:27b
|
|
38
|
+
OLLAMA_API_KEY=ollama-local
|
|
39
|
+
|
|
40
|
+
# 协作平台基础信息(非敏感)
|
|
41
|
+
# 当前默认使用 Gitee。若切换 GitHub,请改为:
|
|
42
|
+
# GIT_PLATFORM=github
|
|
43
|
+
# GIT_API_BASE=https://api.github.com
|
|
44
|
+
GIT_PLATFORM=gitee
|
|
45
|
+
GIT_REPO=owner/repo
|
|
46
|
+
GIT_API_BASE=https://gitee.com/api/v5
|
|
47
|
+
|
|
48
|
+
# 飞书通知功能开关
|
|
49
|
+
FEISHU_ENABLED=true
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
services:
|
|
2
|
+
openclaw:
|
|
3
|
+
image: "${OPENCLAW_IMAGE}:${OPENCLAW_VERSION}"
|
|
4
|
+
container_name: "${OPENCLAW_NAME_PREFIX}-${OPENCLAW_INSTANCE_ID}"
|
|
5
|
+
restart: unless-stopped
|
|
6
|
+
ports:
|
|
7
|
+
- "${OPENCLAW_HTTP_PORT}:${OPENCLAW_CONTAINER_PORT}"
|
|
8
|
+
environment:
|
|
9
|
+
OLLAMA_BASE_URL: "${OLLAMA_BASE_URL}"
|
|
10
|
+
OLLAMA_MODEL: "${OLLAMA_MODEL}"
|
|
11
|
+
OLLAMA_API_KEY: "${OLLAMA_API_KEY}"
|
|
12
|
+
DASHSCOPE_API_KEY: "${DASHSCOPE_API_KEY}"
|
|
13
|
+
QWEN_API_KEY: "${QWEN_API_KEY}"
|
|
14
|
+
OPENCLAW_ROLE: "${OPENCLAW_INSTANCE_ID}"
|
|
15
|
+
GIT_PLATFORM: "${GIT_PLATFORM}"
|
|
16
|
+
GIT_REPO: "${GIT_REPO}"
|
|
17
|
+
FEISHU_ENABLED: "${FEISHU_ENABLED}"
|
|
18
|
+
volumes:
|
|
19
|
+
- "${OPENCLAW_INSTANCE_HOME_DIR}:/home/node/.openclaw"
|
|
20
|
+
- "${OPENCLAW_SHARED_SKILLS_DIR}:/home/node/.openclaw/shared/skills"
|
|
21
|
+
- "${OPENCLAW_INSTANCE_DATA_DIR}:/app/data"
|
|
22
|
+
- "${OPENCLAW_INSTANCE_LOG_DIR}:/app/logs"
|
|
23
|
+
extra_hosts:
|
|
24
|
+
- "host.docker.internal:host-gateway"
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yyy9527/openclaw-manager",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenClaw multi-instance manager for macOS with docker, TUI, and collaboration workflow.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"openclaw-manager": "./scripts/openclaw_ctl.sh",
|
|
10
|
+
"clawctl": "./scripts/openclaw_ctl.sh"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"scripts/",
|
|
14
|
+
"src/",
|
|
15
|
+
"config/",
|
|
16
|
+
"docker-compose.yml",
|
|
17
|
+
"README.md",
|
|
18
|
+
".env.example"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"ctl": "bash ./scripts/openclaw_ctl.sh",
|
|
22
|
+
"help": "bash ./scripts/openclaw_ctl.sh --help",
|
|
23
|
+
"setup": "bash ./scripts/setup_env.sh",
|
|
24
|
+
"install": "bash ./scripts/install_openclaw.sh",
|
|
25
|
+
"start": "bash ./scripts/openclaw_ctl.sh start",
|
|
26
|
+
"stop": "bash ./scripts/openclaw_ctl.sh stop",
|
|
27
|
+
"restart": "bash ./scripts/openclaw_ctl.sh restart",
|
|
28
|
+
"status": "bash ./scripts/openclaw_ctl.sh status",
|
|
29
|
+
"list:claw": "bash ./scripts/openclaw_ctl.sh list-claw",
|
|
30
|
+
"start:claw": "bash ./scripts/openclaw_ctl.sh start-claw",
|
|
31
|
+
"stop:claw": "bash ./scripts/openclaw_ctl.sh stop-claw",
|
|
32
|
+
"status:claw": "bash ./scripts/openclaw_ctl.sh status-claw",
|
|
33
|
+
"logs:claw": "bash ./scripts/openclaw_ctl.sh logs-claw",
|
|
34
|
+
"logs": "bash ./scripts/openclaw_ctl.sh logs",
|
|
35
|
+
"tui": "node ./src/tui/index.js",
|
|
36
|
+
"tui:claw": "bash ./scripts/openclaw_ctl.sh chat-claw",
|
|
37
|
+
"clawhub:login": "clawhub login",
|
|
38
|
+
"check-env": "bash ./scripts/openclaw_ctl.sh check-env",
|
|
39
|
+
"sync-skills": "bash ./scripts/openclaw_ctl.sh sync-skills",
|
|
40
|
+
"sync-model-configs": "bash ./scripts/openclaw_ctl.sh sync-model-configs",
|
|
41
|
+
"apply-config": "bash ./scripts/openclaw_ctl.sh apply-config",
|
|
42
|
+
"bootstrap-models": "bash ./scripts/openclaw_ctl.sh bootstrap-models",
|
|
43
|
+
"set-model:qwen": "bash ./scripts/openclaw_ctl.sh set-qwen",
|
|
44
|
+
"health-check": "bash ./scripts/openclaw_ctl.sh health-check",
|
|
45
|
+
"self-test": "bash ./scripts/openclaw_ctl.sh self-test"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
CONFIG_FILE="${OPENCLAW_CONFIG_FILE:-${PROJECT_ROOT}/config/openclaw.env}"
|
|
7
|
+
|
|
8
|
+
log() {
|
|
9
|
+
printf '[apply-config] %s\n' "$*"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
load_env() {
|
|
13
|
+
[ -f "${CONFIG_FILE}" ] || {
|
|
14
|
+
printf '[apply-config][ERROR] 缺少配置文件:%s\n' "${CONFIG_FILE}" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
set -a
|
|
18
|
+
# shellcheck source=/dev/null
|
|
19
|
+
source "${CONFIG_FILE}"
|
|
20
|
+
set +a
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
load_env
|
|
24
|
+
log "应用配置:先同步家目录模型配置,再重建容器并引导模型"
|
|
25
|
+
bash "${PROJECT_ROOT}/scripts/sync_model_configs.sh"
|
|
26
|
+
bash "${PROJECT_ROOT}/scripts/openclaw_ctl.sh" stop
|
|
27
|
+
bash "${PROJECT_ROOT}/scripts/openclaw_ctl.sh" start
|
|
28
|
+
if [ "${OPENCLAW_FORCE_OLLAMA_AFTER_APPLY:-false}" = "true" ]; then
|
|
29
|
+
bash "${PROJECT_ROOT}/scripts/openclaw_ctl.sh" bootstrap-models
|
|
30
|
+
else
|
|
31
|
+
log "已跳过强制 Ollama 模型引导(保留各实例家目录模型配置)"
|
|
32
|
+
fi
|
|
33
|
+
log "配置应用完成"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
6
|
+
CONFIG_FILE="${OPENCLAW_CONFIG_FILE:-${PROJECT_ROOT}/config/openclaw.env}"
|
|
7
|
+
|
|
8
|
+
log() {
|
|
9
|
+
printf '[bootstrap-models] %s\n' "$*"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
warn() {
|
|
13
|
+
printf '[bootstrap-models][WARN] %s\n' "$*" >&2
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
project_name_for_instance() {
|
|
17
|
+
local instance_id="$1"
|
|
18
|
+
printf '%s-%s' "${OPENCLAW_NAME_PREFIX}" "${instance_id}" | tr '[:upper:]' '[:lower:]'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
load_env() {
|
|
22
|
+
[ -f "${CONFIG_FILE}" ] || {
|
|
23
|
+
warn "缺少配置文件:${CONFIG_FILE}"
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
set -a
|
|
27
|
+
# shellcheck source=/dev/null
|
|
28
|
+
source "${CONFIG_FILE}"
|
|
29
|
+
set +a
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
guard_ollama_override() {
|
|
33
|
+
if [ "${OPENCLAW_ALLOW_OLLAMA_OVERRIDE:-false}" != "true" ]; then
|
|
34
|
+
warn "已拒绝执行:bootstrap-models 会覆盖当前模型主配置。"
|
|
35
|
+
warn "如需继续,请在配置文件中显式设置 OPENCLAW_ALLOW_OLLAMA_OVERRIDE=true。"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
log "已确认允许覆盖当前模型主配置(OPENCLAW_ALLOW_OLLAMA_OVERRIDE=true)"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
target_model() {
|
|
42
|
+
if printf '%s' "${OLLAMA_MODEL}" | awk '/\//{found=1} END{exit found?0:1}'; then
|
|
43
|
+
printf '%s\n' "${OLLAMA_MODEL}"
|
|
44
|
+
else
|
|
45
|
+
printf 'ollama/%s\n' "${OLLAMA_MODEL}"
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
write_models_file() {
|
|
50
|
+
local id="$1"
|
|
51
|
+
local models_file="${OPENCLAW_HOME_ROOT}/${id}/agents/main/agent/models.json"
|
|
52
|
+
mkdir -p "$(dirname "${models_file}")"
|
|
53
|
+
cat > "${models_file}" <<EOF
|
|
54
|
+
{
|
|
55
|
+
"providers": {
|
|
56
|
+
"ollama": {
|
|
57
|
+
"baseUrl": "${OLLAMA_BASE_URL}",
|
|
58
|
+
"api": "ollama",
|
|
59
|
+
"models": [],
|
|
60
|
+
"apiKey": "OLLAMA_API_KEY"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
EOF
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
is_instance_running() {
|
|
68
|
+
local id="$1"
|
|
69
|
+
OPENCLAW_INSTANCE_ID="${id}" \
|
|
70
|
+
OPENCLAW_INSTANCE_ORDINAL="0" \
|
|
71
|
+
OPENCLAW_HTTP_PORT="${OPENCLAW_BASE_HTTP_PORT}" \
|
|
72
|
+
OPENCLAW_CONTAINER_PORT="${OPENCLAW_CONTAINER_PORT:-18789}" \
|
|
73
|
+
OPENCLAW_INSTANCE_HOME_DIR="${OPENCLAW_HOME_ROOT}/${id}" \
|
|
74
|
+
OPENCLAW_SHARED_SKILLS_DIR="${OPENCLAW_SHARED_SKILLS_DIR:-${OPENCLAW_HOME_ROOT}/shared/skills}" \
|
|
75
|
+
OPENCLAW_INSTANCE_DATA_DIR="${OPENCLAW_HOME_ROOT}/${id}" \
|
|
76
|
+
OPENCLAW_INSTANCE_LOG_DIR="${PROJECT_ROOT}/logs/${OPENCLAW_NAME_PREFIX}-${id}" \
|
|
77
|
+
docker compose -p "$(project_name_for_instance "${id}")" -f "${PROJECT_ROOT}/docker-compose.yml" ps --status running --services | awk 'NF{found=1} END{exit found?0:1}'
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
set_model_for_instance() {
|
|
81
|
+
local id="$1"
|
|
82
|
+
local model="$2"
|
|
83
|
+
local retries=3
|
|
84
|
+
local attempt=1
|
|
85
|
+
while [ "${attempt}" -le "${retries}" ]; do
|
|
86
|
+
if OPENCLAW_INSTANCE_ID="${id}" \
|
|
87
|
+
OPENCLAW_INSTANCE_ORDINAL="0" \
|
|
88
|
+
OPENCLAW_HTTP_PORT="${OPENCLAW_BASE_HTTP_PORT}" \
|
|
89
|
+
OPENCLAW_CONTAINER_PORT="${OPENCLAW_CONTAINER_PORT:-18789}" \
|
|
90
|
+
OPENCLAW_INSTANCE_HOME_DIR="${OPENCLAW_HOME_ROOT}/${id}" \
|
|
91
|
+
OPENCLAW_SHARED_SKILLS_DIR="${OPENCLAW_SHARED_SKILLS_DIR:-${OPENCLAW_HOME_ROOT}/shared/skills}" \
|
|
92
|
+
OPENCLAW_INSTANCE_DATA_DIR="${OPENCLAW_HOME_ROOT}/${id}" \
|
|
93
|
+
OPENCLAW_INSTANCE_LOG_DIR="${PROJECT_ROOT}/logs/${OPENCLAW_NAME_PREFIX}-${id}" \
|
|
94
|
+
docker compose -p "$(project_name_for_instance "${id}")" -f "${PROJECT_ROOT}/docker-compose.yml" exec -T openclaw sh -lc "openclaw models set '${model}' >/dev/null && openclaw models status --plain" | awk -v m="${model}" 'index($0,m){ok=1} END{exit ok?0:1}'; then
|
|
95
|
+
log "实例 ${id} 模型已设置为 ${model}"
|
|
96
|
+
return 0
|
|
97
|
+
fi
|
|
98
|
+
warn "实例 ${id} 设置模型失败(${attempt}/${retries}),准备重试。"
|
|
99
|
+
sleep 2
|
|
100
|
+
attempt=$((attempt + 1))
|
|
101
|
+
done
|
|
102
|
+
return 1
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main() {
|
|
106
|
+
load_env
|
|
107
|
+
guard_ollama_override
|
|
108
|
+
local model
|
|
109
|
+
model="$(target_model)"
|
|
110
|
+
log "目标模型:${model}"
|
|
111
|
+
|
|
112
|
+
IFS=',' read -r -a instance_list <<<"${OPENCLAW_INSTANCE_IDS}"
|
|
113
|
+
local failed=0
|
|
114
|
+
for id in "${instance_list[@]}"; do
|
|
115
|
+
write_models_file "${id}"
|
|
116
|
+
if ! is_instance_running "${id}"; then
|
|
117
|
+
warn "实例 ${id} 未运行,跳过模型引导。"
|
|
118
|
+
continue
|
|
119
|
+
fi
|
|
120
|
+
if ! set_model_for_instance "${id}" "${model}"; then
|
|
121
|
+
warn "实例 ${id} 模型引导失败。"
|
|
122
|
+
failed=1
|
|
123
|
+
fi
|
|
124
|
+
done
|
|
125
|
+
|
|
126
|
+
if [ "${failed}" -ne 0 ]; then
|
|
127
|
+
warn "存在实例模型引导失败,请重试 npm run bootstrap-models。"
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
log "模型引导完成"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
main "$@"
|