@lmzhen/dsh-evolution-maintenance 0.17.0 → 0.18.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
@@ -1,4 +1,4 @@
1
- import { i as snapshotFromLibrary, n as PROBE_SIGNALS, r as computeProbe, t as buildEnrichment } from "./enrichment-CjZmhRI9.js";
1
+ import { a as snapshotFromLibrary, i as enrichmentSnapshotOptions, n as computeProbe, r as buildEnrichment, t as PROBE_SIGNALS } from "./probe-Bojb0piw.js";
2
2
  import { AUTHORING_DESCRIPTION_BAR, DEFAULT_CURATOR_MODEL, DEFAULT_HEALTH_THRESHOLDS, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, LOW_QUALITY_THRESHOLD, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_TIMER_DELAY_MS, MIN_STAMP_BODY_CHARS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, computeDriftSignals, findDriftSignal, redactSecrets, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  //#region lib/types/render-facts.js
@@ -266,9 +266,12 @@ function validateAndNormalizeMaintainPlan(raw, report, validSignals) {
266
266
  forcedHuman.push(...item.names.filter((name) => unknownQualitySkills.has(name)));
267
267
  }
268
268
  for (const item of plan) {
269
- const referencesUnknown = item.evidence.some((ev) => {
270
- return findSignalInReport(report, ev.signal)?.verdict === "unknown";
269
+ const unknownIn = (signals) => item.evidence.some((ev) => findDriftSignal(signals, ev.signal)?.verdict === "unknown");
270
+ const namedSkills = item.names.flatMap((name) => {
271
+ const skill = report.skills.find((candidate) => candidate.name.trim() === name);
272
+ return skill === void 0 ? [] : [skill];
271
273
  });
274
+ const referencesUnknown = namedSkills.length > 0 ? namedSkills.some((skill) => unknownIn(skill.signals)) : unknownIn(report.library);
272
275
  const lowConfidence = item.confidence < .6;
273
276
  const irreversible = item.reversibility === "rename" || item.reversibility === "none";
274
277
  if (!item.needs_human && (lowConfidence || irreversible || item.is_override || referencesUnknown)) item.needs_human = true;
@@ -284,9 +287,6 @@ function validateAndNormalizeMaintainPlan(raw, report, validSignals) {
284
287
  forcedHuman
285
288
  };
286
289
  }
287
- function findSignalInReport(report, id) {
288
- return report.library.find((signal) => signal.id === id) ?? report.skills.flatMap((skill) => skill.signals).find((signal) => signal.id === id);
289
- }
290
290
  //#endregion
291
291
  //#region lib/types/orchestrate.js
292
292
  /**
@@ -405,18 +405,10 @@ async function runMaintain(runtime, options = {}) {
405
405
  recommendationCount: 0,
406
406
  error: "dsh-evolution prompt bundle integrity check failed; refusing to run maintain"
407
407
  };
408
- const usageObserved = options.usageObserved ? options.usageObserved() : void 0;
408
+ const enrichment = options.enrichment?.();
409
409
  const readFailures = [];
410
410
  const snapshots = await snapshotFromLibrary(runtime.library, {
411
- supportFiles: options.supportFiles ? options.supportFiles() : void 0,
412
- descriptions: options.descriptions ? options.descriptions() : void 0,
413
- quality: options.quality ? options.quality() : void 0,
414
- protected: options.protected ? options.protected() : void 0,
415
- catalogInvalid: options.catalogInvalid ? options.catalogInvalid() : void 0,
416
- usageObserved,
417
- ...options.demand === void 0 ? {} : { demand: options.demand() },
418
- ...options.liveness === void 0 ? {} : { liveness: options.liveness() },
419
- ...options.supportChars === void 0 ? {} : { supportChars: options.supportChars() },
411
+ ...enrichment === void 0 ? {} : enrichmentSnapshotOptions(enrichment),
420
412
  onReadError: (name, error) => {
421
413
  readFailures.push(name);
422
414
  runtime.logger?.warn(`evolution-maintenance: skipping unreadable skill "${name}": ${error instanceof Error ? error.message : String(error)}`);
@@ -441,7 +433,7 @@ async function runMaintain(runtime, options = {}) {
441
433
  text: "Maintenance scan: empty skill library. Nothing to do."
442
434
  };
443
435
  }
444
- const { facts, report, signalsVersion, signature } = buildMaintainFacts(snapshots, usageObserved, options.redact);
436
+ const { facts, report, signalsVersion, signature } = buildMaintainFacts(snapshots, enrichment?.usageObservedValue, options.redact);
445
437
  const template = renderMaintainTemplate(MAINTAIN_PROMPT, PROMPT_BUNDLE_ID, signalsVersion, signature);
446
438
  const probeRegistered = runtime.tools?.get("maintenance_probe") != null;
447
439
  const probeDegraded = options.toolAllow === void 0 && !probeRegistered;
@@ -589,4 +581,4 @@ ${MAINTAIN_OUTPUT_INSTRUCTION}`;
589
581
  }
590
582
  }
591
583
  //#endregion
592
- export { MAINTAIN_RULE_IDS, PROBE_SIGNALS, buildEnrichment, buildMaintainFacts, computeProbe, renderFacts, renderMaintainTemplate, runMaintain, snapshotFromLibrary, validateAndNormalizeMaintainPlan };
584
+ export { MAINTAIN_RULE_IDS, PROBE_SIGNALS, buildEnrichment, buildMaintainFacts, computeProbe, enrichmentSnapshotOptions, renderFacts, renderMaintainTemplate, runMaintain, snapshotFromLibrary, validateAndNormalizeMaintainPlan };
@@ -52,6 +52,91 @@ async function snapshotFromLibrary(library, options = {}) {
52
52
  return snapshots;
53
53
  }
54
54
  //#endregion
55
+ //#region lib/types/enrichment.js
56
+ /**
57
+ * Enrichment maps shared by the full maintain scan and the `--facts` preview
58
+ * (v12) AND the maintenance_probe tool (0.3.9): one construction = the probe
59
+ * and the facts block can never disagree about descriptions, support files,
60
+ * or quality (the 0.3.8 review found the probe answering "description=missing"
61
+ * while the facts block measured real lengths — probe snapshots carried no
62
+ * enrichment at all).
63
+ */
64
+ /**
65
+ * The ONE enrichment → snapshot-options mapping (T3-02/A30).
66
+ *
67
+ * Three callers assemble drift snapshots from the same enrichment — the full scan, the
68
+ * `--facts` preview, and the `maintenance_probe` tool. Kept as one function because a hand-written
69
+ * literal per caller is a copy that drifts: the probe's literal omitted `liveness`, so the deep-dive
70
+ * channel answered `retire: no-age` ("age unknown ⇒ not enough evidence") for every skill, for ever,
71
+ * while the facts block listed retirement candidates for the same tree. Adding a measured field to
72
+ * {@link Enrichment} now reaches every surface through this mapping.
73
+ * @param enrichment - the built enrichment maps.
74
+ * @returns the snapshot options carrying every field the enrichment measured.
75
+ */
76
+ function enrichmentSnapshotOptions(enrichment) {
77
+ return {
78
+ descriptions: enrichment.descriptions,
79
+ supportFiles: enrichment.supportFiles,
80
+ quality: enrichment.quality,
81
+ protected: enrichment.protected,
82
+ catalogInvalid: enrichment.catalogInvalid,
83
+ usageObserved: enrichment.usageObservedValue,
84
+ demand: enrichment.demand,
85
+ liveness: enrichment.liveness,
86
+ supportChars: enrichment.supportChars
87
+ };
88
+ }
89
+ async function buildEnrichment(ctx, library) {
90
+ const skillUsage = ctx.get("skillUsage");
91
+ const usageMap = skillUsage?.report ? await skillUsage.report() : void 0;
92
+ const usageObservedValue = usageMap ? usageObserved(usageMap) : void 0;
93
+ const descriptions = /* @__PURE__ */ new Map();
94
+ const supportFiles = /* @__PURE__ */ new Map();
95
+ const quality = /* @__PURE__ */ new Map();
96
+ const protectedMap = /* @__PURE__ */ new Map();
97
+ const catalogInvalid = /* @__PURE__ */ new Map();
98
+ const demand = /* @__PURE__ */ new Map();
99
+ const liveness = /* @__PURE__ */ new Map();
100
+ const supportChars = /* @__PURE__ */ new Map();
101
+ const now = /* @__PURE__ */ new Date();
102
+ for (const entry of await library.list()) {
103
+ if (entry.protectionUnknown) protectedMap.set(entry.name, "unknown");
104
+ else if (entry.protectedBy) protectedMap.set(entry.name, entry.protectedBy);
105
+ let body;
106
+ try {
107
+ body = await library.read(entry.name);
108
+ } catch (error) {
109
+ ctx.logger.warn(`evolution-maintenance: enrichment skipped unreadable skill "${entry.name}": ${error instanceof Error ? error.message : String(error)}`);
110
+ continue;
111
+ }
112
+ if (typeof body !== "string") continue;
113
+ const parsed = parseFrontmatter(body);
114
+ if (frontmatterCatalogInvalid(body)) catalogInvalid.set(entry.name, true);
115
+ const description = parsed?.frontmatter.description;
116
+ if (typeof description === "string" && description.trim().length > 0) descriptions.set(entry.name, description);
117
+ const files = await library.listSupportFiles(entry.name);
118
+ if (isPresent(files) && files.value.length > 0) supportFiles.set(entry.name, files.value);
119
+ const record = usageMap?.get(entry.name);
120
+ if (typeof record?.quality_score === "number") quality.set(entry.name, record.quality_score);
121
+ const reads = record?.support_reads;
122
+ if (reads !== void 0 && Object.keys(reads).length > 0) demand.set(entry.name, reads);
123
+ if (record !== void 0) liveness.set(entry.name, { idleDays: idleDays(record, now) });
124
+ const big = await library.supportFileChars(entry.name);
125
+ if (big !== null && Object.keys(big).length > 0) supportChars.set(entry.name, big);
126
+ }
127
+ return {
128
+ descriptions,
129
+ supportFiles,
130
+ quality,
131
+ usageObservedValue,
132
+ protected: protectedMap,
133
+ catalogInvalid,
134
+ demand,
135
+ liveness,
136
+ supportChars
137
+ };
138
+ }
139
+ //#endregion
55
140
  //#region lib/types/probe.js
56
141
  /**
57
142
  * Probe detail computation (011 Phase 3).
@@ -156,64 +241,4 @@ function computeProbe(signal, target, snapshots) {
156
241
  }
157
242
  }
158
243
  //#endregion
159
- //#region lib/types/enrichment.js
160
- /**
161
- * Enrichment maps shared by the full maintain scan and the `--facts` preview
162
- * (v12) AND the maintenance_probe tool (0.3.9): one construction = the probe
163
- * and the facts block can never disagree about descriptions, support files,
164
- * or quality (the 0.3.8 review found the probe answering "description=missing"
165
- * while the facts block measured real lengths — probe snapshots carried no
166
- * enrichment at all).
167
- */
168
- async function buildEnrichment(ctx, library) {
169
- const skillUsage = ctx.get("skillUsage");
170
- const usageMap = skillUsage?.report ? await skillUsage.report() : void 0;
171
- const usageObservedValue = usageMap ? usageObserved(usageMap) : void 0;
172
- const descriptions = /* @__PURE__ */ new Map();
173
- const supportFiles = /* @__PURE__ */ new Map();
174
- const quality = /* @__PURE__ */ new Map();
175
- const protectedMap = /* @__PURE__ */ new Map();
176
- const catalogInvalid = /* @__PURE__ */ new Map();
177
- const demand = /* @__PURE__ */ new Map();
178
- const liveness = /* @__PURE__ */ new Map();
179
- const supportChars = /* @__PURE__ */ new Map();
180
- const now = /* @__PURE__ */ new Date();
181
- for (const entry of await library.list()) {
182
- if (entry.protectionUnknown) protectedMap.set(entry.name, "unknown");
183
- else if (entry.protectedBy) protectedMap.set(entry.name, entry.protectedBy);
184
- let body;
185
- try {
186
- body = await library.read(entry.name);
187
- } catch (error) {
188
- ctx.logger.warn(`evolution-maintenance: enrichment skipped unreadable skill "${entry.name}": ${error instanceof Error ? error.message : String(error)}`);
189
- continue;
190
- }
191
- if (typeof body !== "string") continue;
192
- const parsed = parseFrontmatter(body);
193
- if (frontmatterCatalogInvalid(body)) catalogInvalid.set(entry.name, true);
194
- const description = parsed?.frontmatter.description;
195
- if (typeof description === "string" && description.trim().length > 0) descriptions.set(entry.name, description);
196
- const files = await library.listSupportFiles(entry.name);
197
- if (isPresent(files) && files.value.length > 0) supportFiles.set(entry.name, files.value);
198
- const record = usageMap?.get(entry.name);
199
- if (typeof record?.quality_score === "number") quality.set(entry.name, record.quality_score);
200
- const reads = record?.support_reads;
201
- if (reads !== void 0 && Object.keys(reads).length > 0) demand.set(entry.name, reads);
202
- if (record !== void 0) liveness.set(entry.name, { idleDays: idleDays(record, now) });
203
- const big = await library.supportFileChars(entry.name);
204
- if (big !== null && Object.keys(big).length > 0) supportChars.set(entry.name, big);
205
- }
206
- return {
207
- descriptions,
208
- supportFiles,
209
- quality,
210
- usageObservedValue,
211
- protected: protectedMap,
212
- catalogInvalid,
213
- demand,
214
- liveness,
215
- supportChars
216
- };
217
- }
218
- //#endregion
219
- export { snapshotFromLibrary as i, PROBE_SIGNALS as n, computeProbe as r, buildEnrichment as t };
244
+ export { snapshotFromLibrary as a, enrichmentSnapshotOptions as i, computeProbe as n, buildEnrichment as r, PROBE_SIGNALS as t };
package/lib/tools.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as snapshotFromLibrary, n as PROBE_SIGNALS, r as computeProbe, t as buildEnrichment } from "./enrichment-CjZmhRI9.js";
1
+ import { a as snapshotFromLibrary, i as enrichmentSnapshotOptions, n as computeProbe, r as buildEnrichment, t as PROBE_SIGNALS } from "./probe-Bojb0piw.js";
2
2
  import { assertSkillsRootAliasRetired, newSkillLibrary, redactSecrets, resolveRootConfig } from "@lmzhen/dsh-evolution-core";
3
3
  import z from "@deepseek-ai/schemastery";
4
4
  import { defineTool } from "@deepseek-ai/dsh-tools";
@@ -69,16 +69,7 @@ function apply(ctx, rawConfig = {}) {
69
69
  config: rootConfig,
70
70
  io: ioRegistry.provider()
71
71
  });
72
- const enrichment = await buildEnrichment(ctx, library);
73
- const probe = computeProbe(signal, target, await snapshotFromLibrary(library, {
74
- descriptions: enrichment.descriptions,
75
- supportFiles: enrichment.supportFiles,
76
- quality: enrichment.quality,
77
- protected: enrichment.protected,
78
- catalogInvalid: enrichment.catalogInvalid,
79
- usageObserved: enrichment.usageObservedValue,
80
- demand: enrichment.demand
81
- }));
72
+ const probe = computeProbe(signal, target, await snapshotFromLibrary(library, enrichmentSnapshotOptions(await buildEnrichment(ctx, library))));
82
73
  const redacted = redactSecrets(probe.detail.join("\n"));
83
74
  return {
84
75
  ...probe,
@@ -7,6 +7,7 @@
7
7
  * enrichment at all).
8
8
  */
9
9
  import type { Context } from '@deepseek-ai/cordis';
10
+ import type { SnapshotOptions } from './drift-scan.ts';
10
11
  import { type SkillLibrary, type SkillLiveness } from '@lmzhen/dsh-evolution-core';
11
12
  export interface Enrichment {
12
13
  descriptions: ReadonlyMap<string, string>;
@@ -28,5 +29,18 @@ export interface Enrichment {
28
29
  * common measured-and-clean case adds no field. */
29
30
  supportChars: ReadonlyMap<string, Readonly<Record<string, number>>>;
30
31
  }
32
+ /**
33
+ * The ONE enrichment → snapshot-options mapping (T3-02/A30).
34
+ *
35
+ * Three callers assemble drift snapshots from the same enrichment — the full scan, the
36
+ * `--facts` preview, and the `maintenance_probe` tool. Kept as one function because a hand-written
37
+ * literal per caller is a copy that drifts: the probe's literal omitted `liveness`, so the deep-dive
38
+ * channel answered `retire: no-age` ("age unknown ⇒ not enough evidence") for every skill, for ever,
39
+ * while the facts block listed retirement candidates for the same tree. Adding a measured field to
40
+ * {@link Enrichment} now reaches every surface through this mapping.
41
+ * @param enrichment - the built enrichment maps.
42
+ * @returns the snapshot options carrying every field the enrichment measured.
43
+ */
44
+ export declare function enrichmentSnapshotOptions(enrichment: Enrichment): SnapshotOptions;
31
45
  export declare function buildEnrichment(ctx: Context, library: SkillLibrary): Promise<Enrichment>;
32
46
  //# sourceMappingURL=enrichment.d.ts.map
@@ -4,9 +4,10 @@
4
4
  * text. Deterministic parts stay pure; the subagent call is the only
5
5
  * external dependency (injected, fake-able in tests).
6
6
  */
7
- import { type DriftReport, type DriftSkillSnapshot, type SkillLiveness } from '@lmzhen/dsh-evolution-core';
7
+ import { type DriftReport, type DriftSkillSnapshot } from '@lmzhen/dsh-evolution-core';
8
8
  import type { Agent } from '@deepseek-ai/dsh-agent';
9
9
  import { type SkillLibraryLike } from './drift-scan.ts';
10
+ import { type Enrichment } from './enrichment.ts';
10
11
  /** I-5 (v37): the platform's `SubagentStartRequest` fields this orchestrator sends.
11
12
  * Typed locally (not imported) because the platform type lives behind the subagent row this
12
13
  * package does not depend on; the required `parent` and `signal` mirror the platform. */
@@ -92,18 +93,10 @@ export interface MaintainOptions {
92
93
  provider?: string;
93
94
  toolAllow?: readonly string[];
94
95
  redact?: ((text: string) => string) | undefined;
95
- supportFiles?: () => ReadonlyMap<string, readonly string[]>;
96
- descriptions?: () => ReadonlyMap<string, string>;
97
- quality?: () => ReadonlyMap<string, number>;
98
- protected?: () => ReadonlyMap<string, string>;
99
- catalogInvalid?: () => ReadonlyMap<string, boolean>;
100
- usageObserved?: () => boolean | undefined;
101
- /** Per-support-file read counts per skill (design §5.5). */
102
- demand?: () => ReadonlyMap<string, Readonly<Record<string, number>>>;
103
- /** Idle age per skill (design §5.6). */
104
- liveness?: () => ReadonlyMap<string, SkillLiveness>;
105
- /** Support-file char counts for files that can exceed the cap (design §16.6). */
106
- supportChars?: () => ReadonlyMap<string, Readonly<Record<string, number>>>;
96
+ /** T3-02/A30: the measured enrichment, read through {@link enrichmentSnapshotOptions} — one
97
+ * mapping shared with the `--facts` preview and the probe tool. A closure per field was a second
98
+ * account of the same facts and drifted (the probe's copy lost `liveness`). */
99
+ enrichment?: (() => Enrichment) | undefined;
107
100
  }
108
101
  export interface MaintainOutcome {
109
102
  ok: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-maintenance",
3
3
  "description": "Deterministic maintenance-scan surface: skill-library snapshot assembly, drift signals and mechanical-facts rendering (design 011) (community build)",
4
- "version": "0.17.0",
4
+ "version": "0.18.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,8 +30,8 @@
30
30
  ],
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-core": "^0.17.0"
33
+ "@deepseek-ai/schemastery": "^3.18.4",
34
+ "@lmzhen/dsh-evolution-core": "^0.18.0"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@deepseek-ai/dsh-agent": "^0.2.0-rc.1",