@baize-ai/core 0.3.12 → 0.3.14

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/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to baize-core will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.14] - 2026-08-30
9
+
10
+ ### Fixed
11
+ - A2A 容器重启自愈(D48):entrypoint 检查 A2A config.enabled → 自动启动 baize-a2a daemon——容器重启后 A2A 零手动恢复
12
+ - Web A2A 状态卡证书徽章(D48):显示证书链状态(certValid)——daemon 在线时"自动处理中"、离线时提示"待续签"
13
+
14
+ ## [0.3.13] - 2026-08-28
15
+
16
+ ### Fixed
17
+ - A2A 上传安装后自动 rebuild 原生模块(D44):上传安装用 --ignore-scripts(vendor 包安全),better-sqlite3 等 native 模块不编译 → 上传后 A2A 状态加载失败;安装流程现追加 `npm rebuild --build-from-source`(只编译、不跑 vendor 脚本),失败回滚
18
+ - Docker 镜像 npm 源修复(D43):容器 npm 运行时是 baize 用户(prefix /home/baize/.npm-global)——镜像只写了 /usr/etc/npmrc(root 视角)npm 不读 → ACR 镜像 npm 仍走 npmjs;现同时写 /home/baize/.npmrc(优先级最高必读)
19
+
8
20
  ## [0.3.12] - 2026-08-28
9
21
 
10
22
  ### Added
package/Dockerfile CHANGED
@@ -55,6 +55,10 @@ RUN if [ "${BAIZE_NPM_MIRROR:-off}" = "aliyun" ]; then \
55
55
  # Also drop a system-wide npmrc so the runtime user (baize) and any
56
56
  # docker exec npm use the mainland mirror too.
57
57
  mkdir -p /usr/etc && printf 'registry=https://registry.npmmirror.com\n' > /usr/etc/npmrc; \
58
+ # Container npm runs as USER baize with prefix /home/baize/.npm-global —
59
+ # its globalconfig is NOT /usr/etc/npmrc, so also write the user-level
60
+ # ~/.npmrc (highest precedence, always read) or npm stays on npmjs.
61
+ mkdir -p /home/baize && printf 'registry=https://registry.npmmirror.com\n' > /home/baize/.npmrc; \
58
62
  fi
59
63
  RUN npm install -g pm2@latest
60
64
 
@@ -153,6 +153,27 @@ PM2_PID=$!
153
153
  sleep 3
154
154
  ok "Services started"
155
155
 
