@lmzhen/dsh-evolution-core 0.8.0 → 0.9.0

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/lib/index.js CHANGED
@@ -374,7 +374,7 @@ function describeReferenceRewrite(plan) {
374
374
  */
375
375
  /**
376
376
  * Required argument names per `skill_manage` action — the SINGLE SOURCE read
377
- * by the tool's argument gate (tool-skill-manage executeCore) and the plan
377
+ * by the tool's argument gate (tool-skill-manage write-gates.ts) and the plan
378
378
  * validator (evolution-plan-validator), so the two can never drift.
379
379
  * OPT-05 (2026-09): the plan validator used to accept a `write_file`/
380
380
  * `remove_file` op without `file_path` while the executor required it — the
@@ -512,6 +512,16 @@ const EVOLUTION_WRITE_TOOLS = ["memory", "skill_manage"];
512
512
  * 0.3.16 (T-4): moved here from skill-store.ts so drift-signals (pure, no IO)
513
513
  * can reference it without importing the skill-store module. */
514
514
  const AUTHORING_DESCRIPTION_BAR = 60;
515
+ /** The PLATFORM's default cap on the description a skill catalog shows —
516
+ * `catalogDescriptionMaxLength` on the platform's `tool-skill` row (default 500).
517
+ *
518
+ * Recorded here because it is the third number in the description-length relationship, and the one
519
+ * that is easiest to misread as a family rule: the family's own host/all rows SET that field to
520
+ * `AUTHORING_DESCRIPTION_BAR` (60), so what a family deployment truncates at is the ROW's value —
521
+ * this default only governs compositions that do not override it. It is NOT a refusal threshold:
522
+ * the only refusal is `MAX_DESCRIPTION_LENGTH` / the row's `maxDescriptionLength`, and the catalog
523
+ * cut is a view, not a validation. See tool-skill-manage/README.md for the three-number table. */
524
+ const PLATFORM_CATALOG_DESCRIPTION_DEFAULT = 500;
515
525
  /** The split hint both size refusals share (0.5.0 V1). The same sentence used to
516
526
  * be copied into validateFrontmatter AND the patch path, and neither copy named
517
527
  * where the content should go — the upstream cap message names the destination
@@ -2967,7 +2977,8 @@ function allowRowCollisions(env = process.env) {
2967
2977
  //#endregion
2968
2978
  //#region lib/types/errors.js
2969
2979
  /**
2970
- * THE error-code table: E-301…E-316 with the exact text each one emits.
2980
+ * THE error-code table: E-301…E-318 with the exact text each one emits (E-317 and E-318 are the
2981
+ * write-admission gates' own refusals).
2971
2982
  *
2972
2983
  * The codes used to be spelled out at 33 call sites across two packages, so one
2973
2984
  * code's wording could drift between the branches that answer it and nothing could
@@ -3000,7 +3011,9 @@ const EVOLUTION_ERRORS = Object.freeze({
3000
3011
  "e-309-revision-conflict-you-sent": "E-309: revision conflict — you sent %a1%, the document stands at %a2%. Re-read with /evolution params --json and retry.",
3001
3012
  "e-309-revision-conflict-message-Re": "E-309: revision conflict — %a1%. Re-read with /evolution params --json and retry.",
3002
3013
  "e-310-the-settings-service-refused": "E-310: the settings service refused the write: %a1% — the owning plugin's rule stands (a cross-field pair, or a cap that may only be tightened). /evolution params shows the current value.",
3003
- "e-305-this-invocation-carries-no-2": "E-305: this invocation carries no agent — `%a1%` needs a session-backed call (run it from a session in the GUI or the CLI)."
3014
+ "e-305-this-invocation-carries-no-2": "E-305: this invocation carries no agent — `%a1%` needs a session-backed call (run it from a session in the GUI or the CLI).",
3015
+ "e-317-skill-write-not-confirmed": "E-317: skill \"%a1%\" was not %a2% — the confirmation prompt was declined or dismissed, so nothing was written. The prompt appears on every create and bare delete; repeat the call only if the operator asks for it.",
3016
+ "e-318-skill-write-without-a-read": "E-318: skill \"%a1%\" was not read in this session, so this write is refused. Read it with the `skill` tool first (a read that failed does not count), then repeat the write."
3004
3017
  });
3005
3018
  /**
3006
3019
  * Render one table entry, substituting its interpolation slots.
@@ -5899,6 +5912,89 @@ function foldTurn(session, fromSeq) {
5899
5912
  return signal;
5900
5913
  }
5901
5914
  //#endregion
5915
+ //#region lib/types/skill-reads.js
5916
+ /**
5917
+ * The read-before-write RULE: which writes need a prior read, and which targets count as read.
5918
+ *
5919
+ * ONE rule for TWO enforcement points (design `dsh-evolution-write-gate-design.md` §4.2): the
5920
+ * tool path refuses an unread mutating write (E-318), and the plan path drops such an op from a
5921
+ * background review's plan. Before this module the rule lived in `evolution-review` only, so the
5922
+ * tool path could not see it at all.
5923
+ *
5924
+ * The READER is not here either: `tool-dispatch.collectReadSkillNames(events)` folds a session log
5925
+ * into the names read through a non-failed dispatch — the review's old session-shaped copy was a
5926
+ * line-for-line duplicate of it. What this module adds over it is the session-shaped ADAPTER
5927
+ * (`sessionReadSkillNames`), for the ONE caller that holds a session only STRUCTURALLY (the tool
5928
+ * path's gate, whose exec view may be a bare stub): it answers "which accessor, and what does an
5929
+ * unreadable session mean" — `undefined`, so the gate keeps its previous behavior instead of
5930
+ * refusing every write. The review path reads a real platform `Session` and calls the reader
5931
+ * directly; a fallback there would be dead code for an impossible case.
5932
+ *
5933
+ * v32 REV-06(a) is preserved by the dispatch normalizer: a skill counts as READ only when its read
5934
+ * did not fail, so a failed/timeout read cannot pass the gate and let a writer blind-overwrite
5935
+ * content the model never saw. Matching `tool/call` directly (the pre-v37 form) meant every PTC
5936
+ * session (`tool/ptc-dispatch*`) collected an EMPTY set, so every mutating op the model HAD read
5937
+ * was dropped — and nothing reported the loss.
5938
+ * @module @lmzhen/dsh-evolution-core
5939
+ */
5940
+ /**
5941
+ * The skill names ONE session read, or `undefined` when its log is not readable.
5942
+ *
5943
+ * `undefined` is NOT an empty set: a caller that must decide (the tool path's read-before-write
5944
+ * gate) can then keep its previous behavior instead of refusing every write in a composition whose
5945
+ * session objects expose no log at all.
5946
+ * @param session - the session whose reads are wanted; `undefined` when the call carries none.
5947
+ * @returns the names read through a non-failed `skill` dispatch, or `undefined` when unreadable.
5948
+ */
5949
+ function sessionReadSkillNames(session) {
5950
+ const events = session?.snapshotEvents?.();
5951
+ return events === void 0 ? void 0 : collectReadSkillNames(events);
5952
+ }
5953
+ /** Actions whose target must have been read first (create is authorship, so it is exempt). */
5954
+ const READ_REQUIRED_ACTIONS = Object.freeze([
5955
+ "edit",
5956
+ "update",
5957
+ "patch",
5958
+ "delete",
5959
+ "write_file",
5960
+ "remove_file",
5961
+ "restructure"
5962
+ ]);
5963
+ /**
5964
+ * Does this one op write a skill the caller never read?
5965
+ *
5966
+ * V6-26 (0.3.37): the validator normalizes a missing action to `patch`, so a missing action is a
5967
+ * read-required write, never silently exempt.
5968
+ * @param op - one skill operation (from a tool call or a review plan).
5969
+ * @param readNames - names read this session, from {@link collectReadSkillNames}.
5970
+ * @returns true when the op is a read-required write to an unread target.
5971
+ */
5972
+ function isUnreadWrite(op, readNames) {
5973
+ if (!op.name) return false;
5974
+ return READ_REQUIRED_ACTIONS.includes(op.action ?? "patch") && !readNames.has(op.name);
5975
+ }
5976
+ /**
5977
+ * Drop mutating ops whose target was not read this session, in place.
5978
+ *
5979
+ * Covers the same mutating surface Hermes guards (edit/patch/write_file/remove_file), so a
5980
+ * background review cannot blind-touch support files or edits of skills it never loaded.
5981
+ * @param ops - the plan's ops; dropped entries are removed in place.
5982
+ * @param readNames - names read this session.
5983
+ * @returns the count of dropped ops, so the plan event can report them as rejected.
5984
+ */
5985
+ function filterUnreadSkillOps(ops, readNames) {
5986
+ let dropped = 0;
5987
+ for (let index = ops.length - 1; index >= 0; index -= 1) {
5988
+ const op = ops[index];
5989
+ if (!op) continue;
5990
+ if (isUnreadWrite(op, readNames)) {
5991
+ ops.splice(index, 1);
5992
+ dropped += 1;
5993
+ }
5994
+ }
5995
+ return dropped;
5996
+ }
5997
+ //#endregion
5902
5998
  //#region lib/types/drift-signals.js
5903
5999
  /**
5904
6000
  * Library-level drift signals for the maintenance subagent (design 011).
@@ -8957,6 +9053,20 @@ function readParam(carrier, id) {
8957
9053
  for (const alias of ALIASES_BY_CANONICAL[canonical] ?? []) if (record[alias] !== void 0) return record[alias];
8958
9054
  }
8959
9055
  /**
9056
+ * Chinese display name per group, one entry per line (the scripts read this block
9057
+ * by text, the same way they read PARAM_NAMESPACES). The raw group id is what
9058
+ * `--group` accepts and what the JSON face reports; this only names it on screen.
9059
+ */
9060
+ const PARAM_GROUP_LABELS = Object.freeze({
9061
+ library: "技能库",
9062
+ "write-caps": "写入上限",
9063
+ review: "会话回顾",
9064
+ memory: "记忆",
9065
+ curator: "技能整理",
9066
+ deployment: "安装配置",
9067
+ internal: "内部"
9068
+ });
9069
+ /**
8960
9070
  * The parameter registry. G1/S1.1 seeds it with the review group (G-C); the
8961
9071
  * remaining groups land in S2.1. E3 = behaviour preference the user may change
8962
9072
  * (live); E2 = resource or identity knob that stays with the deployment.
@@ -8970,9 +9080,9 @@ const PARAM_EXPOSURE = Object.freeze([
8970
9080
  owner: "evolution-review",
8971
9081
  applies: "live",
8972
9082
  docAnchor: "PARAMETERS.md#review",
8973
- summary: "Activity units between skill-review injections.",
8974
- label: "技能审查间隔",
8975
- hint: "每多少活动单位触发一次技能审查注入。",
9083
+ summary: "Tool calls between skill-review injections: a turn advances by its tool-call count (a turn with none counts as one), or by 1 when the turn itself used a skill.",
9084
+ label: "技能检查间隔",
9085
+ hint: "每累计多少次工具调用检查一次技能:一轮按该轮工具调用数累加(一轮没有工具调用也算 1 次),本轮本身用到技能则只算 1 次。",
8976
9086
  control: "number",
8977
9087
  unit: "次",
8978
9088
  values: ""
@@ -8985,9 +9095,9 @@ const PARAM_EXPOSURE = Object.freeze([
8985
9095
  owner: "evolution-review",
8986
9096
  applies: "live",
8987
9097
  docAnchor: "PARAMETERS.md#review",
8988
- summary: "Activity units between memory-review injections.",
8989
- label: "记忆审查间隔",
8990
- hint: "每多少活动单位触发一次记忆审查注入。",
9098
+ summary: "Tool calls between memory-review injections: a turn advances by its tool-call count (a turn with none counts as one), or by 1 when the turn itself touched memory.",
9099
+ label: "记忆检查间隔",
9100
+ hint: "每累计多少次工具调用检查一次记忆:一轮按该轮工具调用数累加(一轮没有工具调用也算 1 次),本轮本身用到记忆则只算 1 次。",
8991
9101
  control: "number",
8992
9102
  unit: "次",
8993
9103
  values: ""
@@ -9001,11 +9111,12 @@ const PARAM_EXPOSURE = Object.freeze([
9001
9111
  applies: "live",
9002
9112
  docAnchor: "PARAMETERS.md#review",
9003
9113
  summary: "Which channel may inject a skill review (cadence, completion, both).",
9004
- label: "审查触发通道",
9005
- hint: "哪个通道可以注入技能审查:cadence=按间隔、completion=按完成、both=两者。",
9114
+ label: "技能检查时机",
9115
+ hint: "什么时候检查技能:按间隔/按任务完成/两者。",
9006
9116
  control: "select",
9007
9117
  unit: "",
9008
- values: "cadence|completion|both"
9118
+ values: "cadence|completion|both",
9119
+ valueLabels: "按间隔|按任务完成|两者"
9009
9120
  },
9010
9121
  {
9011
9122
  id: "skillReviewCompletionMinToolCalls",
@@ -9016,8 +9127,8 @@ const PARAM_EXPOSURE = Object.freeze([
9016
9127
  applies: "live",
9017
9128
  docAnchor: "PARAMETERS.md#review",
9018
9129
  summary: "Tool calls a task needs before the completion channel injects.",
9019
- label: "完成通道最少工具调用",
9020
- hint: "走完成通道时,任务至少经过多少次工具调用才注入。",
9130
+ label: "完成时的最少工具调用",
9131
+ hint: "选「按任务完成」时,任务至少用了几次工具才检查。",
9021
9132
  control: "number",
9022
9133
  unit: "次",
9023
9134
  values: ""
@@ -9031,8 +9142,8 @@ const PARAM_EXPOSURE = Object.freeze([
9031
9142
  applies: "live",
9032
9143
  docAnchor: "PARAMETERS.md#review",
9033
9144
  summary: "Master switch for the review plugin.",
9034
- label: "启用审查插件",
9035
- hint: "审查插件的总开关。",
9145
+ label: "启用自动检查",
9146
+ hint: "关闭后不再自动回顾会话。",
9036
9147
  control: "switch",
9037
9148
  unit: "",
9038
9149
  values: ""
@@ -9046,11 +9157,12 @@ const PARAM_EXPOSURE = Object.freeze([
9046
9157
  applies: "live",
9047
9158
  docAnchor: "PARAMETERS.md#review",
9048
9159
  summary: "Run the review in the parent session (inject) or on a subagent.",
9049
- label: "审查运行方式",
9050
- hint: "inject=在父会话内注入,subagent=交给子代理运行。",
9160
+ label: "运行位置",
9161
+ hint: "在哪里运行检查:在当前会话里/交给子代理。",
9051
9162
  control: "select",
9052
9163
  unit: "",
9053
- values: "subagent|inject"
9164
+ values: "subagent|inject",
9165
+ valueLabels: "交给子代理|在当前会话里"
9054
9166
  },
9055
9167
  {
9056
9168
  id: "reviewWakeInject",
@@ -9061,8 +9173,8 @@ const PARAM_EXPOSURE = Object.freeze([
9061
9173
  applies: "live",
9062
9174
  docAnchor: "PARAMETERS.md#review",
9063
9175
  summary: "Deliver the deferred review as a waking follow-up message.",
9064
- label: "审查后续唤醒注入",
9065
- hint: "把延后的审查作为唤醒消息投递。",
9176
+ label: "延后结果发提醒",
9177
+ hint: "会话空闲时,把延后的检查结果作为一条提醒发给你。",
9066
9178
  control: "switch",
9067
9179
  unit: "",
9068
9180
  values: ""
@@ -9136,8 +9248,8 @@ const PARAM_EXPOSURE = Object.freeze([
9136
9248
  applies: "live",
9137
9249
  docAnchor: "PARAMETERS.md#write-caps",
9138
9250
  summary: "Character cap on a SKILL.md body (tighten-only).",
9139
- label: "SKILL.md 正文字符上限",
9140
- hint: "SKILL.md 正文的字符上限(只许收紧)。",
9251
+ label: "技能文件正文上限",
9252
+ hint: "技能 Markdown 正文最多多少字符(只能调小)。",
9141
9253
  control: "number",
9142
9254
  unit: "字符",
9143
9255
  values: ""
@@ -9151,8 +9263,8 @@ const PARAM_EXPOSURE = Object.freeze([
9151
9263
  applies: "live",
9152
9264
  docAnchor: "PARAMETERS.md#write-caps",
9153
9265
  summary: "Byte cap on one support file (tighten-only).",
9154
- label: "支持文件字节上限",
9155
- hint: "单个支持文件的字节上限(只许收紧)。",
9266
+ label: "附带文件大小上限",
9267
+ hint: "技能附带文件单个最大多少字节(只能调小)。",
9156
9268
  control: "number",
9157
9269
  unit: "字节",
9158
9270
  values: ""
@@ -9166,8 +9278,8 @@ const PARAM_EXPOSURE = Object.freeze([
9166
9278
  applies: "live",
9167
9279
  docAnchor: "PARAMETERS.md#write-caps",
9168
9280
  summary: "Character cap on a skill name (tighten-only).",
9169
- label: "技能名字符上限",
9170
- hint: "技能名的字符上限(只许收紧)。",
9281
+ label: "技能名长度上限",
9282
+ hint: "技能名最多多少字符(只能调小)。",
9171
9283
  control: "number",
9172
9284
  unit: "字符",
9173
9285
  values: ""
@@ -9181,8 +9293,8 @@ const PARAM_EXPOSURE = Object.freeze([
9181
9293
  applies: "live",
9182
9294
  docAnchor: "PARAMETERS.md#write-caps",
9183
9295
  summary: "Character cap on a skill description (tighten-only).",
9184
- label: "技能描述字符上限",
9185
- hint: "技能描述的字符上限(只许收紧)。",
9296
+ label: "技能描述长度上限",
9297
+ hint: "技能描述最多多少字符(只能调小)。",
9186
9298
  control: "number",
9187
9299
  unit: "字符",
9188
9300
  values: ""
@@ -9196,8 +9308,8 @@ const PARAM_EXPOSURE = Object.freeze([
9196
9308
  applies: "live",
9197
9309
  docAnchor: "PARAMETERS.md#write-caps",
9198
9310
  summary: "Refuse a description over the authoring bar instead of advising.",
9199
- label: "描述严格档",
9200
- hint: "描述超过写作门槛时拒绝写入,而不是只提示。",
9311
+ label: "描述不合规即拒绝",
9312
+ hint: "描述不符合要求时直接拒绝写入(默认只提醒)。",
9201
9313
  control: "switch",
9202
9314
  unit: "",
9203
9315
  values: ""
@@ -9211,8 +9323,8 @@ const PARAM_EXPOSURE = Object.freeze([
9211
9323
  applies: "live",
9212
9324
  docAnchor: "PARAMETERS.md#write-caps",
9213
9325
  summary: "Refuse writes whose catalog entry resolves outside the family.",
9214
- label: "跨源严格档",
9215
- hint: "目录项解析到家族之外时拒绝写入。",
9326
+ label: "引用外部内容即拒绝",
9327
+ hint: "技能引用了本插件之外的文件时拒绝写入。",
9216
9328
  control: "switch",
9217
9329
  unit: "",
9218
9330
  values: ""
@@ -9226,11 +9338,12 @@ const PARAM_EXPOSURE = Object.freeze([
9226
9338
  applies: "live",
9227
9339
  docAnchor: "PARAMETERS.md#write-caps",
9228
9340
  summary: "Refuse a move that would leave a dangling reference, or verify it.",
9229
- label: "引用校验档",
9230
- hint: "移动或合并时对引用的处置:verify=校验、refuse=直接拒绝。",
9341
+ label: "引用检查方式",
9342
+ hint: "移动或合并技能时怎么处理引用:先检查/直接拒绝。",
9231
9343
  control: "select",
9232
9344
  unit: "",
9233
- values: "verify|refuse"
9345
+ values: "verify|refuse",
9346
+ valueLabels: "先检查|直接拒绝"
9234
9347
  },
9235
9348
  {
9236
9349
  id: "referenceRewrite",
@@ -9261,11 +9374,12 @@ const PARAM_EXPOSURE = Object.freeze([
9261
9374
  applies: "live",
9262
9375
  docAnchor: "PARAMETERS.md#write-caps",
9263
9376
  summary: "Warn about an oversize support file, or refuse the write.",
9264
- label: "支持文件超限档",
9265
- hint: "支持文件超出字符上限时:report=只报告、enforce=拒写。",
9377
+ label: "附带文件超限时",
9378
+ hint: "附带文件超出上限时:只提醒/拒绝写入。",
9266
9379
  control: "select",
9267
9380
  unit: "",
9268
- values: "report|enforce"
9381
+ values: "report|enforce",
9382
+ valueLabels: "只提醒|拒绝写入"
9269
9383
  },
9270
9384
  {
9271
9385
  id: "memoryChars",
@@ -9276,8 +9390,8 @@ const PARAM_EXPOSURE = Object.freeze([
9276
9390
  applies: "live",
9277
9391
  docAnchor: "PARAMETERS.md#memory",
9278
9392
  summary: "Character budget the memory store enforces for MEMORY.md.",
9279
- label: "MEMORY.md 字符预算",
9280
- hint: "memory 存储对 MEMORY.md 的字符上限。",
9393
+ label: "记忆库上限",
9394
+ hint: "长期记忆文件(MEMORY.md)最多多少字符。",
9281
9395
  control: "number",
9282
9396
  unit: "字符",
9283
9397
  values: ""
@@ -9291,8 +9405,8 @@ const PARAM_EXPOSURE = Object.freeze([
9291
9405
  applies: "live",
9292
9406
  docAnchor: "PARAMETERS.md#memory",
9293
9407
  summary: "Character budget the memory store enforces for USER.md.",
9294
- label: "USER.md 字符预算",
9295
- hint: "memory 存储对 USER.md 的字符上限。",
9408
+ label: "用户画像上限",
9409
+ hint: "用户画像文件(USER.md)最多多少字符。",
9296
9410
  control: "number",
9297
9411
  unit: "字符",
9298
9412
  values: ""
@@ -9316,8 +9430,8 @@ const PARAM_EXPOSURE = Object.freeze([
9316
9430
  applies: "live",
9317
9431
  docAnchor: "PARAMETERS.md#memory",
9318
9432
  summary: "Characters of one memory entry shown in a tool result preview.",
9319
- label: "条目预览字符数",
9320
- hint: "单条记忆预览保留多少字符。",
9433
+ label: "记忆预览长度",
9434
+ hint: "列表里每条记忆最多显示多少字符。",
9321
9435
  control: "number",
9322
9436
  unit: "字符",
9323
9437
  values: ""
@@ -9331,8 +9445,8 @@ const PARAM_EXPOSURE = Object.freeze([
9331
9445
  applies: "live",
9332
9446
  docAnchor: "PARAMETERS.md#memory",
9333
9447
  summary: "Prefix stored memory entries with their date heading.",
9334
- label: "记忆条目加日期前缀",
9335
- hint: "写入记忆时为条目加上日期标题。",
9448
+ label: "记忆条目加日期",
9449
+ hint: "写入时在条目开头加上日期。",
9336
9450
  control: "switch",
9337
9451
  unit: "",
9338
9452
  values: ""
@@ -9346,8 +9460,8 @@ const PARAM_EXPOSURE = Object.freeze([
9346
9460
  applies: "live",
9347
9461
  docAnchor: "PARAMETERS.md#memory",
9348
9462
  summary: "Consolidation failures one turn tolerates before the tool gives up.",
9349
- label: "合并失败容忍次数",
9350
- hint: "一轮内合并失败多少次后工具放弃。",
9463
+ label: "合并失败重试",
9464
+ hint: "合并记忆连续失败多少次后停止。",
9351
9465
  control: "number",
9352
9466
  unit: "次",
9353
9467
  values: ""
@@ -9361,8 +9475,8 @@ const PARAM_EXPOSURE = Object.freeze([
9361
9475
  applies: "live",
9362
9476
  docAnchor: "PARAMETERS.md#curator",
9363
9477
  summary: "Minimum hours between deterministic curation passes.",
9364
- label: "策展间隔",
9365
- hint: "两次确定性策展之间至少间隔多少小时。",
9478
+ label: "自动整理间隔",
9479
+ hint: "两次自动整理之间至少间隔多少小时。",
9366
9480
  control: "number",
9367
9481
  unit: "小时",
9368
9482
  values: ""
@@ -9376,8 +9490,8 @@ const PARAM_EXPOSURE = Object.freeze([
9376
9490
  applies: "live",
9377
9491
  docAnchor: "PARAMETERS.md#curator",
9378
9492
  summary: "Inactive days before a skill counts as stale.",
9379
- label: "判为陈旧的天数",
9380
- hint: "技能多少天没被使用即算陈旧。",
9493
+ label: "多久没用算过时",
9494
+ hint: "技能连续多少天没被用到就算过时。",
9381
9495
  control: "number",
9382
9496
  unit: "天",
9383
9497
  values: ""
@@ -9391,8 +9505,8 @@ const PARAM_EXPOSURE = Object.freeze([
9391
9505
  applies: "live",
9392
9506
  docAnchor: "PARAMETERS.md#curator",
9393
9507
  summary: "Inactive days before a stale skill is archived (must be >= staleAfterDays).",
9394
- label: "归档天数",
9395
- hint: "陈旧技能再过多少天归档(须 ≥ 判为陈旧的天数)。",
9508
+ label: "过时后归档",
9509
+ hint: "过时技能再过多少天移入归档(不能小于上一项)。",
9396
9510
  control: "number",
9397
9511
  unit: "天",
9398
9512
  values: ""
@@ -9406,8 +9520,8 @@ const PARAM_EXPOSURE = Object.freeze([
9406
9520
  applies: "live",
9407
9521
  docAnchor: "PARAMETERS.md#curator",
9408
9522
  summary: "Age at which a low quality score starts warning.",
9409
- label: "低质量告警天数",
9410
- hint: "质量分偏低时从多少天开始告警。",
9523
+ label: "质量偏低提醒",
9524
+ hint: "质量评分偏低时,从多少天开始提醒。",
9411
9525
  control: "number",
9412
9526
  unit: "天",
9413
9527
  values: ""
@@ -9421,8 +9535,8 @@ const PARAM_EXPOSURE = Object.freeze([
9421
9535
  applies: "live",
9422
9536
  docAnchor: "PARAMETERS.md#curator",
9423
9537
  summary: "Idle hours required before an automatic curation pass runs.",
9424
- label: "空闲门槛",
9425
- hint: "至少空闲多少小时才跑自动策展。",
9538
+ label: "最少空闲时长",
9539
+ hint: "你至少多少小时没用,才运行自动整理。",
9426
9540
  control: "number",
9427
9541
  unit: "小时",
9428
9542
  values: ""
@@ -9436,8 +9550,8 @@ const PARAM_EXPOSURE = Object.freeze([
9436
9550
  applies: "live",
9437
9551
  docAnchor: "PARAMETERS.md#curator",
9438
9552
  summary: "Let the idle gate open when the activity probe is unavailable.",
9439
- label: "空闲探针失败时放行",
9440
- hint: "活动探针不可用时,是否让空闲门槛直接放行。",
9553
+ label: "检测不到活动也运行",
9554
+ hint: "无法判断你是否空闲时,仍然运行自动整理。",
9441
9555
  control: "switch",
9442
9556
  unit: "",
9443
9557
  values: ""
@@ -9451,8 +9565,8 @@ const PARAM_EXPOSURE = Object.freeze([
9451
9565
  applies: "live",
9452
9566
  docAnchor: "PARAMETERS.md#curator",
9453
9567
  summary: "Enable the LLM nomination pass on top of the deterministic lifecycle.",
9454
- label: "启用 LLM 提名",
9455
- hint: "在确定性生命周期之上再跑一遍 LLM 提名。",
9568
+ label: "用模型挑选",
9569
+ hint: "在固定规则之外,再用模型挑一遍候选项。",
9456
9570
  control: "switch",
9457
9571
  unit: "",
9458
9572
  values: ""
@@ -9466,8 +9580,8 @@ const PARAM_EXPOSURE = Object.freeze([
9466
9580
  applies: "live",
9467
9581
  docAnchor: "PARAMETERS.md#curator",
9468
9582
  summary: "Token budget of the curator LLM review.",
9469
- label: "策展 LLM token 预算",
9470
- hint: "策展 LLM 审查可用的 token 预算。",
9583
+ label: "模型处理上限",
9584
+ hint: "每次用模型挑选时最多消耗多少 token。",
9471
9585
  control: "number",
9472
9586
  unit: "token",
9473
9587
  values: ""
@@ -9481,8 +9595,8 @@ const PARAM_EXPOSURE = Object.freeze([
9481
9595
  applies: "live",
9482
9596
  docAnchor: "PARAMETERS.md#curator",
9483
9597
  summary: "Wall-clock bound of the curator LLM review.",
9484
- label: "策展 LLM 超时",
9485
- hint: "策展 LLM 审查的墙钟上限。",
9598
+ label: "模型处理超时",
9599
+ hint: "一次模型挑选最长允许运行多久。",
9486
9600
  control: "number",
9487
9601
  unit: "毫秒",
9488
9602
  values: ""
@@ -9496,8 +9610,8 @@ const PARAM_EXPOSURE = Object.freeze([
9496
9610
  applies: "live",
9497
9611
  docAnchor: "PARAMETERS.md#curator",
9498
9612
  summary: "Body character line the health view judges against.",
9499
- label: "正文软带",
9500
- hint: "健康视图判定正文长度的软带。",
9613
+ label: "正文长度参考值",
9614
+ hint: "技能正文超过多少字符算偏长(只用于健康提示)。",
9501
9615
  control: "number",
9502
9616
  unit: "字符",
9503
9617
  values: ""
@@ -9511,8 +9625,8 @@ const PARAM_EXPOSURE = Object.freeze([
9511
9625
  applies: "live",
9512
9626
  docAnchor: "PARAMETERS.md#curator",
9513
9627
  summary: "Stamp density per KB that flags log-like content in a body.",
9514
- label: "标记密度阈值",
9515
- hint: "每 KB 出现多少个时间标记就算「像日志」。",
9628
+ label: "日志化判定阈值",
9629
+ hint: "每 KB 出现多少个时间标记,就判为「像日志」。",
9516
9630
  control: "number",
9517
9631
  unit: "处/KB",
9518
9632
  values: ""
@@ -9526,8 +9640,8 @@ const PARAM_EXPOSURE = Object.freeze([
9526
9640
  applies: "live",
9527
9641
  docAnchor: "PARAMETERS.md#curator",
9528
9642
  summary: "Patches without a read that flag a write-ghost skill.",
9529
- label: "空写判定补丁数",
9530
- hint: "多少次改动都没有任何读取,即判为「写幽灵」。",
9643
+ label: "只写不读判定次数",
9644
+ hint: "连续多少次改动都没有被读取,就判为「只写不读」。",
9531
9645
  control: "number",
9532
9646
  unit: "处",
9533
9647
  values: ""
@@ -10300,4 +10414,4 @@ function sessionAudited(ctx, sessionId, sessionScoped) {
10300
10414
  return false;
10301
10415
  }
10302
10416
  //#endregion
10303
- export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, advanceReview, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, canonicalWriteId, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, duplicateHeadings, emptyRecord, errorText, evaluateThreat, eventsFile, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, idleDays, installParamSection, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, neutralizePromptVariables, newSkillLibrary, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, paramNamespace, paramSectionOverrides, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseLockBody, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readNumberParam, readParam, recordMutation, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionSeesFamilyTools, skillReadNameOf, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, writeDurableTmp, yamlPlainScalarNeedsQuotes };
10417
+ export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, advanceReview, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, canonicalWriteId, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, duplicateHeadings, emptyRecord, errorText, evaluateThreat, eventsFile, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, filterUnreadSkillOps, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, idleDays, installParamSection, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, neutralizePromptVariables, newSkillLibrary, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, paramNamespace, paramSectionOverrides, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseLockBody, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readNumberParam, readParam, recordMutation, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionReadSkillNames, sessionSeesFamilyTools, skillReadNameOf, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, writeDurableTmp, yamlPlainScalarNeedsQuotes };
@@ -21,7 +21,7 @@
21
21
  */
22
22
  /**
23
23
  * Required argument names per `skill_manage` action — the SINGLE SOURCE read
24
- * by the tool's argument gate (tool-skill-manage executeCore) and the plan
24
+ * by the tool's argument gate (tool-skill-manage write-gates.ts) and the plan
25
25
  * validator (evolution-plan-validator), so the two can never drift.
26
26
  * OPT-05 (2026-09): the plan validator used to accept a `write_file`/
27
27
  * `remove_file` op without `file_path` while the executor required it — the
@@ -128,6 +128,16 @@ export declare const EVOLUTION_WRITE_TOOLS: readonly ["memory", "skill_manage"];
128
128
  * 0.3.16 (T-4): moved here from skill-store.ts so drift-signals (pure, no IO)
129
129
  * can reference it without importing the skill-store module. */
130
130
  export declare const AUTHORING_DESCRIPTION_BAR = 60;
131
+ /** The PLATFORM's default cap on the description a skill catalog shows —
132
+ * `catalogDescriptionMaxLength` on the platform's `tool-skill` row (default 500).
133
+ *
134
+ * Recorded here because it is the third number in the description-length relationship, and the one
135
+ * that is easiest to misread as a family rule: the family's own host/all rows SET that field to
136
+ * `AUTHORING_DESCRIPTION_BAR` (60), so what a family deployment truncates at is the ROW's value —
137
+ * this default only governs compositions that do not override it. It is NOT a refusal threshold:
138
+ * the only refusal is `MAX_DESCRIPTION_LENGTH` / the row's `maxDescriptionLength`, and the catalog
139
+ * cut is a view, not a validation. See tool-skill-manage/README.md for the three-number table. */
140
+ export declare const PLATFORM_CATALOG_DESCRIPTION_DEFAULT = 500;
131
141
  /** The split hint both size refusals share (0.5.0 V1). The same sentence used to
132
142
  * be copied into validateFrontmatter AND the patch path, and neither copy named
133
143
  * where the content should go — the upstream cap message names the destination
@@ -1,5 +1,6 @@
1
1
  /**
2
- * THE error-code table: E-301…E-316 with the exact text each one emits.
2
+ * THE error-code table: E-301…E-318 with the exact text each one emits (E-317 and E-318 are the
3
+ * write-admission gates' own refusals).
3
4
  *
4
5
  * The codes used to be spelled out at 33 call sites across two packages, so one
5
6
  * code's wording could drift between the branches that answer it and nothing could
@@ -33,6 +34,8 @@ export declare const EVOLUTION_ERRORS: Readonly<{
33
34
  readonly 'e-309-revision-conflict-message-Re': "E-309: revision conflict — %a1%. Re-read with /evolution params --json and retry.";
34
35
  readonly 'e-310-the-settings-service-refused': "E-310: the settings service refused the write: %a1% — the owning plugin's rule stands (a cross-field pair, or a cap that may only be tightened). /evolution params shows the current value.";
35
36
  readonly 'e-305-this-invocation-carries-no-2': "E-305: this invocation carries no agent — `%a1%` needs a session-backed call (run it from a session in the GUI or the CLI).";
37
+ readonly 'e-317-skill-write-not-confirmed': "E-317: skill \"%a1%\" was not %a2% — the confirmation prompt was declined or dismissed, so nothing was written. The prompt appears on every create and bare delete; repeat the call only if the operator asks for it.";
38
+ readonly 'e-318-skill-write-without-a-read': "E-318: skill \"%a1%\" was not read in this session, so this write is refused. Read it with the `skill` tool first (a read that failed does not count), then repeat the write.";
36
39
  }>;
37
40
  /** One table key. */
38
41
  export type EvolutionErrorId = keyof typeof EVOLUTION_ERRORS;
@@ -20,7 +20,8 @@
20
20
  * evolution-policy/threat, both stores, review, maintenance.
21
21
  * - **Core domain stores/logic** — `skill-store.ts` (skill tree engine +
22
22
  * IO-seam consumer), `memory-store.ts`, `usage.ts`, `curator.ts`,
23
- * `quality.ts`, `signals.ts`, `drift-signals.ts`, `skill-health.ts`,
23
+ * `quality.ts`, `signals.ts`, `skill-reads.ts` (the read-before-write rule, shared by the
24
+ * tool path and the review's plan path), `drift-signals.ts`, `skill-health.ts`,
24
25
  * `preset-composition.ts`, `prompts.ts`, `learn-prompt.ts`,
25
26
  * `evolution-events.ts`, `io.ts` (the ctx.evolutionIo seam itself).
26
27
  * @module @lmzhen/dsh-evolution-core
@@ -50,6 +51,7 @@ export * from './write-inventory.ts';
50
51
  export * from './scope.ts';
51
52
  export * from './skill-health.ts';
52
53
  export * from './signals.ts';
54
+ export * from './skill-reads.ts';
53
55
  export * from './drift-signals.ts';
54
56
  export * from './skill-store.ts';
55
57
  export * from './state-store.ts';
@@ -43,6 +43,12 @@ export declare function canonicalWriteId(id: string): string;
43
43
  export declare function readParam(carrier: object | undefined, id: string): unknown;
44
44
  /** Exposure group (design §7.2): the unit a developer changes together. */
45
45
  export type ParamGroup = 'library' | 'write-caps' | 'review' | 'memory' | 'curator' | 'deployment' | 'internal';
46
+ /**
47
+ * Chinese display name per group, one entry per line (the scripts read this block
48
+ * by text, the same way they read PARAM_NAMESPACES). The raw group id is what
49
+ * `--group` accepts and what the JSON face reports; this only names it on screen.
50
+ */
51
+ export declare const PARAM_GROUP_LABELS: Readonly<Record<ParamGroup, string>>;
46
52
  /** Exposure tier (design §7.1): the interface combination a parameter gets. */
47
53
  export type ParamTier = 'E0' | 'E1' | 'E2' | 'E3' | 'E4';
48
54
  /** Where the authoritative value lives. */
@@ -61,14 +67,17 @@ export type ParamAuthority = 'code' | 'cordis' | 'install';
61
67
  * writable through the user layer (a cordis.yml change still follows the
62
68
  * deployment's patch-reload policy).
63
69
  *
64
- * UI METADATA (0.7.0): every E3 row carries the optional tail
70
+ * UI METADATA (0.7.0): every E3 row carries the tail
65
71
  * `label, hint, control, unit, values` — in that order, directly after
66
- * `summary`, still one entry per line. E3 is the only tier the settings cards
67
- * render, so the card's Chinese name, help text, control kind, unit suffix and
68
- * value domain come from THIS registry and nowhere else; the browser half is
69
- * generated from this text (`gen-param-client-view.mjs`). Non-E3 rows must NOT
70
- * carry the tail (there is no UI surface for them), and `control: 'select'`
71
- * requires a non-empty pipe-joined `values`.
72
+ * `summary`, still one entry per line — plus an OPTIONAL trailing
73
+ * `valueLabels` (0.9.0). E3 is the only tier the settings cards render, so the
74
+ * card's Chinese name, help text, control kind, unit suffix and value domain
75
+ * come from THIS registry and nowhere else; the browser half is generated from
76
+ * this text (`gen-param-client-view.mjs`). Non-E3 rows must NOT carry the tail
77
+ * (there is no UI surface for them); `control: 'select'` requires a non-empty
78
+ * pipe-joined `values`, and `valueLabels` — allowed on select rows only — names
79
+ * those values for display, one label per value, in the same order. The stored
80
+ * value is never translated: only what the control shows.
72
81
  */
73
82
  export interface ParamExposure {
74
83
  id: string;
@@ -89,6 +98,11 @@ export interface ParamExposure {
89
98
  unit?: string;
90
99
  /** Pipe-joined allowed values; non-empty exactly when control is 'select'. */
91
100
  values?: string;
101
+ /**
102
+ * Pipe-joined display names for `values`, same order and count (optional).
103
+ * The stored value stays the raw one; this only names it on the card.
104
+ */
105
+ valueLabels?: string;
92
106
  }
93
107
  /**
94
108
  * The parameter registry. G1/S1.1 seeds it with the review group (G-C); the
@@ -0,0 +1,47 @@
1
+ /** The session-log accessor the platform exposes (0.1.5 on; `session.events` before it). */
2
+ export interface EvolutionSessionLogView {
3
+ /** @returns the session's events, oldest first. */
4
+ snapshotEvents?: () => Iterable<{
5
+ type: string;
6
+ data?: unknown;
7
+ }>;
8
+ }
9
+ /**
10
+ * The skill names ONE session read, or `undefined` when its log is not readable.
11
+ *
12
+ * `undefined` is NOT an empty set: a caller that must decide (the tool path's read-before-write
13
+ * gate) can then keep its previous behavior instead of refusing every write in a composition whose
14
+ * session objects expose no log at all.
15
+ * @param session - the session whose reads are wanted; `undefined` when the call carries none.
16
+ * @returns the names read through a non-failed `skill` dispatch, or `undefined` when unreadable.
17
+ */
18
+ export declare function sessionReadSkillNames(session: EvolutionSessionLogView | undefined): ReadonlySet<string> | undefined;
19
+ /** Actions whose target must have been read first (create is authorship, so it is exempt). */
20
+ export declare const READ_REQUIRED_ACTIONS: readonly string[];
21
+ /**
22
+ * Does this one op write a skill the caller never read?
23
+ *
24
+ * V6-26 (0.3.37): the validator normalizes a missing action to `patch`, so a missing action is a
25
+ * read-required write, never silently exempt.
26
+ * @param op - one skill operation (from a tool call or a review plan).
27
+ * @param readNames - names read this session, from {@link collectReadSkillNames}.
28
+ * @returns true when the op is a read-required write to an unread target.
29
+ */
30
+ export declare function isUnreadWrite(op: {
31
+ action?: string;
32
+ name?: string;
33
+ }, readNames: ReadonlySet<string>): boolean;
34
+ /**
35
+ * Drop mutating ops whose target was not read this session, in place.
36
+ *
37
+ * Covers the same mutating surface Hermes guards (edit/patch/write_file/remove_file), so a
38
+ * background review cannot blind-touch support files or edits of skills it never loaded.
39
+ * @param ops - the plan's ops; dropped entries are removed in place.
40
+ * @param readNames - names read this session.
41
+ * @returns the count of dropped ops, so the plan event can report them as rejected.
42
+ */
43
+ export declare function filterUnreadSkillOps(ops: Array<{
44
+ action?: string;
45
+ name?: string;
46
+ }>, readNames: ReadonlySet<string>): number;
47
+ //# sourceMappingURL=skill-reads.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-core",
3
3
  "description": "Shared stores, prompts, signals and lifecycle logic for the dsh-evolution plugin family (community build)",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },