Files
dsh_shenxian/dsh-server-docs/skills/dsh-opensource-release/SKILL.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

64 KiB
Raw Blame History


name: dsh-opensource-release description: DSH 多租户托管平台的「开源导出与版本迭代」技能 —— 把私有代码仓导出成可公开的开源副本(脱敏 / 去插件 / 分层授权 / 重写说明文档),并在后续版本里安全地重跑导出、登记版本。当用户说「开源一份」「导出到 GitHub」「发新版本」「改一下开源那份的脱敏/授权/说明」「开源那份同步一下」时触发。核心:源仓库只读 + 阻断性探针 0 命中才准放行 + OVERLAY 手工撰写层不得被重建抹掉。 version: 1.6.0 updated_at: 2026-09-15 last_change: 1.6.0(2026-09-15):用户立 K8s 长期策略 —— 「后续获取开发项目代码时跳过 K8s 相关部分,就用当前清除/修改后的版本」⇒ 新增 R-O14(源仓那侧视为废弃分支;判定标准 = 构建 blocking hits: 0),并修掉会误导未来会话的过期事实:① §2「保留」列表原写 deploy/(11) 与 poc/(16) 要保留 —— 与 K8s 政策直接冲突(会让未来会话把它们加回来)⇒ 改为「K8s 相关一律不带」+ 指向 _K8s排除台账.md / _k8s_scan.py;② §0 的 dsh-web-platform → dsh-users-platform、中文母本 → 英文为主(*.zh-CN.md)、首发行 → v1.1.0 / 153 文件 / 历史已重置为单条提交 a327649、补计数现状(OVERLAY 26 · REQUIRED 54 · INCLUDE_DIRS 6 · EXCLUDE_FILES 9 · DROP_SCRIPTS 8);③ 标注 K8S_SEMANTIC_RULES(清「不含 k8s 字样但语义已不成立」的描述)与 _apply_k8s_semantics.py(本机 --force 被安全删除层拦下时的热应用替代路径)。1.5.2(2026-09-13):assets/ 漏收录 + 空括号残渣两处真问题。 agent_created: true

dsh-opensource-release — 开源导出与版本迭代

何时用

  • 要把 dsh_shenxian(私有部署版)导出成可公开的仓库副本;
  • 要发新版本(v1.0.1 / v1.1.0 …)→ 重跑导出 + 登记版本表;
  • 要改开源那份的脱敏口径 / 保留范围 / 授权结构 / 说明文档;
  • 有人问「开源那份怎么维护 / 怎么保证不泄密」。

不适用:日常平台改造(用 dsh-change-workflow)、知识库维护(用 dsh-knowledge-upkeep)。


0.5 🔴 事故清单(真发生过 —— 开工前 30 秒读完)

