@baize-ai/core 0.2.0 → 0.3.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/.dockerignore +8 -18
- package/CHANGELOG.md +19 -1
- package/Dockerfile +66 -12
- package/README.md +85 -6
- package/README.zh-CN.md +63 -3
- package/assets/logo.png +0 -0
- package/cli/baize.js +6 -0
- package/cli/commands/a2a.js +124 -0
- package/cli/commands/add.js +126 -86
- package/cli/commands/component.js +27 -4
- package/cli/commands/doctor.js +2 -2
- package/cli/commands/init.js +28 -0
- package/cli/commands/self-uninstall.js +1 -1
- package/cli/lib/__tests__/instruction-split.test.js +1 -1
- package/cli/lib/a2a.js +235 -0
- package/cli/lib/lock.js +3 -3
- package/cli/lib/self-upgrade.js +1 -1
- package/docker-compose.yml +1 -1
- package/docs/docker.md +18 -4
- package/docs/release.md +150 -0
- package/package.json +1 -1
- package/scripts/docker-publish.sh +70 -0
- package/scripts/install.sh +4 -4
- package/scripts/pack-release.sh +361 -0
- package/skills/comm-bridge/package.json +7 -3
- package/skills/comm-bridge/scripts/c4-receive.js +23 -2
- package/skills/scheduler/package.json +2 -2
- package/skills/web-console/SKILL.md +34 -0
- package/skills/web-console/package.json +2 -2
- package/skills/web-console/public/app.js +900 -4
- package/skills/web-console/public/index.html +126 -0
- package/skills/web-console/public/styles.css +130 -0
- package/skills/web-console/scripts/a2a-admin.js +506 -0
- package/skills/web-console/scripts/channel-admin.js +99 -16
- package/skills/web-console/scripts/server.js +386 -1
- package/skills/web-console/scripts/skill-catalog.js +179 -0
- package/templates/claude-system.md +22 -0
- package/templates/pm2/ecosystem.config.cjs +4 -1
- package/test/a2a-cli.test.js +180 -0
- package/test/agent-card-api.test.js +261 -0
- package/test/channel-admin.test.js +87 -0
- package/test/component-lock.test.js +216 -0
- package/test/skill-catalog.test.js +118 -0
- package/test/web-console-routes.test.js +488 -1
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# pack-release.sh — Baize A2A 套件私有交付打包脚本(D25 U4)
|
|
4
|
+
#
|
|
5
|
+
# 定位:baize-ai 根目录不是 git 仓库(aiagentpro 根仓库 .gitignore 忽略
|
|
6
|
+
# /baize-ai/),故本脚本随 baize-core 仓库维护,运行时自动定位 baize-ai 根。
|
|
7
|
+
#
|
|
8
|
+
# 产出(默认 dist = <baize-ai>/dist/):
|
|
9
|
+
# baize-a2a-<v>.tgz A2A channel 包(npm-pack 兼容结构:
|
|
10
|
+
# package/package.json 在包根,name=@baize-ai/baize-a2a;
|
|
11
|
+
# 兼容 web 控制台上传与 `baize add --file` 两种安装)
|
|
12
|
+
# baize-admin-workspace-<v>.tgz admin 套件源码:server 源码 + admin-ui 构建产物 +
|
|
13
|
+
# Dockerfile + 部署说明(自建镜像 / 自托管用)
|
|
14
|
+
# baize-admin-workspace-<v>.tar docker save 的 admin 镜像(docker load 直接运行,推荐)
|
|
15
|
+
# INSTALL.md 客户侧安装说明(上传 / --file 安装 + 切集群 + admin 部署)
|
|
16
|
+
#
|
|
17
|
+
# 用法:
|
|
18
|
+
# ./pack-release.sh [version] [dist-dir]
|
|
19
|
+
# version 版本号;缺省读取 baize-a2a/package.json 的 version
|
|
20
|
+
# dist-dir 输出目录;缺省 <baize-ai>/dist(可用环境变量 DIST_DIR 覆盖)
|
|
21
|
+
#
|
|
22
|
+
# 依赖:node/npm(a2a 包优先 npm pack)、docker(admin 镜像 docker save)、tar、jq
|
|
23
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
|
|
26
|
+
# ── 定位 baize-ai 根(本脚本位于 baize-ai/baize-core/scripts/)───────────────
|
|
27
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
|
+
BAIZE_AI_ROOT="${BAIZE_AI_ROOT:-$(cd "${SCRIPT_DIR}/../.." && pwd)}"
|
|
29
|
+
if [ ! -f "${BAIZE_AI_ROOT}/baize-a2a/package.json" ]; then
|
|
30
|
+
echo "!! 找不到 baize-ai 根目录(期望 ${BAIZE_AI_ROOT}/baize-a2a/package.json)" >&2
|
|
31
|
+
echo " 可设置 BAIZE_AI_ROOT 指向 baize-ai 目录" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
A2A_DIR="${BAIZE_AI_ROOT}/baize-a2a"
|
|
35
|
+
ADMIN_DIR="${BAIZE_AI_ROOT}/baize-admin-workspace"
|
|
36
|
+
|
|
37
|
+
# ── 版本 ────────────────────────────────────────────────────────────────────
|
|
38
|
+
VERSION="${1:-}"
|
|
39
|
+
if [ -z "${VERSION}" ]; then
|
|
40
|
+
VERSION="$(jq -r '.version' "${A2A_DIR}/package.json")"
|
|
41
|
+
fi
|
|
42
|
+
if [[ ! "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
43
|
+
echo "!! 非法版本号: ${VERSION}(期望形如 0.1.0)" >&2
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
# 套件版本一致性:显式版本必须与 a2a / admin 两个 package.json 的 version 一致,
|
|
47
|
+
# 否则产物 manifest 与文件名不符(npm pack 以 package.json 版本为准)。
|
|
48
|
+
for _pkg in "${A2A_DIR}/package.json" "${ADMIN_DIR}/package.json"; do
|
|
49
|
+
_pv="$(jq -r '.version' "${_pkg}")"
|
|
50
|
+
if [ "${_pv}" != "${VERSION}" ]; then
|
|
51
|
+
echo "!! 版本不一致: ${_pkg} 声明 ${_pv},请求打包 ${VERSION}" >&2
|
|
52
|
+
echo " 请先同步 package.json 版本,或省略版本参数使用默认版本(${_pv})" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
DIST_DIR="${DIST_DIR:-${BAIZE_AI_ROOT}/dist}"
|
|
58
|
+
if [ $# -ge 2 ] && [ -n "${2:-}" ]; then DIST_DIR="${2}"; fi
|
|
59
|
+
mkdir -p "${DIST_DIR}"
|
|
60
|
+
|
|
61
|
+
# 清理同版本旧产物,避免新旧混留
|
|
62
|
+
rm -f "${DIST_DIR}/baize-a2a-${VERSION}.tgz" \
|
|
63
|
+
"${DIST_DIR}/baize-admin-workspace-${VERSION}.tgz" \
|
|
64
|
+
"${DIST_DIR}/baize-admin-workspace-${VERSION}.tar"
|
|
65
|
+
|
|
66
|
+
TMP="$(mktemp -d "${TMPDIR:-/tmp}/pack-release.XXXXXX")"
|
|
67
|
+
CREATED_NPMIGNORE=0
|
|
68
|
+
cleanup() {
|
|
69
|
+
rm -rf "${TMP}"
|
|
70
|
+
if [ "${CREATED_NPMIGNORE}" = "1" ]; then
|
|
71
|
+
rm -f "${A2A_DIR}/.npmignore"
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
trap cleanup EXIT
|
|
75
|
+
|
|
76
|
+
log() { printf '%s\n' "$*"; }
|
|
77
|
+
step() { printf '\n==> %s\n' "$*"; }
|
|
78
|
+
size() { du -h "$1" | awk '{print $1}'; }
|
|
79
|
+
|
|
80
|
+
# ── 1. A2A channel 包 ───────────────────────────────────────────────────────
|
|
81
|
+
build_a2a_tgz() {
|
|
82
|
+
step "打包 A2A channel 包 v${VERSION}"
|
|
83
|
+
local out="${DIST_DIR}/baize-a2a-${VERSION}.tgz"
|
|
84
|
+
|
|
85
|
+
# 优先 npm pack:临时 .npmignore 限定包内容(结束后删除,不留在 a2a 仓库)
|
|
86
|
+
if command -v npm >/dev/null 2>&1; then
|
|
87
|
+
if [ ! -f "${A2A_DIR}/.npmignore" ]; then
|
|
88
|
+
cat > "${A2A_DIR}/.npmignore" <<'EOF'
|
|
89
|
+
test/
|
|
90
|
+
docs/
|
|
91
|
+
.npm-cache/
|
|
92
|
+
*.tgz
|
|
93
|
+
.gitignore
|
|
94
|
+
EOF
|
|
95
|
+
CREATED_NPMIGNORE=1
|
|
96
|
+
fi
|
|
97
|
+
if (cd "${A2A_DIR}" && npm pack --json --pack-destination "${TMP}" >"${TMP}/npm-pack.json" 2>"${TMP}/npm.err"); then
|
|
98
|
+
local packed
|
|
99
|
+
packed="$(jq -r '.[0].filename // empty' "${TMP}/npm-pack.json")"
|
|
100
|
+
if [ -n "${packed}" ] && [ -f "${TMP}/${packed}" ]; then
|
|
101
|
+
# npm ≥9 的 npm pack 默认不再包含 package-lock.json —— 补回(交付规范要求
|
|
102
|
+
# package-lock.json 随包,客户安装可离线 npm ci)
|
|
103
|
+
if ! tar -tzf "${TMP}/${packed}" | grep -q '^package/package-lock.json$'; then
|
|
104
|
+
log " npm pack 未含 package-lock.json,补回"
|
|
105
|
+
local fixdir="${TMP}/a2a-fix"
|
|
106
|
+
mkdir -p "${fixdir}"
|
|
107
|
+
tar -xzf "${TMP}/${packed}" -C "${fixdir}"
|
|
108
|
+
cp "${A2A_DIR}/package-lock.json" "${fixdir}/package/package-lock.json"
|
|
109
|
+
rm -f "${TMP}/${packed}"
|
|
110
|
+
tar -czf "${TMP}/${packed}" -C "${fixdir}" package
|
|
111
|
+
fi
|
|
112
|
+
mv "${TMP}/${packed}" "${out}"
|
|
113
|
+
log " npm pack → ${out} ($(size "${out}"))"
|
|
114
|
+
return 0
|
|
115
|
+
fi
|
|
116
|
+
log " npm pack 输出解析失败,降级手工打包"
|
|
117
|
+
else
|
|
118
|
+
log " npm pack 失败($(tail -1 "${TMP}/npm.err")),降级手工打包"
|
|
119
|
+
fi
|
|
120
|
+
else
|
|
121
|
+
log " npm 不可用,降级手工打包(结构一致)"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# 降级:tar 手工打包,结构与 npm pack 一致(package/ 前缀包装)
|
|
125
|
+
local stage="${TMP}/a2a-stage"
|
|
126
|
+
mkdir -p "${stage}/package"
|
|
127
|
+
cp -R "${A2A_DIR}/src" "${A2A_DIR}/scripts" "${stage}/package/"
|
|
128
|
+
cp "${A2A_DIR}/SKILL.md" "${A2A_DIR}/ecosystem.config.cjs" \
|
|
129
|
+
"${A2A_DIR}/package.json" "${A2A_DIR}/package-lock.json" "${stage}/package/"
|
|
130
|
+
if [ -f "${A2A_DIR}/README.md" ]; then
|
|
131
|
+
cp "${A2A_DIR}/README.md" "${stage}/package/"
|
|
132
|
+
fi
|
|
133
|
+
tar -czf "${out}" -C "${stage}" package
|
|
134
|
+
log " tar 打包 → ${out} ($(size "${out}"))"
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
# ── 2. Admin 套件源码 tgz ───────────────────────────────────────────────────
|
|
138
|
+
build_admin_tgz() {
|
|
139
|
+
step "打包 admin 套件源码 v${VERSION}"
|
|
140
|
+
local out="${DIST_DIR}/baize-admin-workspace-${VERSION}.tgz"
|
|
141
|
+
local stage="${TMP}/admin-stage/baize-admin-workspace-${VERSION}"
|
|
142
|
+
mkdir -p "${stage}"
|
|
143
|
+
|
|
144
|
+
cp "${ADMIN_DIR}/package.json" "${ADMIN_DIR}/package-lock.json" \
|
|
145
|
+
"${ADMIN_DIR}/Dockerfile" "${ADMIN_DIR}/README.md" "${stage}/"
|
|
146
|
+
cp -R "${ADMIN_DIR}/server" "${stage}/server" # server 源码(src + test)
|
|
147
|
+
cp -R "${ADMIN_DIR}/scripts" "${stage}/scripts"
|
|
148
|
+
mkdir -p "${stage}/admin-ui"
|
|
149
|
+
cp -R "${ADMIN_DIR}/admin-ui/dist" "${stage}/admin-ui/dist" # 构建产物
|
|
150
|
+
if [ -f "${ADMIN_DIR}/admin-ui/package.json" ]; then
|
|
151
|
+
cp "${ADMIN_DIR}/admin-ui/package.json" "${stage}/admin-ui/"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
tar -czf "${out}" -C "${TMP}/admin-stage" "baize-admin-workspace-${VERSION}"
|
|
155
|
+
log " → ${out} ($(size "${out}"))"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# ── 3. Admin Docker 镜像(docker save)──────────────────────────────────────
|
|
159
|
+
save_admin_image() {
|
|
160
|
+
step "导出 admin Docker 镜像"
|
|
161
|
+
local image="baize-admin-workspace:test"
|
|
162
|
+
if ! docker image inspect "${image}" >/dev/null 2>&1; then
|
|
163
|
+
echo "!! 镜像 ${image} 不存在(先构建:cd ${ADMIN_DIR} && docker build -t ${image} .)" >&2
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
local out="${DIST_DIR}/baize-admin-workspace-${VERSION}.tar"
|
|
167
|
+
docker save -o "${out}" "${image}"
|
|
168
|
+
log " docker save ${image} → ${out} ($(size "${out}"))"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# ── 4. INSTALL.md ───────────────────────────────────────────────────────────
|
|
172
|
+
write_install_md() {
|
|
173
|
+
step "生成 INSTALL.md"
|
|
174
|
+
local out="${DIST_DIR}/INSTALL.md"
|
|
175
|
+
cat > "${TMP}/INSTALL.md.tpl" <<'INSTALL_EOF'
|
|
176
|
+
# Baize A2A 套件安装说明(私有交付 v__VERSION__)
|
|
177
|
+
|
|
178
|
+
> 私有交付物:不通过 npm / 公开镜像分发,由厂商人工发放。
|
|
179
|
+
> 适用:安装 A2A 通道包(每实例组件)+ 部署 Admin 控制面(集群控制面)。
|
|
180
|
+
|
|
181
|
+
## 交付物清单
|
|
182
|
+
|
|
183
|
+
| 文件 | 用途 |
|
|
184
|
+
|------|------|
|
|
185
|
+
| `baize-a2a-__VERSION__.tgz` | A2A 通道包(channel)。安装到本机 baize 环境:web 控制台上传 或 `baize add --file` |
|
|
186
|
+
| `baize-admin-workspace-__VERSION__.tgz` | Admin 套件源码:server 源码 + admin-ui 构建产物 + Dockerfile + 部署说明(自建镜像 / 自托管用) |
|
|
187
|
+
| `baize-admin-workspace-__VERSION__.tar` | Admin Docker 镜像(docker save 产物):`docker load` 后直接运行(推荐) |
|
|
188
|
+
| `INSTALL.md` | 本说明 |
|
|
189
|
+
|
|
190
|
+
## 一、安装 A2A 通道包
|
|
191
|
+
|
|
192
|
+
### 方式 A:web 控制台上传(推荐)
|
|
193
|
+
|
|
194
|
+
1. 打开 Baize web 控制台,进入「A2A」页;
|
|
195
|
+
2. 在「模块安装」区选择 `baize-a2a-__VERSION__.tgz` 并上传;
|
|
196
|
+
3. 上传通过基础校验(manifest:package.json name=`@baize-ai/baize-a2a` + 版本;大小 / 路径穿越检查)后完成安装。
|
|
197
|
+
|
|
198
|
+
### 方式 B:CLI(baize add --file)
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
baize add a2a --file baize-a2a-__VERSION__.tgz
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
校验安装:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
baize a2a status
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 二、切集群(启用 A2A 互联)
|
|
211
|
+
|
|
212
|
+
### 方式 A:web 控制台
|
|
213
|
+
|
|
214
|
+
A2A 页「模式卡」→ 切换为集群 → 填写 `admin_url` / `advertise_url` → 确认。模式变为「集群·在线」。
|
|
215
|
+
|
|
216
|
+
### 方式 B:CLI
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
baize a2a enable --admin https://<admin主机>:<端口> --advertise https://<本机>:<端口>
|
|
220
|
+
baize a2a status # 期望:集群·在线
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
说明:
|
|
224
|
+
|
|
225
|
+
- `enable` = 切集群事务:写入 `mode: cluster` → 启动 daemon(PM2 优先,不可用则 nohup)→ TCP 就绪探测(≤30s)→ 注册 admin;
|
|
226
|
+
- 未配置证书时自动生成自签证书(SAN 含 advertise_url 主机名 + 127.0.0.1 + localhost);
|
|
227
|
+
- 任一步失败自动回滚为单机模式,本地能力不受影响。
|
|
228
|
+
|
|
229
|
+
### 切回单机
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
baize a2a disable # 停 daemon,保留配置与注册数据,模式回 standalone
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 三、部署 Admin(控制面)
|
|
236
|
+
|
|
237
|
+
### 方式 A:Docker 镜像(推荐)
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
docker load -i baize-admin-workspace-__VERSION__.tar
|
|
241
|
+
docker run -d --name baize-admin -p 8080:8080 \
|
|
242
|
+
-v baize-admin-data:/data \
|
|
243
|
+
-e BAIZE_ADMIN_TOKEN='<初始口令>' \
|
|
244
|
+
baize-admin-workspace:test
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
- 访问 `http://<主机>:8080`,首次登录:`admin` + 初始口令(日志打印或 `BAIZE_ADMIN_TOKEN`);
|
|
248
|
+
- 登录后立即修改口令;数据全部落在 `/data` 卷(SQLite 库与签名密钥),务必持久化;
|
|
249
|
+
- 公网部署建议放在 HTTPS 反代后面,`baize a2a enable --admin` 使用对外 HTTPS 地址。
|
|
250
|
+
|
|
251
|
+
### 方式 B:源码套件(自建镜像 / 自托管)
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
tar xzf baize-admin-workspace-__VERSION__.tgz
|
|
255
|
+
cd baize-admin-workspace-__VERSION__
|
|
256
|
+
docker build -t baize-admin-workspace . # 多阶段:node:22 构建 admin-ui → node:22-slim 运行
|
|
257
|
+
docker run -d --name baize-admin -p 8080:8080 -v baize-admin-data:/data baize-admin-workspace
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- 本地运行:`npm ci && npm start`(Node ≥ 20.11,默认 8080);
|
|
261
|
+
- 前端构建产物已含在 `admin-ui/dist`(容器内 `/app/dist`),可与 API 同源静态提供。
|
|
262
|
+
|
|
263
|
+
## 四、卸载
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
baize a2a disable # 先切回单机 / 停服务
|
|
267
|
+
baize uninstall a2a confirm
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 五、常见问题
|
|
271
|
+
|
|
272
|
+
- **上传校验失败**(manifest / 大小 / 路径穿越):确认使用的是厂商交付的原包 `baize-a2a-__VERSION__.tgz`,未被篡改;
|
|
273
|
+
- **enable 失败**:daemon 起不来或注册 admin 失败会自动回滚单机;查看 `baize a2a status` 与 daemon 日志;
|
|
274
|
+
- **admin 无法连接**:确认 admin 已部署(`/healthz` 可访问)、`--admin` 地址与端口正确、网络互通。
|
|
275
|
+
INSTALL_EOF
|
|
276
|
+
sed "s/__VERSION__/${VERSION}/g" "${TMP}/INSTALL.md.tpl" > "${out}"
|
|
277
|
+
log " → ${out}"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# ── 5. 产物校验 ─────────────────────────────────────────────────────────────
|
|
281
|
+
verify() {
|
|
282
|
+
step "校验产物"
|
|
283
|
+
local rc=0
|
|
284
|
+
local a2a_tgz="${DIST_DIR}/baize-a2a-${VERSION}.tgz"
|
|
285
|
+
local admin_tgz="${DIST_DIR}/baize-admin-workspace-${VERSION}.tgz"
|
|
286
|
+
local admin_tar="${DIST_DIR}/baize-admin-workspace-${VERSION}.tar"
|
|
287
|
+
|
|
288
|
+
# A2A tgz:可解压 + package.json 存在且 name/version 正确 + 关键文件齐全
|
|
289
|
+
if tar -tzf "${a2a_tgz}" >/dev/null 2>&1 \
|
|
290
|
+
&& tar -tzf "${a2a_tgz}" | grep -q '^package/package.json$' \
|
|
291
|
+
&& [ "$(tar -xOzf "${a2a_tgz}" package/package.json 2>/dev/null | jq -r '.name // empty')" = "@baize-ai/baize-a2a" ] \
|
|
292
|
+
&& [ "$(tar -xOzf "${a2a_tgz}" package/package.json 2>/dev/null | jq -r '.version // empty')" = "${VERSION}" ]; then
|
|
293
|
+
local entries
|
|
294
|
+
entries="$(tar -tzf "${a2a_tgz}" | tr '\n' ' ')"
|
|
295
|
+
local missing=0
|
|
296
|
+
for f in package/SKILL.md package/ecosystem.config.cjs package/package-lock.json package/scripts/cli.js; do
|
|
297
|
+
case " ${entries} " in
|
|
298
|
+
*" ${f} "*) ;;
|
|
299
|
+
*) echo " !! ${a2a_tgz} 缺少 ${f}" >&2; missing=1 ;;
|
|
300
|
+
esac
|
|
301
|
+
done
|
|
302
|
+
if [ "${missing}" = "0" ]; then
|
|
303
|
+
log " OK ${a2a_tgz} ($(size "${a2a_tgz}")) 解压 OK · name=@baize-ai/baize-a2a · version=${VERSION}"
|
|
304
|
+
else
|
|
305
|
+
rc=1
|
|
306
|
+
fi
|
|
307
|
+
else
|
|
308
|
+
echo " !! ${a2a_tgz} 校验失败(解压或 manifest 不正确)" >&2
|
|
309
|
+
rc=1
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
# Admin 套件 tgz:可解压 + package.json 存在且 name 正确 + 关键文件齐全
|
|
313
|
+
local admin_ent
|
|
314
|
+
admin_ent="baize-admin-workspace-${VERSION}"
|
|
315
|
+
if tar -tzf "${admin_tgz}" >/dev/null 2>&1 \
|
|
316
|
+
&& tar -tzf "${admin_tgz}" | grep -q "^${admin_ent}/package.json$" \
|
|
317
|
+
&& [ "$(tar -xOzf "${admin_tgz}" "${admin_ent}/package.json" 2>/dev/null | jq -r '.name // empty')" = "@baize-ai/baize-admin-workspace" ]; then
|
|
318
|
+
local a_entries missing2=0
|
|
319
|
+
a_entries="$(tar -tzf "${admin_tgz}" | tr '\n' ' ')"
|
|
320
|
+
for f in "${admin_ent}/Dockerfile" "${admin_ent}/README.md" "${admin_ent}/server/src/index.js" "${admin_ent}/admin-ui/dist/index.html"; do
|
|
321
|
+
case " ${a_entries} " in
|
|
322
|
+
*" ${f} "*) ;;
|
|
323
|
+
*) echo " !! ${admin_tgz} 缺少 ${f}" >&2; missing2=1 ;;
|
|
324
|
+
esac
|
|
325
|
+
done
|
|
326
|
+
if [ "${missing2}" = "0" ]; then
|
|
327
|
+
log " OK ${admin_tgz} ($(size "${admin_tgz}")) 解压 OK · name=@baize-ai/baize-admin-workspace"
|
|
328
|
+
else
|
|
329
|
+
rc=1
|
|
330
|
+
fi
|
|
331
|
+
else
|
|
332
|
+
echo " !! ${admin_tgz} 校验失败(解压或 manifest 不正确)" >&2
|
|
333
|
+
rc=1
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
# docker save 产物:存在且非空
|
|
337
|
+
if [ -s "${admin_tar}" ]; then
|
|
338
|
+
log " OK ${admin_tar} ($(size "${admin_tar}")) 存在且非空"
|
|
339
|
+
else
|
|
340
|
+
echo " !! ${admin_tar} 不存在或为空" >&2
|
|
341
|
+
rc=1
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
[ -f "${DIST_DIR}/INSTALL.md" ] && log " OK ${DIST_DIR}/INSTALL.md ($(size "${DIST_DIR}/INSTALL.md"))"
|
|
345
|
+
return "${rc}"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
# ── 执行 ────────────────────────────────────────────────────────────────────
|
|
349
|
+
log "Baize A2A 套件私有交付打包"
|
|
350
|
+
log " 版本: ${VERSION} 输出: ${DIST_DIR}"
|
|
351
|
+
build_a2a_tgz
|
|
352
|
+
build_admin_tgz
|
|
353
|
+
save_admin_image
|
|
354
|
+
write_install_md
|
|
355
|
+
verify
|
|
356
|
+
|
|
357
|
+
step "完成 — 交付物清单(${DIST_DIR})"
|
|
358
|
+
ls -lh "${DIST_DIR}"/baize-a2a-"${VERSION}".tgz \
|
|
359
|
+
"${DIST_DIR}"/baize-admin-workspace-"${VERSION}".tgz \
|
|
360
|
+
"${DIST_DIR}"/baize-admin-workspace-"${VERSION}".tar \
|
|
361
|
+
"${DIST_DIR}"/INSTALL.md
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
"init": "node scripts/c4-db.js init",
|
|
9
9
|
"test": "node --test scripts/__tests__/*.test.js"
|
|
10
10
|
},
|
|
11
|
-
"keywords": [
|
|
11
|
+
"keywords": [
|
|
12
|
+
"baize",
|
|
13
|
+
"ai-agent",
|
|
14
|
+
"communication"
|
|
15
|
+
],
|
|
12
16
|
"author": "Baize AI",
|
|
13
17
|
"license": "Apache-2.0",
|
|
14
18
|
"dependencies": {
|
|
15
|
-
"better-sqlite3": "^
|
|
19
|
+
"better-sqlite3": "^13.0.3"
|
|
16
20
|
}
|
|
17
|
-
}
|
|
21
|
+
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
25
|
const __dirname = path.dirname(__filename);
|
|
26
26
|
const AM_SOCKET_PATH = path.join(ACTIVITY_MONITOR_DIR, 'am.sock');
|
|
27
|
-
const ROUTER_IPC_TIMEOUT_MS =
|
|
27
|
+
const ROUTER_IPC_TIMEOUT_MS = 3000;
|
|
28
28
|
const STATUS_NOTICE_COOLDOWN_SECONDS = Number.parseInt(process.env.C4_STATUS_NOTICE_COOLDOWN_SECONDS || '600', 10);
|
|
29
29
|
|
|
30
30
|
function printUsage() {
|
|
@@ -346,7 +346,28 @@ async function main() {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
|
|
349
|
+
// Route decision via activity-monitor IPC; on IPC failure/timeout degrade to
|
|
350
|
+
// the local health file (readHealthStatusFile) instead of blocking intake for
|
|
351
|
+
// ROUTER_IPC_TIMEOUT_MS — a slow/unresponsive monitor must not stall message
|
|
352
|
+
// delivery to C4 (D21 container test: monitor IPC took 19-25s without Claude
|
|
353
|
+
// auth, stalling every inbound message past the 20s c4-receive timeout).
|
|
354
|
+
let route;
|
|
355
|
+
try {
|
|
356
|
+
route = await queryRoute(channel, endpoint, noReply);
|
|
357
|
+
} catch {
|
|
358
|
+
const status = readHealthStatusFile();
|
|
359
|
+
const health = publicHealth(status?.health);
|
|
360
|
+
route =
|
|
361
|
+
health === 'ok'
|
|
362
|
+
? { recovered: true, health: 'ok', fallback: true }
|
|
363
|
+
: {
|
|
364
|
+
recovered: false,
|
|
365
|
+
health,
|
|
366
|
+
reason: status?.unavailable_reason || health,
|
|
367
|
+
userMessage: buildFallbackMessage(status),
|
|
368
|
+
fallback: true,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
350
371
|
const replyEndpoint = noReply ? null : endpoint;
|
|
351
372
|
let dbContent = content;
|
|
352
373
|
const dbStatus = route.recovered ? 'pending' : 'delivered';
|
|
@@ -60,6 +60,40 @@ Browser ──► Web Console Server ──► C4 Bridge ──► Claude
|
|
|
60
60
|
| `/api/poll?since_id=N` | GET | Poll for new messages |
|
|
61
61
|
| `/api/health` | GET | Server health check |
|
|
62
62
|
|
|
63
|
+
## A2A Admin (agent card + call authorization)
|
|
64
|
+
|
|
65
|
+
The web console also hosts the A2A admin surface (identity registration, peer
|
|
66
|
+
directory, task board, message log). Agent card and call-authorization policy
|
|
67
|
+
are persisted in the same `config.json` the baize-a2a daemon reads
|
|
68
|
+
(`BAIZE_A2A_CONFIG`, default `~/baize/components/a2a/config.json`; polled every
|
|
69
|
+
3s → hot reload).
|
|
70
|
+
|
|
71
|
+
| Endpoint | Method | Description |
|
|
72
|
+
|----------|--------|-------------|
|
|
73
|
+
| `/api/admin/a2a/card` | GET/PUT | Agent card (name / description / skills) |
|
|
74
|
+
| `/api/admin/a2a/card/skills` | GET | Installed skill catalogue for the card |
|
|
75
|
+
| `/api/admin/a2a/authz` | GET/PUT | Call-authorization policy (see below) |
|
|
76
|
+
|
|
77
|
+
### Authz policy semantics
|
|
78
|
+
|
|
79
|
+
```jsonc
|
|
80
|
+
// config.json "authz" field
|
|
81
|
+
"authz": {
|
|
82
|
+
"mode": "open", // "open" | "allowlist"
|
|
83
|
+
"allow": ["<agent_id>"], // allowlist mode: peers allowed to call
|
|
84
|
+
"block": ["<agent_id>"] // open mode: peers blocked from calling
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- `open` (default): accept every approved agent except the `block` list.
|
|
89
|
+
- `allowlist`: only the `allow` list may call (empty list = nobody may call).
|
|
90
|
+
- The check applies to calls from other agents (message/task/cancel); query
|
|
91
|
+
endpoints keep their existing caller matching.
|
|
92
|
+
- `PUT /api/admin/a2a/authz` validates: `mode` must be `open` or `allowlist`;
|
|
93
|
+
`allow`/`block` must be arrays of non-empty strings (entries are trimmed and
|
|
94
|
+
deduplicated; duplicates/empty/whitespace entries are rejected with 400).
|
|
95
|
+
Other `config.json` fields are preserved.
|
|
96
|
+
|
|
63
97
|
## Files
|
|
64
98
|
|
|
65
99
|
```
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"start": "node server.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"better-sqlite3": "^
|
|
11
|
+
"better-sqlite3": "^13.0.3",
|
|
12
12
|
"dotenv": "^16.6.1",
|
|
13
13
|
"express": "^4.18.2",
|
|
14
14
|
"multer": "^2.1.1",
|
|
@@ -18,4 +18,4 @@
|
|
|
18
18
|
"path-to-regexp": "0.1.13",
|
|
19
19
|
"qs": "6.15.2"
|
|
20
20
|
}
|
|
21
|
-
}
|
|
21
|
+
}
|