156
+ # ── Step 3b: A2A self-heal (D48) ─────────────────────────────────────────────
157
+ # After a container restart, a previously-enabled A2A component must come back
158
+ # up by itself (zero manual ops). If the A2A config says enabled, start the
159
+ # baize-a2a daemon — it registers/renews its certificate with the admin and
160
+ # serves the advertise port. Idempotent: pm2 start restarts an existing entry.
161
+ if [ -f "${BAIZE_DIR}/components/a2a/config.json" ]; then
162
+ A2A_ENABLED=$(node -e "
163
+ try {
164
+ const c = JSON.parse(require('fs').readFileSync('${BAIZE_DIR}/components/a2a/config.json','utf8'));
165
+ process.stdout.write(c.enabled ? '1' : '0');
166
+ } catch { process.stdout.write('0'); }
167
+ " 2>/dev/null || echo "0")
168
+ if [ "$A2A_ENABLED" = "1" ]; then
169
+ ok "A2A enabled — starting baize-a2a daemon"
170
+ ( cd "${BAIZE_DIR}/.claude/skills/a2a" && pm2 start ecosystem.config.cjs >/dev/null 2>&1 ) || \
171
+ warn "A2A daemon start failed — check 'docker exec <c> pm2 logs baize-a2a'"
172
+ fi
173
+ fi
174
+
175
+ # ── Step 4: Start the configured agent runtime in tmux ───────────────────────
176
+
156
177
  # ── Step 4: Start the configured agent runtime in tmux ───────────────────────
157
178
  # Determine runtime: BAIZE_RUNTIME env var always wins; fall back to config.json.
158
179
  if [ -z "${BAIZE_RUNTIME:-}" ]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baize-ai/core",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "type": "module",
5
5
  "description": "Baize (\u767d\u6cfd) \u2014 autonomous AI agent infrastructure",
6
6
  "main": "cli/baize.js",
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env bash
2
2
  # Multi-platform build + push to Aliyun ACR for the mainland distribution.
3
- # Usage: bash build-push-acr.sh [VERSION] (default 0.3.11)
3
+ # Usage: bash build-push-acr.sh [VERSION] (default = latest published)
4
+ # IMPORTANT: bump this default when a new version is published — it must
5
+ # track @baize-ai/core latest (never point at an un-released version).
4
6
  # Requires: docker login already done, qemu-arm64 registered
5
7
  # (apt install qemu-user-binfmt), registry mirror configured.
6
8
  set -euo pipefail
7
9
 
8
- VERSION="${1:-0.3.11}"
10
+ VERSION="${1:-0.3.13}"
9
11
  ACR="crpi-8bg62qbrjs3cr3as.cn-hangzhou.personal.cr.aliyuncs.com/baize01/baize-core"
10
12
 
11
13
  echo "== Configure buildkit registry mirror (mainland Docker Hub access) =="
@@ -35,6 +35,10 @@ docker build \
35
35
  -t "${GHCR_IMAGE}:${VERSION}" \
36
36
  -t "${GHCR_IMAGE}:latest" \
37
37
  .
38
+ "${BUILD_ARGS[@]}" \
39
+ -t "${GHCR_IMAGE}:${VERSION}" \
40
+ -t "${GHCR_IMAGE}:latest" \
41
+ .
38
42
 
39
43
  if [ -n "${ACR_REGISTRY}" ] && [ -n "${ACR_NAMESPACE}" ]; then
40
44
  ACR_IMAGE="${ACR_REGISTRY}/${ACR_NAMESPACE}/baize-core"
@@ -1655,6 +1655,19 @@ async function loadA2aStatus(basePath) {
1655
1655
  state.textContent = enabled ? '已启用' : '未启用';
1656
1656
  state.className = `channel-state ${enabled ? 'ok' : 'warn'}`;
1657
1657
  }
1658
+ // D48: certificate health — the daemon self-heals (re-registers) when the
1659
+ // admin rotated its CA. Only claim "auto-healing" when the daemon is
1660
+ // actually alive to run the 5-min renewal check; otherwise the user must
1661
+ // act (daemon down / renewals exhausted).
1662
+ const certValid = body.certValid === true;
1663
+ const daemonUp = body.daemonHealthy === true;
1664
+ let certLabel = '正常';
1665
+ if (!certValid) {
1666
+ certLabel = daemonUp ? '需续签(自动处理中)' : '证书待续签(daemon 未运行)';
1667
+ }
1668
+ const certRow = body.enabled === true
1669
+ ? `<div class="conn-summary-row"><span class="conn-summary-name">证书状态</span><span class="conn-summary-detail"><span class="channel-state ${certValid ? 'ok' : 'warn'}">${certLabel}</span></span></div>`
1670
+ : '';
1658
1671
  const rows = [
1659
1672
  ['启用', enabled ? '是' : '否'],
1660
1673
  ['Agent ID', body.agentId],
@@ -1664,7 +1677,7 @@ async function loadA2aStatus(basePath) {
1664
1677
  ['Endpoint', body.endpoint],
1665
1678
  ['版本', body.version],
1666
1679
  ].filter(([, v]) => v !== undefined && v !== null && v !== '');
1667
- el.innerHTML = rows.map(([k, v]) => `<div class="conn-summary-row"><span class="conn-summary-name">${escapeHtml(k)}</span><span class="conn-summary-detail">${escapeHtml(String(v))}</span></div>`).join('');
1680
+ el.innerHTML = rows.map(([k, v]) => `<div class="conn-summary-row"><span class="conn-summary-name">${escapeHtml(k)}</span><span class="conn-summary-detail">${escapeHtml(String(v))}</span></div>`).join('') + certRow;
1668
1681
  updateA2aInstallArea(body);
1669
1682
  updateA2aModeCard(body);
1670
1683
  updateA2aConfigArea(body);
@@ -328,6 +328,39 @@ function npmInstallDeps(cwd) {
328
328
  });
329
329
  }