# 事故(真实) 正确做法 详见
1 误放别的会话的全局执行锁 —— 抢锁失败没看输出 + claim/release 写在同一条命令 ⇒ 末尾的 --release-exec 是 rm -rf 语义,删掉了 R1-注入层-1104 的锁 抢锁单独一条命令并当场看输出;看到占用者不是自己 ⇒ 停手;放锁前 cat 交接单/.exec-lock/OWNER 确认首行是自己;误放则按 handoff-guard.sh:43 格式原样重建并告知用户 §8 坑 16
2 导出基线在漂 —— 导出脚本复制的是工作树,而多会话在并行改源码仓 ⇒ 导出混入别人未提交的改动,还会冒出新的需脱敏标识('dsh-plugin-mcn-suite' 触发探针) 发布前按 commit 取(git archive <commit>)=冻结版本;否则每次重建都必须重跑探针并复核 README 描述与实际一致 §10
3 盲替 _build_export.py 自身 —— 脚本里同时有「源模式」与「目标值」,批量替换把源模式改掉 ⇒ 改名规则静默失效 改脚本只用精确 Edit;改完必须重建 + grep 复查 §8 坑 9
4 Dockerfile / Dockerfile.dsh 整份跳过脱敏 —— is_text() 按扩展名判断 is_text() 已加特判;新增无扩展名文件要复核是否进了脱敏 §8 坑 10
5 package.json 手改被重建覆盖 —— 它属「源派生」而不是 OVERLAY 项目自有字段(version/description/repository/license)必须写成 GLOBAL 规则 §8 坑 11
6 废弃的中间候选名静默残留 —— 探针只探最老的名字,_overlay 里的中间名(dsh-hosting)漏了 72 处 所有曾用名都进 LEAK_PROBES §8 坑 14
7 说明文档文案连改 7 轮(替别人宣传 / 开头讲基线 / 议论式表述 / 授权在最前 / 把未验证的当可用 / 致谢太长) 严格照 R-O9–R-O12 写;写完自审一遍再交付 R-O9–R-O12
8 脚本里用键名当标题(marks[k][0] 拿到的是键 "A" 不是标题)⇒ 结构改写打歪,误删 PoC 的一个字母 结构改写用完整标题字符串做锚点;改完读回原文复核关键块 本表 #7 的同一节
9 改工作根时漏改脚本常量 ⇒ 旧目录被"重建复活"(2026-09-13 迁移到 dsh-laijing-github 时:先搬目录、后改 OUT,中间跑了一次重建 ⇒ 旧位置被重新建出 135 个文件,且因旧位置没有 _overlay 而缺了 6 个手工层文件;_overlay 本身侥幸没被洗掉) 顺序必须是:① 改脚本常量(OUT+EX)→ ② 再搬/删目录 → ③ 重建验证。迁完必查旧目录没有复活(ls),并核对 find <repo> -type f | wc -l 与手工层 6 个文件是否都在 §8 坑 17
10 白名单收录静默漏项:assets/ 没进 INCLUDE_DIRS(2026-09-13 用户问"确认都同步了吗"时查出)—— 导出的仓库缺 assets/inject/{recovery,assist}.js:proxy.ts 的 loadInject 会 fail-fast 抛错(平台起不来)、仓库自带 scripts/verify-inject.cjs 也会判失败;package.json 的 files 同样缺 assets(npm/git 安装也会缺) 已补 INCLUDE_DIRS、package.json files 规则,并新增 REQUIRED_EXPORT 清单(23 项):缺任何一项 ⇒ 构建判失败(return 1)。以后新增"运行时要读的文件"必须同步加进该清单 §3 · §8 坑 18
10 🔴 "顺手清理"的正则把 ASCII 标点也吃进去 ⇒ 直接改坏源码(2026-09-13 去「档案 NN」时:清理规则写成 [((]\s*[))] / [;;,,]\s*[))],字符类里混了 ASCII ( ) , ; ⇒ 源码里所有 foo() 被删成 foo,whitelist.ts / security-scan.ts 当场语法错(tsc 报 Invalid character / Unterminated string literal)。而当时 leak 探针全过) ⛔ 清理类正则只准碰全角标点(()·、,:;),绝不可把 ASCII 语法符号写进字符类;
✅ 改完必跑 _verify_tsc.mjs,exit 0 + no diagnostics 是"没改坏代码"的唯一证据 —— 探针全过 ≠ 代码还活着,两者查的是完全不同的东西;
另:(\s*/\s* 这类"吃掉前导斜杠"的规则会毁掉 (/api/x) 路径,一律不要写
本表新条目 · 台账 §八 D
11 🔴 同一个名字既当"脱敏目标"又当"公开值" ⇒ 自相矛盾(2026-09-13 填 PUBLISH_* 时:maogeigei 同时在 GLOBAL(替换为占位符)与 LEAK_PROBES(判泄露)里 ⇒ ① 刚填好的公开值被规则改回占位符,② 探针报 blocking hits: 4。"占位符残留 0"是假象) ⛔ 任何进入 PUBLISH_* 的值,先 grep -n "<该值>" _build_export.py 确认它不在 GLOBAL/LEAK_PROBES/INFO_PROBES 里;升格为公开身份后要同时从 GLOBAL 与 探针移除(只删一处 = 另一种错);
公开联系方式的兜底应靠更具体的探针(如私有仓库域名 work.alotbuy),不要靠账号名
台账 §八 D2
12 ⚠️ --dry-run 报"假成功"(2026-09-13 真机预演时:run() 会把命令加 [dry-run] 前缀跳过执行,但结果提示语是硬编码的 ⇒ 预演满屏 ✓ 构建完成 / ✓ 服务已启动 / ✓ 部署完成;更糟的是打印了一个假的初始管理员密码 —— bootstrap-admin 根本没跑,用户会照着登录失败。另:未设域名时文案出现空缺「把 与 *. 的 DNS A 记录」) dry-run 必须"只读":既不落盘,也不得宣称成功。所有结果类提示(不只是动作)都要有 DRY_RUN 分支;凡是"执行后才产生的值"(密码/ID/路径)在 dry-run 下必须标为"未生成";文案里的变量要有 ${VAR:-默认} 兜底。
验收方式:--dry-run 的输出里不允许出现任何 ✓,只允许 [dry-run]
台账 §八 E
13 🔴 _build_export.py --force 在本机跑不动(2026-09-14 实测:shutil.rmtree(DST) 被 WorkBuddy 的「安全删除层」shim 拦下 ⇒ SAFE_DELETE_FAIL_CLOSED;⚠️ 而且 --force 会连导出物里的本地 .git 一起删 —— 本轮实测提交历史被吃掉后由会话重新 git init 建单条提交) ① 新规则要抽成具名列表(如 K8S_SEMANTIC_RULES)再 REGEX_RULES += …,不要直接内联 —— 具名才能被热应用工具复用;
② 本机改规则后用 <导出根>\_apply_k8s_semantics.py --write 就地热应用(不删任何东西,结果与整目录重建逐字节一致,且幂等:复跑命中 0);
③ 确实要整目录重建:先 mv dsh-users-platform/.git <导出根>/_keep_git_tmp,重建完 mv 回来
台账 §五·补
14 🔴 「K8s 残留」只按 k8s 字面量清 ⇒ 清不干净(2026-09-14:字面量已清零,仍有 10 处注释在讲 Pod / file sidecar —— 描述的是已被移除的 K8s 形态,属悬空描述) 判据是**「这段描述在单机形态下还成立吗」,不是「有没有 k8s 字样」:Pod(K8s Pod ≠ DSH 子进程)· sidecar(已移除的 per-user file sidecar)· a Linux Pod 都要清;
⛔ 噪音不要清:--profile headless(dsh 自己的 profile 名)· headless-univer(第三方插件包名)· manifest(npm 包清单,不是 K8s manifest)· egress(nftables 出网护栏,本项目
保留**能力);
复核用 <导出根>\_k8s_comment_scan.py [--wide] —— 它按「注释 / 代码」分类输出,可直接核对「只清注释」这件事
台账 §五·补
15 🔴 只删「构建步骤」、没删「使用者」⇒ CI 必红(2026-09-15 实测:撤下 Dockerfile.dsh 后,构建 dsh:ci 镜像的那条步骤删了,但 3 条使用者仍在 —— Smoke — dsh resolves runtime plugin / Trivy — dsh / Push dsh to ACR ⇒ 首次推送 CI 必红) 判据 =「产物不在,引用它的步骤也不该在」:删任何产物(镜像 / 文件 / 模块 / 脚本)时,必须把它的「使用者」一并处理(本次已把 3 条步骤整块删除 + 把 dsh:ci 加进 LEAK_PROBES);
⚠️ 复核务必用 os.walk 脚本(_k8s_comment_scan.py),bash grep -r 会漏隐藏目录 —— 见 #16
影响说明 §7
16 🔴 bash grep -r 不遍历隐藏目录 ⇒ 静默漏掉 .github/(2026-09-15 实测:据此一度误判「CI 没问题」,靠 Read 才看到 dsh:ci 仍在) 全仓复核用自带脚本(走 os.walk)或给显式路径;
本机另注:bash 的 PATH 会被 shim 重置(dirname/grep/awk 全 command not found)⇒ 先 export PATH=<PortableGit>/usr/bin:<…>/mingw64/bin:/c/Windows/System32:/c/Windows:$PATH,python / node 一律用绝对路径
影响说明 §8

0. 事实(硬编码,勿猜)

项 值
中文名 / English name DSH 用户平台 / DSH Users Platform(2026-09-14 由 dsh-web-platform 定稿改名)
文档语言(2026-09-14 定稿,覆盖 R-O13) 英文为主:主文档 *.md 为英文 + 顶部中文入口;中文全文在 *.zh-CN.md;manual/ 8 篇 ×2 语言;架构图也分语言(diagrams/architecture{,.zh-CN}.svg)
内容来源(用户 2026-09-13 定的重点卖点) 全部代码与文档由 AI 生成 —— 模型 DeepSeek V4 / V4.1 flash(不写工具名)。README 里有专节 ## AI 生成(位于「目录」之后、「亮点」之前),Hero 区还有一行声明 + 2 个徽章(code & docs-AI-generated、DeepSeek V4 / V4.1 flash)—— 这三处一个都不能少
文档语言 ⛔ 本行已作废 —— 2026-09-14 起改为英文为主,见上表「文档语言(2026-09-14 定稿)」行;
R-O13 的「中文母本 + *.en.md」口径同时作废,现状是 *.zh-CN.md 副本
技术标识(仓库·包·服务·env 前缀) dsh-users-platform | DSH_USERS_PLATFORM_* | /var/lib/dsh-users-platform(中文名「DSH 用户平台」/ English「DSH Users Platform」)
曾用名(全部必须在 LEAK_PROBES 里) dshs · dsh-multitenant · dsh-hosting · dsh-web-platform · DSH_WEB_PLATFORM_* · /var/lib/dsh-web-platform;taimiao 未落地也一并加入
前名(已废弃,现为阻断探针项) dsh-multitenant / DSH_MULTITENANT_* / /var/lib/dsh-multitenant —— 2026-09-13 20:2x 由用户定名 dsh-web-platform 取代;LEAK_PROBES 已收录,出现即判泄露
源仓库(只读!) D:\github\dsh_shenxian
工作根(GitHub 开源专用文件夹) E:\ProgramData\AI技能\dsh-laijing-github\(2026-09-13 由 aliyun-dsh-server\_开源导出_20260913\ 整体迁入;本项目的独立开源工作区,不再是 aliyun-dsh-server 的子目录)
仓库根(可直接 git init) <导出根>\dsh-web-platform\
构建脚本 <导出根>\_build_export.py(默认拒跑,须 --force)
手工撰写层快照 <导出根>\_overlay\(脚本自动维护)
类型检查 <导出根>\_verify_tsc.mjs(建 junction → tsc → rmdirSync 拆)
给人看的台账 <导出根>\_导出说明与脱敏台账.md(不随仓库上传;§七 = 改名记录)
手工撰写层(OVERLAY:重建时自动快照→恢复,不得被抹掉) 现为 3 份:README.md · PLUGIN-PORTING.md · install.sh(原另有 LICENSE / LICENSE-UPSTREAM-MIT.txt / THIRD-PARTY-NOTICES.md,2026-09-13 已按用户要求移除 —— 见 §5)
当前版本 v1.1.0 / 2026-09-14,153 文件;历史已按用户要求重置为单条提交(a327649,强推覆盖)| 首发 v1.0.0 / 2026-09-13
计数现状(2026-09-15) OVERLAY 26 | REQUIRED_EXPORT 54 | INCLUDE_DIRS 6 | EXCLUDE_FILES 9 | DROP_SCRIPTS 8
上游基线(三方) 上游骨架仓库(已按要求不再具名) → MIT(GitHub 仓库 + DSH 插件目录已收录)
运行期上游 @deepseek-ai/dsh(DeepSeek Harness)→ MIT
本机 Python /e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe

⚠️ 工作根 = E:\ProgramData\AI技能\dsh-laijing-github\(独立 GitHub 开源文件夹)。不要再改名或迁移 —— 这个名字被 _build_export.py 的 OUT、_verify_tsc.mjs 的 EX、本技能、项目 MEMORY 同时引用。真要迁:先改这几处,再复跑重建 + tsc,并检查旧目录没有被重建脚本重新建出来(迁完曾因漏改 OUT 而复活一次)。


1. 硬规则 R-O1–R-O13(= 用户原始要求 + 实际踩过的坑,任何会话不得放宽)

# 规则 判据
R-O1 源仓库只读 所有改写只落在导出副本。任何 git/写操作碰 D:\github\dsh_shenxian = 违规
R-O2 去掉本机 / 服务器信息 域名 / IP / 账号 / 绝对路径 / 私有仓库地址 → 占位符或通用化;收尾探针 0 命中
R-O3 去掉所有已投放的插件 插件包目录 + 插件投放脚本 + 构建产物(*.tgz)全部不带;代码注释里的插件名也要中性化 —— ⚠️ 唯一例外见下表:dsh-univer-office 经用户 2026-09-13 特许保留
R-O4 不带任何项目文档与 skill docs/、档案类 md、skills/、.workbuddy/、lib/、.git 一律不带;只留 4 个新写文档(见 §6)
R-O5 授权:个人/非商业免费 + 商业收费 → 2026-09-13 用户定:授权类内容全部移除、不再处理、不再上抛 见 §5;但「上游 MIT 不得被附加限制」是事实,保留

外加操作纪律与文档口径(R-O6–R-O12),每条都对应 §0.5 里的真实事故:

  • R-O6 未经明确要求 不做 git init / commit / push / scp(同项目 §4)。
  • R-O7 导出的手工撰写层(README / LICENSE / NOTICE / PLUGIN-PORTING / install.sh)是资产,不得被重建抹掉 —— 靠 _overlay 自动快照恢复。
  • R-O8 · 命名 —— 绝不沿用三方项目名(详下)。
  • R-O9 · 能力宣称 —— 只写「已验证的」:有代码 + 有单测 + 有 PoC 都不等于可用;未验证的标「实验性 · 未验证」(详下)。
  • R-O10 · 出处 —— 只放文末,且只写一行致谢;不写骨架枚举、不写自我表扬、不写改名理由(详下)。
  • R-O11 · README 内容口径 —— 开头写重心不写门槛 · 面向读者不写议论 · 每条亮点带机制与数值 · 亮点先读码再写(详下)。
  • R-O12 · README 结构顺序 —— 认知漏斗 Hook→Onboarding→Content→Trust→Meta · 授权压轴 · Hero 前 50 行有可视块 · TOC 锚点机检(详下)。
  • R-O13 · 双语文档 —— 中文是母本;英文版在同步 GitHub 之前才生成(*.en.md),两份顶部再加语言切换行;法律文本不翻译(详下)。

R-O8 · 命名规则(2026-09-13 立,因踩过)

上游 dshs 是 上游作者(已按要求不再具名) 的三方项目(GitHub 仓库 + 已被 DSH 插件目录收录,含 L1–L5 验证记录)。 沿用它当发布名 = 冒名 / 指代混淆,还会让上游作者的工作被误认作本项目产出。

发布前必须做三件事:

# 动作 判据
1 起自己的名,并实测未被占用(npm registry.npmjs.org/<name> + 插件目录 dshbase.com/plugins/<name>,两处都 404 才可用) 本项目命名口径(用户 2026-09-13 定):中文 DSH Web 平台 | English DSH Web Platform | 技术标识 dsh-web-platform(短横连写用于仓库/包/服务/env 前缀)。
⚠️ 已排除的两个候选:dsh-hive(第三方插件 llluchy/dsh-hive 已占用);dsh-hosting(本会话中间候选,已被用户口径取代 ⇒ 仓库里不得残留,已列入阻断性探针)
2 改完全部自指标识:包名 / bin / cordis plugin id / env 前缀(36 种)/ 数据根 / systemd 单元 / nginx conf / 库文件名 / 镜像与 k8s / 导出目录名 全仓 grep 旧名,只剩出处引用才算干净
3 保留出处并正式致敬 —— 但只放在文末(用户 2026-09-13 明确:"在最后提一下引用了谁就行,不要上来就重点讲用了谁") ① LICENSE-UPSTREAM-MIT.txt 逐字节不动(MIT 强制);② README 不得在开头单独设「名称与渊源 / 基于 XX」章节 —— 出处只出现在文末的「第三方组件与致谢」里,一句话带过;③ 法律归属由 LICENSE 第一层说明 + THIRD-PARTY-NOTICES.md §4 承载(这两处必须完整,不受"轻描淡写"影响)

⚠️ 改名时最容易误伤的两处:① 把「致敬上游」的引用一起改掉(= 抹掉出处,法律与道义双重问题);② 把脚本里作源模式的旧名改掉(见 §8 坑 9)。

R-O9 · 只写「已验证的」能力

用户原话:「模式 B · Kubernetes 去掉这个,根本没验证,应该是待开发验证」。

规则 做法
宣称必须可复现 只把真正跑过端到端验收的路径写成「可用」。有代码 + 有单元测试 + 有 PoC 记录,都不等于可用
未验证的照实标注,不删代码 保留代码与清单,但标注 「实验性 · 未验证」,并与可用路径在同一张表里用状态行对照,不要让读者自己猜
删掉「已完整落地 / Phase 0–4」式表述 这类词最容易把"写完了"说成"验证过了"(2026-09-13 从「部署形态」章节删掉的就是它)
配置表 / 脚本文案同步标注 未验证路径的 env 变量统一加「(模式 X · 未验证)」前缀;install.sh 的报错/提示文案要与 README 口径一致
FAQ 给一句直答 加一条「X 现在能用吗?」→ 直接回答「还不能」,并说清缺哪一步(如「从未做过端到端部署验收」)
归属措辞也要改 出处/致谢里描述对方贡献时,把「双部署形态」降级为「双部署框架」,避免暗示未验证的路径是可选项
落点清单(照抄) README:部署形态表 + 快速开始 + 配置表 + 功能详解 + 安全模型 + 亮点 + 目录结构 + FAQ;install.sh 文案;LICENSE 与 THIRD-PARTY-NOTICES.md 的归属措辞


R-O10 · 出处的位置与措辞

用户原话:「在最后提一下引用了谁就行,不要上来就重点讲用了谁,感觉是在宣传别人的项目,已经很多地方深度改造过了。」

规则 说明
位置 只在文末(README 的「第三方组件与致谢」+ LICENSE 第一层 + THIRD-PARTY-NOTICES.md §4)。不得在开头/前部单设「名称与渊源」「基于 XX」章节
主语 正文一律以本项目为主语。写「本项目做了…」,不要写成「上游提供了骨架,我们在此基础上…」这种自我降格的框架
措辞 用「起步时参考了 X(作者,许可证)—— 感谢作者开源」;不要用「仅仅接着往前走了一步」「离开它就没有这个项目」这类过度抬举,也不要补「我们做了大量深度改造」这类自我表扬(见下表「致谢只写一行」)
边界 「轻描淡写」只作用于 README 正文;MIT 要求的版权与许可声明(LICENSE-UPSTREAM-MIT.txt)与授权分层说明一处都不能省
JS/注释里的名字 代码注释里也不主动出现上游名(它们已经被 R-O8 第 2 步改成新名;只剩出处语境才允许)
致谢只写一行(2026-09-13 第七次纠正) 出处行 = 「起步时参考了 X(作者,许可证)—— 感谢作者开源」,一行结束。不要写:① 骨架范围的枚举(那是 LICENSE 第一层与 THIRD-PARTY-NOTICES.md §4 的职责,重复即冗余);② 「此后我们做了大量深度改造」(自我表扬,致谢不是讲功绩的地方);③ 「项目名从它的 X 换成我们的 Y(避免指代混淆…)」(内部事务,读者不关心,改名说明留在 NOTICE 的「更名说明」行即可)。用户原话:「有必要讲这么多吗,好好想想」
别解释我们为什么这么写 「—— 这是 MIT 的硬性要求,必须保留」「因此 README 与 install.sh 一律以模式 A 为准」这类关于文档自身的话术删掉;正文只陈述事实与规则本体
指针行不重复 「机制见亮点」这类导航指针全文留 1–2 处(Hero + 功能详解)即可,Content 各节末尾各来一句 = 冗余

R-O11 · README 内容口径

🧭 体例 = 说明书,不是技术文档(2026-09-13 20:4x 用户定):「readme 是说明不是技术文档 用语需要简明扼要 排版要方便观看」。 ⇒ 只写怎么用 / 有什么 / 限制;机制级细节(链名、flag、常量、函数语义)留给代码注释与 PLUGIN-PORTING.md; ⇒ 不写内部变更日志式长表(如「v1.0.0 的六组改造」);表格单元格要短、可扫读;多用列表少用长段落。

用户原话:「部署到一台服务器,多个用户注册并经管理员审核,各自获得一套相互隔离 —— 这个只是项目的基础不是重点,重点是多租户各自进程的安全隔离、状态恢复、插件和技能的管理。多看看项目找出这个项目的亮点」「对了多想想 不要弄了半天亮点都体现不出来」。

规则 做法
开头 = 亮点,不是门槛 开篇不要写「部署到一台服务器,多个用户注册…」这类「能跑」描述(那是基线)。改成一句定位 + 三条主线速览:① 进程级安全隔离 ② 故障自愈与状态恢复 ③ 插件与技能的受控管理
亮点必须先于功能清单 README 的第一个正文章节就是亮点(## 亮点),且要早于「快速开始 / 功能详解」。功能清单只做索引,并在开头声明「机制见亮点」
每条亮点必须带机制 禁止「真隔离」「会自愈」这类空词。每条要写具体机制 + 关键数值/常量 + 为什么这么设计(例:端口守卫要在 OUTPUT 链按客户端 uid 匹配、且 -I OUTPUT 1 插链首,否则 ufw/conntrack 的 ACCEPT 会先吃包;宿主不支持就 fail loud)
先读代码再写亮点 亮点必须来自实际读码(src/** 的头注与关键函数就写得很好),不要凭 README 旧文或印象复述。读法:find src -name '*.ts' | xargs wc -l | sort -rn 找最重的模块 → 读头注 → 再挑 3-5 个「反直觉且踩过坑」的细节
「难在哪」心里有数(但别写进 README) 每条主线要能回答「为什么这不容易」(租户之间真的隔得住 / 崩溃后无感恢复 / 装了不出事)—— 用于决定亮点写什么;⚠️ 但「多租户演示十分钟就能写出来」这类对比式议论本身不许出现在 README(见下表「面向读者」)
补一节工程纵深 用「双后端同接口 / 关键决策是纯函数 / npm test 覆盖 + 注入脚本运行时校验」这类事实回答「凭什么信这些机制」
面向读者,不是面向作者(2026-09-13 第三次纠正) README 是给使用者 / 贡献者看的。禁止出现「重点不是 X,而是 Y」「X 十分钟就能写出来」这类议论式 / 对比式表述 —— 那是在跟作者对话,读者不关心。直接陈述「项目做什么 + 重心在哪」即可
小节标题别加议论 标题只写名词短语(### 一、进程级安全隔离),不要写成 (不是「同机不同目录」) (「能装」和「装了不出事」是两件事) 这种反问/抖机灵。对比与理由放到表格单元格里当技术说明
别重复定位句 标题下的一句 tagline 与 badges 之后的描述段不要重复同一个句式(「把 DSH 变成…」说了两遍)。tagline 一句话,描述段讲用户视角的事实 + 三条重心


R-O12 · README 结构顺序

依据:readme-craft(SkillHub 技能,蒸馏 awesome-readme / Standard README / Art of README / Make a README / GitHub Docs / thoughtbot)+ standard-readme。核心是认知漏斗:Hook → Onboarding → Content → Trust → Meta,不得倒序。

本项目定稿顺序(Hero + 16 节)

标题 → 一行描述 → 徽章(**5 个**:Node · Version · built on DSH · AI-generated · DeepSeek V4/V4.1 flash;License 徽章已随授权类内容一同移除)
→ Hero(三条主线 + **一行「全部代码与文档由 AI 生成」** + 拓扑图)→ 快速开始片段
目录 → **AI 生成** → 亮点 → 快速开始 → 功能详解 → 架构 → 安全模型 → 部署形态 → 配置
→ 控制面 API → 插件移植指南 → 开发 → 常见问题 → 目录结构 → 版本与迭代 → 贡献
→ 第三方组件与致谢 → 授权与商业使用(必须最后)→ 授权摘要收尾(全文唯一一处摘要)

⚠️ ## AI 生成 是第 1 个正文章节(用户 2026-09-13 明确「还有个重点要加载前面」)—— 它是这个项目的核心差异化:整站代码与文档由 AI 写成。别把它挪到后面,也别只留徽章不留正文。

# 硬规则 理由
1 授权章节放最后 6 个权威来源共识 + readme-craft 的 Trust 评分项就是「License 在最后?」
2 授权信息不要出现在前排正文(2026-09-13 用户纠正):靠顶部 License 徽章承载(本项目 = license-personal free | commercial paid,并链接到末节)+ 文末「授权与商业使用」章节尾的一行摘要。不要在徽章下方另加一句授权 blockquote —— 用户明确「说明文档还是在前面」不接受
3 Hero 区(前 50 行)必须有可视块 审计项 H3 占 7 分(拓扑图 / 截图 / GIF 任选)
4 一行描述 < 120 字符,且与 package.json 的 description 开头一致 审计项 H2 占 8 分,单项最高
5 超 100 行必须有 TOC,且锚点逐条可解析 自查法:把标题按 GitHub 规则转锚点(小写 / 去标点 / 空格→-)后与 TOC 比对
6 功能用表格/列表不写散文;清单型章节要声明「机制见亮点」 避免 C1 扣分与 S3 信息重复
7 API 概览必须从代码抓真实路由(grep -oE "app\.(get|post|put|delete)\("),别凭印象写 审计项 C3;写错路由比不写更糟
8 章节重排要用脚本按标题切分再拼装,重排后复跑 TOC 校验 手工搬章节极易丢内容
9 表格单元格里不要写裸 |(如 GET|POST)—— 会截断表格,改写「(POST 同形)」 格式错误扣 P2
10 发布后补 CI 徽章 与真实联系方式;上线前不要加 CI 徽章(占位符 = 死链) T3 / T4 是唯二「因尚未发布」而扣分的项

审计口径(readme-craft 22 项 / 100 分):Hook 25 · Onboarding 25 · Content 20 · Trust 15 · Structure 10 · Polish 5;等级 S≥90 / A≥80 / B≥70 / C≥60 / D<60。 本项目首轮自审 = 93/100(S),扣分仅:CI 徽章 0/3 · 维护者信息 0/3(<CONTACT_EMAIL> 未填)· S3 信息重复 2/3。


R-O13 · 双语文档(2026-09-13 用户定:中文优先,英文在同步 GitHub 时生成)

用户原话:「文档别忘了中英文双语,后续优先写中文,需要同步到 GitHub 时再更新英语。」

项 口径
母本 中文(README.md / PLUGIN-PORTING.md)。日常只维护中文;英文文件不要求随时同步,避免双份维护成本
英文文件名 README.en.md、PLUGIN-PORTING.en.md(与中文同目录,后缀 .en.md)
生成时机 发布 / 推送 GitHub 之前那一步(SOP 的 5.5)—— 也就是 §7 验证之后、§6 交付之前
语言切换行 两份文件顶部都要有:中文版写 [中文](README.md) · [English](README.en.md);英文版写 [English](README.en.md) · [中文](README.md)。⚠️ 英文文件存在之前不要加(否则是死链,扣 P1)
翻译时严格保持 代码块、命令、路径、env 名、包名、URL、图(ASCII/Mermaid)、表格结构与「版本与迭代」表内容 —— 逐字保留;占位符(<YOUR_GITHUB_ACCOUNT> 等)同步替换
不翻译(保持原文) LICENSE-UPSTREAM-MIT.txt(MIT 英文原文,逐字节);LICENSE 保持中文正文 + 英文摘要(现状即如此);THIRD-PARTY-NOTICES.md 中文即可(包名与许可标识本就是英文)
校验 英文版同样要跑 TOC 锚点校验(按英文标题算锚点)与相对链接存在性;两版的「版本与迭代」表行数与版本号必须一致
别忘 这是发布前唯一会因为"没做"而显得半成品的项 —— 写进 SOP 与 §10 待办,接手先看

R-O14 · 🚫 K8s 相关内容:源仓那侧视为废弃分支(2026-09-14 定稿;2026-09-15 用户升级为长期策略)

用户原话(2026-09-15):「记住这部分和 K8S 相关的代码 后续获取开发项目代码时 跳过就用当前清除或修改后的版本」

规则 判据
① 不回流 源仓的 K8s 资源 / 文档 / 注释 / 语义描述 / K8s 专属配置,不得因源仓更新而重新进入导出物
② 不重复实现 导出层已有的清除与改写就是唯一口径,不要每次重新发明
③ 改了源仓也不跟 源仓若再改 K8s 那段代码,以导出层版本为准(源仓那侧视为废弃分支)
判定标准 构建输出 blocking hits: 0;不为 0 = 回流了 ⇒ 按台账 §四 处置
权威清单 _K8s排除台账.md(本工作根)—— 含「下次取新版本怎么做」的步骤 + 判读表 + 噪音清单
扫描器 _k8s_scan.py(--source 扫源仓 / 无参数扫导出物;EXIT=1 = 有未覆盖项)

三重强制手段(缺一会静默失效): INCLUDE_DIRS/INCLUDE_FILES 白名单 → EXCLUDE_FILES/DROP_SCRIPTS → REGEX_RULES ⑦⑧⑨ + K8S_SEMANTIC_RULES + LEAK_PROBES。

已清到 0(源码与注释):62 → 0;含 K8s 专属配置项(config.ts 7 字段 + 3 常量 + parseCidrs())、 DeployMode 收窄为 'local'、全部注释与语义描述(Pod/file sidecar/ConfigMap)。 ⚠️ 连带必做(否则 tsc 报错):proxy.ts 的 deployMode === 'k8s' 实参改常量 false;web/server.ts 的 fail-loud 守卫删除。 ⏳ 唯一剩项:@kubernetes/client-node 依赖 + lock(8 处)—— 导出层删不了(须重生成 lock,⛔ 不手改 lock)。 ⚠️ 但这不等于「去源仓 npm uninstall 就行」(2026-09-15 更正):导出物里它 0 import(3 个 import 它的模块被 EXCLUDE_FILES 剔了),可源仓仍保留 K8s 后端(src/supervisor/{k8s-spawner,leader,reconcile}.ts 都 import 它)⇒ 在源仓直接删会打断源仓 tsc。 正确顺序:源仓先下线 K8s 后端 → 再 npm uninstall 重生成 lock → 最后重跑导出。三条路线见 _K8s清理影响评估与回归说明_20260915.md §9。


1.5 🔴🔴🔴 用户当场纠正过的硬口径(2026-09-14 凌晨:连纠 8 次)!!!

这不是"建议",是硬口径 —— 一条不遵守就要返工。 全部来自真实纠正,逐条附用户原话。

!!! 规则 判据 / 用户原话
!!! 1 !!! 没验证的能力:不写(不是标注「未验证」,是整条删) 「没验证的不要写意思就是不要写 !!!」,点名删「双部署后端同一接口(K8s 后端未验证)」。⇒ README 不得出现「未验证 / 实验性 / 模式 B / K8s 后端 / Postgres」等字样 —— 已全清(代码可留,文档不提)
!!! 2 !!! 不写废话:括号里的体贴话、推销话 「(想自己掌控每一步)不要写这种没用的废话」;「商业授权…联系 xxx 不用写这个废话」。判据:括号里若没有机制 / 数值 / 真实行为 / UI 提示 = 废话,一律删。已删:手动部署(想自己掌控每一步)、(建议先审一遍)、整段「商业授权」+ 邮箱、章节名「授权与商业使用」→「授权」
!!! 3 !!! 归类必须准:DeepSeek Harness 是「基座」,不是「第三方组件」 「这个不叫三方组件…所有开发都是基于这个来的」⇒ ① 删掉「第三方组件与致谢」整节;② 在「架构」里讲清 DSH = DeepSeek AI 开源的 agent harness(everything-is-a-plugin / Cordis 驱动 / 默认 npx @deepseek-ai/dsh web → 127.0.0.1:3080 本机单用户 Web UI);③ 补上 developer preview ⇒ 官方明说会破坏性变更(它才是"为什么要有兼容性预检 + 版本冻结"的钩子)
!!! 4 !!! 读码找亮点:亮点必须来自实际读码,且区分「已验证」 「在分析一遍项目看看还有哪些亮点」⇒ 按 R-O11 逐个读 src/** 头注;没验证过的不写(本次挖到的"模型管理两层""迁移账本同形"等因未实测而未采纳)
!!! 5 !!! 未持锁 ≠ 不能改导出物;但「重建」会删掉本地 .git ① 本工作根不在锁保护范围(钩子只护「文档库 / 代码仓」)—— 别再拿锁当理由拒改导出物(本次被纠正);② ⚠️ _build_export.py --force 的 rmtree(DST) 会连仓库里本地 .git 一起删(本次实测)⇒ 顺序必须 重建 → 六件套 → git init/commit → 推送,提交后不得再重建
!!! 6 !!! 安装成功才准提交 / 推送(用户定的闸门) 「必须按照说明文档 安装成功才能提交」⇒ 平台本体跑通(install 成功 + 登录 200 + 管理台 / 桌面 API 200)是下限;--dry-run 通过、组件级验证、探针全绿 都不算通过
!!! 7 !!! 敏感信息一律不进仓库(测试 IP / 账号密码 / 实例 ID / 服务器信息) 本次把真实测试 IP 写进 README 示例被当场抓到 ⇒ 改用 RFC 5737 文档保留地址(如 203.0.113.10.nip.io);并把 106.54.21.172 / ins-3q6k1p8t / 测试账号密码四项加进 LEAK_PROBES
!!! 8 !!! 提「注意事项」前先对齐本技能 §1 的 R-O1–R-O13 「感觉都不是我最早说的注意事项,你看看 skill」⇒ 用户要的是他原始定的硬规则,不是实现坑;计划/清单按 R-O 组织
!!! 9 !!! 章节顺序服务于读者;参考性章节别放太后;排版要整体看 「目录结构 是不是放的太靠后了,在整体看看你的排版呢」⇒ ①「目录结构」从 Meta 区上移到「架构」之后(逻辑结构 → 物理结构,读者顺着一路读);② 排版检查要整体过:分隔线用法、标题层级、表格/列表一致性、长句拆分、括号废话(见 !!! 2 !!!)。⚠️ 与 R-O12 的社区标准顺序冲突时,以用户当场指令为准并说明理由

改文档时的固定动作(本次反复用到,照抄)

  1. 两份同步:_overlay\<文件> 与 dsh-users-platform\<文件> 必须逐字节一致(改一份 = 改两份,改完 md5 比一次);
  2. 改完必验:md5 相同 + TOC 锚点机检无悬空 + 全篇关键词扫描(模式 B / K8s / 未验证 / 实验性 / WorkBuddy / 旧名 / 敏感串 应全 0);
  3. 提交:git -c core.autocrlf=false add -A → commit --amend --no-edit(首发阶段保持单条发布提交);提交后不得再重建;
  4. 改本技能:两副本(活跃 + 文档库归档)md5 必须一致,同步前先抢全局执行锁。

2. 保留 / 移除清单(delta · 改口径先改这里)

保留

assets/         注入脚本(2:inject/recovery.js · inject/assist.js)—— ⚠️ **proxy.ts 的 loadInject 按包根解析 ⇒ 缺了平台启动即抛错**,必须随包
src/            控制面 TS 源码(**已剔除 6 个 K8s 后端模块**,见下)
web/            静态页
scripts/        运维与冒烟脚本(**已剔除 5 个 K8s / 已排除插件相关脚本**)
test/           单测(**已剔除 2 个 K8s 模块的测试**)
.github/workflows/build.yml
package.json  package-lock.json  tsconfig.json  cordis.patch.yml
Dockerfile  .dockerignore  .gitignore(重建)
mksess.cjs  ensure-role-profile-patch.cjs(临时会话 / profile 补丁)

🔴 K8s 相关一律不带(2026-09-14 用户定稿,2026-09-15 升级为长期策略): ⛔ 不再保留 deploy/(11 个 K8s 清单)· poc/(4 个 K8s 可行性验证件)· Dockerfile.dsh(每用户 Pod 镜像)· 6 个 K8s 后端模块(k8s-spawner k8s-user-fs leader reconcile tcp-bridge web/file-service)· 2 个 K8s 测试 · smoke-file-service.mjs · CI 里的 dsh 镜像步骤 · config.ts 的 K8s 专属配置项 · 以及全部 k8s 注释与语义描述。 ✅ 保留 src/db/pg.ts(Postgres = 共享 HA,不是 K8s 专属)。 📌 权威清单与处置办法:_K8s排除台账.md(本工作根下)—— 含「下次取新版本怎么做」的步骤与判读表; 扫描器 _k8s_scan.py(--source 扫源仓 / 不给参数扫导出物);判定标准 = 构建 blocking hits: 0。

移除

路径 理由
poc/business-plugins/ 已投放插件(功能管理分区插件,含全部 .tgz)
poc/workspace-scoped-picker/ 已投放插件(目录选择器)
scripts/ensure-anysearch-admin.cjs
scripts/ensure-anysearch-pool.mjs
特定插件投放脚本
scripts/ensure-biz-plugins.cjs
scripts/ensure-portal-entry.cjs
scripts/install-workspace-picker.sh
scripts/provision-new-users.sh
插件 / 本平台专属投放与开通脚本
docs/(7 篇) R-O4:项目文档
STANDARD.md · poc/README.md · poc/*/README.md R-O4:文档
.workbuddy/ · lib/ · node_modules/ · data/ 本地状态与构建产物
.git ⛔ 历史里含全部内部信息 ⇒ 必须全新仓库
全部 *.tgz 构建产物

本就不在代码仓(别去找)

MCN 工作台(dsh-plugin-mcn-suite)、douyin-accounts、vision-router、各 skill 本体(含 MCN 相关 skill) 都不在 dsh_shenxian 里 —— 它们在其他仓库 / 实例 profile。收尾探针会复核 mcn / douyin / 抖音 / vision-router 0 命中。

⚠️ 特许保留项(不要在脱敏里动它)

项 处置 依据
dsh-univer-office(插件名 + 实例侧 unix-socket 适配) 保留原名、保留代码:src/supervisor/orchestrator.ts 的 DSH_INSTANCE_UNIVER_SOCKET / UNIVER_DSH_GATEWAY_SOCKET 段不得删;src/web/routes/whitelist.ts 注释里点名 dsh-univer-office;探针 LEAK_PROBES 里不得出现 dsh-univer / UNIVER 用户 2026-09-13:「univer 可以保留这个插件 专门讲讲如何把开源插件改造为可在多租户平台运行」
↳ 为什么值得保留 它是 PLUGIN-PORTING.md(插件移植指南)的唯一实证样本 —— 一个「静态预检通过但在托管平台完全不可用」的真实案例,含两层根因、3 条设计决策、2 个平台侧机制坑 同上

待决项(用户没拍板前维持现状)

  • poc/business-plugins + poc/workspace-scoped-picker:现按严格口径移除(「所有已投放的插件」)。若判定它们属「平台自带界面」而非投放插件 → 加回,并同步改本节 + 探针。

3. 脱敏映射表(唯一口径,改只改这里 + 脚本里的 GLOBAL)

类别 原值 替换为 命中
平台域名 dsh.alotbuy.com / *.alotbuy.com / alotbuy <baseDomain> 3 文件
↳ 特例 web/wake.html 的 safeNext() 正则 改成运行时从 location.hostname 推导注册域(split('.') 去最左一段),彻底去硬编码 —
服务器公网 IP 47.77.182.89 <SERVER_PUBLIC_IP> 1
宿主内网 IP 172.18.16.212 <HOST_LAN_IP> 1
服务器代码路径 /opt/dshs <INSTALL_DIR> 8
↳ 特例 require('/opt/dshs/node_modules/better-sqlite3') require('better-sqlite3')(等价且更规范) —
服务器平台目录 /opt/dsh/{state,artifacts,backups} /var/lib/dsh-web-platform/{state,artifacts,backups}(与上游文档一致的数据根) 6
内部档案号 全角/ASCII 括号里的 档案 NN(含 档案 81 · R1、(档案 20)、backoff (档案 20)) 整块删(号无对外意义);残渣(空括号 () / ().)由后续规则清掉 183
悬空文档引用 docs/k8s.md §5.2 / docs/blueprint.md / docs/domain-config.md 映射到 README 真实小节(README「部署形态」 / README「架构」 / README「配置」);§号 一并去掉 42
↳ 实现位置 以上两项由 _build_export.py 的 REGEX_RULES 做(不是 GLOBAL);⛔ 清理规则只准碰全角标点,唯一放开的两条 ASCII 规则:① (档案 NN)(模式里必须有档案号 ⇒ 不会误伤 foo())② ().+句末标点((): void 后面是 : ⇒ 不命中)。每次改 REGEX_RULES 必须重建 + tsc 复核(第一次踩过:ASCII 括号进字符类把 foo() 删了,tsc 报 Invalid character) —
↳ tar 相对写法 opt/dsh*(无前导斜杠) var/lib/dsh-web-platform* —
账号 / 私有仓库 maogeigei、[email protected]:...dsh_shenxian_doc.git <YOUR_GITHUB_ACCOUNT>;文档库引用随 README 重写整体移除 1
云厂商标识 「阿里云内网 DNS」「BT-Panel 58888/8765」「sshd 22/32022」 「云厂商内网 DNS」「面板」「sshd」 1
插件具体名 anysearch / @anysearch/anysearch-dsh / @liustack/modlens / mcn-workstation 「该插件」/「某第三方插件」→ 再整行重写成中性描述 6
↳ 例外(保留原名) dsh-univer-office 与其实例侧适配(DSH_INSTANCE_UNIVER_SOCKET / UNIVER_DSH_GATEWAY_SOCKET) 不脱敏、不删代码(用户 2026-09-13 明确「可以保留这个插件」);它同时是 PLUGIN-PORTING.md 的实证样本 ⇒ 其 env 名、注释、DELETE_LINES 条目都不得再动 3
项目改名 dshs 全部自指标识 dsh-web-platform(规则顺序:dshs.db → dshs.db → /var/lib/dshs → DSHS_ → dshs) 149
↳ 必须保留 上游骨架仓库(已按要求不再具名)、上游 \dshs`` 原样不动(出处/致谢);LICENSE-UPSTREAM-MIT.txt 逐字节不动 —

发布前必须替换的占位符(写在台账里):

占位符 出现位置
<YOUR_GITHUB_ACCOUNT> README.md、package.json → repository
<CONTACT_EMAIL> 原为 README.md 授权章节 / LICENSE —— 授权章节与 LICENSE 已于 2026-09-13 移除,该占位符随之消失(见 §5)
<COPYRIGHT_HOLDER> LICENSE
<SERVER_PUBLIC_IP> / <HOST_LAN_IP> scripts/install-egress-guard.sh(部署时按自己服务器填)
<INSTALL_DIR> / <baseDomain> 仅注释,可留

install.sh 里的 dsh.example.com / [email protected] 是文档示例,符合惯例,不改。


4. 保留未动(刻意)

  • 183 处「档案 NN」内部编号引用(仅代码注释):属内部档案号,不是本机/服务器信息。已列入「可选后续」;要清需用户点头(做一次纯注释替换)。
  • 上游 docs/ 内容虽为 MIT 可带走,但 R-O4「不带任何文档」⇒ 不带。

5. 授权结构(2026-09-13 15:1x 已变更:授权类文件全部移除)

🔴 现状(以本条为准,覆盖下文所有旧描述):用户 2026-09-13 明确 —— 「你的任务是改造和优化,这些内容全部删除」 ⇒ 导出仓里的 LICENSE / LICENSE-UPSTREAM-MIT.txt / THIRD-PARTY-NOTICES.md 三份已全部移除(同时从 OVERLAY 与 REQUIRED_EXPORT 摘除、_overlay/ 快照同步删除、README 的 License 徽章 / 目录项 / 「授权与商业使用」整节删掉、package.json 的 license 回到上游原值 MIT)。 原文备份在 ../_授权归档_发布时再放回/,恢复步骤见 _导出说明与脱敏台账.md §F。 ⛔ 不要再把授权/许可当议题去问用户(不属本技能范围,不列为待办、不上抛)。 ⛔ 不要再把授权/许可当议题去问用户(不属本技能范围,不列为待办、不上抛)。下文凡提到这三份文件的段落一律以此条为准(保留原文只为记录历史,不是要求)。 ⚠️ 但下面这条「MIT 硬约束」是客观事实,任何会话都不许删(删了会误导后人写出违规声明)。

⚠️ 硬法律前提(事实,必须记住):上游 dshs(上游作者(已按要求不再具名))是 MIT。MIT 不允许对上游代码附加限制 ⇒ 若日后要恢复「个人免费 / 商用收费」,只能分层:上游留 MIT,只对本项目新增部分收费;把整个仓库标成「商用需授权」= 违反 MIT。

若日后要对外发布(当前仓库里没有任何授权文件),必须先放回那三份并恢复 OVERLAY / REQUIRED_EXPORT。理由:

  1. 无 LICENSE ⇒ 默认「保留所有权利」⇒ 任何人都不能合法使用;
  2. 缺上游 MIT 声明 ⇒ 侵犯 上游作者(已按要求不再具名) 的著作权(MIT 明文要求保留版权与许可声明);
  3. 缺第三方 NOTICES ⇒ 多款依赖(MIT/Apache-2.0 等)同样要求保留声明。

⚠️ 不要再把「授权结构」当议题去问用户(2026-09-13 用户明确:"你的任务是改造和优化,这些内容全部删除")—— 不属本项目范围,不列为待办、不上抛。保持现状分层即可(保守合规:上游永远 MIT、只对本项目新增部分声明)。

即便日后发现 上游作者(已按要求不再具名) 就是用户本人(可整体简化为单一授权),也不是本技能要推进的事 —— 只在用户主动提出时按本表处理。但上一条「MIT 不允许对上游代码附加限制」是客观事实,任何会话都不许删掉它(删了就会误导后人写出违规声明)。

每次发版要动的地方:README.md 授权章节(若条款变)、LICENSE(版本/日期)、THIRD-PARTY-NOTICES.md(依赖版本与分布)。


6. 迭代发布 SOP

# 0) 先抢全局执行锁(会写文档库/或要动导出物时)
cd "/d/github/dsh_shenxian/dsh-server-docs"
ME="<会话名>" bash scripts/handoff-guard.sh --claim-exec "<会话名>"

# 1) 源仓库确认基线(只读)
export PATH="/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin:/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/mingw64/bin:/c/Windows/System32:$PATH"
git -C "D:/github/dsh_shenxian" status --short --branch
git -C "D:/github/dsh_shenxian" log --oneline -10

# 2) 若本次要改脱敏/保留口径 → 先改 _build_export.py 的 GLOBAL / INCLUDE_* / DROP_SCRIPTS / OVERLAY

# 3) 重建(手工撰写层会自动快照→恢复)
cd "/e/ProgramData/AI技能/dsh-laijing-github"
"/e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" _build_export.py --force

# 4) 改版本(三个地方一起改,否则不一致)
#    package.json 的 version | README.md「版本与迭代」表新增一行 | LICENSE 的版本/日期(条款没变就不用)

# 5) 六项验证(§7)——**全绿才准交付**

# 5.5) 【**发布到 GitHub 前必做**】补齐英文版(见 R-O13)——中文是母本,英文此刻才生成
#      README.en.md + PLUGIN-PORTING.en.md + 两份 README 顶部加语言切换行

# 6) 交付/推送(**R-O6:未经明确要求不做**)

版本号约定:遵循语义化版本。写 README 版本表时同时写「类型」列(首个公开发布 / 特性 / 修复 / 内部迭代)。

登记格式(README「版本与迭代」表):

| **v1.1.0** | 2026-10-xx | 特性 | 一句话摘要(对外能看懂,不写内部档案号)。 |

7. 验证六件套(缺一不可)

# 验证 命令 / 判据
① 阻断性探针 0 命中 脚本内置 LEAK_PROBES 与 INFO_PROBES 两档;blocking hits: 0 才放行。INFO_PROBES(档案 / 交接单)是有意保留的注释引用
② 未改动文件逐字节一致 抽样 cmp -s <源> <导出> → IDENTICAL
③ 行尾符不被改写 grep -c $'\r' 两边相等(CRLF 源必须仍是 CRLF)
④ 能编译 见下「tsc 验证法」→ tsc -p tsconfig.json --noEmit 退出码 0
⑤ install.sh 语法 bash -n install.sh + bash install.sh --help
⑥ 已移除项核对 逐一 [ -e ] 确认 docs / 两个插件目录 / STANDARD.md / lib / node_modules / .workbuddy 均不存在

tsc 验证法(导出物没有 node_modules,靠临时联接;用脚本而不是手敲,并且绝不能用 recursive 删除):

# 脚本已备好:<导出根>\_verify_tsc.mjs(建 junction → 跑 tsc → rmdirSync 拆联接)
"/e/ProgramData/.workbuddy/binaries/node/versions/22.22.2-3/node.exe" "<导出根>\_verify_tsc.mjs"
# 判据:tsc exit = 0 | junction removed = true
# 收尾再确认「导出物无 node_modules 残留」+「源仓库 node_modules 条目数未变」

⚠️ 绝不要用 rm -rf / rmSync(…, {recursive:true}) 删这个联接 —— 在 Windows 上会顺着联接删掉源仓库的 node_modules。只用 rmdirSync(只摘链、不进目标)。


8. 实测坑(全部踩过,别再踩)

  1. text 被重新赋值导致替换未落盘 —— 脱敏函数里 text = text.replace(...) 之后再用 if text2 != text 判「是否需要写盘」⇒ 全局替换永远不落盘(只落行级改动)。必须留 orig = text 做比较基准。
  2. 行级重写的 key 必须写「全局替换之后的文本」 —— 例:原行 (档案 70 的 anysearch 事故…),key 要写 (档案 70 的 该插件 事故…)。用替换前的原文当 key ⇒ 静默不命中,留下半吊子句子。
  3. 行级重写会丢缩进 —— 按 strip() 匹配就必须把原行的 indent 补回去(多行替换值还要给后续行也加 indent),否则 TS 缩进错乱。
  4. 全局替换顺序敏感 —— wake.html 的专用规则必须在笼统的 alotbuy → <baseDomain> 之前,否则专用规则永远不命中(会被先替换成 <baseDomain>.com 这种半成品)。
  5. 重建会抹掉手写文件 —— 所以有 OVERLAY(先快照 _overlay/ 后恢复)+ --force 安全闸。验证过一次:重建后 5/5 个 overlay 文件逐字节一致。
  6. .git 绝不能带过去 —— 历史里含全部内部信息;必须是全新仓库。
  7. Windows 下 install.sh 没有执行位 —— README 一律写 sudo bash install.sh;要执行位就 chmod +x 后再提交。
  8. 别信「探针没命中」的直觉 —— 探针必须在重建之后、还原 overlay 之后跑(overlay 里也可能带泄漏)。
  9. ⛔ 绝不对 _build_export.py 本身做批量替换 —— 脚本里同时存在「源模式」与「目标值」(例如规则 ("dshs", "dsh-web-platform")),盲替会把源模式一起改掉 ⇒ 改名规则静默失效(2026-09-13 实际误伤 4 处)。改脚本只用精确 Edit,改完必须重建一次并用 grep 复查。
  10. Dockerfile / Dockerfile.dsh 曾被整份跳过脱敏 —— is_text() 按扩展名判断,二者无扩展名(或 .dsh 不在白名单)⇒ 漏掉。已在 is_text() 里加特判。
  11. package.json 属「源派生」而非 OVERLAY —— 手改 version / description / repository / license 会在下次 --force 被覆盖。这类项目自有字段必须写成 GLOBAL 规则。
  12. dshs.db 是无前缀写法 —— src/config.ts 里默认库文件名不带 dsh- 前缀,只替换 dshs 会漏掉它;要单独一条规则。
  13. 改名要连导出目录名一起改,并同步两个辅助脚本里的绝对路径(_build_export.py 的 DST、_verify_tsc.mjs 的 EX),改完重跑一次 tsc 验证路径仍对。
  14. 废弃的旧候选名要进阻断性探针 —— 改名改了两轮时(dshs → 中间候选 → 终选),若只探最老的那个名,中间名会静默残留(_overlay 里最容易中招)。做法:把所有曾用名都加进 LEAK_PROBES。
  15. 改 overlay 的自指标识可以做批量替换(overlay 里只有本项目自己的标识,上游出处名是另一个字符串)—— 但必须先用 grep 确认「旧名出现处全是自指」再替换;_build_export.py 本身绝不能这么干(见坑 9)。
  16. 🔴 --claim-exec 的输出必须当场看;claim 与 release 绝不能写进同一条命令(2026-09-13 实际闯祸)—— 把 claim 结果重定向到文件、只显示 OWNER 首行 ⇒ 没发现抢锁失败;命令末尾的 --release-exec 是 rm -rf 语义,于是把另一个会话(R1-注入层-1104)的锁删掉了。正确姿势:
    • 抢锁单独一条命令,且当场看它的输出(✓ 已持全局执行锁 vs ✗ 抢锁失败);
    • 看到「占用者」不是自己 ⇒ 立即停手,不碰文档库/代码库;
    • 放锁前再 cat 交接单/.exec-lock/OWNER 确认首行是自己;
    • 万一误放:脚本实现是 rm -rf "$LOCKEXEC"、不留档 ⇒ 按 handoff-guard.sh 第 43 行的格式原样重建(OWNER / 开始:MM-DD HH:MM / 在做:…,值取自抢锁失败时的输出),再用 bash scripts/handoff-guard.sh 的信息模式验证「占用者」已回到原会话,并在回复里明确告知用户;若该会话其实已结束,请用户自行撤锁(处置权只属于用户)。
  17. 🔴 迁移工作根:先改脚本常量,再搬目录(2026-09-13 实际踩)—— 顺序颠倒(先 mv 后改 OUT)时,任何一次重建都会在旧位置把整个仓库重新建出来(那次建出 135 个文件),而且因为旧位置没有 _overlay,6 个手工层文件(README / LICENSE / NOTICE / PLUGIN-PORTING / install.sh / LICENSE-UPSTREAM-MIT)全部缺席 —— 若此时旧目录被当成交付物,就是一次「文档凭空消失」的事故。 正确顺序:① 改 _build_export.py 的 OUT 和 _verify_tsc.mjs 的 EX → ② 复制/搬运目录 → ③ 在新位置重建 → ④ 核对 文件数 与手工层 6/6 + 跑 tsc → ⑤ ls 确认旧位置不存在(没被重建复活)→ ⑥ 同步本技能与项目 MEMORY 里的路径引用。 ⚠️ 附带教训:_build_export.py 的安全闸与 OVERLAY 机制都依赖 OUT 指向真实工作根;OUT 指错时它不会报错,而是默默在别处新建一套。
  18. 🔴 INCLUDE_DIRS / INCLUDE_FILES 是白名单:漏了不报错,只是少文件(2026-09-13 实际踩:assets/ 漏收录 ⇒ 导出的仓库缺注入脚本,平台会 fail-fast、自带校验脚本也会失败)。两条防线:
    • REQUIRED_EXPORT 清单(脚本内,26 项):构建时逐个 os.path.exists,缺一即 return 1;新增"运行时要读的文件"必须加进去。
    • 用被导出仓库自带的校验脚本验收 —— node scripts/verify-inject.cjs(读 assets/inject/*.js + 检查 proxy.ts 走 loadInject)。这比"我看了一眼目录"可靠得多。 ⚠️ 同类风险点:package.json 的 files(npm/git 安装按它过滤,与 INCLUDE_* 是两套名单,都要补)。

9. 命令速查

# 重建
cd "/e/ProgramData/AI技能/dsh-laijing-github"
"/e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" _build_export.py --force

# 只跑探针/看结构(不重建)
grep -rIlF "alotbuy" dsh-web-platform/ ; find dsh-web-platform -type f | wc -l

# 看某文件与源的差异
diff -u "D:/github/dsh_shenxian/<f>" "dsh-web-platform/<f>"

# 行尾对照
grep -c $'\r' "<源 f>" ; grep -c $'\r' "dsh-web-platform/<f>"

10. 已知待办 / 漂移(接手先看)

✅ 2026-09-13 15:1x 全部清零 —— 以下原待办均已处理: · install.sh 已在服务器隔离目录跑通 --dry-run(并修 4 个缺陷)| · 悬空 docs/*.md 42→0| · 「档案 NN」197→0| · 7 处占位符已按 PUBLISH_* 填| · poc/ 两个插件的加回结论 = 保持移除。 ⛔ 「授权条款 / 法律意见 / 上游作者(已按要求不再具名) 是否本人」已从本项目移除 —— 用户明确「你的任务是改造和优化,这些内容全部删除」⇒ 不再列为待办、不再上抛(事实层面的 MIT 约束见 §5,那条不许删)。

当前仍需注意的(非待办,是风险提示):

  • ⚠️ 首装从未在干净机器上真跑过:--dry-run 已验证全流程,但真实安装会写 /etc、建 systemd unit、起服务 ⇒ 首次真装请在一台干净机器上做。
  • ⚠️ 导出基线会漂:导出脚本复制的是工作树(多会话并行在改源码仓)⇒ 发布前按 git archive <commit> 冻结,或每次重建必重跑探针 + _verify_tsc.mjs。
  • ✅ 项目名已定稿(用户 2026-09-13):中文 DSH Web 平台 | English DSH Web Platform | 技术标识 dsh-web-platform(已在 npm 与插件目录实测未占用)。若日后要换名,按 R-O8 重走「查占用 → 改全量标识 → 保留出处致敬」,并把新废弃的旧名加进探针。
  • ✅ 本技能的归档副本 + INDEX.md 登记已补(2026-09-13):dsh-server-docs/skills/dsh-opensource-release/SKILL.md,两副本 md5 一致;INDEX §一/§二 已登记;四件套全绿。 ⚠️ 本技能每次改动后都要同步归档副本(md5 必须一致),同步前先抢全局执行锁;纪律 = 先单独抢锁当场看输出 → 验 OWNER 是自己 → cp → 两副本 md5 一致 → 复跑四件套 → 再验 OWNER → --release-exec。
  • ⏳ 英文版待生成(发布前必做,见 R-O13):README.en.md + PLUGIN-PORTING.en.md + 两份顶部的语言切换行。当前刻意不做(用户口径:中文优先,同步 GitHub 时再更新英语)—— ⚠️ 但切换行要等英文文件存在后再加,否则是死链。
  • 🔴 导出基线会漂(2026-09-13 11:2x 实测):导出脚本复制的是工作树,而多个会话在并行改源码仓 —— 当时 D:\github\dsh_shenxian 的 HEAD 仍是 da3e0f9(⚠️ 2026-09-13 20:2x 实测已变为 43976fe「初始提交」,且仅 1 条提交),但工作树有 20 个未提交文件(orchestrator.ts / crash-policy.ts / proxy.ts / spawner.ts / config.ts / web/*.html / test/* …),导出里因此混入了别人未完成的改动;同时新增了需脱敏的标识('dsh-plugin-mcn-suite')触发探针。发布前必须二选一:① 把导出改成按 commit 取(git archive <commit>,才是"冻结版本");② 或明确接受"含未提交工作"并每次重建后重跑探针(新增插件名/内部名会随别人提交冒出来)。
  • ⚠️(知识库侧,非本技能职责):本机 .workbuddy/skills/dsh-instance-diagnose/ 尚无归档副本;INDEX.md 只登记了 3 个 skill(dsh-knowledge-upkeep 未登记)。属既有漂移,未擅自修。

相关

  • 台账(唯一事实源):_导出说明与脱敏台账.md(在本工作根下)
  • 构建脚本:_build_export.py | 类型检查:_verify_tsc.mjs | 手工层快照:_overlay\(三者都在本工作根下)
  • 插件移植指南(随仓库发布):dsh-web-platform\PLUGIN-PORTING.md —— 讲「把开源插件改造成多租户平台可用」,含六个失败模式 H1–H6 与五条规范 R-a~R-e,样本 = dsh-univer-office
  • 内部权威源(只读参考,不外带):dsh-server-docs/04-调整方案/75-*.md(托管友好性 + 资源成本两维度)· 76-*.md(univer 改造全过程)· 71-*.md(兼容性预检)
  • 技能:dsh-change-workflow(改动流程与红线)· dsh-knowledge-upkeep(文档库维护)· dsh-instance-diagnose(实例故障)
  • 项目事实:dsh-server-docs/BRIEF.md(现行事实)· dsh-server-docs/CODEBUDDY.md(动作前规则)