@lmzhen/dsh-evolution-core 0.3.56 → 0.3.57

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
@@ -311,6 +311,10 @@ function nodeEvolutionIo(lockAttempts = 40) {
311
311
  retryDelay: 100
312
312
  }).catch(async () => {
313
313
  const body = await readFile(lock, "utf8").catch(() => "");
314
+ if (pendingSelfCleanup.size >= 64) {
315
+ const oldest = pendingSelfCleanup.keys().next().value;
316
+ if (oldest !== void 0) pendingSelfCleanup.delete(oldest);
317
+ }
314
318
  pendingSelfCleanup.set(lock, body);
315
319
  });
316
320
  }
@@ -428,7 +432,7 @@ function nodeEvolutionIo(lockAttempts = 40) {
428
432
  },
429
433
  async rename(path, destination) {
430
434
  await mkdir(dirname(destination), { recursive: true });
431
- await rename(path, destination);
435
+ await renameWithRetry(path, destination);
432
436
  },
433
437
  async copy(path, destination) {
434
438
  await mkdir(dirname(destination), { recursive: true });
@@ -1207,8 +1211,8 @@ async function appendEvolutionEvent(io, path, event, rotateAt = EVENT_LOG_ROTATE
1207
1211
  return current;
1208
1212
  }
1209
1213
  }
1210
- const nextEvents = await rotateIfDue(io, path, await rotateIfDue(io, path, v1EventRecords(parsedBody), rotateAt), rotateAt);
1211
- let maxSeq = nextEvents.reduce((max, entry) => Math.max(max, entry.seq), 0);
1214
+ const events = await rotateIfDue(io, path, v1EventRecords(parsedBody), rotateAt);
1215
+ let maxSeq = events.reduce((max, entry) => Math.max(max, entry.seq), 0);
1212
1216
  if (maxSeq === 0) for (const name of await listEventArchives(io, path)) maxSeq = Math.max(maxSeq, Number.parseInt(name.slice(7, name.length - 5), 10));
1213
1217
  const record = {
1214
1218
  ...event,
@@ -1218,7 +1222,7 @@ async function appendEvolutionEvent(io, path, event, rotateAt = EVENT_LOG_ROTATE
1218
1222
  assigned = record.seq;
1219
1223
  return JSON.stringify({
1220
1224
  version: 1,
1221
- events: [...nextEvents, record]
1225
+ events: [...events, record]
1222
1226
  }, null, 2);
1223
1227
  });
1224
1228
  if (assigned === 0) throw new Error(`${refuseMessage || "evolution event log is malformed and was not touched"}: ${path}`);
@@ -3109,9 +3113,11 @@ function observeEvent(signal, event) {
3109
3113
  return;
3110
3114
  }
3111
3115
  if (event.type === "tool/call") {
3116
+ const data = event.data;
3117
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return;
3112
3118
  signal.toolCalls += 1;
3113
- if (event.data.name === "skill") signal.skillSignal = true;
3114
- if (event.data.name === "skill_manage") signal.skillSignal = true;
3119
+ const name = data.name;
3120
+ if (name === "skill" || name === "skill_manage") signal.skillSignal = true;
3115
3121
  }
3116
3122
  }
3117
3123
  /** Compute review cadence after `turn/end`. */
@@ -4145,6 +4151,9 @@ var SkillLibrary = class {
4145
4151
  }