330
330
 
331
+ /** Rebuild native modules after --ignore-scripts install (D44).
332
+ * --ignore-scripts skips postinstall, so better-sqlite3 etc. never compile
333
+ * their native binary. Rebuilding runs node-gyp only (no vendor lifecycle
334
+ * scripts) — the security stance is kept while the module becomes loadable. */
335
+ function rebuildNativeDeps(cwd) {
336
+ return new Promise((resolve) => {
337
+ const child = spawn('npm', ['rebuild', '--build-from-source', '--no-audit', '--no-fund'], {
338
+ cwd, env: { ...process.env }, stdio: ['ignore', 'pipe', 'pipe'],
339
+ });
340
+ let stderr = '';
341
+ let settled = false;
342
+ child.stderr.on('data', (d) => { stderr += String(d); });
343
+ const timer = setTimeout(() => {
344
+ if (settled) return;
345
+ settled = true;
346
+ child.kill('SIGTERM');
347
+ resolve({ ok: false, error: `npm rebuild 超时(${Math.round(NPM_INSTALL_TIMEOUT_MS / 1000)}s)` });
348
+ }, NPM_INSTALL_TIMEOUT_MS);
349
+ child.on('error', (err) => {
350
+ if (settled) return;
351
+ settled = true;
352
+ clearTimeout(timer);
353
+ resolve({ ok: false, error: err.message });
354
+ });
355
+ child.on('close', (code) => {
356
+ if (settled) return;
357
+ settled = true;
358
+ clearTimeout(timer);
359
+ resolve(code === 0 ? { ok: true } : { ok: false, error: (stderr.trim() || `exit ${code}`).slice(-500) });
360
+ });
361
+ });
362
+ }
363
+
331
364
  /**
332
365
  * Install @baize-ai/baize-a2a from an uploaded .tar.gz (D25 私有交付).
333
366
  * Pipeline: entry listing + path-safety vetting (no `..`/absolute/links) →
@@ -342,6 +375,7 @@ export async function installA2aTarball(tarballPath, {
342
375
  skillsDir = defaultSkillsDir(),
343
376
  componentsFile: componentsPath = componentsFile(),
344
377
  installDeps = npmInstallDeps,
378
+ rebuildDeps = rebuildNativeDeps,
345
379
  originalName = null,
346
380
  } = {}) {
347
381
  const file = String(tarballPath || '');
@@ -401,6 +435,13 @@ export async function installA2aTarball(tarballPath, {
401
435
  fs.rmSync(targetDir, { recursive: true, force: true });
402
436
  return { ok: false, error: `npm install 失败: ${depResult.error}` };
403
437
  }
438
+ // D44: --ignore-scripts skipped native compilation — rebuild modules so
439
+ // better-sqlite3 etc. are loadable (node-gyp only, no vendor scripts).
440
+ const rebuildResult = await rebuildDeps(targetDir);
441
+ if (!rebuildResult.ok) {
442
+ fs.rmSync(targetDir, { recursive: true, force: true });
443
+ return { ok: false, error: `native 模块重建失败: ${rebuildResult.error}` };
444
+ }
404
445
  const components = readComponents(componentsPath);
405
446
  components.a2a = {
406
447
  version: pkg.version,