@lmzhen/dsh-evolution-commands 0.7.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
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { effectiveSessionPolicy } from "@lmzhen/dsh-evolution-approval";
4
4
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
5
- import { DEFAULT_SKILL_LIMITS, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_NAMESPACES, appendEvolutionEvent, assertSkillsRootAliasRetired, buildLearnPrompt, canonicalWriteId, clampedNumber, composePresetComposition, eventsFile, evolutionRoot, isDeprecatedParamId, isMissingPath, newSkillLibrary, policyStageLimits, resolveParamId, resolveRootConfig, scopedProbeReport } from "@lmzhen/dsh-evolution-core";
5
+ import { DEFAULT_SKILL_LIMITS, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, appendEvolutionEvent, assertSkillsRootAliasRetired, buildLearnPrompt, canonicalWriteId, clampedNumber, composePresetComposition, errorText, eventsFile, evolutionRoot, isDeprecatedParamId, isMissingPath, newSkillLibrary, policyStageLimits, resolveParamId, resolveRootConfig, scopedProbeReport } from "@lmzhen/dsh-evolution-core";
6
6
  import { buildEnrichment, buildMaintainFacts, runMaintain, snapshotFromLibrary } from "@lmzhen/dsh-evolution-maintenance";
7
7
  import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
8
  import { dirname, join } from "node:path";
@@ -643,15 +643,46 @@ function renderValue(value) {
643
643
  if (typeof value === "string") return value;
644
644
  return JSON.stringify(value);
645
645
  }
646
+ const WIDE_CHAR = new RegExp("[" + [
647
+ "ᄀ-ᅟ",
648
+ "⺀-〾",
649
+ "ぁ-㏿",
650
+ "㐀-䶿",
651
+ "一-鿿",
652
+ "가-힣",
653
+ "豈-﫿",
654
+ "︰-﹯",
655
+ "＀-⦆",
656
+ "¢-₩"
657
+ ].join("") + "]");
646
658
  /**
647
- * Render the rows as fixed-width text (one parameter per line, never truncated).
648
- * @param rows - rows from {@link paramSurfaceRows}.
649
- * @param options - whether the settings service answered at all.
650
- * @returns the command text.
659
+ * Pad one cell to a display width, counting CJK characters as two columns.
660
+ * @param text - the cell text.
661
+ * @param columns - the target width in terminal columns.
662
+ * @returns the text plus at least one space, so columns never touch.
651
663
  */