4146
4152
  async create(name, content, origin = "foreground") {
4147
4153
  const normalized = name.trim();
4154
+ return await this.serial(() => this.createCore(normalized, content, origin));
4155
+ }
4156
+ async createCore(normalized, content, origin) {
4148
4157
  const bad = this.badName(normalized);
4149
4158
  if (bad) return {
4150
4159
  ok: false,
@@ -4882,9 +4891,10 @@ var SkillLibrary = class {
4882
4891
  */
4883
4892
  async restoreFromArchive(rawName) {
4884
4893
  const name = rawName.trim();
4885
- if (!SKILL_NAME_RE.test(name)) return {
4894
+ const bad = this.badName(name);
4895
+ if (bad) return {
4886
4896
  ok: false,
4887
- message: `Invalid skill name "${name}". Use lowercase letters, digits, and hyphens.`
4897
+ message: bad
4888
4898
  };
4889
4899
  if (await this.io.exists(join(this.dirOf(name), "SKILL.md"))) return {
4890
4900
  ok: false,
@@ -5013,6 +5023,9 @@ var SkillLibrary = class {
5013
5023
  }
5014
5024
  async removeSupportFile(rawName, filePath, origin = "foreground") {
5015
5025
  const name = rawName.trim();
5026
+ return await this.serial(() => this.removeSupportFileCore(name, filePath, origin));
5027
+ }
5028
+ async removeSupportFileCore(name, filePath, origin) {
5016
5029
  const badName = this.badName(name);
5017
5030
  if (badName) return {
5018
5031
  ok: false,
@@ -5064,36 +5077,41 @@ var SkillLibrary = class {
5064
5077
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5065
5078
  let dest = join(backupRoot, `skills-${stamp}`);
5066
5079
  while (await this.io.exists(dest)) dest = join(backupRoot, `skills-${stamp}-${Math.random().toString(36).slice(2, 8)}`);
5067
- const names = await listNames(this.root, this.io);
5068
- await Promise.all(names.map(async (name) => {
5069
- await this.io.copy(this.dirOf(name), join(dest, name));
5070
- }));
5071
- const sidecars = [];
5072
- for (const sidecar of [usageFile(this.root), suppressedFile(this.root)]) if (await this.io.exists(sidecar)) {
5073
- const name = basename(sidecar);
5074
- await this.io.copy(sidecar, join(dest, name));
5075
- sidecars.push(name);
5076
- }
5077
- const archiveRoot = join(this.root, ".archive");
5078
- let hasArchive = false;
5079
- if (await this.io.exists(archiveRoot)) {
5080
- await this.io.copy(archiveRoot, join(dest, ".archive"));
5081
- hasArchive = true;
5080
+ try {
5081
+ const names = await listNames(this.root, this.io);
5082
+ await Promise.all(names.map(async (name) => {
5083
+ await this.io.copy(this.dirOf(name), join(dest, name));
5084
+ }));
5085
+ const sidecars = [];
5086
+ for (const sidecar of [usageFile(this.root), suppressedFile(this.root)]) if (await this.io.exists(sidecar)) {
5087
+ const name = basename(sidecar);
5088
+ await this.io.copy(sidecar, join(dest, name));
5089
+ sidecars.push(name);
5090
+ }
5091
+ const archiveRoot = join(this.root, ".archive");
5092
+ let hasArchive = false;
5093
+ if (await this.io.exists(archiveRoot)) {
5094
+ await this.io.copy(archiveRoot, join(dest, ".archive"));
5095
+ hasArchive = true;
5096
+ }
5097
+ const validExtras = extras.filter((extra) => SNAPSHOT_EXTRA_NAME_RE.test(extra.name));
5098
+ const extraNames = validExtras.map((extra) => extra.name);
5099
+ await Promise.all(validExtras.map(async (extra) => {
5100
+ await this.io.writeText(join(dest, "extras", extra.name), extra.content);
5101
+ }));
5102
+ await this.io.writeText(join(dest, "manifest.json"), JSON.stringify({
5103
+ reason,
5104
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5105
+ skills: names,
5106
+ sidecars,
5107
+ hasArchive,
5108
+ extras: extraNames
5109
+ }, null, 2));
5110
+ await this.retainSnapshots(5);
5111
+ } catch (error) {
5112
+ await this.io.remove(dest).catch(() => {});
5113
+ throw error;
5082
5114
  }
5083
- const validExtras = extras.filter((extra) => SNAPSHOT_EXTRA_NAME_RE.test(extra.name));
5084
- const extraNames = validExtras.map((extra) => extra.name);
5085
- await Promise.all(validExtras.map(async (extra) => {
5086
- await this.io.writeText(join(dest, "extras", extra.name), extra.content);
5087
- }));
5088
- await this.io.writeText(join(dest, "manifest.json"), JSON.stringify({
5089
- reason,
5090
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5091
- skills: names,
5092
- sidecars,
5093
- hasArchive,
5094
- extras: extraNames
5095
- }, null, 2));
5096
- await this.retainSnapshots(5);
5097
5115
  return dest;
5098
5116
  }
5099
5117
  /** Read and normalize a snapshot manifest; null when the file is missing or unparsable. */
@@ -321,6 +321,7 @@ export declare class SkillLibrary {
321
321
  */
322
322
  setPinned(name: string, pinned: boolean, origin?: WriteOrigin): Promise<SkillActionResult>;
323
323
  create(name: string, content: string, origin?: WriteOrigin): Promise<SkillActionResult>;
324
+ private createCore;
324
325
  update(rawName: string, content: string, origin?: WriteOrigin): Promise<SkillActionResult>;
325
326
  private updateCore;
326
327
  patch(rawName: string, oldString: string, newString: string, filePath?: string, replaceAll?: boolean, origin?: WriteOrigin): Promise<SkillActionResult>;
@@ -378,6 +379,7 @@ export declare class SkillLibrary {
378
379
  writeSupportFile(rawName: string, filePath: string, content: string, origin?: WriteOrigin): Promise<SkillActionResult>;
379
380
  private writeSupportFileCore;
380
381
  removeSupportFile(rawName: string, filePath: string, origin?: WriteOrigin): Promise<SkillActionResult>;
382
+ private removeSupportFileCore;
381
383
  /**
382
384
  * Snapshot the recoverable skills state: active tree, usage/suppression
383
385
  * sidecars, `.archive/` and caller-supplied extras. `extras` are opaque
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.3.56",
4
+ "version": "0.3.57",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },