Files
admin 3efd68517f chore: 并入已删除会话的在途成果(防丢失;原会话已删,未做功能验收)
**背景**:这些改动原属本工作区另外几个会话(T01/T02 等),**那些会话已被用户删除** ⇒
工作树里的成果处于"无主"状态,一次错误 checkout / 覆盖即**永久丢失** ⇒ 代入库保全。
口径遵循本项目**先例**(`39a1f2e` / `b617cdb`:**别人的活,代入库并在提交信息里注明**)。

**内容**:档案 101「能力管理」改名 + 页内 tab 分页|档案 102 语言切换搬入「用户设置」|
`07-实例UI分区登记表.md`|`scripts/find-ui*.mjs`(UI 元素定位工具)|`poc/portal-entry/`(0.5.3)|
`src/web/locale-pref.ts` + `home-files.ts`(语言偏好持久化)|`test/locale-pref.test.mjs`|
`package.json`|`BRIEF.md` / `INDEX.md` / `docs-manifest.json` / `03-路线图与待办.md` / 档案 100 增量。

**已做最小健全性检查**(⚠️ **未跑完整构建 / 单测** —— 那是原会话的验收职责,本次只求"不丢"):
- JSON 合法:`package.json` / `poc/business-plugins/package.json` / `docs-manifest.json` ✓
- 4 个 TS 文件 `{}`/`()` 配平 ✓;新增文件均非空 ✓
- 规模:13 文件改动 +340/−210,新增 12 条

**未 push**(按 §4 提交边界:用户说"提交",未说"推送")。
2026-09-15 21:17:12 +08:00

91 lines
3.1 KiB
Python
Raw Permalink 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 python3
# -*- coding: utf-8 -*-
"""compare-tree.py —— 把**本地 git 基线**(manifest:mode/type/sha\\tpath)与服务器工作树逐文件比对。
输出三类(这是"能不能整树覆盖"的唯一判据,不盲覆盖):
· 一致 :服务器文件内容 == 本地基线
· 不一致 :两边都有但内容不同(**要逐个看是谁的改动**)
· 服务器独有:服务器有、基线里没有(**绝不能抹**)
再加一类「仅在基线里」:本地有、服务器缺(同步时要补上)。
用法(在服务器上):python3 scripts/compare-tree.py <manifest> <工作树根>
"""
import os
import subprocess
import sys
manifest, root = sys.argv[1], sys.argv[2]
entries = []
for line in open(manifest, encoding='utf-8'):
line = line.rstrip('\n')
if not line.strip():
continue
head, path = line.split('\t', 1)
mode, typ, sha = head.split()
entries.append((path, sha))
paths = [p for p, _ in entries]
present = [p for p in paths if os.path.isfile(os.path.join(root, p))]
missing = [p for p in paths if p not in set(present)]
# 批量算 sha(git hash-object --stdin-paths)
hash_out = {}
if present:
proc = subprocess.run(['git', 'hash-object', '--stdin-paths'], cwd=root,
input='\n'.join(present) + '\n', capture_output=True, text=True)
for p, h in zip(present, proc.stdout.split('\n')):
if h.strip():
hash_out[p] = h.strip()
same, diff = [], []
for p, sha in entries:
if p in missing:
continue
if hash_out.get(p) == sha:
same.append(p)
else:
diff.append((p, sha, hash_out.get(p)))
# 服务器独有:扫同一批顶层目录,取基线里没有的文件
tops = sorted({p.split('/')[0] for p, _ in entries})
known = set(paths)
extra = []
for top in tops:
base = os.path.join(root, top)
if not os.path.isdir(base):
continue
for dirpath, dirnames, filenames in os.walk(base):
dirnames[:] = [d for d in dirnames if d not in ('node_modules', '.git', 'dist')]
for fn in filenames:
rel = os.path.relpath(os.path.join(dirpath, fn), root).replace(os.sep, '/')
if rel not in known:
extra.append(rel)
print('=== 汇总 ===')
print(' 基线条目 : %d' % len(entries))
print(' 一致 : %d' % len(same))
print(' 不一致 : %d' % len(diff))
print(' 仅基线有(缺) : %d' % len(missing))
print(' 服务器独有 : %d' % len(extra))
if diff:
print('\n=== 不一致(要逐个判断是谁的改动)===')
for p, want, got in diff[:60]:
print(' %-58s 基线 %s 服务器 %s' % (p, want[:10], (got or '')[:10]))
if len(diff) > 60:
print(' … 还有 %d 个' % (len(diff) - 60))
if missing:
print('\n=== 仅基线有(服务器缺)===')
for p in missing[:40]:
print(' ' + p)
if len(missing) > 40:
print(' … 还有 %d 个' % (len(missing) - 40))
if extra:
print('\n=== 服务器独有(⛔ 覆盖前必须保留/处理)===')
for p in extra[:60]:
print(' ' + p)
if len(extra) > 60:
print(' … 还有 %d 个' % (len(extra) - 60))