@minonl/dia 0.0.7 → 0.0.9
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/dist/cli.js +241 -44
- package/docs/cli.md +2 -2
- package/docs/msg-collab-m1.md +14 -0
- package/docs/service-noun.md +76 -0
- package/docs/status.md +1 -0
- package/package.json +1 -1
- package/packages/wt/bin/dia-wt +158 -101
- package/packages/wt/tests/adopt.test.sh +67 -143
package/docs/status.md
CHANGED
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
| D0.21 | worktree 抽取 `packages/wt` | **完成** | 7 处 python→node;`dia wt`;4 套测试原样迁移全绿 |
|
|
91
91
|
| D0.23 | doctor 平台版本自检 | **完成** | `platform:opencode` / `platform:dsh` 报版本(缺宿主 = warn,不判红);`tests/active-doctor.test.ts` |
|
|
92
92
|
| D0.44 | 配置迁移走 LLM 任务 | **完成** | `docs/migrations/llm-migration.md`:升级只改声明;迁移=任务+判据+回滚;禁止代码里堆版本分支(安全敏感/原子场景例外) |
|
|
93
|
+
| D0.61 | kit 空内容拒绝 + doctor 只查引用 kit | **完成** | `kit add` 拒绝空清单/空树(E_MANIFEST/E_KIT_EMPTY);doctor 按 persona lock 的 kits 校验,孤儿不再拖红 |
|
|
93
94
|
| D0.60 | persona --force 覆盖内联内容 / update --force | **完成** | `kit.renderContent` 支持 force(写盘前备份到 `backups/force-*`);`persona update --force`;版本冲突错误给可执行提示;`tests/kit.test.ts` |
|
|
94
95
|
| D0.59 | 包内容守卫 | **完成** | 单测覆盖 docs 回退;publish workflow 发布前断言 tarball 含 docs/deps.jsonl + docs/platforms/registry.json(防「发完才发现缺文件」) |
|
|
95
96
|
| D0.58 | 推送前敏感扫描 | **完成** | `dia wt adopt` 的 pre-push 扫描新增行:真实家目录/私钥/token 形态;`DIA_WT_GUARD_SCAN=0` 逃生;`adopt.test.sh` 34 pass |
|
package/package.json
CHANGED
package/packages/wt/bin/dia-wt
CHANGED
|
@@ -1167,22 +1167,31 @@ wt_default_branch() {
|
|
|
1167
1167
|
printf '%s' "$b"
|
|
1168
1168
|
}
|
|
1169
1169
|
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
cat > "$hooksdir/$name" <<'HOOK'
|
|
1173
|
-
#!/usr/bin/env bash
|
|
1174
|
-
# dia-wt guard(managed by `dia wt adopt`;勿手改)
|
|
1170
|
+
wt_guard_body() {
|
|
1171
|
+
cat <<'HOOKBODY'
|
|
1175
1172
|
set -uo pipefail
|
|
1176
|
-
|
|
1173
|
+
# 钩子名:生成的钩子用 basename $0;`dia wt guard` 用环境变量指定
|
|
1174
|
+
name="${DIA_WT_HOOK_NAME:-$(basename "$0")}"
|
|
1177
1175
|
top="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
1178
1176
|
common="$(git rev-parse --git-common-dir 2>/dev/null || true)"
|
|
1179
|
-
case "$common" in /*) ;; *) common="$(cd "$top" && cd "$common" 2>/dev/null && pwd -P)" ;; esac
|
|
1177
|
+
case "$common" in /*) ;; *) common="$(cd "$top" 2>/dev/null && cd "$common" 2>/dev/null && pwd -P)" ;; esac
|
|
1178
|
+
[ -n "$common" ] || exit 0
|
|
1180
1179
|
gd="$(git rev-parse --git-dir 2>/dev/null || true)"
|
|
1181
|
-
case "$gd" in /*) ;; *) gd="$(cd "$top" && cd "$gd" 2>/dev/null && pwd -P)" ;; esac
|
|
1180
|
+
case "$gd" in /*) ;; *) gd="$(cd "$top" 2>/dev/null && cd "$gd" 2>/dev/null && pwd -P)" ;; esac
|
|
1182
1181
|
is_main=0; [ "$gd" = "$common" ] && is_main=1
|
|
1183
1182
|
branch="$(git symbolic-ref --short HEAD 2>/dev/null || true)"
|
|
1184
|
-
prot=" main master develop dev "
|
|
1185
1183
|
probe="${DIA_WT_GUARD_PROBE:-0}"
|
|
1184
|
+
|
|
1185
|
+
# 只对已 adopt 的仓生效;未 adopt → 纯透传(保持本机其它仓行为不变)
|
|
1186
|
+
cfg="$common/dia/config.json"
|
|
1187
|
+
adopted=0; [ -f "$cfg" ] && adopted=1
|
|
1188
|
+
def=""
|
|
1189
|
+
if [ "$adopted" = 1 ]; then
|
|
1190
|
+
def="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("defaultBranch") or "")' "$cfg" 2>/dev/null || true)"
|
|
1191
|
+
fi
|
|
1192
|
+
prot=" main master develop dev $def "
|
|
1193
|
+
prot="${prot// / }"
|
|
1194
|
+
|
|
1186
1195
|
wt_guard_scan() {
|
|
1187
1196
|
local ls="$1" rs="$2" range="" base="" hits=""
|
|
1188
1197
|
if [ -n "$rs" ] && [ "$rs" != "0000000000000000000000000000000000000000" ] && git cat-file -e "$rs" 2>/dev/null; then
|
|
@@ -1197,72 +1206,81 @@ hits="$(git diff -U0 "$range" -- . 2>/dev/null | grep -E '^\+' | grep -vE '^\+\+
|
|
|
1197
1206
|
if [ -n "$hits" ]; then
|
|
1198
1207
|
echo "[dia-wt] 推送包含敏感内容(已阻断):" >&2
|
|
1199
1208
|
printf '%s\n' "$hits" >&2
|
|
1200
|
-
echo "[dia-wt] 误报请修扫描规则(hooks 由 dia wt adopt
|
|
1209
|
+
echo "[dia-wt] 误报请修扫描规则(hooks 由 dia wt adopt 安装),不提供关闭开关" >&2
|
|
1201
1210
|
return 1
|
|
1202
1211
|
fi
|
|
1203
1212
|
}
|
|
1204
1213
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
[ "$is_main" = 1 ] &&
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
esac
|
|
1242
|
-
|
|
1214
|
+
if [ "$probe" = 1 ]; then
|
|
1215
|
+
case "$name" in
|
|
1216
|
+
pre-commit) { [ "$adopted" = 1 ] && [ "$is_main" = 1 ] && [[ "$prot" == *" $branch "* ]]; } && exit 1 || exit 0 ;;
|
|
1217
|
+
pre-push) { [ "$adopted" = 1 ] && [ "$is_main" = 1 ]; } && exit 1 || exit 0 ;;
|
|
1218
|
+
*) exit 0 ;;
|
|
1219
|
+
esac
|
|
1220
|
+
fi
|
|
1221
|
+
|
|
1222
|
+
if [ "$adopted" = 1 ]; then
|
|
1223
|
+
case "$name" in
|
|
1224
|
+
pre-commit)
|
|
1225
|
+
if [ "$is_main" = 1 ] && [[ "$prot" == *" $branch "* ]]; then
|
|
1226
|
+
echo "[dia-wt] 主 checkout 禁止在 $branch 直接提交;请先:dia wt create <repo> <feature>" >&2
|
|
1227
|
+
exit 1
|
|
1228
|
+
fi ;;
|
|
1229
|
+
pre-push)
|
|
1230
|
+
if [ "$is_main" = 1 ]; then
|
|
1231
|
+
echo "[dia-wt] 主 checkout 禁止直接 push;请走 worktree 分支 + MR" >&2
|
|
1232
|
+
exit 1
|
|
1233
|
+
fi
|
|
1234
|
+
# 先把 stdin 全读进来:既要逐条判 ref / 扫敏感内容,也要原样喂给仓库自己的钩子
|
|
1235
|
+
push_lines=()
|
|
1236
|
+
while IFS= read -r line; do push_lines+=("$line"); done
|
|
1237
|
+
for line in "${push_lines[@]}"; do
|
|
1238
|
+
read -r _lr ls rr rs <<<"$line"
|
|
1239
|
+
case "${rr:-}" in
|
|
1240
|
+
refs/heads/main|refs/heads/master|refs/heads/develop|refs/heads/dev)
|
|
1241
|
+
echo "[dia-wt] 禁止直接 push ${rr#refs/heads/};请走 MR" >&2; exit 1 ;;
|
|
1242
|
+
esac
|
|
1243
|
+
[ -n "${ls:-}" ] || continue
|
|
1244
|
+
wt_guard_scan "$ls" "${rs:-}" || exit 1
|
|
1245
|
+
done ;;
|
|
1246
|
+
post-checkout)
|
|
1247
|
+
if [ "$is_main" = 1 ] && [[ "$prot" != *" $branch "* ]]; then
|
|
1248
|
+
echo "[dia-wt] 提示:主 checkout 当前在 $branch(建议回到默认分支)" >&2
|
|
1249
|
+
fi ;;
|
|
1250
|
+
esac
|
|
1251
|
+
fi
|
|
1252
|
+
|
|
1253
|
+
# 链式:仓库自己的钩子(simple-git-hooks 等管理器生成在 <common>/hooks)
|
|
1243
1254
|
orig="$common/hooks/$name"
|
|
1244
|
-
if [ -x "$orig" ] && [ "$orig" != "$0" ]; then
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
python3 - "$hooksdir/$name" "$chain" <<'PYCHAIN'
|
|
1249
|
-
import sys
|
|
1250
|
-
p, chain = sys.argv[1], sys.argv[2]
|
|
1251
|
-
s = open(p).read()
|
|
1252
|
-
s = s.replace('chain="${DIA_WT_CHAIN_DIR:-}"', 'chain="${DIA_WT_CHAIN_DIR:-%s}"' % chain.replace('\\', '\\\\').replace('"', '\\"'))
|
|
1253
|
-
open(p, "w").write(s)
|
|
1254
|
-
PYCHAIN
|
|
1255
|
-
fi
|
|
1256
|
-
if [ -n "$extra" ]; then
|
|
1257
|
-
python3 - "$hooksdir/$name" "$extra" <<'PYGT'
|
|
1258
|
-
import sys, re
|
|
1259
|
-
p, extra = sys.argv[1], sys.argv[2]
|
|
1260
|
-
s = open(p).read()
|
|
1261
|
-
s = re.sub(r'^prot=" main master develop dev "$', f'prot=" main master develop dev {extra} "', s, flags=re.M)
|
|
1262
|
-
open(p, "w").write(s)
|
|
1263
|
-
PYGT
|
|
1255
|
+
if [ -x "$orig" ] && [ "$orig" != "$0" ]; then
|
|
1256
|
+
if [ "$name" = "pre-push" ] && [ ${#push_lines[@]} -gt 0 ]; then
|
|
1257
|
+
printf '%s\n' "${push_lines[@]}" | "$orig" "$@"
|
|
1258
|
+
exit $?
|
|
1264
1259
|
fi
|
|
1265
|
-
|
|
1260
|
+
exec "$orig" "$@"
|
|
1261
|
+
fi
|
|
1262
|
+
exit 0
|
|
1263
|
+
HOOKBODY
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
wt_global_hooks_dir() { printf '%s/hooks' "$(dia_wt_data_root 2>/dev/null || echo "${DIA_ROOT:-$HOME/.dia}")"; }
|
|
1267
|
+
wt_write_global_hooks() {
|
|
1268
|
+
local dir; dir="$(wt_global_hooks_dir)"
|
|
1269
|
+
mkdir -p "$dir"
|
|
1270
|
+
local h
|
|
1271
|
+
for h in pre-commit pre-push post-checkout; do
|
|
1272
|
+
{ printf '#!/usr/bin/env bash\n# dia-wt guard(本机全局钩子;由 `dia wt adopt` 安装,勿手改)\n'; wt_guard_body; } > "$dir/$h"
|
|
1273
|
+
chmod +x "$dir/$h"
|
|
1274
|
+
done
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
cmd_guard() {
|
|
1278
|
+
local name="${1:-}"
|
|
1279
|
+
case "$name" in
|
|
1280
|
+
pre-commit|pre-push|post-checkout) ;;
|
|
1281
|
+
*) echo "usage: dia wt guard <pre-commit|pre-push|post-checkout>" >&2; return 2 ;;
|
|
1282
|
+
esac
|
|
1283
|
+
DIA_WT_HOOK_NAME="$name" eval "$(wt_guard_body)"
|
|
1266
1284
|
}
|
|
1267
1285
|
|
|
1268
1286
|
cmd_adopt() {
|
|
@@ -1305,19 +1323,18 @@ cmd_adopt() {
|
|
|
1305
1323
|
local common cfgdir cfg hooksdir prev
|
|
1306
1324
|
common="$(wt_common_dir "$repo")" || die "无法解析 git-common-dir"
|
|
1307
1325
|
cfgdir="$common/dia"; cfg="$cfgdir/config.json"; hooksdir="$cfgdir/hooks"
|
|
1308
|
-
prev="$(git -C "$repo" config --get core.hooksPath 2>/dev/null || true)"
|
|
1326
|
+
prev="$(git -C "$repo" config --local --get core.hooksPath 2>/dev/null || true)"
|
|
1309
1327
|
[ -n "$template" ] || template='{{parent}}/{{repo}}-worktree--{{feature}}'
|
|
1310
1328
|
[ -n "$def" ] || def="$(wt_default_branch "$repo")"
|
|
1311
1329
|
|
|
1312
1330
|
if [ "$mode" = "revert" ]; then
|
|
1313
1331
|
[ -f "$cfg" ] || die "未 adopt(缺 $cfg)"
|
|
1314
1332
|
local saved
|
|
1315
|
-
saved="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksPrevious") or "")' "$cfg")"
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1333
|
+
saved="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksPrevious") or "")' "$cfg" 2>/dev/null || true)"
|
|
1334
|
+
# 只还原 adopt 之前就存在的仓库级 hooksPath;当前若被别人改过则不动
|
|
1335
|
+
if [ -n "$saved" ] && [ "$prev" = "$hooksdir" ]; then
|
|
1336
|
+
git -C "$repo" config --local core.hooksPath "$saved"
|
|
1319
1337
|
fi
|
|
1320
|
-
if [ -n "$saved" ]; then git -C "$repo" config --local core.hooksPath "$saved"; else git -C "$repo" config --local --unset core.hooksPath 2>/dev/null || true; fi
|
|
1321
1338
|
rm -rf "$cfgdir"
|
|
1322
1339
|
echo "reverted:$cfgdir"
|
|
1323
1340
|
return 0
|
|
@@ -1331,17 +1348,16 @@ cmd_adopt() {
|
|
|
1331
1348
|
local cfgDef; cfgDef="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("defaultBranch") or "")' "$cfg" 2>/dev/null || true)"
|
|
1332
1349
|
[ -n "$cfgDef" ] && def="$cfgDef"
|
|
1333
1350
|
fi
|
|
1334
|
-
|
|
1351
|
+
local ghd ghp
|
|
1352
|
+
ghd="$(wt_global_hooks_dir)"
|
|
1353
|
+
ghp="$(git config --global --get core.hooksPath 2>/dev/null || true)"
|
|
1354
|
+
[ "$ghp" = "$ghd" ] || { echo "FAIL D02 全局 core.hooksPath 未指向 $ghd(当前:${ghp:-未设置})"; bad=1; }
|
|
1335
1355
|
for h in pre-commit pre-push post-checkout; do
|
|
1336
|
-
[ -x "$
|
|
1356
|
+
[ -x "$ghd/$h" ] || { echo "FAIL D02 缺全局钩子 $h"; bad=1; }
|
|
1337
1357
|
done
|
|
1338
|
-
if [ -n "$def" ] && [ -
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
if wt_is_main_checkout "$repo" && [ "$(git -C "$repo" symbolic-ref --short HEAD 2>/dev/null)" = "$def" ]; then
|
|
1342
|
-
( cd "$repo" && DIA_WT_GUARD_PROBE=1 "$hooksdir/pre-commit" >/dev/null 2>&1 ) \
|
|
1343
|
-
&& { echo "FAIL D03 守卫探针未拦截主 checkout 的 $def 提交"; bad=1; }
|
|
1344
|
-
fi
|
|
1358
|
+
if [ -n "$def" ] && wt_is_main_checkout "$repo" && [ "$(git -C "$repo" symbolic-ref --short HEAD 2>/dev/null)" = "$def" ]; then
|
|
1359
|
+
( cd "$repo" && DIA_WT_GUARD_PROBE=1 "$ghd/pre-commit" >/dev/null 2>&1 ) \
|
|
1360
|
+
&& { echo "FAIL D03 守卫探针未拦截 $def 提交"; bad=1; }
|
|
1345
1361
|
fi
|
|
1346
1362
|
if [ "$json" = 1 ]; then
|
|
1347
1363
|
python3 -c 'import json,sys;print(json.dumps({"repo":sys.argv[1],"ok":sys.argv[2]=="0","defaultBranch":sys.argv[3]},ensure_ascii=False,separators=(",",":")))' "$repo" "$bad" "$def"
|
|
@@ -1366,6 +1382,36 @@ cmd_adopt() {
|
|
|
1366
1382
|
|
|
1367
1383
|
[ -n "$def" ] || die "默认分支不可解析;请 --default-branch main"
|
|
1368
1384
|
mkdir -p "$hooksdir"
|
|
1385
|
+
# 安装/刷新本机全局钩子,并让本仓走全局钩子(不改 package.json、不占用仓库钩子目录)
|
|
1386
|
+
local ghd ghp
|
|
1387
|
+
ghd="$(wt_global_hooks_dir)"
|
|
1388
|
+
ghp="$(git config --global --get core.hooksPath 2>/dev/null || true)"
|
|
1389
|
+
# 配置外溢防线:全局 hooksPath 若已被别人设置,绝不覆盖
|
|
1390
|
+
if [ -n "$ghp" ] && [ "$ghp" != "$ghd" ]; then
|
|
1391
|
+
die "全局 core.hooksPath 已指向 $ghp(非 dia),拒绝覆盖;请先自行处理该配置"
|
|
1392
|
+
fi
|
|
1393
|
+
wt_write_global_hooks
|
|
1394
|
+
git config --global core.hooksPath "$ghd"
|
|
1395
|
+
# 仓库级 hooksPath:旧版 dia 目录 → 撤掉迁移;别人的管理器(husky/.githooks)→ 保留并提示
|
|
1396
|
+
if [ -n "$prev" ] && [ "$prev" != "$ghd" ]; then
|
|
1397
|
+
if [ "$prev" = "$hooksdir" ]; then
|
|
1398
|
+
git -C "$repo" config --local --unset core.hooksPath 2>/dev/null || true; prev=""
|
|
1399
|
+
else
|
|
1400
|
+
echo "[dia-wt] ⚠️ 该仓本地 core.hooksPath=$prev(由 hook manager 接管),全局守卫对本仓不生效" >&2
|
|
1401
|
+
fi
|
|
1402
|
+
fi
|
|
1403
|
+
rm -rf "$hooksdir" 2>/dev/null || true
|
|
1404
|
+
python3 - "$cfg" "$repo" "$def" "$template" "$prev" <<'PYG'
|
|
1405
|
+
import json, sys, datetime
|
|
1406
|
+
cfg, repo, br, tmpl, prev = sys.argv[1:6]
|
|
1407
|
+
json.dump({
|
|
1408
|
+
"schema": 2, "repo": repo, "defaultBranch": br, "template": tmpl,
|
|
1409
|
+
"hooksManager": "global", "hooksPrevious": prev or None,
|
|
1410
|
+
"adoptedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
|
1411
|
+
}, open(cfg, "w"), ensure_ascii=False, indent=1)
|
|
1412
|
+
PYG
|
|
1413
|
+
echo "adopted:$repo(守卫 = 本机全局钩子 $(wt_global_hooks_dir))"
|
|
1414
|
+
return 0
|
|
1369
1415
|
# 保留首次 adopt 记下的 hooksPrevious(重复 apply 时 prev 已是我们自己的 hooksdir)
|
|
1370
1416
|
local savedPrev=""
|
|
1371
1417
|
[ -f "$cfg" ] && savedPrev="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksPrevious") or "")' "$cfg" 2>/dev/null || true)"
|
|
@@ -1384,11 +1430,6 @@ data = {
|
|
|
1384
1430
|
}
|
|
1385
1431
|
json.dump(data, open(cfg, "w"), ensure_ascii=False, indent=1)
|
|
1386
1432
|
PY
|
|
1387
|
-
# 提示:simple-git-hooks / husky 的 postinstall 会重写 core.hooksPath 下的钩子,
|
|
1388
|
-
# 每次 `pnpm/npm install` 后可能把守卫冲掉 → 用 `dia wt doctor --fix` 或重跑 adopt --apply 修复。
|
|
1389
|
-
if grep -qs '"simple-git-hooks"\|"husky"\|lefthook' "$repo/package.json" "$repo/.lefthook.yml" 2>/dev/null; then
|
|
1390
|
-
echo "[dia-wt] 注意:该仓使用 hook manager(simple-git-hooks/husky/lefthook),install 后若守卫被重写,跑 dia wt doctor --fix" >&2
|
|
1391
|
-
fi
|
|
1392
1433
|
wt_write_hook "$hooksdir" pre-commit "$def" "$chain"
|
|
1393
1434
|
wt_write_hook "$hooksdir" pre-push "$def" "$chain"
|
|
1394
1435
|
wt_write_hook "$hooksdir" post-checkout "$def" "$chain"
|
|
@@ -1419,7 +1460,7 @@ cmd_doctor() {
|
|
|
1419
1460
|
git -C "$repo" rev-parse --git-dir >/dev/null 2>&1 || continue
|
|
1420
1461
|
local common cfgdir cfg hooksdir prev def
|
|
1421
1462
|
common="$(wt_common_dir "$repo")"; cfgdir="$common/dia"; cfg="$cfgdir/config.json"; hooksdir="$cfgdir/hooks"
|
|
1422
|
-
prev="$(git -C "$repo" config --get core.hooksPath 2>/dev/null || true)"
|
|
1463
|
+
prev="$(git -C "$repo" config --local --get core.hooksPath 2>/dev/null || true)"
|
|
1423
1464
|
def=""
|
|
1424
1465
|
if [ -f "$cfg" ]; then
|
|
1425
1466
|
def="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("defaultBranch") or "")' "$cfg" 2>/dev/null || true)"
|
|
@@ -1427,6 +1468,13 @@ cmd_doctor() {
|
|
|
1427
1468
|
[ -n "$def" ] || def="$(wt_default_branch "$repo")"
|
|
1428
1469
|
# --fix:无损修复(重写三个守卫钩子 + hooksPath 绝对路径)。只对已 adopt 的仓生效。
|
|
1429
1470
|
if [ "$fix" = 1 ] && [ -f "$cfg" ]; then
|
|
1471
|
+
wt_write_global_hooks
|
|
1472
|
+
git config --global core.hooksPath "$(wt_global_hooks_dir)"
|
|
1473
|
+
[ "$json" = 0 ] && echo "FIX $repo 全局钩子已重装"
|
|
1474
|
+
fi
|
|
1475
|
+
if [ "$fix" = 1 ] && [ -f "$cfg" ] && [ "$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksManager") or "")' "$cfg" 2>/dev/null || true)" = "global" ]; then
|
|
1476
|
+
:
|
|
1477
|
+
elif [ "$fix" = 1 ] && [ -f "$cfg" ]; then
|
|
1430
1478
|
local fixChain=""
|
|
1431
1479
|
fixChain="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksChain") or "")' "$cfg" 2>/dev/null || true)"
|
|
1432
1480
|
[ -n "$fixChain" ] || fixChain="$common/hooks"
|
|
@@ -1438,22 +1486,29 @@ cmd_doctor() {
|
|
|
1438
1486
|
prev="$hooksdir"
|
|
1439
1487
|
[ "$json" = 0 ] && echo "FIX $repo 钩子已重装(chain=$fixChain)"
|
|
1440
1488
|
fi
|
|
1441
|
-
local bad=0
|
|
1489
|
+
local bad=0 mcfg=""
|
|
1442
1490
|
[ -f "$cfg" ] || { echo "FAIL D01 $repo 未 adopt"; bad=1; }
|
|
1443
|
-
|
|
1491
|
+
[ -f "$cfg" ] && mcfg="$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1])).get("hooksManager") or "")' "$cfg" 2>/dev/null || true)"
|
|
1492
|
+
local ghd ghp
|
|
1493
|
+
ghd="$(wt_global_hooks_dir)"
|
|
1494
|
+
ghp="$(git config --global --get core.hooksPath 2>/dev/null || true)"
|
|
1495
|
+
# D20 全局配置归属:只认 dia 自己的 hooksPath,被别人占用就报出来(绝不自动覆盖)
|
|
1496
|
+
[ "$ghp" = "$ghd" ] || { echo "FAIL D20 全局 core.hooksPath 未指向 $ghd(当前:${ghp:-未设置})"; bad=1; }
|
|
1444
1497
|
for h in pre-commit pre-push post-checkout; do
|
|
1445
|
-
[ -x "$
|
|
1498
|
+
[ -x "$ghd/$h" ] || { echo "FAIL D02 缺全局钩子 $h"; bad=1; }
|
|
1446
1499
|
done
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
( cd "$repo" && DIA_WT_GUARD_PROBE=1 "$hooksdir/pre-commit" >/dev/null 2>&1 ) \
|
|
1454
|
-
&& { echo "FAIL D03 $repo 守卫未拦截 $def 提交"; bad=1; }
|
|
1500
|
+
# D21 仓库级 hooksPath 外溢:本地设置会覆盖全局(husky/.githooks 等)
|
|
1501
|
+
if [ -n "$prev" ]; then
|
|
1502
|
+
if [ "$prev" = "$hooksdir" ]; then
|
|
1503
|
+
echo "FAIL D21 $repo 旧版本地 hooksPath 残留($prev);跑 dia wt adopt --apply 迁移到全局钩子"; bad=1
|
|
1504
|
+
else
|
|
1505
|
+
echo "WARN D21 $repo 本地 hooksPath=$prev 覆盖全局钩子,本仓守卫不生效"
|
|
1455
1506
|
fi
|
|
1456
1507
|
fi
|
|
1508
|
+
if [ -n "$def" ] && wt_is_main_checkout "$repo" && [ "$(git -C "$repo" symbolic-ref --short HEAD 2>/dev/null)" = "$def" ]; then
|
|
1509
|
+
( cd "$repo" && DIA_WT_GUARD_PROBE=1 "$ghd/pre-commit" >/dev/null 2>&1 ) \
|
|
1510
|
+
&& { echo "FAIL D03 $repo 守卫探针未拦截 $def 提交"; bad=1; }
|
|
1511
|
+
fi
|
|
1457
1512
|
if wt_is_main_checkout "$repo"; then
|
|
1458
1513
|
[ -z "$(git -C "$repo" status --porcelain 2>/dev/null)" ] || echo "WARN D04 $repo 主 checkout 有未提交改动"
|
|
1459
1514
|
[ "$(git -C "$repo" symbolic-ref --short HEAD 2>/dev/null)" = "$def" ] || echo "WARN D04 $repo 主 checkout 不在 $def"
|
|
@@ -1507,6 +1562,7 @@ case "${1:-}" in
|
|
|
1507
1562
|
status) shift; cmd_status "$@" ;;
|
|
1508
1563
|
check) shift; cmd_check "$@" ;;
|
|
1509
1564
|
adopt) shift; cmd_adopt "$@" ;;
|
|
1565
|
+
guard) shift; cmd_guard "$@" ;;
|
|
1510
1566
|
doctor) shift; cmd_doctor "$@" ;;
|
|
1511
1567
|
gate) shift; cmd_gate "$@" ;;
|
|
1512
1568
|
clean) shift; cmd_clean "$@" ;;
|
|
@@ -1522,6 +1578,7 @@ dia wt —— worktree 目录形式选型 + 创建(唯一实现)
|
|
|
1522
1578
|
dia wt status [repo-path] # ★ 清理前必查:唯一工作副本 + 改动重叠(只读)
|
|
1523
1579
|
dia wt check [<repo>...] [--all] [--deep] [--quiet]
|
|
1524
1580
|
# ★ 依赖体检(R20):软链/逃逸/悬空;--all 扫全部仓
|
|
1581
|
+
dia wt guard <pre-commit|pre-push|post-checkout> # 守卫本体(供 hook manager 调用)
|
|
1525
1582
|
dia wt adopt <repo>|--all [--apply|--check|--revert] [--template T] [--default-branch B] [--json]
|
|
1526
1583
|
# 配置路径模板 + 守卫钩子(默认 dry-run;--all 扫仓根)
|
|
1527
1584
|
# 守卫含推送前敏感扫描(不提供关闭开关;误报修规则)
|