Files
apes-sidebar/scripts/e2e-aggregate-mount.sh
T
figmar 5a7e2139a0 chore(sync): re-base the fork onto upstream dsh-better-sidebar v0.19.1
The fork was pinned at upstream v0.18.0. That is the entire reason the window
ran TWO sidebars and TWO near-identical panel toggles: DSH 2.0.10 ships its own
right sidebar (@deepseek-ai/dsh-client-ui-sidebar-right), and upstream only
adopted it in v0.19.0-alpha.1 — which arrived after our fork point. v0.19.1 is
also the one upstream line whose support range actually matches our host
(engines.dsh >=0.1.5-rc.1, 14 DSH peers ^0.1.5-rc.1, host = 0.1.5-rc.2), so it
is the only tag the host's startup precheck accepts.

What upstream v0.18.0 → v0.19.1 brings
- src/client/native/{index,surface,tab-adapter}.tsx: every tab the plugin can
  draw becomes an OFFICIAL native tab type + body, and an external plugin's
  descriptor registered later gets its native type too. This is what retires
  the fork's own right panel — and with it the duplicate toggle cluster
  (`toggleCluster` is gone from v0.19.1).
- native tab-chip icons via the `sidebar.right.pane.tab.title` seat, coloured
  built-in tab icons, file/folder glyphs from DSH's own `FileTypeIcon`.
