@lmzhen/dsh-evolution-maintenance 0.3.51 → 0.3.53
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/README.md +6 -2
- package/lib/{enrichment-Di8Y4kev.js → enrichment-B7tEHkM5.js} +1 -1
- package/lib/index.js +22 -8
- package/lib/tools.js +1 -1
- package/lib/types/orchestrate.d.ts +12 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -18,7 +18,11 @@ package owns assembly and rendering only.
|
|
|
18
18
|
`evolution-maintenance-tools`) is available to maintenance subagents only
|
|
19
19
|
through the orchestrate `toolFilter` allow-list; it is globally visible to
|
|
20
20
|
every session as a read-only query (same exposure tier as the `skill`
|
|
21
|
-
tool — never a write path).
|
|
22
|
-
|
|
21
|
+
tool — never a write path). V10 (F-02): orchestrate soft-probes the tools
|
|
22
|
+
registry before spawning and degrades the filter to `skill`-only (declared
|
|
23
|
+
in the subagent prompt) when the tool row is not mounted, instead of failing
|
|
24
|
+
the spawn; an explicit `toolAllow` option bypasses the probe.
|
|
25
|
+
- The model-visible template (`MAINTAIN_PROMPT`) and the subagent output
|
|
26
|
+
instruction (`MAINTAIN_OUTPUT_INSTRUCTION`, V10 F-16) ship in `evolution-core`
|
|
23
27
|
`PROMPT_BUNDLE`; the joint-signature mismatch protocol is honored by
|
|
24
28
|
`renderFacts` callers, not by this package alone.
|
|
@@ -132,7 +132,7 @@ async function buildEnrichment(ctx, library) {
|
|
|
132
132
|
for (const entry of await library.list()) {
|
|
133
133
|
if (entry.protectedBy) protectedMap.set(entry.name, entry.protectedBy);
|
|
134
134
|
const body = await library.read(entry.name);
|
|
135
|
-
if (body === null) continue;
|
|
135
|
+
if (body === void 0 || body === null) continue;
|
|
136
136
|
const parsed = parseFrontmatter(body);
|
|
137
137
|
if (frontmatterYamlUnsafeValues(body).length > 0) catalogInvalid.set(entry.name, true);
|
|
138
138
|
const description = parsed?.frontmatter.description;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as snapshotFromLibrary, n as PROBE_SIGNALS, r as computeProbe, t as buildEnrichment } from "./enrichment-
|
|
2
|
-
import { AUTHORING_DESCRIPTION_BAR, DEFAULT_HEALTH_THRESHOLDS, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, LOW_QUALITY_THRESHOLD, MAINTAIN_PROMPT, MIN_STAMP_BODY_CHARS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, computeDriftSignals, findDriftSignal, redactSecrets, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
1
|
+
import { i as snapshotFromLibrary, n as PROBE_SIGNALS, r as computeProbe, t as buildEnrichment } from "./enrichment-B7tEHkM5.js";
|
|
2
|
+
import { AUTHORING_DESCRIPTION_BAR, DEFAULT_HEALTH_THRESHOLDS, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, LOW_QUALITY_THRESHOLD, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, 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
|
|
5
5
|
/**
|
|
@@ -321,9 +321,12 @@ function buildMaintainFacts(snapshots, usageObserved, redact) {
|
|
|
321
321
|
};
|
|
322
322
|
}
|
|
323
323
|
/** V6-38 (0.3.36): a field value carrying its own standalone `Notes:` line is
|
|
324
|
-
* indistinguishable from the plan's section header in the RENDERED text
|
|
325
|
-
*
|
|
326
|
-
*
|
|
324
|
+
* indistinguishable from the plan's section header in the RENDERED text, which
|
|
325
|
+
* made the rendered plan read as if it ended early. Mark such lines so they
|
|
326
|
+
* can never read as the header. (The former text-based recommendation counter
|
|
327
|
+
* that motivated this marker is gone — V10-09/F-05 moved the count into
|
|
328
|
+
* `MaintainOutcome.recommendationCount` — but the rendered text stays
|
|
329
|
+
* unambiguous for the human reader.) */
|
|
327
330
|
function sanitizeField(value) {
|
|
328
331
|
return value.split("\n").map((line) => line === "Notes:" ? "> Notes: (inside the field above)" : line).join("\n");
|
|
329
332
|
}
|
|
@@ -361,6 +364,7 @@ async function runMaintain(runtime, options = {}) {
|
|
|
361
364
|
try {
|
|
362
365
|
if (!verifyPromptBundle(PROMPT_BUNDLE)) return {
|
|
363
366
|
ok: false,
|
|
367
|
+
recommendationCount: 0,
|
|
364
368
|
error: "dsh-evolution prompt bundle integrity check failed; refusing to run maintain"
|
|
365
369
|
};
|
|
366
370
|
const usageObserved = options.usageObserved ? options.usageObserved() : void 0;
|
|
@@ -374,18 +378,23 @@ async function runMaintain(runtime, options = {}) {
|
|
|
374
378
|
});
|
|
375
379
|
if (snapshots.length === 0) return {
|
|
376
380
|
ok: true,
|
|
381
|
+
recommendationCount: 0,
|
|
377
382
|
runId: randomUUID(),
|
|
378
383
|
verdict: "no_issues",
|
|
379
384
|
text: "Maintenance scan: empty skill library. Nothing to do."
|
|
380
385
|
};
|
|
381
386
|
const { facts, report, signalsVersion, signature } = buildMaintainFacts(snapshots, usageObserved, options.redact);
|
|
382
387
|
const template = renderMaintainTemplate(MAINTAIN_PROMPT, PROMPT_BUNDLE_ID, signalsVersion, signature);
|
|
383
|
-
const
|
|
388
|
+
const probeRegistered = runtime.tools?.get("maintenance_probe") != null;
|
|
389
|
+
const probeDegraded = options.toolAllow === void 0 && !probeRegistered;
|
|
390
|
+
const toolAllow = options.toolAllow ?? (probeRegistered ? ["skill", "maintenance_probe"] : ["skill"]);
|
|
391
|
+
const prompt = `${facts}${probeDegraded ? "\n\n[tools] maintenance_probe is not registered in this session — the scan degrades to the `skill` tool only; the facts block above remains the complete evidence base. Do not call maintenance_probe." : ""}
|
|
384
392
|
|
|
385
|
-
|
|
393
|
+
${MAINTAIN_OUTPUT_INSTRUCTION}`;
|
|
386
394
|
const timeoutMs = options.timeoutMs ?? 6e5;
|
|
387
395
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 4294967295) return {
|
|
388
396
|
ok: false,
|
|
397
|
+
recommendationCount: 0,
|
|
389
398
|
error: `maintain: --timeout must be a positive integer in ms, at most 4294967295; got ${String(timeoutMs)}`
|
|
390
399
|
};
|
|
391
400
|
const signal = AbortSignal.timeout(timeoutMs);
|
|
@@ -403,7 +412,7 @@ async function runMaintain(runtime, options = {}) {
|
|
|
403
412
|
maxDepth: typeof options.maxDepth === "number" && Number.isFinite(options.maxDepth) && options.maxDepth >= 1 ? options.maxDepth : 1,
|
|
404
413
|
agentOptions,
|
|
405
414
|
persona: template,
|
|
406
|
-
toolFilter: { allow: [...
|
|
415
|
+
toolFilter: { allow: [...toolAllow] },
|
|
407
416
|
outputSchema: {
|
|
408
417
|
type: "object",
|
|
409
418
|
additionalProperties: false,
|
|
@@ -481,16 +490,19 @@ async function runMaintain(runtime, options = {}) {
|
|
|
481
490
|
if (raw === void 0) {
|
|
482
491
|
if (runResult?.stopReason === "aborted") return {
|
|
483
492
|
ok: false,
|
|
493
|
+
recommendationCount: 0,
|
|
484
494
|
error: "Maintenance scan was aborted (the run was cancelled before the subagent produced a plan) — retry when the session is idle; concurrent re-submission cancels the previous scan."
|
|
485
495
|
};
|
|
486
496
|
return {
|
|
487
497
|
ok: false,
|
|
498
|
+
recommendationCount: 0,
|
|
488
499
|
error: "Maintain subagent returned no structured plan (the model did not emit the structured plan, or the run ended without one) — retry; if it repeats, raise --timeout or check the model output shape."
|
|
489
500
|
};
|
|
490
501
|
}
|
|
491
502
|
const validated = validateAndNormalizeMaintainPlan(raw, report, existingSignalIds(report));
|
|
492
503
|
if (!validated.ok) return {
|
|
493
504
|
ok: false,
|
|
505
|
+
recommendationCount: 0,
|
|
494
506
|
error: `Maintain plan rejected by validator: ${validated.errors.slice(0, 5).join("; ")}`
|
|
495
507
|
};
|
|
496
508
|
const runId = randomUUID();
|
|
@@ -499,6 +511,7 @@ async function runMaintain(runtime, options = {}) {
|
|
|
499
511
|
runId,
|
|
500
512
|
verdict: validated.plan.verdict,
|
|
501
513
|
forcedHuman: validated.forcedHuman,
|
|
514
|
+
recommendationCount: validated.plan.plan.length,
|
|
502
515
|
text: formatPlan(validated, runId)
|
|
503
516
|
};
|
|
504
517
|
} finally {
|
|
@@ -513,6 +526,7 @@ async function runMaintain(runtime, options = {}) {
|
|
|
513
526
|
const message = error instanceof Error ? error.message : String(error);
|
|
514
527
|
return {
|
|
515
528
|
ok: false,
|
|
529
|
+
recommendationCount: 0,
|
|
516
530
|
error: abortSignal?.aborted === true || name === "AbortError" || message === "This operation was aborted" ? "Maintenance scan was aborted (cancellation or timeout) before a plan was produced — retry, or raise the timeout (evolution-commands maintainTimeoutMs) on a slow/large library." : `Maintenance scan failed: ${message}`
|
|
517
531
|
};
|
|
518
532
|
}
|
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-
|
|
1
|
+
import { i as snapshotFromLibrary, n as PROBE_SIGNALS, r as computeProbe, t as buildEnrichment } from "./enrichment-B7tEHkM5.js";
|
|
2
2
|
import { SkillLibrary, redactSecrets, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
|
|
3
3
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
4
4
|
//#region lib/types/tools.js
|
|
@@ -34,6 +34,13 @@ export interface MaintainRuntime {
|
|
|
34
34
|
curatorModel?: string | undefined;
|
|
35
35
|
} | undefined;
|
|
36
36
|
} | undefined;
|
|
37
|
+
/** F-02: tools-registry soft probe, wired from the host context
|
|
38
|
+
* (`ctx.get('tools')`) with the platform's `get(name)` accessor shape.
|
|
39
|
+
* Optional — an absent accessor means the tools service is not mounted at
|
|
40
|
+
* all, so no tool beyond `skill` can be assumed registered. */
|
|
41
|
+
tools?: {
|
|
42
|
+
get(name: string): unknown;
|
|
43
|
+
} | undefined;
|
|
37
44
|
}
|
|
38
45
|
export interface MaintainOptions {
|
|
39
46
|
timeoutMs?: number;
|
|
@@ -56,6 +63,11 @@ export interface MaintainOutcome {
|
|
|
56
63
|
verdict?: 'issues' | 'no_issues' | undefined;
|
|
57
64
|
text?: string | undefined;
|
|
58
65
|
forcedHuman?: string[] | undefined;
|
|
66
|
+
/** V10-09 (F-05): structured count of recommendations in the VALIDATED plan
|
|
67
|
+
* (plan entries, never notes). Consumers must read this field instead of
|
|
68
|
+
* parsing the rendered `text` — the text is display-only. 0 on every
|
|
69
|
+
* non-success outcome. */
|
|
70
|
+
recommendationCount: number;
|
|
59
71
|
}
|
|
60
72
|
/** Render template-M placeholders from the signal vocabulary (011 single-source rule). */
|
|
61
73
|
export declare function renderMaintainTemplate(template: string, bundleVersion: string, signalsVersion: string, signature: string): string;
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.3.
|
|
4
|
+
"version": "0.3.53",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/lmzhen/dsh-evolution.git",
|
|
11
|
-
"directory": "packages/
|
|
11
|
+
"directory": "packages/evolution-maintenance"
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "lib/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
37
|
+
"@lmzhen/dsh-evolution-core": "^0.3.53"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|