@lmzhen/dsh-evolution-core 0.32.3 → 0.32.5

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 (37) hide show
  1. package/README.md +63 -117
  2. package/lib/composition/index.js +2 -2
  3. package/lib/{composition-DSesmTvf.js → composition-3QFfEe56.js} +1 -1
  4. package/lib/{ensure-BuWsjPGD.js → ensure-C2tUoF5U.js} +1 -1
  5. package/lib/{errors-Br2-uUSK.js → errors-DRZ9A187.js} +1 -0
  6. package/lib/index.js +423 -113
  7. package/lib/restrictor.js +1 -1
  8. package/lib/subagent/index.js +1 -1
  9. package/lib/types/errors.d.ts +1 -0
  10. package/lib/types/errors.js +1 -0
  11. package/lib/types/events.d.ts +1 -0
  12. package/lib/types/index.d.ts +1 -0
  13. package/lib/types/index.js +1 -0
  14. package/lib/types/mutation-storage-adapter.d.ts +5 -2
  15. package/lib/types/mutation-storage-adapter.js +59 -22
  16. package/lib/types/mutation-unit.d.ts +2 -2
  17. package/lib/types/mutation-unit.js +18 -45
  18. package/lib/types/params.js +1 -1
  19. package/lib/types/platform-services.js +0 -1
  20. package/lib/types/session-projection.d.ts +14 -0
  21. package/lib/types/session-projection.js +12 -3
  22. package/lib/types/skill-reads.d.ts +19 -0
  23. package/lib/types/skill-reads.js +42 -2
  24. package/lib/types/skill-store.js +4 -2
  25. package/lib/types/tool-dispatch.d.ts +16 -0
  26. package/lib/types/tool-dispatch.js +42 -11
  27. package/lib/types/unit-journal.d.ts +5 -3
  28. package/lib/types/unit-journal.js +7 -6
  29. package/lib/types/unit-storage.d.ts +5 -4
  30. package/lib/types/unit-storage.js +8 -8
  31. package/lib/types/unit-transaction.js +5 -7
  32. package/lib/types/write-gates.d.ts +4 -0
  33. package/lib/types/write-gates.js +16 -1
  34. package/lib/types/write-kernel.d.ts +81 -0
  35. package/lib/types/write-kernel.js +155 -0
  36. package/package.json +2 -2
  37. package/persisted-write-inventory.json +1 -10
package/README.md CHANGED
@@ -1,123 +1,69 @@
1
1
  # @lmzhen/dsh-evolution-core
2
2
 