664
+ function pad(text, columns) {
665
+ let used = 0;
666
+ for (const char of text) used += WIDE_CHAR.test(char) ? 2 : 1;
667
+ return text + " ".repeat(Math.max(1, columns - used));
668
+ }
669
+ /** Settings timing, in the operator's words. */
670
+ const APPLIES_LABELS = Object.freeze({
671
+ live: "立即",
672
+ restart: "重启后",
673
+ none: "不生效"
674
+ });
675
+ /** Where a row's effective value comes from, in the operator's words. */
676
+ const SOURCE_LABELS = Object.freeze({
677
+ user: "我改过",
678
+ deployment: "默认",
679
+ unregistered: "不可改"
680
+ });
681
+ /** What the E-tiers mean, so the count line reads without the docs. */
682
+ const TIER_LEGEND = "档位:E0 固定/E1 只读/E2 安装时定/E3 你可改/E4 装完固化。";
652
683
  function renderParamRows(rows, options) {
653
- const header = "PARAMETER".padEnd(36) + "GROUP".padEnd(12) + "TIER".padEnd(5) + "APPLIES".padEnd(9) + "SOURCE".padEnd(14) + "VALUE";
654
- const body = rows.map((row) => row.id.padEnd(36) + row.group.padEnd(12) + row.tier.padEnd(5) + row.applies.padEnd(9) + row.source.padEnd(14) + renderValue(row.value));
684
+ const header = pad("参数", 36) + pad("分组", 12) + pad("档位", 6) + pad("生效", 8) + pad("来源", 10) + "当前值";
685
+ const body = rows.map((row) => pad(row.id, 36) + pad(PARAM_GROUP_LABELS[row.group], 12) + pad(row.tier, 6) + pad(APPLIES_LABELS[row.applies] ?? row.applies, 8) + pad(SOURCE_LABELS[row.source] ?? row.source, 10) + renderValue(row.value));
655
686
  const tiers = [
656
687
  "E0",
657
688
  "E1",
@@ -660,13 +691,14 @@ function renderParamRows(rows, options) {
660
691
  "E4"
661
692
  ].map((tier) => `${tier} ${rows.filter((row) => row.tier === tier).length}`).join(" / ");
662
693
  const userRows = rows.filter((row) => row.source === "user").length;
663
- const overrides = options.providerMounted ? `${userRows} overridden by the user.` : "overrides UNKNOWN (no settings provider).";
664
- const note = options.providerMounted ? "SOURCE: user = you set it in settings; deployment = the row/policy value applies; unregistered = the owner publishes no user layer." : "settings provider not mounted — the user layer is unavailable, so every row shows its deployment face (this is NOT \"no overrides\").";
694
+ const counts = options.providerMounted ? `共 ${rows.length} 个参数:${tiers};你改过的:${userRows} 项。` : `共 ${rows.length} 个参数:${tiers};是否改过:未知(没有设置服务)。`;
695
+ const note = options.providerMounted ? "来源:我改过=你在设置里改的;默认=安装时的配置;不可改=该功能不提供用户可改项。" : "设置服务未挂载——读不到你改过的值,所以每行显示的都是安装时的配置(这不等于「你没改过」)。";
665
696
  return [
666
697
  header,
667
698
  ...body,
668
699
  "",
669
- `${rows.length} parameter(s): ${tiers}; ${overrides}`,
700
+ counts,
701
+ TIER_LEGEND,
670
702
  note
671
703
  ].join("\n");
672
704
  }
@@ -709,79 +741,79 @@ function renderParamJson(rows) {
709
741
  const COMMAND_ENTRIES = [
710
742
  {
711
743
  usage: "pending [--detail]",
712
- summary: "list staged evolution writes (--detail shows staged args)"
744
+ summary: "列出暂存的写入(--detail 显示参数)"
713
745
  },
714
746
  {
715
747
  usage: "approve <id>",
716
- summary: "replay an approved staged write through its runner"
748
+ summary: "执行一条已批准的写入"
717
749
  },
718
750
  {
719
751
  usage: "reject <id>",
720
- summary: "drop a staged write without running it"
752
+ summary: "丢弃一条暂存写入,不执行"
721
753
  },
722
754
  {
723
755
  usage: "release <id>",
724
- summary: "return an orphaned EXECUTING write to the pending window (verify the effect first, then approve or reject)"
756
+ summary: "把卡在执行中的写入放回待批窗口(先确认效果再批准 or reject)"
725
757
  },
726
758
  {
727
759
  usage: "doctor [--json]",
728
- summary: "read-only self-check: install form, conflicts, env, services (--json feeds scripts)"
760
+ summary: "只读自检:安装形态、冲突、环境、服务(--json 供脚本用)"
729
761
  },
730
762
  {
731
763
  usage: "curator run|pause|resume|status|report|scope",
732
- summary: "run one curation pass, control or inspect automatic curation"
764
+ summary: "立即运行一次自动整理,或暂停/恢复/查看状态"
733
765
  },
734
766
  {
735
767
  usage: "mutations",
736
- summary: "list skill-mutation audit records"
768
+ summary: "列出技能改动记录"
737
769
  },
738
770
  {
739
771
  usage: "restore",
740
- summary: "restore skills from the latest snapshot"
772
+ summary: "从最近的快照恢复技能"
741
773
  },
742
774
  {
743
775
  usage: "consolidate <target> <sources...> [--plan <runId>]",
744
- summary: "merge source skills into a target umbrella skill"
776
+ summary: "把若干技能合并进一个总括技能"
745
777
  },
746
778
  {
747
779
  usage: "skill restore <name>",
748
- summary: "restore one archived skill by name"
780
+ summary: "按名字恢复一个已归档的技能"
749
781
  },
750
782
  {
751
783
  usage: "skills health",
752
- summary: "structure-health verdicts for the skill library"
784
+ summary: "技能库结构体检"
753
785
  },
754
786
  {
755
787
  usage: "skills refresh",
756
- summary: "drop the catalog caches and re-read the tree"
788
+ summary: "丢弃目录缓存并重新读取技能树"
757
789
  },
758
790
  {
759
791
  usage: "learn [request]",
760
- summary: "send a learning request to this session"
792
+ summary: "向本会话发一条学习请求"
761
793
  },
762
794
  {
763
795
  usage: "maintain [--timeout=<ms> | --facts]",
764
- summary: "run a maintenance scan (--facts: 0-token preview)"
796
+ summary: "运行一次维护扫描(--facts 为 0 token 预览)"
765
797
  },
766
798
  {
767
799
  usage: "policy set <id> <value> [--expect <revision>]",
768
- summary: "write one user-writable parameter through the settings service (E3 only; E1/E2 stay in cordis.yml)"
800
+ summary: "通过设置服务写入一个你可改的参数 (E3 only; E1/E2 stay in cordis.yml)"
769
801
  },
770
802
  {
771
803
  usage: "params [--group <name>] [--json]",
772
- summary: "list every registered parameter: group, tier, timing, source and value (--json feeds scripts)"
804
+ summary: "列出全部参数:分组、档位、生效时机、来源与当前值(--json feeds scripts)"
773
805
  },
774
806
  {
775
807
  usage: "preset install [--base <name>[,<name>...]]",
776
- summary: "generate one Evolution agent preset per named base into the user root (bases from the agent package's bases.json)"
808
+ summary: "按指定基础生成自进化 Agent 预设到用户 root (bases from the agent package's bases.json)"
777
809
  },
778
810
  {
779
811
  usage: "restructure <name> \"<heading>\" <to_file> [--plan <runId>]",
780
- summary: "move a body section into a references/ file"
812
+ summary: "把技能正文的一节移到 references 文件"
781
813
  },
782
814
  {
783
815
  usage: "replay",
784
- summary: "compare plan outcomes across sessions and restarts (backfilled from the activity store)"
816
+ summary: "比较不同会话与重启之间的计划结果(从活动记录回填)"
785
817
  }
786
818
  ];
787
819
  /** The input-declaration hint (single line, ` | `-separated). */
@@ -818,7 +850,7 @@ function apply(ctx, rawConfig = {}) {
818
850
  const commands = commandCtx.commands;
819
851
  const evolutionCommand = {
820
852
  name: "evolution",
821
- description: "Self-evolution status and approval controls",
853
+ description: "自进化:状态与待批准写入",
822
854
  recordInput: false,
823
855
  input: { hint: renderHint() },
824
856
  run: async (invocation) => {
@@ -833,18 +865,18 @@ function apply(ctx, rawConfig = {}) {
833
865
  text
834
866
  });
835
867
  const invocationAgent = invocation.agent;
836
- const agentMissing = (need) => invocationAgent === void 0 ? err(`E-305: this invocation carries no agent — \`${need}\` needs a session-backed call (run it from a session in the GUI or the CLI).`) : void 0;
868
+ const agentMissing = (need) => invocationAgent === void 0 ? err(errorText("e-305-this-invocation-carries-no", { a1: need })) : void 0;
837
869
  const unreplayableWriteRefusal = (what) => {
838
870
  if (approval === void 0) return void 0;
839
871
  const session = invocationAgent?.session;
840
872
  const sessionPolicy = effectiveSessionPolicy(ctx, session);
841
873
  if (!(approval.isEnabled !== false && sessionPolicy !== "never" && approval.stageForeground !== false)) return void 0;
842
- return err(`E-306: this deployment stages foreground writes, but \`/evolution ${what}\` is not replayable through the skill runner — there is nothing to stage. Run it from a session whose approval policy is 'never', or set \`stageForeground: false\` on the evolution-approval row, then repeat the command.`);
874
+ return err(errorText("e-306-this-deployment-stages-foreground", { a1: what }));
843
875
  };
844
876
  const approval = ctx.get("evolutionApproval");
845
877
  const pendingMatch = /^pending(?: --detail)?$/.exec(input);
846
878
  if (pendingMatch) {
847
- if (!approval) return err("E-301: approval service not mounted — pending writes cannot be listed or replayed. Next: the evolution-approval row ships with evolution-host/evolution-all — run /evolution doctor to see which services are mounted.");
879
+ if (!approval) return err(errorText("e-301-approval-service-not-mounted"));
848
880
  const listed = [...await approval.list("pending"), ...await approval.list("executing")];
849
881
  const pending = [...new Map(listed.map((row) => [row.id, row])).values()];
850
882
  if (pending.length === 0) return ok("No pending evolution writes.");
@@ -860,7 +892,7 @@ function apply(ctx, rawConfig = {}) {
860
892
  const id = input.slice(8).trim();
861
893
  const result = approval ? await approval.approve(id) : {
862
894
  ok: false,
863
- message: "E-301: approval service not mounted. Next: the evolution-approval row ships with evolution-host/evolution-all — run /evolution doctor to see which services are mounted."
895
+ message: errorText("e-301-approval-service-not-mounted-2")
864
896
  };
865
897
  return result.ok ? ok(result.message) : err(result.message);
866
898
  }
@@ -868,27 +900,27 @@ function apply(ctx, rawConfig = {}) {
868
900
  const id = input.slice(7).trim();
869
901
  const result = approval ? await approval.reject(id) : {
870
902
  ok: false,
871
- message: "E-301: approval service not mounted. Next: the evolution-approval row ships with evolution-host/evolution-all — run /evolution doctor to see which services are mounted."
903
+ message: errorText("e-301-approval-service-not-mounted-2")
872
904
  };
873
905
  return result.ok ? ok(result.message) : err(result.message);
874
906
  }
875
907
  if (input.startsWith("release ")) {
876
908
  const id = input.slice(8).trim();
877
- if (!approval) return err("E-301: approval service not mounted. Next: the evolution-approval row ships with evolution-host/evolution-all — run /evolution doctor to see which services are mounted.");
878
- if (!approval.release) return err("E-304: the mounted approval service predates the release capability — reject the record instead.");
909
+ if (!approval) return err(errorText("e-301-approval-service-not-mounted-2"));
910
+ if (!approval.release) return err(errorText("e-304-the-mounted-approval-service"));
879
911
  const result = await approval.release(id);
880
912
  return result.ok ? ok(result.message) : err(result.message);
881
913
  }
882
914
  if (input === "curator run") {
883
915
  const curator = ctx.get("evolutionCurator");
884
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
916
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
885
917
  const result = await curator.run({ ignoreGates: true });
886
918
  if (result.skipped !== void 0) return ok(`Curator run skipped (${result.skipped}): no curation pass was executed.\nrunId=${result.report.runId}`);
887
919
  return ok(`Curator run complete: ${result.stale.length} stale, ${result.archived.length} archived, ${result.errors.length} failed.\nrunId=${result.report.runId}${result.report.snapshotPath ? `\nsnapshot=${result.report.snapshotPath}` : ""}`);
888
920
  }
889
921
  if (input === "curator pause" || input === "curator resume") {
890
922
  const curator = ctx.get("evolutionCurator");
891
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
923
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
892
924
  const paused = input === "curator pause";
893
925
  await curator.setPaused(paused);
894
926
  const notPersisted = ctx.get("evolutionState") !== void 0 ? "" : "\nNOTE: no evolution state service is mounted — this setting is NOT persisted and will not survive this process.";
@@ -896,7 +928,7 @@ function apply(ctx, rawConfig = {}) {
896
928
  }
897
929
  if (input === "curator status") {
898
930
  const curator = ctx.get("evolutionCurator");
899
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
931
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
900
932
  const state = await curator.status();
901
933
  if (!state) return ok("No curator state yet: the first automatic pass is deferred until the interval elapses.");
902
934
  const lastRun = typeof state.lastRunAt === "number" && Number.isFinite(state.lastRunAt) && state.lastRunAt > 0 ? new Date(state.lastRunAt).toISOString() : "unknown";
@@ -909,7 +941,7 @@ function apply(ctx, rawConfig = {}) {
909
941
  }
910
942
  if (input === "mutations") {
911
943
  const curator = ctx.get("evolutionCurator");
912
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
944
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
913
945
  const records = await curator.skills.listMutations();
914
946
  const usable = Array.isArray(records) ? records.filter((row) => typeof row === "object" && row !== null && typeof row.at === "string" && typeof row.skillName === "string" && typeof row.action === "string" && typeof row.summary === "string") : [];
915
947
  if (usable.length === 0) return ok("No mutation records yet.");
@@ -918,7 +950,7 @@ function apply(ctx, rawConfig = {}) {
918
950
  }
919
951
  if (input === "curator scope") {
920
952
  const curator = ctx.get("evolutionCurator");
921
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
953
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
922
954
  const view = await curator.scopeView();
923
955
  const line = (label, names) => `${label}: ${names.length}${names.length === 0 ? "" : `\n ${names.join(", ")}`}`;
924
956
  return ok([
@@ -932,7 +964,7 @@ function apply(ctx, rawConfig = {}) {
932
964
  }
933
965
  if (input === "curator report") {
934
966
  const curator = ctx.get("evolutionCurator");
935
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
967
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
936
968
  const report = await curator.latestReport();
937
969
  if (!report) return ok("No curator report available.");
938
970
  if (typeof report !== "object" || typeof report.runId !== "string" || typeof report.startedAt !== "string" || !Array.isArray(report.archived) || !Array.isArray(report.failed)) return err("Report file unreadable.");
@@ -958,7 +990,7 @@ function apply(ctx, rawConfig = {}) {
958
990
  const curator = ctx.get("evolutionCurator");
959
991
  const result = curator ? await curator.restoreSnapshot() : {
960
992
  ok: false,
961
- message: "E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor."
993
+ message: errorText("e-302-curator-service-not-mounted")
962
994
  };
963
995
  return result.ok ? ok(result.message) : err(result.message);
964
996
  }
@@ -972,7 +1004,7 @@ function apply(ctx, rawConfig = {}) {
972
1004
  const curator = ctx.get("evolutionCurator");
973
1005
  const result = curator ? await curator.consolidate(target, sources) : {
974
1006
  ok: false,
975
- message: "E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor."
1007
+ message: errorText("e-302-curator-service-not-mounted")
976
1008
  };
977
1009
  if (!result.ok) return err(result.message);
978
1010
  return ok(planRunId ? `${result.message}\n[audit] plan=${planRunId}` : result.message);
@@ -985,13 +1017,13 @@ function apply(ctx, rawConfig = {}) {
985
1017
  const curator = ctx.get("evolutionCurator");
986
1018
  const result = curator ? await curator.restore(name) : {
987
1019
  ok: false,
988
- message: "E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor."
1020
+ message: errorText("e-302-curator-service-not-mounted")
989
1021
  };
990
1022
  return result.ok ? ok(result.message) : err(result.message);
991
1023
  }
992
1024
  if (input === "skills health") {
993
1025
  const curator = ctx.get("evolutionCurator");
994
- if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
1026
+ if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
995
1027
  const [rows, observed] = await Promise.all([curator.healthView(), curator.usageObserved()]);
996
1028
  const banner = observed ? "" : "Usage observation not yet established — churn (write-ghost) rows are suppressed.";
997
1029
  const line = (row) => `${row.verdict.padEnd(18)} ${row.name}${row.reasons.length > 0 ? ` — ${row.reasons.join("; ")}` : ""}`;
@@ -1024,7 +1056,7 @@ function apply(ctx, rawConfig = {}) {
1024
1056
  agent.followup(message);
1025
1057
  woke = true;
1026
1058
  } else if (typeof agent.inject === "function") agent.inject(message);
1027
- else return err("E-305: the invocation agent exposes neither `followup` nor `inject` — this learn request has no delivery channel.");
1059
+ else return err(errorText("e-305-the-invocation-agent-exposes"));
1028
1060
  const eventIo = ctx.get("evolutionIo")?.provider();
1029
1061
  if (eventIo) appendEvolutionEvent(eventIo, eventsFile(evolutionRoot()), {
1030
1062
  type: "learn",
@@ -1203,7 +1235,7 @@ function apply(ctx, rawConfig = {}) {
1203
1235
  const session = invocationAgent?.session;
1204
1236
  const sessionPolicy = effectiveSessionPolicy(ctx, session);
1205
1237
  const stagesForeground = approval.isEnabled !== false && sessionPolicy !== "never" && approval.stageForeground !== false;
1206
- if (stagesForeground && session === void 0) return err("E-306: this deployment stages foreground writes, but this invocation carries no agent session — `/evolution restructure` would stage a record with no session attribution. Run it from a session in the GUI or the CLI, or set `stageForeground: false` on the evolution-approval row, then repeat the command.");
1238
+ if (stagesForeground && session === void 0) return err(errorText("e-306-this-deployment-stages-foreground-2"));
1207
1239
  if (stagesForeground && !approval.hasRunner("skill")) return err("Restructure cannot be staged: no skill replay runner is registered — mount the tool-skill-manage row (evolution-agent preset, or evolution-all) or disable evolution-approval.");
1208
1240
  const decision = await approval.request({
1209
1241
  kind: "skill",
@@ -1248,7 +1280,7 @@ function apply(ctx, rawConfig = {}) {
1248
1280
  }
1249
1281
  if (input === "replay") {
1250
1282
  const replay = ctx.get("evolutionReplay");
1251
- if (!replay) return err("E-303: replay service not mounted. Next: mount the evolution-replay row (evolution-host/evolution-all) and run /evolution doctor.");
1283
+ if (!replay) return err(errorText("e-303-replay-service-not-mounted"));
1252
1284
  return ok(replay.compare().report);
1253
1285
  }
1254
1286
  const paramsMatch = /^params(?: --group ([a-z-]+))?(?: --json)?$/.exec(input);
@@ -1264,52 +1296,68 @@ function apply(ctx, rawConfig = {}) {
1264
1296
  sections.set(descriptor.ns, section);
1265
1297
  }
1266
1298
  } catch (error) {
1267
- return err(`E-307: the settings service could not report its sections (${error instanceof Error ? error.message : String(error)}). /evolution params needs the user layer to tell an override from a deployment value; run /evolution doctor to see which services are mounted.`);
1299
+ return err(errorText("e-307-the-settings-service-could", { a1: error instanceof Error ? error.message : String(error) }));
1268
1300
  }
1269
1301
  const rows = paramSurfaceRows(sections, PARAM_EXPOSURE);
1270
1302
  const group = paramsMatch[1];
1271
1303
  const selected = group === void 0 ? rows : rows.filter((row) => row.group === group);
1272
- if (group !== void 0 && selected.length === 0) return err(`E-308: unknown parameter group "${group}" — known groups: ${paramGroups(PARAM_EXPOSURE).join(", ")}.`);
1304
+ if (group !== void 0 && selected.length === 0) return err(errorText("e-308-unknown-parameter-group-group", {
1305
+ a1: group,
1306
+ a2: paramGroups(PARAM_EXPOSURE).join(", ")
1307
+ }));
1273
1308
  if (input.endsWith("--json")) return ok(renderParamJson(selected));
1274
1309
  return ok(renderParamRows(selected, { providerMounted: provider !== void 0 }));
1275
1310
  }
1276
1311
  const policySetMatch = /^policy set ([A-Za-z][A-Za-z0-9.-]*) (.+?)(?: --expect (\d+))?$/.exec(input);
1277
1312
  if (policySetMatch) {
1278
1313
  const provider = ctx.get("settings");
1279
- if (provider?.update === void 0 || provider.describe === void 0) return err("E-311: no settings service is mounted, so there is no user layer to write. Mount the settings row (packages/settings/settings-file) and retry; this command never edits cordis.yml — a deployment value belongs to the deployment. /evolution doctor lists the mounted services.");
1314
+ if (provider?.update === void 0 || provider.describe === void 0) return err(errorText("e-311-no-settings-service-is"));
1280
1315
  const rawId = policySetMatch[1] ?? "";
1281
1316
  const rawValue = policySetMatch[2] ?? "";
1282
1317
  let id;
1283
1318
  try {
1284
1319
  id = canonicalWriteId(rawId);
1285
1320
  } catch (error) {
1286
- return err(`E-312: ${error instanceof Error ? error.message : String(error)} — /evolution params lists the canonical ids.`);
1321
+ return err(errorText("e-312-error-instanceof-Error-error", { a1: error instanceof Error ? error.message : String(error) }));
1287
1322
  }
1288
1323
  const entry = PARAM_EXPOSURE.find((candidate) => candidate.id === id);
1289
- if (entry === void 0) return err(`E-313: unknown parameter "${id}" — /evolution params lists every registered id with its tier and user layer.`);
1290
- if (entry.tier !== "E3") return err(`E-314: "${id}" is a deployment parameter (tier ${entry.tier}, owner ${entry.owner}) — it is written in cordis.yml on its plugin or policy row, not from a session. /evolution params shows who may write each row.`);
1324
+ if (entry === void 0) return err(errorText("e-313-unknown-parameter-id-evolution", { a1: id }));
1325
+ if (entry.tier !== "E3") return err(errorText("e-314-id-is-a-deployment", {
1326
+ a1: id,
1327
+ a2: entry.tier,
1328
+ a3: entry.owner
1329
+ }));
1291
1330
  const namespace = PARAM_NAMESPACES[entry.owner];
1292
- if (namespace === void 0) return err(`E-315: "${id}" has no user layer — owner ${entry.owner} publishes no settings namespace, so the value stays with the deployment.`);
1331
+ if (namespace === void 0) return err(errorText("e-315-id-has-no-user", {
1332
+ a1: id,
1333
+ a2: entry.owner
1334
+ }));
1293
1335
  let descriptor;
1294
1336
  try {
1295
1337
  descriptor = provider.describe({ redactSecrets: false }).find((candidate) => candidate.ns === namespace);
1296
1338
  } catch (error) {
1297
- return err(`E-307: the settings service could not report its sections (${error instanceof Error ? error.message : String(error)}). /evolution policy set needs the current revision to write safely; run /evolution doctor to see which services are mounted.`);
1339
+ return err(errorText("e-307-the-settings-service-could-2", { a1: error instanceof Error ? error.message : String(error) }));
1298
1340
  }
1299
- if (descriptor === void 0) return err(`E-316: namespace "${namespace}" is not registered — owner ${entry.owner} is not mounted in this composition, so its parameters cannot be written from here. /evolution params marks those rows 'unregistered'.`);
1341
+ if (descriptor === void 0) return err(errorText("e-316-namespace-namespace-is-not", {
1342
+ a1: namespace,
1343
+ a2: entry.owner
1344
+ }));
1300
1345
  const current = descriptor.value;
1301
1346
  const resolved = typeof current === "object" && current !== null ? current : void 0;
1302
1347
  const expectedRaw = policySetMatch[3];
1303
1348
  const expected = expectedRaw === void 0 ? descriptor.revision : Number(expectedRaw);
1304
- if (expectedRaw !== void 0 && descriptor.revision !== void 0 && Number(expectedRaw) !== descriptor.revision) return err(`E-309: revision conflict — you sent ${expectedRaw}, the document stands at ${descriptor.revision}. Re-read with /evolution params --json and retry.`);
1349
+ if (expectedRaw !== void 0 && descriptor.revision !== void 0 && Number(expectedRaw) !== descriptor.revision) return err(errorText("e-309-revision-conflict-you-sent", {
1350
+ a1: expectedRaw,
1351
+ a2: descriptor.revision
1352
+ }));
1305
1353
  const value = parseParamValue(rawValue);
1306
1354
  try {
1307
1355
  await provider.update(namespace, { [id]: value }, expected);
1308
1356
  } catch (error) {
1309
1357
  const code = error?.code;
1310
1358
  const message = error instanceof Error ? error.message : String(error);
1311
- if (code === "SETTINGS_CONFLICT") return err(`E-309: revision conflict — ${message}. Re-read with /evolution params --json and retry.`);
1312
- return err(`E-310: the settings service refused the write: ${message} — the owning plugin's rule stands (a cross-field pair, or a cap that may only be tightened). /evolution params shows the current value.`);
1359
+ if (code === "SETTINGS_CONFLICT") return err(errorText("e-309-revision-conflict-message-Re", { a1: message }));
1360
+ return err(errorText("e-310-the-settings-service-refused", { a1: message }));
1313
1361
  }
1314
1362
  return ok(renderPolicySet({
1315
1363
  id,
@@ -1325,7 +1373,7 @@ function apply(ctx, rawConfig = {}) {
1325
1373
  if (input === "doctor --json") return ok(JSON.stringify(report, null, 2));
1326
1374
  return ok(renderDoctorText(report));
1327
1375
  }
1328
- return ok(`Evolution: memory, skills, review, curator — self-evolution status, approval and maintenance.\n${renderHelpText()}`);
1376
+ return ok(`自进化:记忆、技能、会话回顾、技能整理——状态、待批准写入与维护。\n${renderHelpText()}`);
1329
1377
  },
1330
1378
  handler: (invocation) => evolutionCommand.run(invocation).catch((error) => ({
1331
1379
  kind: "error",
@@ -52,12 +52,6 @@ export declare function paramSurfaceRows(sections: ReadonlyMap<string, ParamSect
52
52
  * @returns distinct group names.
53
53
  */
54
54
  export declare function paramGroups(entries?: readonly ParamExposure[]): string[];
55
- /**
56
- * Render the rows as fixed-width text (one parameter per line, never truncated).
57
- * @param rows - rows from {@link paramSurfaceRows}.
58
- * @param options - whether the settings service answered at all.
59
- * @returns the command text.
60
- */
61
55
  export declare function renderParamRows(rows: readonly ParamSurfaceRow[], options: {
62
56
  providerMounted: boolean;
63
57
  }): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-commands",
3
3
  "description": "Human commands for the evolution family (/evolution pending|curator|maintain|doctor) (community build)",
4
- "version": "0.7.0",
4
+ "version": "0.9.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,12 +27,12 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.1",
30
- "@lmzhen/dsh-evolution-approval": "^0.7.0",
31
- "@lmzhen/dsh-evolution-core": "^0.7.0",
32
- "@lmzhen/dsh-evolution-maintenance": "^0.7.0"
30
+ "@lmzhen/dsh-evolution-approval": "^0.9.0",
31
+ "@lmzhen/dsh-evolution-core": "^0.9.0",
32
+ "@lmzhen/dsh-evolution-maintenance": "^0.9.0"
33
33
  },
34
34
  "optionalDependencies": {
35
- "@lmzhen/dsh-evolution-agent-preset": "^0.7.0"
35
+ "@lmzhen/dsh-evolution-agent-preset": "^0.9.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",