odai-dsh-agent 0.2.23 → 0.2.25

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.
Files changed (38) hide show
  1. package/README.md +4 -4
  2. package/build/bin/odai-dsh-agent.mjs +9 -2
  3. package/build/bin/odai-dsh-agent.mjs.map +1 -1
  4. package/build/src/control-center-installer.d.mts.map +1 -1
  5. package/build/src/control-center-installer.mjs +90 -50
  6. package/build/src/control-center-installer.mjs.map +1 -1
  7. package/build/src/installer.d.mts +3 -0
  8. package/build/src/installer.d.mts.map +1 -1
  9. package/build/src/installer.mjs +145 -24
  10. package/build/src/installer.mjs.map +1 -1
  11. package/build/src/operation-lock.d.mts +2 -0
  12. package/build/src/operation-lock.d.mts.map +1 -0
  13. package/build/src/operation-lock.mjs +48 -0
  14. package/build/src/operation-lock.mjs.map +1 -0
  15. package/package.json +1 -1
  16. package/preset/odai/runtime/governance.d.mts +2 -0
  17. package/preset/odai/runtime/governance.d.mts.map +1 -1
  18. package/preset/odai/runtime/governance.mjs +15 -4
  19. package/preset/odai/runtime/governance.mjs.map +1 -1
  20. package/preset/odai/runtime/model-route.d.mts.map +1 -1
  21. package/preset/odai/runtime/model-route.mjs +21 -14
  22. package/preset/odai/runtime/model-route.mjs.map +1 -1
  23. package/preset/odai/runtime/semantic-memory.d.mts.map +1 -1
  24. package/preset/odai/runtime/semantic-memory.mjs +63 -25
  25. package/preset/odai/runtime/semantic-memory.mjs.map +1 -1
  26. package/preset/odai/runtime/session-evidence.d.mts.map +1 -1
  27. package/preset/odai/runtime/session-evidence.mjs +4 -104
  28. package/preset/odai/runtime/session-evidence.mjs.map +1 -1
  29. package/preset/odai/runtime/store-lock.d.mts.map +1 -1
  30. package/preset/odai/runtime/store-lock.mjs +42 -11
  31. package/preset/odai/runtime/store-lock.mjs.map +1 -1
  32. package/preset/odai/skills/odai/SKILL.md +1 -1
  33. package/preset/odai/skills/odai/assets/routing-roles/controller.md +2 -2
  34. package/preset/odai/skills/odai/references/dao.md +1 -1
  35. package/preset/odai/skills/odai/references/leverage.md +3 -2
  36. package/preset/odai/skills/odai/references/support.md +2 -2
  37. package/preset/odai/skills/odai/references/verification.md +2 -2
  38. package/preset/odai/skills/odai/scripts/install-routing.mjs +69 -14
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { closeSync, fsyncSync, mkdirSync, openSync, readFileSync, rmSync, writeSync, } from "node:fs";
2
+ import { closeSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeSync, } from "node:fs";
3
3
  import { dirname } from "node:path";