3
- Shared pure library for the family: `SkillLibrary`/`MemoryStore`, the prompts and guidance text, the threat/quality/drift signals, the skill CONTENT history (`skill-history.ts`: content-addressed versions behind every write) and the frame classification the plan path reports over (`evidence.ts`), plus the IO primitives (`nodeEvolutionIo`, `transactIo`, `evolutionIoAdapter`), the two helpers every host route surface shares (`http-routes.ts`: the loopback fence, the bounded JSON body reader and the JSON writer), the run lifecycle owner and the shared report window (`run-registry.ts`: the single owner of what is in flight, how a run ended and where its result lives, with read-time orphan convergence and no timer; `reports.ts`: one bucket sweep for every run-report kind, plus the per-home lock target both sweeps hold), and the long-run inventory the published table is rendered from (`long-runs.ts`). It is **not a Cordis row** — it registers no service, tool or prompt
4
- section, and importing the package root is its only entry.
5
-
6
- ## Model surface
7
-
8
- - **Model-visible:** nothing of its own: the guidance text and memory snapshot it renders are injected by the rows that consume it (`tool-memory`, `tool-skill-manage`).
9
- - **Prompt prefix / KV cache:** unchanged by this package: family-level rules single-sourced in `packages/README.md` §"Model-visible prompt prefix and the KV cache".
10
- - **Mount it?** no: a library, not a row; consumed by the family's rows (e.g. `evolution-threat`, `evolution-policy`, `memory-files`, `skill-usage`, `evolution-state-json`).
11
-
12
- ## Known limitations
13
-
14
- - **The family tree IS the platform's USER skill root.** `skillsRoot()` resolves to `<dshHome>/skills` — the root the platform's `skill-filesystem` serves at rank 400 — so "the same tree" holds while that root is enabled. Two divergences stay documented rather than mirrored: a platform row with `includeDefaultRoots:false` (or a composition without this family's catalog row) removes the only providers that serve the tree while family writes still succeed, and the platform's CWD-derived PROJECT roots (`<cwd>/.dsh/skills`, `<cwd>/.agents/skills`) are not read by the family at all, so `ctx.skills.get(name).path` and `SkillLibrary.read(name)` can name different files. Mirroring project roots is `U-3`, deliberately not started; point `customSkillDirs` (platform side) or `root` (family side) at a shared directory when the project tree has to be visible to both.
15
- - This package is a library, not a Cordis row; do not mount it as a plugin.
16
- - 数值配置已在消费方 Config 面钳制(`min 1`/各字段域);`MemoryStore` 内部对 `limit <= 0` 仍按 unbounded 防御处理——那是库内部防御,不构成"0 = 禁用"的配置语义。
17
- - **Content-history storage grows with the number of DISTINCT bodies a skill has ever been written
18
- with, not with the retained count.** Trimming drops index entries; the blobs they point at stay on
19
- disk (they are shared by content, so a reference count would have to span every skill's index, and no
20
- sweeper exists yet). Measured on a 3.6 KB skill written 41 times: a 5.7 KB index over 20 entries and
21
- 41 blob files totalling 150 KB (41x the live body); unchanged writes add nothing. Plan disk accordingly
22
- or remove `.history/blobs` entries by hand.
23
- - Skill-library writes are serialized in-process; cross-process writers to the SAME skill file must go through the single-file paths (`update`, `patch`, `writeSupportFile`). The full concurrency model, its two-phase exceptions and their provenance are in Notes and history.
24
-
25
- **Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
26
-
27
- ## Notes and history
28
-
29
- - Similarity is TWO NAMED QUESTIONS plus a projection the caller declares (`quality.ts`): `identity(text)` ("is it the same text?", a normalized-content hash) and `affinity(a, b)` ("how much vocabulary do these two share?", Jaccard over two `vocabulary()` sets), asked over `projectionText(projection, input)` — `body` for the library-wide scan, `summary` (name + description) for the create-time hint. `computePrefixClusters` stays a name-side STRUCTURAL index, not a score. Adding a projection is one entry in that table; a caller that wants a fourth ruler should name the question it is really asking instead.
30
- - A whole-body replacement that keeps less than half of the previous body appends one line to its own result
31
- (`contentRetentionFeedback`, design §4 item 3): the ratio, both character counts, and the fact that the
32
- replaced version is still in the history. Computed in the write funnel where both bodies are in hand, feedback
33
- only — no ratio refuses a write, and the function owns no configuration.
34
- - **A REMOVAL now leaves an entry (E2, 2026-09-30).** `nextHistoryIndex` mints an entry from the AFTER side,
35
- so an operation with `after === null` (removing a support file) used to record nothing once its bytes were
36
- already indexed: the deletion was invisible and its action vocabulary unreachable. A removal records the bytes
37
- it removed, labeled with the write that removed them, so a face can say "these bytes are gone" and undoing that
38
- entry puts the file back. The entry deliberately carries no `beforeHash` (its own hash IS the removed content).
39
- - `anchorVerdict` is exported: the stage-time anchor rule ("does this write's target still hold the bytes the
40
- caller staged against?") has ONE implementation, and read-only readers (a preview, a dry run) call it instead
41
- of re-deriving a `contentHash` comparison.
42
- - Content history is HISTORY ONLY: the skill tree is the single truth for current content, and no judgement reads the version index (design invariant I1). Recording is best-effort but happens inside the write lock, so the index never describes content that did not land; a failed record warns once per instance instead of failing the write.
43
- - Skill-library mutations are read-modify-write on one file, so `SkillLibrary` serializes them in-process with a `makeSerialQueue` chain: `update`, `patch`, `restructure`, `writeSupportFile` and (since 0.3.46) `consolidate`'s target read→merge→commit run their whole read→validate→write under one serial task, so two concurrent mutators on one skill never interleave in this process.
44
- - `create` is INSIDE the serial chain and, when a transact backend is bound, its exists check runs inside the same per-file transact (v18); `archive`/`consolidate` are rename-based two-phase paths and stay outside the single-file serial chain.
45
- - **v18 residual (updated):** `create`, `removeSupportFile` and `setPinned` now run on the serial chain (`removeSupportFile`'s delete also goes through the per-file transact), so the remaining single-file residual is the protection TOCTOU (a marker check outside the transact) and the multi-file two-phase paths `archive`/`consolidate`/`restructure`.
46
- - The race needs a concurrent mutator on the SAME skill file/package; the exposure is acknowledged and the protection check is the next candidate (see the v18 optimization plan, E-5).
47
- - When the backend provides `transact` (nodeEvolutionIo and the io adapter do), the constructor binds it BY DEFAULT since 0.3.27: the single-file entry points (`update`, `patch`, `writeSupportFile`, and each per-file piece of `restructure`) run their read→write inside the cross-process lock for every instantiation, so same-file concurrent writes from different processes no longer resolve to last-writer-wins there.
48
- - The two-phase paths deliberately stay outside that lock: `create`'s exists probe runs inside the transact when a transact backend is bound (v18), so only a transact-less custom backend can still double-pass the probe across processes; `archive`/`consolidate` are rename-based with best-effort rollback (an archive loser's rollback surfaces the raw failure when the source vanished), and `restructure`'s multi-file swap can expose an interleaved tree to a concurrent reader.
49
- - These residual windows are documented rather than locked: cross-process writers to the SAME skill file should serialize through the single-file paths above.
3
+ > 内部引擎,支撑记忆、技能、历史、恢复和审批。
50
4
 
51
- ## Events (the family's own, process-local)
5
+ ## 你会看到
6
+
7
+ 没有直接入口;用户看到的是记忆、技能、历史和撤销。
8
+
9
+ ## 什么时候会用到
10
+
11
+ 每次 Agent 写记忆/技能、看历史、恢复时。
12
+
13
+ ## 默认 / 前提
52
14
 
53
- Eight process events ride the cordis bus (`evolution-core/src/events.ts` declares the payloads;
54
- producers call `ctx.emit`, consumers `ctx.on`). They are NOT session events — appending one to a
55
- session log made the session unresumable (A-line P0-1), which is why the payload file says so.
15
+ 随 all/host/分层安装自动工作。
16
+
17
+ ## 边界
18
+
19
+ 普通用户不需要知道其中的事务/状态机。
20
+
21
+ ## 维护者参考(用户可跳过)
22
+
23
+ ## Events (the family's own, process-local)
56
24
 
57
- | event | mode today | emitted by |
25
+ | 事件 | the `@mode` | 用途 |
58
26
  |---|---|---|
59
- | `evolution/skill-mutated` | emit (notification) | `evolution-core` skill store |
60
- | `evolution/skills-refresh` | emit (notification) | `evolution-commands` `/evolution` verbs |
61
- | `evolution/review-scheduled` | emit (notification) | `evolution-review` cadence paths |
62
- | `evolution/review-error` | emit (notification) | `evolution-review` failure paths |
63
- | `evolution/review-completed` | emit (notification) | `evolution-review` after a plugin branch settles |
64
- | `evolution/memory-applied` | emit (notification) | `memory` after a memory write |
65
- | `evolution/memory-provider-registered` | emit (notification) | `memory` when a provider registers |
66
- | `evolution/approval-decided` | emit (notification) | `evolution-approval` after an approval decision lands |
67
-
68
- `evolution/plan-applied` is declared for old activity ledgers; `evolution-review` now emits it from a branch review once that branch settles, with real action counts. `reviewMode: "inject"` still emits none by design.
69
-
70
- The mode column is what the code does today: every one of them is an announcement, and each
71
- declaration carries it as a `@mode` tag (finding O-1, landed) — `verify-arch-guards`' rule **N33** checks that
72
- tag against THIS table and against the dispatch site (`ctx.emit('…'`), so a declaration that drifts from
73
- the table, or an event with no `@mode`, fails. This table stays the set's ONE home: the machine check here
74
- (`machine.kind = event-mode`) re-derives the SET from the emit sites, so an event added or renamed in
75
- code without this table fails N19.
76
-
77
- The last two rows have no in-family consumer: `evolution/review-scheduled` and `evolution/review-error`
78
- are emitted for operators and observability (5 and 3 dispatch sites, 0 `ctx.on` subscribers here). They are
79
- **kept deliberately** — the observation surface is the point, and a deployment's own listener is the intended
80
- consumer — so the `@mode` target stays at six (decision 10, provisional: keep).
81
-
82
- ## 错误码(THE error-code table)
83
-
84
- > 本节的表与 `src/errors.ts` 的码表必须**同集**,并写明**区间**:CI 门禁 `verify-error-codes.mjs <root>`
85
- > 到 `<root>/evolution-core/README.md` 逐码核对(新增码要同时进表与区间行)。
86
- | `E-301` / `E-302` / `E-303` | approval / curator / replay service not mounted | mount the row (they ship with host/all), then run doctor |
87
- | `E-306` | this deployment stages foreground writes, but the named command is not replayable through the skill runner | approve-and-execute it directly, or set `stageForeground: false` deliberately |
88
- | `E-304` | the mounted approval service predates the release capability (a skewed/partial upgrade) | `reject` the pending record instead of `release` |
89
- | `E-305` | the invocation carries no agent (a script/headless caller reached a session-backed branch) | run the command from a session in the GUI or the CLI |
90
- | `E-307` / `E-311` | the settings service is missing or cannot report its sections (`/evolution params`, `/evolution policy set`) | mount the settings row (ships with host/all), then run doctor |
91
- | `E-312` | a parameter id or value was rejected, with the reason included | run `/evolution params` to see the canonical ids |
92
- | `E-308` / `E-313` | unknown parameter group or id | list them: `/evolution params` shows every registered id with its tier and owner |
93
- | `E-314` / `E-315` / `E-316` | the id is a deployment parameter, has no user layer, or its owner is not mounted | write it in `cordis.yml`, or mount the owner row — the message names tier, owner and namespace |
94
- | `E-309` / `E-310` | your write lost a revision race, or the settings service refused it (the reason is included) | re-read with `/evolution params` and retry |
95
- | `E-317` | you declined the confirmation the tool asked before creating or deleting a skill (a foreground create or bare delete asks when `skillWriteConfirm` is `ask` or `timeout`; the default `auto` does not ask at all) | nothing was written; repeat the call if you do want it |
96
- | `E-318` | a write without a read: the session never loaded that skill, so the write is refused (skills only; the foreground operator session is exempt) | load it with the `skill` tool, then repeat the write |
97
- | `E-320` | the profile home is not reported by this host, so the legacy settings document cannot be located | run the command in a session whose profile home is set |
98
- | `E-321` | no evolution-io provider is mounted, so the legacy settings document cannot be read | mount the `evolution-io-node` row |
99
- | `E-322` | a cross-field parameter constraint would be broken (the field, its floor and the attempted value are included) | raise the value to the named floor, or lower the sibling first |
100
- | `E-323` | the subagent channel is unavailable: no subagents/agentPresets service, or the spawn provider lacks the agentPreset capability | run `/evolution doctor`; review keeps its inject channel, maintenance reports the channel unavailable instead of degrading silently |
101
- | `E-324` | a restricted preset could not be created (parent preset read, YAML parse, register, or restrictor mount failed; the reason is included) | run `/evolution doctor` to see the preset id, allow set and failure reason; the review/maintenance channel stays unavailable until it is fixed |
102
- | `E-325` | the host data plane is unavailable: no connection service, so panel/approval routes are not registered | use `/evolution pending`, `approve`, `reject` (same service methods) and run `/evolution doctor` |
103
- | `E-319` | the confirmation before a create or bare delete went unanswered for `skillWriteConfirmTimeoutSeconds` (`skillWriteConfirm: 'timeout'`), so the write was cancelled | set `skillWriteConfirm` to `auto` (write without asking), keep `ask` (wait until answered), or raise the timeout |
104
- Symptom → next step; the exact text of every code (`E-301`–`E-325`) is stored once in
105
-
106
- ## 单元与撤销(本包负责的契约)
107
-
108
- - 本包持有单元契约的**类型与折叠**:SkillVersion.unitHead 两形态互斥(代表片 { moves, sources }/路标 { skill }),判别式固定为 moves !== undefined;读端折叠必须带上新字段,否则下一次写就丢。
109
- - 成员解析与孤路标判定在 src/unit-members.ts:candidateSkills(代表片首位、去重保序)、resolveUnitMembersFromIndexes(只按已知 key、三向校验)、landmarkVerdict 与 staleRouteStubs(可跳 ⟺ 目标存在 ∧ 其索引仍持该 unitId;输出按 skill/version/owner 确定性排序)。
110
- - 写作端的硬规则:kind 判 previous === null(不是 undefined);path 抄循环里既有的 rel;同一目标写两次时清单保留最后一次写入的 afterRef。
111
- - 面向读者的完整说明见仓库 docs/units-and-undo.md。
112
-
113
- ## Restricted preset ids
114
-
115
- The review and maintenance channels run under two internally generated restricted presets (they are
116
- NOT user-facing preset picker entries):
117
-
118
- - `evolution-reviewer-readonly` — the review channel's child preset;
119
- - `evolution-maintainer-readonly` — the maintenance channel's child preset.
120
-
121
- The family's own agent-preset ids (`EVOLUTION_PRESET_IDS`) are `evolution`, `evolution-ptc`,
122
- `evolution-cordis` and `evolution-minimal`. The two id sets are deliberately separate: a restricted
123
- preset is created at runtime from a parent preset, never installed or selected.
27
+ | `evolution/skill-mutated` | emit (one-way) | 技能树写入后失效目录缓存 |
28
+ | `evolution/skills-refresh` | emit (one-way) | `/evolution skills refresh` 显式刷新 |
29
+ | `evolution/review-scheduled` | emit (one-way) | 审查已安排 |
30
+ | `evolution/review-completed` | emit (one-way) | branch 审查完成 |
31
+ | `evolution/review-error` | emit (one-way) | 审查流水线失败 |
32
+ | `evolution/plan-applied` | emit (one-way) | 计划执行结果 |
33
+ | `evolution/memory-applied` | emit (one-way) | 记忆写入成功 |
34
+ | `evolution/memory-provider-registered` | emit (one-way) | 记忆 provider 注册 |
35
+
36
+ 预设 id:`evolution`、`evolution-ptc`、`evolution-cordis`、`evolution-minimal`、`evolution-reviewer-readonly`、`evolution-maintainer-readonly`。
37
+
38
+ ## 维护者参考:错误码表(用户可跳过)
39
+
40
+ (`E-301`–`E-326`):命令/服务不可用时的明确提示;具体文案在 `src/errors.ts`。
41
+
42
+ | 代码 | 含义 |
43
+ |---|---|
44
+ | `E-301` | 批准服务未挂载 |
45
+ | `E-302` | 策展服务未挂载 |
46
+ | `E-303` | 回放服务未挂载 |
47
+ | `E-304` | 批准服务版本过旧 |
48
+ | `E-305` | 调用无 agent/投递通道 |
49
+ | `E-306` | 前台写入无法回放 |
50
+ | `E-307` | 设置分区/修订不可读 |
51
+ | `E-308` | 未知参数分组 |
52
+ | `E-309` | 参数修订冲突 |
53
+ | `E-310` | 设置服务拒绝写入 |
54
+ | `E-311` | 无设置服务 |
55
+ | `E-312` | 参数写入失败 |
56
+ | `E-313` | 未知参数 id |
57
+ | `E-314` | 部署参数不可从会话写 |
58
+ | `E-315` | 参数无用户层 |
59
+ | `E-316` | 命名空间未注册 |
60
+ | `E-317` | 技能写入未确认 |
61
+ | `E-318` | 技能未读先写 |
62
+ | `E-319` | 确认超时取消 |
63
+ | `E-320` | 无 profile home |
64
+ | `E-321` | 无 evolution-io |
65
+ | `E-322` | 参数跨字段约束 |
66
+ | `E-323` | 子代理通道不可用 |
67
+ | `E-324` | 受限 preset 不可用 |
68
+ | `E-325` | Host 数据面不可用 |
69
+ | `E-326` | 支撑文件未读先写 |
@@ -1,3 +1,3 @@
1
- import { a as entryListSchema, c as MAINTAINER_PRESET_ID, d as RESTRICTED_TOOLS_ROW_ID, f as RESTRICTOR_MODULE, h as restrictedPresetId, i as composeRestrictedPresetDefinition, l as RESTRICTED_PRESET_DELIVERY, m as normalizeAllow, n as ensureRestrictedPreset, o as parsePresetRows, p as REVIEWER_PRESET_ID, r as restrictedPresetState, s as EVOLUTION_PRESET_IDS, t as disposeRestrictedPreset, u as RESTRICTED_PRESET_DISPLAY } from "../ensure-BuWsjPGD.js";
2
- import { C as trimTrailingBlankLines, S as rowSiblingEnd, _ as presetRowId, a as composePresetComposition, b as resolveBasePresetPatch, c as composePresetRow, d as listDirectories, f as loadRowOverrides, g as presetRowBody, h as presetRowBlock, i as basePresetPlugins, l as compositionRowIds, m as presetPatchText, n as AGENT_PRESET_ROOT_HINT, o as composePresetEntry, p as mergePresetRow, r as EMPTY_PATCH_SEED, s as composePresetInsert, t as AGENT_PRESET_PACKAGE, u as denseBlockSequence, v as probeDesktopScope, x as rowBlockSpan, y as removePresetRow } from "../composition-DSesmTvf.js";
1
+ import { a as entryListSchema, c as MAINTAINER_PRESET_ID, d as RESTRICTED_TOOLS_ROW_ID, f as RESTRICTOR_MODULE, h as restrictedPresetId, i as composeRestrictedPresetDefinition, l as RESTRICTED_PRESET_DELIVERY, m as normalizeAllow, n as ensureRestrictedPreset, o as parsePresetRows, p as REVIEWER_PRESET_ID, r as restrictedPresetState, s as EVOLUTION_PRESET_IDS, t as disposeRestrictedPreset, u as RESTRICTED_PRESET_DISPLAY } from "../ensure-C2tUoF5U.js";
2
+ import { C as trimTrailingBlankLines, S as rowSiblingEnd, _ as presetRowId, a as composePresetComposition, b as resolveBasePresetPatch, c as composePresetRow, d as listDirectories, f as loadRowOverrides, g as presetRowBody, h as presetRowBlock, i as basePresetPlugins, l as compositionRowIds, m as presetPatchText, n as AGENT_PRESET_ROOT_HINT, o as composePresetEntry, p as mergePresetRow, r as EMPTY_PATCH_SEED, s as composePresetInsert, t as AGENT_PRESET_PACKAGE, u as denseBlockSequence, v as probeDesktopScope, x as rowBlockSpan, y as removePresetRow } from "../composition-3QFfEe56.js";
3
3
  export { AGENT_PRESET_PACKAGE, AGENT_PRESET_ROOT_HINT, EMPTY_PATCH_SEED, EVOLUTION_PRESET_IDS, MAINTAINER_PRESET_ID, RESTRICTED_PRESET_DELIVERY, RESTRICTED_PRESET_DISPLAY, RESTRICTED_TOOLS_ROW_ID, RESTRICTOR_MODULE, REVIEWER_PRESET_ID, basePresetPlugins, composePresetComposition, composePresetEntry, composePresetInsert, composePresetRow, composeRestrictedPresetDefinition, compositionRowIds, denseBlockSequence, disposeRestrictedPreset, ensureRestrictedPreset, entryListSchema, listDirectories, loadRowOverrides, mergePresetRow, normalizeAllow, parsePresetRows, presetPatchText, presetRowBlock, presetRowBody, presetRowId, probeDesktopScope, removePresetRow, resolveBasePresetPatch, restrictedPresetId, restrictedPresetState, rowBlockSpan, rowSiblingEnd, trimTrailingBlankLines };
@@ -1,4 +1,4 @@
1
- import { _ as scopedPackageName } from "./ensure-BuWsjPGD.js";
1
+ import { _ as scopedPackageName } from "./ensure-C2tUoF5U.js";
2
2
  import { dirname, join } from "node:path";
3
3
  import { existsSync, readFileSync, readdirSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
@@ -1,4 +1,4 @@
1
- import { n as errorText } from "./errors-Br2-uUSK.js";
1
+ import { n as errorText } from "./errors-DRZ9A187.js";
2
2
  import { dirname, join } from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
@@ -36,6 +36,7 @@ const EVOLUTION_ERRORS = Object.freeze({
36
36
  "e-310-the-settings-service-refused": "E-310: 设置服务拒绝了这次写入:%a1% —— 归属插件的规则优先(跨字段成对约束,或只能收紧的上限)。/evolution params 会显示当前值。",
37
37
  "e-317-skill-write-not-confirmed": "E-317: 技能 \"%a1%\" 未被%a2% —— 确认提示被拒绝或关闭,因此没有写入任何内容。每次创建与裸删除都会出现该提示;只有操作者要求时才重复调用。",
38
38
  "e-318-skill-write-without-a-read": "E-318: 本会话没有读取技能 \"%a1%\",因此拒绝这次写入。请先用 `skill` 工具读取它(失败的读取不算),然后重复该写入。",
39
+ "e-326-support-write-without-a-read": "E-326: 本会话没有读取技能 \"%a1%\" 的支撑文件 \"%a2%\",因此拒绝这次写入。只读技能正文不算读过支撑文件;请先读取该文件(失败的读取不算),然后重复该写入。",
39
40
  "e-320-the-profile-home-is-not": "E-320: 本宿主没有报告 profile home,因此无法定位旧设置文档。/evolution migrate 读取 `<profile home>/settings.yaml.imported`;请在由 profile 启动的会话里运行。",
40
41
  "e-322-a-parameter-would-break-a": "E-322: %a1% 至少应为 %a2%,但这次写入把它设成 %a3%。未写入任何内容。",
41
42
  "e-321-no-io-provider-is": "E-321: 没有挂载 evolution-io 提供方,因此无法读取旧设置文档。请挂载 evolution-io 行(evolution-host/evolution-all)后重试。",