chore(仓库对齐): 文档库结构治理 + IM/插件线落地
build / build-and-scan (push) Canceled after 0s

文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
This commit is contained in:
admin committed 2026-09-24 07:25:16 +08:00
1 parent 3d8f50e366
commit e6207aa691
239 files changed
+34477 -14633

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env bash
# op-lock.sh — 「平台高危操作锁」(服务器侧第二把锁)
#
# 为什么需要它:所有会话**共用一台服务器**,而下面这些操作跨会话没有任何互斥 ——
# 重启 dshs / drain 实例 scope / 改实例 env·MemoryMax / 批量铺插件 /
# 改 nginx vhost·证书·nft
# 文档冲突靠 git status / mtime 能看出来,**服务器态变更看不出来**
# (systemctl 不会告诉你 10 分钟前谁重启过)→ 只能靠显式锁。
#
# 与文档库锁的关系:`05-交接单/.doing-<单>` + `.exec-lock` 管「文档与单子」;本锁管「生产态」。
# 顺序:**先抢全局执行锁 → 再占本锁**。
#
# 用法:
# bash 07-scripts/op-lock.sh claim <操作名> "<影响面/时长>" [占用者]
# bash 07-scripts/op-lock.sh release <操作名>
# bash 07-scripts/op-lock.sh status
#
# 判据:`mkdir` 原子 —— 成功 = 你拿到;报 File exists = 有别的会话正在动线上 → **停手**。
# 退出码:0 = 成功/无人占用;1 = 已被占用(claim 失败)或环境错误。
set -uo pipefail
REMOTE="${OP_LOCK_REMOTE:-bt-server}"
LOCKROOT="${OP_LOCK_DIR:-/opt/dsh/state/.op-lock}"
OP="${2:-}"
WHO="${4:-${ME:-unknown-session}}"
NOW="$(date '+%Y-%m-%d %H:%M')"
usage() {
sed -n '3,20p' "$0" | sed 's/^# \{0,1\}//'
exit 2
}
case "${1:-}" in
claim)
[ -n "$OP" ] || usage
IMPACT="${3:-(未声明影响面 —— 补上:谁会被断、断多久)}"
if ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" "mkdir '$LOCKROOT/$OP' 2>/dev/null"; then
ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" \
"printf '占用者:%s\n开始时间:%s\n操作摘要:%s\n影响面:%s\n' '$WHO' '$NOW' '$OP' '$IMPACT' > '$LOCKROOT/$OP/OWNER'" || true
echo "✅ 已占位:$LOCKROOT/$OP(占用者 $WHO,$NOW)"
if [ "$WHO" = "unknown-session" ]; then
echo " ⚠ 未提供会话名 → 已记作 unknown-session。后果有两个(2026-09-12 实测踩到):"
echo " ① handoff-guard 的【1d】会把它当成**别人的锁**(连你自己都被挡住);"
echo " ② release 的归属校验会拒绝你。请改用:"
echo " ME=\"<会话名>\" bash 07-scripts/op-lock.sh claim <操作名> \"<影响面>\""
fi
echo " 完工请:bash 07-scripts/op-lock.sh release $OP"
exit 0
fi
echo "❌ 占位失败 —— 该锁已存在(有会话正在动线上)→ 停手。" >&2
bash "$0" status >&2 || true
exit 1
;;
release)
[ -n "$OP" ] || usage
# 归属校验(R9,2026-09-12 补):锁只能由**持有者自己**释放 ——
# 否则 release 就成了绕过 R9 的后门(AI 读一下 status 拿到操作名,就能把别人的锁 rm 掉)。
RWHO="${4:-${ME:-unknown-session}}"
ROWN="$(ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" \
"sed -n '1p' '$LOCKROOT/$OP/OWNER' 2>/dev/null" 2>/dev/null | sed 's/^占用者://')"
if [ -z "$ROWN" ]; then
echo "❌ 拒绝释放:「$OP」没有 OWNER 记录(无法确认归属)。" >&2
echo " 按 **R9**:锁的处置权只属于用户本人 —— 请报告用户,由用户处置。" >&2
exit 1
fi
if [ "$ROWN" != "$RWHO" ] && [ "${FORCE:-0}" != "1" ]; then
echo "❌ 拒绝释放:「$OP」的占用者是「$ROWN」,而你是「$RWHO」。" >&2
echo " 按 **R9**(禁止接管 / 删锁):抢不到锁 = 停手 + 报告用户;**锁的处置权只属于用户本人**。" >&2
echo " (确需处置:由**用户本人**执行;或用户明确点头后用 FORCE=1,并在回报里写明理由。)" >&2
exit 1
fi
ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" "rm -rf '$LOCKROOT/$OP'" || { echo "❌ 释放失败(ssh 不可达?)" >&2; exit 1; }
echo "✅ 已释放:$OP(归属已核:$ROWN)"
;;
status)
echo "—— 平台操作锁($REMOTE:$LOCKROOT)——"
OUT="$(ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" \
"ls -1 '$LOCKROOT' 2>/dev/null | grep -v '^README$'" 2>/dev/null)"
if [ -z "$OUT" ]; then
if ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" "test -d '$LOCKROOT'" 2>/dev/null; then
echo " (无人占用 ✓)"
else
echo " ⚠ 锁根目录不存在:$LOCKROOT(需先建立)" >&2
exit 1
fi
else
for L in $OUT; do
echo " 🔴 $L"
ssh -o BatchMode=yes -o ConnectTimeout=10 "$REMOTE" \
"sed 's/^/ /' '$LOCKROOT/$L/OWNER' 2>/dev/null" || true
done
exit 1
fi
;;
*) usage ;;
esac