@lmzhen/dsh-evolution-commands 0.3.34 → 0.3.36

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 (2) hide show
  1. package/lib/index.js +22 -10
  2. package/package.json +4 -4
package/lib/index.js CHANGED
@@ -93,9 +93,10 @@ function apply(ctx, rawConfig = {}) {
93
93
  const curator = ctx.get("evolutionCurator");
94
94
  if (!curator) return err("Curator service not mounted.");
95
95
  const records = await curator.skills.listMutations();
96
- if (records.length === 0) return ok("No mutation records yet.");
97
- const recent = records.slice(-5).reverse().map((record) => `${record.at.slice(0, 19)} ${record.skillName} ${record.action} ${record.summary}`);
98
- return ok(`Mutations: ${records.length} recorded (recent 5):\n${recent.join("\n")}`);
96
+ 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") : [];
97
+ if (usable.length === 0) return ok("No mutation records yet.");
98
+ const recent = usable.slice(-5).reverse().map((record) => `${record.at.slice(0, 19)} ${record.skillName} ${record.action} ${record.summary}`);
99
+ return ok(`Mutations: ${usable.length} recorded (recent 5):\n${recent.join("\n")}`);
99
100
  }
100
101
  if (input === "curator scope") {
101
102
  const curator = ctx.get("evolutionCurator");
@@ -108,7 +109,7 @@ function apply(ctx, rawConfig = {}) {
108
109
  line("Watched (stale / quality-warned)", view.watched),
109
110
  line("Quality-warned", view.qualityWarned),
110
111
  line("Exempted (exclude / referenced)", view.exempted),
111
- line("Protected (pinned / bundled / hub)", view.protected)
112
+ line("Protected (pinned / bundled / hub / builtin)", view.protected)
112
113
  ].join("\n"));
113
114
  }
114
115
  if (input === "curator report") {
@@ -116,11 +117,15 @@ function apply(ctx, rawConfig = {}) {
116
117
  if (!curator) return err("Curator service not mounted.");
117
118
  const report = await curator.latestReport();
118
119
  if (!report) return ok("No curator report available.");
120
+ 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.");
121
+ const reportAny = report;
122
+ const nameOf = (item) => typeof item === "object" && item !== null && typeof item.name === "string" ? item.name : "?";
123
+ const reasonOf = (item) => typeof item === "object" && item !== null && typeof item.reason === "string" ? item.reason : "?";
119
124
  return ok([
120
- `runId=${report.runId}`,
121
- `startedAt=${report.startedAt}`,
122
- `archived=${report.archived.map((item) => item.name).join(", ") || "(none)"}`,
123
- `failed=${report.failed.map((item) => `${item.name}: ${item.reason}`).join(", ") || "(none)"}`
125
+ `runId=${reportAny.runId}`,
126
+ `startedAt=${reportAny.startedAt}`,
127
+ `archived=${reportAny.archived.map(nameOf).join(", ") || "(none)"}`,
128
+ `failed=${reportAny.failed.map((item) => `${nameOf(item)}: ${reasonOf(item)}`).join(", ") || "(none)"}`
124
129
  ].join("\n"));
125
130
  }
126
131
  if (input.startsWith("restore ")) {
@@ -208,7 +213,7 @@ function apply(ctx, rawConfig = {}) {
208
213
  const maintainArgs = /^maintain(?: --timeout (\d+))?\s*$/.exec(input);
209
214
  if (maintainArgs) {
210
215
  const runTimeoutMs = maintainArgs[1] ? Number(maintainArgs[1]) : config.maintainTimeoutMs ?? 6e5;
211
- if (!Number.isSafeInteger(runTimeoutMs) || runTimeoutMs <= 0) return err("Invalid --timeout value: expected a positive integer number of milliseconds (e.g. /evolution maintain --timeout 600000).");
216
+ if (!Number.isSafeInteger(runTimeoutMs) || runTimeoutMs <= 0 || runTimeoutMs > 4294967295) return err("Invalid --timeout value: expected a positive integer number of milliseconds up to 4294967295 (e.g. /evolution maintain --timeout 600000).");
212
217
  if (maintainInFlightSince > 0) return ok(`Maintenance scan is already running (since ~${Math.max(1, Math.round((Date.now() - maintainInFlightSince) / 1e3))}s ago) — re-submitting now would cancel it. Wait for it to settle; the result appears when it finishes.`);
213
218
  const cooldownMs = config.maintainCooldownMs ?? 3e4;
214
219
  const sinceLast = Date.now() - lastMaintainAt;
@@ -375,6 +380,8 @@ const defaultFs = {
375
380
  */
376
381
  function atomicWriteFiles(targetDir, writes, fs = defaultFs) {
377
382
  const stage = (name) => join(targetDir, `${name}.tmp`);
383
+ const dupes = [...new Set(writes.map((write) => write.name).filter((name, index, all) => all.indexOf(name) !== index))];
384
+ if (dupes.length > 0) throw new Error(`atomicWriteFiles: duplicate input names: ${dupes.join(", ")}`);
378
385
  try {
379
386
  for (const { name, content } of writes) fs.writeFileSync(stage(name), content);
380
387
  for (const { name } of writes) {
@@ -391,7 +398,12 @@ function atomicWriteFiles(targetDir, writes, fs = defaultFs) {
391
398
  fs.renameSync(tmp, finalPath);
392
399
  committed.push(name);
393
400
  } catch {
394
- fs.rmSync(finalPath, { force: true });
401
+ try {
402
+ fs.rmSync(finalPath, { force: true });
403
+ } catch (removeError) {
404
+ const already = committed.length > 0 ? `; already committed: ${committed.join(", ")}` : "";
405
+ throw new Error(`atomicWriteFiles: could not remove "${name}" to replace it (${removeError instanceof Error ? removeError.message : String(removeError)})${already}`);
406
+ }
395
407
  try {
396
408
  fs.renameSync(tmp, finalPath);
397
409
  committed.push(name);
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 (community build)",
4
- "version": "0.3.34",
4
+ "version": "0.3.36",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,9 +30,9 @@
30
30
  ],
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@lmzhen/dsh-evolution-approval": "^0.3.34",
34
- "@lmzhen/dsh-evolution-core": "^0.3.34",
35
- "@lmzhen/dsh-evolution-maintenance": "^0.3.34"
33
+ "@lmzhen/dsh-evolution-approval": "^0.3.36",
34
+ "@lmzhen/dsh-evolution-core": "^0.3.36",
35
+ "@lmzhen/dsh-evolution-maintenance": "^0.3.36"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",