4
4
  function errorCode(error) {
5
5
  if (error === null || typeof error !== "object" || !("code" in error))
@@ -55,24 +55,55 @@ function releaseLock(handle, lockPath, owner) {
55
55
  throw new Error(`Odai configuration lock ownership changed before release: ${lockPath}`);
56
56
  rmSync(lockPath);
57
57
  }
58
- export function acquireOwnedStoreLock(path, label) {
59
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
60
- const lockPath = `${path}.lock`;
61
- const claimPath = `${lockPath}.claim`;
58
+ function acquireClaim(claimPath, label) {
62
59
  const owner = `${process.pid}:${randomUUID()}`;
63
- const claimOwner = `${process.pid}:${randomUUID()}`;
64
- let claimHandle;
65
60
  try {
66
- claimHandle = createLock(claimPath, claimOwner);
61
+ return { handle: createLock(claimPath, owner), owner };
67
62
  }
68
63
  catch (error) {
69
- if (errorCode(error) === "EEXIST") {
70
- throw new Error(`${label} lock acquisition is already in progress; retry the tool call`);
64
+ if (errorCode(error) !== "EEXIST")
65
+ throw error;
66
+ }
67
+ const current = readLockOwner(claimPath);
68
+ if (current === undefined || processIsAlive(current.pid)) {
69
+ throw new Error(`${label} lock acquisition is already in progress; retry the tool call`);
70
+ }
71
+ const displacedPath = `${claimPath}.recovery-${process.pid}-${randomUUID()}`;
72
+ try {
73
+ renameSync(claimPath, displacedPath);
74
+ }
75
+ catch (error) {
76
+ if (errorCode(error) === "ENOENT") {
77
+ throw new Error(`${label} lock acquisition changed during recovery; retry the tool call`);
71
78
  }
72
79
  throw error;
73
80
  }
81
+ let displacedWasStale = false;
82
+ try {
83
+ const displaced = readLockOwner(displacedPath);
84
+ if (displaced?.value !== current.value) {
85
+ throw new Error(`${label} lock acquisition ownership changed during recovery; displaced successor preserved at ${displacedPath}; retry the tool call`);
86
+ }
87
+ displacedWasStale = true;
88
+ return { handle: createLock(claimPath, owner), owner };
89
+ }
90
+ finally {
91
+ if (displacedWasStale)
92
+ rmSync(displacedPath, { force: true });
93
+ }
94
+ }
95
+ export function acquireOwnedStoreLock(path, label) {
96
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
97
+ const lockPath = `${path}.lock`;
98
+ const claimPath = `${lockPath}.claim`;
99
+ const owner = `${process.pid}:${randomUUID()}`;
100
+ const claim = acquireClaim(claimPath, label);
74
101
  let handle;
75
102
  try {
103
+ const activeClaim = readLockOwner(claimPath);
104
+ if (activeClaim?.value !== claim.owner) {
105
+ throw new Error(`${label} lock acquisition ownership changed before update; retry the tool call`);
106
+ }
76
107
  try {
77
108
  handle = createLock(lockPath, owner);
78
109
  }
@@ -89,7 +120,7 @@ export function acquireOwnedStoreLock(path, label) {
89
120
  }
90
121
  finally {
91
122
  try {
92
- releaseLock(claimHandle, claimPath, claimOwner);
123
+ releaseLock(claim.handle, claimPath, claim.owner);
93
124
  }
94
125
  catch (error) {
95
126
  if (handle !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"store-lock.mjs","sourceRoot":"","sources":["../src/store-lock.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store-lock.mjs","sourceRoot":"","sources":["../src/store-lock.mts"],"names":[],"mappings":"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"}
@@ -41,7 +41,7 @@ description: 以“成事而不妄为”为入口处理通用任务。用户点
41
41
  - **日常关怀**:疲惫、焦虑、自我怀疑、反刍、羞耻、怕错、消极或失去行动感时读 `references/care.md`;非危机支持不诊断,也不自动改变模型或持久化状态。
42
42
  - **危机保护**:持续或加重低落、绝望、负担感、自伤、轻生或即时危险信号出现时主动读 `references/human-safety.md`。明确自残、轻生或即时危险时任务让位:先关怀并确认即时安全;迫近时连接当地急救或急诊与可信任者,避免独处并在安全时远离危险物。
43
43
 
44
- 探索、决定与实施不自动切换;明确要求执行才实施,纠正后重新对齐。支撑只能补当前缺口,不能降低目标、删减验收或把停手冒充完成。
44
+ 探索、决定与实施不自动切换;明确要求执行才实施。用户纠正使目标、范围或授权变化时,重新对齐受影响部分;只指出遗漏、未执行或错误完成声明时,在仍有效的授权内补做并重验,不等待再次启动。支撑只能补当前缺口,不能降低目标、删减验收或把停手冒充完成。
45
45
 
46
46
  ## 共同行动边界
47
47
 
@@ -1,12 +1,12 @@
1
1
  跟随用户当前的主要语言;面向用户的任务列表、计划、状态更新、委派说明与回交也使用该语言,正式产物另有用户或项目约定时除外。你是 odai 的唯一总控:持续持有真实目标、授权、全局状态、路线、实施、修正回路与最终交付。调查、规划、前端制作和验收是按需分离的责任,不是必须走完的阶段。
2
2
 
3
- 能在当前上下文可靠闭环时,直接谋定、行动、验证和交付,不为展示路由调用其他角色。调查限于宿主指定的项目根,不向父目录、兄弟目录、用户目录或其他工作区扩散。只有决定阻断问题需要多源事实或较大原始材料,且实测压缩收益覆盖交接和抽查成本时,才调用 __ODAI_RESEARCHER_ROLE__;只在独立判断能改变路线时调用 __ODAI_PLANNER_ROLE__;只在独立判断能改变放行结果时调用 __ODAI_REVIEWER_ROLE__;只在界面设计或前端制作存在当前总控不能可靠闭合的专业缺口时调用 __ODAI_FRONTEND_ROLE__。复杂、高风险、便宜模型可用或角色已配置,都不单独触发分工。
3
+ 能在当前上下文可靠闭环时,直接谋定、行动、验证和交付,不为展示路由调用其他角色。调查以宿主指定的项目根和用户点名对象为边界;根外材料只有当前结果确实依赖且已获相应授权时才读取,不因名称相似或方便向父目录、兄弟目录、用户目录或其他工作区扩散。只有决定阻断问题需要多源事实或较大原始材料,且实测压缩收益覆盖交接和抽查成本时,才调用 __ODAI_RESEARCHER_ROLE__;只在独立判断能改变路线时调用 __ODAI_PLANNER_ROLE__;只在独立判断能改变放行结果时调用 __ODAI_REVIEWER_ROLE__;只在界面设计或前端制作存在当前总控不能可靠闭合的专业缺口时调用 __ODAI_FRONTEND_ROLE__。复杂、高风险、便宜模型可用或角色已配置,都不单独触发分工。
4
4
 
5
5
  规划只冻结会改变结果的决定、允许与禁止范围、待核实前提、验收与停止条件,不预做实施。收到规划后,不重做首次调查;只读实施所需的目标原件、直接依赖与验收入口。局部做法不改变目标、范围、契约与验收时,总控自主决定;新证据推翻路线时,只重判受影响部分。
6
6
 
7
7
  实施失败但路线仍成立时,总控在当前上下文做最小修正;失败证据推翻路线时,由总控或 planner 增量改路。创建角色默认使用新鲜独立上下文与有界任务包,不复制完整总控会话;只有无法裁剪的既往交互本身是决定性证据、继承范围与用量可核实且净收益覆盖缓存失效、压缩和延迟成本时才继承。reviewer 只读不可变证据包,不重新扫描仓库或重跑已成功的确定性检查。reviewer 发现实施偏差就返回总控,发现路线或验收设计失效才返回规划,缺用户取舍或外部条件则准确停在边界。
8
8
 
9
- 验证按属性和证据版本去重。相关实现、依赖与验收源未变化时,不为安心、交接或形式完整重复同一调查、命令、浏览器验证或模型判断。相干修正后只重跑受影响的验收,最终全套验收最多一次。已有决定性证据闭合所有要求时立即收口。
9
+ 验证按属性和证据版本去重。相关实现、依赖与验收源未变化时,不为安心、交接或形式完整重复同一调查、命令、浏览器验证或模型判断。相干修正后只重跑受影响的验收;只有修正改变组合状态、共享契约或使整体证据失效时,才重新执行相称的全套验收。已有决定性证据闭合所有要求时立即收口。
10
10
 
11
11
  所有角色共享 odai 内核,但只有总控持有完整任务和最终交付。角色自报、调用请求或生成配置不能证明实际路由成功;必须核对宿主返回的线程、角色、真实模型和用量证据。
12
12
 
@@ -9,7 +9,7 @@
9
9
  - 能自行查证的事实先查证,普通实现细节自主决定。意图证据不足时,只询问会区分实质路线、且无法从现有材料确定的用户结果、价值取舍、范围、不可接受结果或外部条件;用户也不知道答案时,共同探索可区分的事实与假设,不要求用户先给实现方案。
10
10
  - 疑似误写、否定要求或彼此冲突的约束、多种合理理解会改变结果时,说明当前理解与分歧;只有唯一解释且不改变目标与边界时可标明前提后继续,否则由用户决定。
11
11
  - 实施、提交或发布授权在目标唯一后才生效,不能让目标变唯一;它只对当时已对齐的目标、范围和后果有效。用户纠正或新证据使其中任一项实质变化时,受影响的旧计划、验收和授权失效;未受影响部分可保留,重新对齐后再决定后续动作。
12
- - “更好看、更顺、更高级”等感知目标先结合现有基线、参考和场景形成可逆方案。只有多条路线会产生实质不同结果或连续调整仍不收敛时才请用户选择;不得把模型方案冒充用户已经验收。
12
+ - “更好看、更顺、更高级”等感知目标先结合现有基线、参考和场景形成可逆方案。尚未对齐时,方案只供讨论比较,不因可撤回就写入目标或参考源。已获实施授权且结果与边界清楚时,自主选择实现细节并验证;多条路线会产生实质不同结果,或调整暴露未决取舍时,才请用户决定。不得把模型方案冒充用户已经验收。
13
13
 
14
14
  ## 目标、参考与写入
15
15
 
@@ -8,8 +8,9 @@
8
8
  - 调查、规划、前端制作与验收是可分离责任,不是必走阶段。实施始终由总控负责;单一充分能力的总控能可靠闭环时,在同一线程查明、谋定、行动、验证和交付,不为展示路由启动任何角色。
9
9
  - **researcher** 只补多源事实获取与原始上下文压缩缺口。只有一个会改变后续决定的具体问题需要多份权威来源或较大材料,且有界来源账本能直接补足该决定缺口时才使用。它只读返回事实、精确来源、权威与时效、冲突、未知和停止依据,不选方案、冻结计划、实施或放行。单一权威来源、普通仓库查看、实现期调试、泛泛“调查”、任务复杂或仅有便宜模型都不触发;总控或 planner 仍抽查每个会改路的原始来源。
10
10
  - researcher 运行时只判任务适配,不感知模型价格;映射只是用户显式启用窄触发,不证明或保证降本,缺可比权威价格与实测 usage 时不得作节省承诺。
11
- - **planner** 只补独立判断缺口。当用户前提、根因、路线或验收设计仍有会改变结果的分支,且新上下文能增加当前线程拿不到的判断时才调用。planner 只冻结目标、证据、边界、决定、验收与停止条件,不预做实施;完成后把有界计划交回总控。原任务已授权实施且目标与范围未变化时,总控接回计划后继续实施,不再等待用户说“继续”;plan-only、新任务、扩围、用户纠正或缺少用户决定时先重新对齐。
12
- - **reviewer** 只在独立判断能改变尚未放行的具体属性时使用。宿主把当前有效的用户决定及其精确相关原文、对齐问题与用户回答、规划、实际 diff 与决定性工具结果各保留一份组成不可变证据包;后续明确决定只取代与其冲突的早期要求,未冲突要求继续有效,assistant 摘要不产生或取代用户决定。reviewer 不扫描仓库或重复成功检查。实施偏差回总控,路线失效回总控或 planner,缺用户决定或外部条件则停在安全边界。
11
+ - **planner** 只补独立判断缺口。当用户前提、根因、路线或验收设计仍有会改变结果的分支,且新上下文能增加当前线程拿不到的判断时才调用。planner 只冻结目标、证据、边界、决定、验收与停止条件,不预做实施;完成后把有界计划交回总控。原任务已授权实施且目标与范围未变化时,总控接回计划后继续实施,不再等待用户说“继续”;plan-only、新任务、扩围、授权变化或缺少用户决定时先重新对齐,用户纠正的影响遵循 `SKILL.md`。
12
+ - **reviewer** 只在独立判断能改变尚未放行的具体属性时使用。用户明确要求独立复核时,独立性本身就是验收属性。
13
+ 宿主把当前有效的用户决定及其精确相关原文、对齐问题与用户回答、规划、实际 diff 与决定性工具结果各保留一份组成不可变证据包;后续明确决定只取代与其冲突的早期要求,未冲突要求继续有效,assistant 摘要不产生或取代用户决定。reviewer 不扫描仓库或重复成功检查。实施偏差回总控,路线失效回总控或 planner,缺用户决定或外部条件则停在安全边界。
13
14
  - **frontend** 只补界面设计或前端制作的专业能力缺口,不是领域资料包,也不构成按数据库、安全等领域名称追加平行责任的先例。只有当前总控不能可靠闭合且专长能改变成品质量时才使用;局部样式、文案和窄修复直接完成。宿主可在当前线程取得该责任,也可启动有界独立上下文;责任合同不绑定模型、预算或调度形态。目标、范围或验收未冻结时回 planner 或总控,冻结后的具体制作与界面验证遵循 `references/craft.md`,不在本文件复制工艺。
14
15
  - agent 启动默认选择新鲜独立上下文,只交付按缺口裁剪的有界任务包,不得复制完整总控会话。任务包只保留当前有效决定及其必要精确原文、被取代决定的最小关系、当前目标与约束、责任合同、commit / diff / 文件指针、决定性工具结果和未决问题,省略完整会话、长聊天、重复工具输出与过程叙述。
15
16
  - 任务包显式写明用户当前主要语言;除正式产物另有用户或项目约定外,任务标题、委派说明与回交都使用该语言,避免宿主原样转发异语内容。
@@ -4,11 +4,11 @@
4
4
 
5
5
  ## 按表现升降
6
6
 
7
- 不以模型名称、价格或名声判断能力。当前理解准确、要求完整、证据与结论对应且能收口时保持自主。用户纠正、工具或测试失败、证据冲突、遗漏要求、同一路线没有新证据却继续尝试、范围漂移或无法收口,都是支撑不足的可观察信号。
7
+ 不以模型名称、价格或名声判断能力。当前理解准确、要求完整、证据与结论对应且能收口时保持自主。用户指出误解或执行偏差、工具或测试失败、证据冲突、遗漏要求、同一路线没有新证据却继续尝试、范围漂移或无法收口,都是支撑不足的可观察信号。
8
8
 
9
9
  按当前缺口选最小充分项,不把下列清单当固定阶段:
10
10
 
11
- 1. 重新对齐当前真实结果、不可接受结果和验收,让受用户纠正影响的旧计划、授权与完成判断失效。
11
+ 1. 对照当前用户要求与实际产物,定位缺失结果或失效证据,修正旧计划和完成判断;授权是否变化遵循 `SKILL.md`,不因需要纠错自动撤销仍有效的授权。
12
12
  2. 分开事实、假设、建议与待决定事项。
13
13
  3. 把下一步缩成能独立验证的动作。
14
14
  4. 读取一份能解决明确缺口的工艺或项目资料。
@@ -5,7 +5,7 @@
5
5
  ## 建立验收
6
6
 
7
7
  - 先确认验收对应用户已对齐的真实结果,而非模型自行选择的根因、手段或交付物;再把明确结果、限制、具体对象、输入、位置和不可接受结果映射成可观察证据,证据证明为目标所必需的条件也纳入。
8
- - 只验证相关属性和主要回归风险。测试、构建、静态检查、diff、截图、日志和人工观察各自只证明实际覆盖的内容,不能互相冒充。
8
+ - 只验证相关属性和主要回归风险,每份证据绑定实际覆盖的交付对象与属性。配套构建或测试通过只证明对应配套结果,主要交付物仍须有与用户目标对应的完成证据。测试、构建、静态检查、diff、截图、日志和人工观察不能互相冒充。
9
9
  - 项目已指定某项事实的权威筛选、查询、命令、样本或来源时,按该入口核验;相似字段、近似范围、替代命令或其他来源不能冒充同一对象与含义。
10
10
  - 验证强度由失败代价、影响范围、不确定性和已有证据覆盖共同决定;用户可见、工具可用或追求完整本身不构成升级理由。较轻证据已覆盖目标与主要风险时即采用;只有关键属性仍无法判定,或出现失败、冲突与新风险时,才升级到更接近真实场景的验证。
11
11
  - 验收先写要证明的属性,不把模型自行选择的命令、工具或流程升级成成功条件;只有用户或权威约定明确点名时,指定方法本身才属于契约。指定验证器因当前启动入口或依赖不可用而失败时,先核对现有环境能否用兼容入口运行同一验证器;仍不可用才采用真正覆盖同一属性的其他证据,并明确它没有证明原验证器已通过,不把自写近似检查称为等价。证据仍缺失就如实标明。
@@ -15,7 +15,7 @@
15
15
  - 用户已对齐的真实结果已经成立,明确要求均有结果,主要风险有相称证据,才算完成。局部未知只阻断依赖它的部分,其余继续交付。
16
16
  - 声明、配置和注释只证明“写了什么”;局部观测只证明观测范围;真实调用或使用链才证明端到端结果。
17
17
  - 两个或更多写入批次共同组成一个交付物时,组件完成不具有传递性。主流程只在唯一组合状态上核对实际改动范围、共享契约、依赖顺序和完整验收;各批次分别通过或分别受审不能替代组合证据。
18
- - 组合时出现的冲突解决或兼容性编辑属于新的获授权写入,须有自己的范围和验收。用户要求独立复核,或组合跨越重大安全、数据、并发、兼容、迁移或公共契约边界时,对组合状态进行独立复核。
18
+ - 组合时出现的冲突解决或兼容性编辑属于新的获授权写入,须有自己的范围和验收。组合跨越重大安全、数据、并发、兼容、迁移或公共契约边界时,辨明尚未被现有证据闭合、需要独立判断的组合属性,按 `references/leverage.md` 取得独立复核;不只凭边界名称制造角色。用户明确要求的独立复核必须完成,重复自检不能替代独立证据;能力不可得时按同一 owner 的降级边界处理。
19
19
  - 改动落地但关键场景未验证时,明确区分已实施、已验证与未验证,不用“应该、看起来、理论上”表达成功。
20
20
  - 实际结果或用户反馈与原判断不符时,将其视为新证据,修正结论、验收或后续做法,并让受影响的旧证据与完成判断失效;不把已说过的话当成必须维护的立场。
21
21
  - 版本、候选、阶段、提交、发布或迁移状态属于可验证结果。先核对机器可读事实源、当前产物与真实事件;前一状态未实际结束时更新同一状态,不创建后继值或把当前候选写成历史。确需迁移时,核对权威载体与用户文档指向同一当前值,历史记录按事实保留但不与现役状态争夺所有权。
@@ -292,7 +292,20 @@ function assertManagedState(root, layoutValue, manifest) {
292
292
  if (conflicts.length) fail(`目标已有非 odai 管理的配置:${conflicts.join(", ")}`);
293
293
  return;
294
294
  }
295
- if (manifest.id !== "odai-routing-installation" || manifest.host !== args.host) fail("无效的 odai 路由清单");
295
+ if (manifest.id !== "odai-routing-installation" || manifest.host !== args.host || manifest.scope !== args.scope) fail("无效的 odai 路由清单");
296
+ if (typeof manifest.target !== "string" || path.resolve(manifest.target) !== targetRoot) fail("旧路由清单的目标与当前配置根不匹配");
297
+ const expectedSetting = layoutValue.settings;
298
+ const installedSetting = manifest.settings;
299
+ if (expectedSetting) {
300
+ if (!installedSetting
301
+ || installedSetting.file !== expectedSetting.file
302
+ || installedSetting.key !== expectedSetting.key
303
+ || installedSetting.installed !== expectedSetting.value) {
304
+ fail("旧路由缺少可恢复的宿主设置记录");
305
+ }
306
+ } else if (installedSetting) {
307
+ fail("旧路由包含当前宿主不支持的设置记录");
308
+ }
296
309
  const accepted = new Set([...(layoutValue.knownFiles || layoutValue.managedFiles), ...layoutValue.retiredFiles]);
297
310
  for (const [relative, expected] of Object.entries(manifest.files || {})) {
298
311
  if (!accepted.has(relative)) fail(`旧路由包含未知文件:${relative}`);
@@ -316,30 +329,72 @@ function removeObsolete(root, manifest, desiredFiles) {
316
329
 
317
330
  function uninstall(root, manifestPathValue, manifest) {
318
331
  const files = Object.keys(manifest.files || {});
332
+ const plannedFiles = new Map();
319
333
  for (const relative of files) {
320
- const file = path.join(root, relative);
321
334
  const original = manifest.originalFiles?.[relative];
322
- if (original?.existed) atomicWrite(file, Buffer.from(original.content_base64 || "", "base64"));
323
- else if (existsSync(file)) unlinkSync(file);
335
+ if (!original?.existed) {
336
+ plannedFiles.set(relative, null);
337
+ continue;
338
+ }
339
+ const content = Buffer.from(original.content_base64 || "", "base64");
340
+ if (sha256(content) !== original.sha256) fail(`旧路由的原始文件恢复记录已损坏:${relative}`);
341
+ plannedFiles.set(relative, content);
342
+ }
343
+ const settingPlan = manifest.settings ? planSettingRestore(root, manifest.settings) : null;
344
+ const snapshots = new Map();
345
+ for (const relative of files) snapshot(root, relative, snapshots);
346
+ if (settingPlan) snapshot(root, settingPlan.relative, snapshots);
347
+ snapshot(root, manifestName, snapshots);
348
+
349
+ try {
350
+ for (const [relative, content] of plannedFiles) applyFileState(path.join(root, relative), content);
351
+ if (settingPlan) applyFileState(path.join(root, settingPlan.relative), settingPlan.content);
352
+ unlinkSync(manifestPathValue);
353
+ } catch (error) {
354
+ try {
355
+ restore(root, snapshots);
356
+ } catch (restoreError) {
357
+ throw new AggregateError([error, restoreError], "路由卸载失败且无法完整回滚;请检查现有托管清单与文件状态");
358
+ }
359
+ throw error;
324
360
  }
325
- if (manifest.settings) restoreSetting(root, manifest.settings);
326
- unlinkSync(manifestPathValue);
327
361
  return [...files, ...(manifest.settings ? [`${manifest.settings.file}#${manifest.settings.key}`] : []), manifestName];
328
362
  }
329
363
 
330
- function restoreSetting(root, spec) {
331
- const file = path.join(root, spec.file);
332
- const current = readJsonObject(file);
364
+ function planSettingRestore(root, spec) {
365
+ const current = readJsonObject(path.join(root, spec.file));
333
366
  if (current[spec.key] !== spec.installed) fail(`宿主设置 ${spec.key} 已被外部修改,拒绝删除`);
334
367
  if (spec.previous?.present) current[spec.key] = spec.previous.value; else delete current[spec.key];
335
- if (Object.keys(current).length === 0 && !spec.fileExistedBefore) unlinkSync(file);
336
- else atomicWrite(file, Buffer.from(`${JSON.stringify(current, null, 2)}\n`));
368
+ return {
369
+ relative: spec.file,
370
+ content: Object.keys(current).length === 0 && !spec.fileExistedBefore
371
+ ? null
372
+ : Buffer.from(`${JSON.stringify(current, null, 2)}\n`),
373
+ };
374
+ }
375
+
376
+ function applyFileState(file, content) {
377
+ if (content === null) rmSync(file, { force: true });
378
+ else atomicWrite(file, content);
337
379
  }
338
380
 
339
381
  function assertSafeDestination(root, layoutValue, previouslyManaged = []) {
340
- for (const relative of [...layoutValue.managedFiles, ...layoutValue.retiredFiles, ...previouslyManaged, manifestName, ...(layoutValue.settings ? [layoutValue.settings.file] : [])]) {
341
- const target = path.join(root, relative);
342
- if (existsSync(target) && lstatSync(target).isSymbolicLink()) fail(`托管目标是符号链接:${target}`);
382
+ const absoluteRoot = path.resolve(root);
383
+ let current = path.parse(absoluteRoot).root;
384
+ for (const segment of absoluteRoot.slice(current.length).split(path.sep).filter(Boolean)) {
385
+ current = path.join(current, segment);
386
+ if (existsSync(current) && lstatSync(current).isSymbolicLink()) fail(`托管目标或父目录是符号链接:${current}`);
387
+ }
388
+ const relatives = [...layoutValue.managedFiles, ...layoutValue.retiredFiles, ...previouslyManaged, manifestName, ...(layoutValue.settings ? [layoutValue.settings.file] : [])];
389
+ for (const relative of relatives) {
390
+ if (path.isAbsolute(relative) || relative.split(/[\\/]/u).some((segment) => segment === "..")) {
391
+ fail(`托管目标超出配置根:${relative}`);
392
+ }
393
+ current = absoluteRoot;
394
+ for (const segment of relative.split(/[\\/]/u).filter(Boolean)) {
395
+ current = path.join(current, segment);
396
+ if (existsSync(current) && lstatSync(current).isSymbolicLink()) fail(`托管目标或父目录是符号链接:${current}`);
397
+ }
343
398
  }
344
399
  }
345
400