- guide descriptions (DSH renders them while the guide lists <= 4 entries),
  tab bodies that fill the panel, and the 0.1.5-rc.2 adaptation work we were
  carrying by hand (peer/devDep pinning, primitives' transitive devDeps).

How the sync was done
Rebuilt the tree from the v0.19.1 tag rather than resolving 53 conflicted
files: our v0.18.0 delta was measured first and is only (a) one mechanical
rename `dsh-better-sidebar` -> `dsh-apes-sidebar` and (b) ten real edits. So:
tag tree + rename (scoped: code/config/scripts/tests/README, while the 46
historical docs/plans records and switch.sh's upstream package name stay
untouched) + re-applied deltas + our apes module.

Fork deltas re-applied on the new base
- src/client/apes/ (icons / locales / tabs): the three apes:* information-layer
  tabs (agents / apps / profile), registered through the same BetterSidebarService
  as the builtins — which is exactly why they now ride upstream's native adapter
  into the official sidebar for free.
- identity: package.json (name/version 1.2.0/description/forkedFrom), dsh.plugin.json
  (id/version), SIDEBAR_SERVICE_VERSION 1.2.0, README fork notice,
  docs/external-plugin-guide.md.
- scripts/switch.sh + the pnpm switch* scripts (apes <-> upstream two-line switch).
- tests/apes-tabs.spec.ts (unescaped: it starts from the v0.19.1 base).

Dropped
- the Phase A native-registration spike (`apes/native-tabs.tsx` + its spec): it
  re-derived by hand exactly what upstream's native layer already does — the
  hand-written bridge is dead weight now, and v0.19.1's own e2e/jsdom lanes
  cover the same seat contract far better.
- the unused apesProfileGuideDesc key and the two package.json.bak.* backups.

Verified on the new base: typecheck clean; build clean; 1351 passed / 9 skipped
(128 files), up from 1255 on the old base.
2026-10-03 22:51:09 +08:00

125 lines
6.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# =============================================================================
# dsh-apes-sidebar 聚合双挂载冒烟(CI + 本地):
#
# 场景:一个聚合 bundle(tests/fixtures/aggregate-better-sidebar)先以独立
# 条目 id 挂载 dsh-apes-sidebar,插件自身的 bundle patch 后到 —— 旧行为
# 两个实例都注册 /sidebar/api,整个插件树启动失败(duplicate prefix
# route);新行为插件行检测到已有启用中的同包名挂载后自动 disabled,由
# 聚合行接管 sidebar。
#
# 流程:
# 1. 打包 fixture 聚合包;
# 2. 用官方 CLI 把 fixture 先装进全新 scratch profile,再把插件 tarball
# 装进同一 profile(复刻真实安装顺序:聚合先行、dsh plugin add 后到);
# 3. 启动真实 `dsh web`(keyless,--port 0);
# 4. 断言:日志出现启动 URL、无 "duplicate prefix route"、/sidebar/api
# 路由存活(POST 未知方法应返回 404 JSON 而非崩溃)。
#
# 用法:
# bash scripts/e2e-aggregate-mount.sh
#
# 环境变量(均可省略):
# DSH_CMD dsh 命令;缺省 PATH 上的 `dsh`,回退 npx 拉官方包
# (同 e2e-mount.sh)
# TARBALL 插件 tarball;缺省仓库根 dsh-apes-sidebar-*.tgz(须已 pack)
# PORT 固定端口(默认 0 = OS 分配,从日志解析 URL)
# DSH_HOME_BASE scratch 根目录(默认系统临时目录)。脚本始终在其下新建
# 本调用拥有的独立子目录,只写入/删除该子目录;调用方提供
# 的目录本身(可能是真实 ~/.dsh)绝不写入或删除。
# KEEP_HOME 非空时保留 scratch 目录(调试用)
#
# 退出码 = 0 通过;非 0 失败。服务器与 scratch 目录由 trap 兜底清理。
# 日志/前置校验/DSH_CMD 与 tarball 解析/scratch profile 三件套/清理 trap/
# dsh web 启动与就绪轮询的共享骨架见 scripts/e2e-common.sh。
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
FIXTURE_DIR="$ROOT/tests/fixtures/aggregate-better-sidebar"
E2E_TAG=e2e-aggregate-mount
source "$SCRIPT_DIR/e2e-common.sh"
DSH_CMD="${DSH_CMD:-dsh}"
TARBALL="${TARBALL:-}"
PORT="${PORT:-0}"
KEEP_HOME="${KEEP_HOME:-}"
e2e_require_cmd node "DSH 运行需要 Node.js >= 20"
e2e_require_cmd pnpm "dsh plugin 转发给 pnpm"
e2e_require_cmd npm "打包 fixture 需要"
e2e_require_cmd curl
e2e_resolve_dsh_cmd
e2e_resolve_tarball || die "未找到插件 tarball:先在本仓库跑 pnpm build && npm pack,或用 TARBALL 指定"
# ── scratch home ────────────────────────────────────────────────────────────
# DSH_HOME 直接用 $SCRATCH(mount lane 用子路径 home/——两 lane 既有差异);
# DSH_HOME_BASE 语义与清理 trap 见 e2e-common.sh。
e2e_make_scratch dsh-e2e-agg
export DSH_HOME="$SCRATCH"
LOG_DIR="$DSH_HOME/logs"; mkdir -p "$LOG_DIR"
OUT_LOG="$LOG_DIR/dsh-web.out.log"; ERR_LOG="$LOG_DIR/dsh-web.err.log"
SERVER_PID=""
TMP_DIR=""
trap e2e_cleanup EXIT
# ── 打包 fixture 聚合包 ─────────────────────────────────────────────────────
TMP_DIR="$(mktemp -d)"
( cd "$FIXTURE_DIR" && npm pack --silent --pack-destination "$TMP_DIR" >/dev/null )
FIXTURE_TGZ="$(ls "$TMP_DIR"/*.tgz 2>/dev/null | head -1 || true)"
[ -n "$FIXTURE_TGZ" ] || die "fixture 打包失败"
# ── 引导 scratch profile(web 模板)────────────────────────────────────────
# 三件套 heredoc 及 pnpm-workspace 的 allowBuilds / minimumReleaseAgeExclude
# 理由见 e2e-common.sh 的 e2e_write_profile。
PROFILE_DIR="$DSH_HOME/profiles/web"
e2e_write_profile "$PROFILE_DIR"
# ── 组装 profile:聚合先行,插件后到 ──────────────────────────────────────
say "安装 fixture 聚合包(先行)…"
$DSH_CMD plugin --profile web add "file:$FIXTURE_TGZ"
say "安装插件 tarball(后到)…"
$DSH_CMD plugin --profile web add "file:$TARBALL"
# ── 启动真实 dsh web ───────────────────────────────────────────────────────
say "启动 dsh web(--port ${PORT},日志 ${LOG_DIR})…"
e2e_start_dsh_web "$OUT_LOG" "$ERR_LOG"
# 等待启动 URL 或进程退出(最多 120s)。这里有意只取 origin:0.1.2-alpha.1+
# 的就绪行是 `…/?token=<43字符>` 鉴权 URL,但下方的探活全部打插件的
# /sidebar/api/* 路由——webserver carrier 不做鉴权(只有 /api、index 与
# remote.mux 升级在 browser auth 之后),origin 拼路径即正确且两版通用。
E2E_READY_RE='http://127\.0\.0\.1:[0-9]+'
E2E_READY_PICK=tail
e2e_wait_dsh_web_ready "$OUT_LOG" || true
if [ -z "$URL" ]; then
warn "out log 尾部:$(tail -5 "$OUT_LOG" 2>/dev/null || true)"
warn "err log 尾部:$(tail -5 "$ERR_LOG" 2>/dev/null || true)"
die "dsh web 未在 120s 内启动"
fi
say "已启动:$URL"
# ── 断言 ────────────────────────────────────────────────────────────────────
if grep -q "duplicate prefix route" "$ERR_LOG" "$OUT_LOG" 2>/dev/null; then
die "检测到 duplicate prefix route(双挂载未退让)"
fi
# 真实方法探活:terminal.deps 是插件自己的 handler(writeOk → HTTP 200 +
# {"ok":true,...})。成功响应证明至少一个实例真正注册了 /sidebar/api 路由
# ——generic missing-route 404 无法冒充(P2: Probe a real sidebar API method)。
DEPS="$(curl -s -X POST "$URL/sidebar/api/terminal.deps" 2>/dev/null || true)"
if ! printf '%s' "$DEPS" | grep -q '"ok":true'; then
die "/sidebar/api/terminal.deps 未返回 ok:true(响应:$(printf '%s' "$DEPS" | head -c 200))"
fi
say "/sidebar/api/terminal.deps → ok:true(真实 handler 存活)"
STATUS="$(curl -s -o /dev/null -w '%{http_code}' -X POST "$URL/sidebar/api/__e2e_unknown__" 2>/dev/null || true)"
say "/sidebar/api POST 未知方法 → HTTP ${STATUS}(期望 404)"
[ "$STATUS" = "404" ] || die "/sidebar/api 未知方法未按预期返回 404(HTTP ${STATUS})"
say "通过:聚合双挂载场景下插件自动退让,侧边栏由聚合行接管。"