@lmzhen/dsh-evolution-core 0.3.17 → 0.3.18
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 +32 -2
- package/lib/types/events.d.ts +12 -0
- package/lib/types/io.d.ts +8 -0
- package/lib/types/skill-health.d.ts +7 -0
- package/lib/types/skill-store.d.ts +11 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -45,6 +45,10 @@ function evolutionIoAdapter(provider) {
|
|
|
45
45
|
isSymlink: (path) => {
|
|
46
46
|
const io = provider();
|
|
47
47
|
return io.isSymlink ? io.isSymlink(path) : Promise.resolve(null);
|
|
48
|
+
},
|
|
49
|
+
mtime: (path) => {
|
|
50
|
+
const io = provider();
|
|
51
|
+
return io.mtime ? io.mtime(path) : Promise.resolve(null);
|
|
48
52
|
}
|
|
49
53
|
};
|
|
50
54
|
}
|
|
@@ -226,6 +230,14 @@ function nodeEvolutionIo() {
|
|
|
226
230
|
} catch {
|
|
227
231
|
return null;
|
|
228
232
|
}
|
|
233
|
+
},
|
|
234
|
+
async mtime(path) {
|
|
235
|
+
try {
|
|
236
|
+
return (await stat(path)).mtimeMs;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (isMissing(error)) return null;
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
229
241
|
}
|
|
230
242
|
};
|
|
231
243
|
}
|
|
@@ -2469,7 +2481,7 @@ function assessStructureHealth(snapshot, thresholds = DEFAULT_HEALTH_THRESHOLDS)
|
|
|
2469
2481
|
const needs = snapshot.bodyChars >= thresholds.softBodyChars * 2;
|
|
2470
2482
|
if (needs) reasons.push(`body ${snapshot.bodyChars} chars is >= 2x the soft limit (${thresholds.softBodyChars}) — consider splitting or offloading`);
|
|
2471
2483
|
else if (snapshot.bodyChars >= thresholds.softBodyChars) reasons.push(`body ${snapshot.bodyChars} chars above the soft limit (${thresholds.softBodyChars})`);
|
|
2472
|
-
if (snapshot.bodyText && snapshot.bodyChars >=
|
|
2484
|
+
if (snapshot.bodyText && snapshot.bodyChars >= 2e3) {
|
|
2473
2485
|
const kb = Math.max(1, snapshot.bodyChars / 1024);
|
|
2474
2486
|
dims.stampDensityPerKb = (snapshot.bodyText.match(HEALTH_STAMP_RE) ?? []).length / kb;
|
|
2475
2487
|
if (dims.stampDensityPerKb >= thresholds.stampDensityPerKb) reasons.push(`stamp density ${dims.stampDensityPerKb.toFixed(1)}/KB (rc/sha/date lines — log-like content in the body)`);
|
|
@@ -2752,6 +2764,14 @@ const SNAPSHOT_EXTRA_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
|
2752
2764
|
function skillsRoot(env = process.env) {
|
|
2753
2765
|
return join(env.DSH_HOME || join(homedir(), ".dsh"), "skills");
|
|
2754
2766
|
}
|
|
2767
|
+
/** 0.3.18 (S4.1, E-30): the ONE root resolution for every member that reads
|
|
2768
|
+
* the skills tree — tool-skill-manage / evolution-skill-catalog / skill-usage
|
|
2769
|
+
* / evolution-learning-graph used to each resolve `config.root || skillsRoot()`
|
|
2770
|
+
* (and the graph ignored config entirely). Empty/whitespace config falls
|
|
2771
|
+
* through to the default; callers pass their raw Config. */
|
|
2772
|
+
function resolveSkillsRoot(config = {}) {
|
|
2773
|
+
return (config.root ?? "").trim() || skillsRoot();
|
|
2774
|
+
}
|
|
2755
2775
|
/**
|
|
2756
2776
|
* Map a requesting session onto the two origin surfaces (rc.44 plan M2-2.3):
|
|
2757
2777
|
* the APPROVAL surface treats every delegated subagent as the autonomous
|
|
@@ -3580,6 +3600,12 @@ var SkillLibrary = class {
|
|
|
3580
3600
|
ok: false,
|
|
3581
3601
|
message: threat
|
|
3582
3602
|
};
|
|
3603
|
+
if (writeContent.trimEnd() + "\n" === md) return {
|
|
3604
|
+
ok: true,
|
|
3605
|
+
message: `Skill "${name}" unchanged: old_string already equals the replacement (${patchLabel}); nothing written.`,
|
|
3606
|
+
noop: true,
|
|
3607
|
+
path: dir
|
|
3608
|
+
};
|
|
3583
3609
|
await this.io.writeText(target, writeContent.trimEnd() + "\n");
|
|
3584
3610
|
await this.audit(name, "patch", md, writeContent, `patched ${patchLabel}`);
|
|
3585
3611
|
this.notifyMutation({
|
|
@@ -3613,6 +3639,10 @@ var SkillLibrary = class {
|
|
|
3613
3639
|
message: `Skill "${name}" is protected (${protection}).`
|
|
3614
3640
|
};
|
|
3615
3641
|
if (options.absorbedInto) {
|
|
3642
|
+
if (options.absorbedInto.trim() === name) return {
|
|
3643
|
+
ok: false,
|
|
3644
|
+
message: "absorbed_into cannot be the skill being archived (cannot absorb into itself)."
|
|
3645
|
+
};
|
|
3616
3646
|
if (!await this.io.readText(join(this.dirOf(options.absorbedInto), "SKILL.md"))) return {
|
|
3617
3647
|
ok: false,
|
|
3618
3648
|
message: `absorbed_into="${options.absorbedInto}" does not exist.`
|
|
@@ -4370,4 +4400,4 @@ function evolutionHome(env = process.env) {
|
|
|
4370
4400
|
return join(env.DSH_HOME || join(homedir(), ".dsh"), "evolution");
|
|
4371
4401
|
}
|
|
4372
4402
|
//#endregion
|
|
4373
|
-
export { AUTHORING_DESCRIPTION_BAR, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, LOW_QUALITY_THRESHOLD, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MEMORY_REVIEW_PROMPT, MUTATIONS_FILE_VERSION, MemoryStore, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, QUALITY_WEIGHTS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, advanceReview, appendEvolutionEvent, applyCuratorFields, applyCuratorLifecycleFields, applyCuratorMetaFields, assessStructureHealth, authoringFeedback, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpUse, bumpView, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, createGateSet, duplicateHeadings, emptyRecord, evaluateThreat, eventsFile, evolutionHome, evolutionIoAdapter, findDriftSignal, foldCuratorFields, foldTurn, frontmatterBlock, frontmatterYamlUnsafeValues, getRecord, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadSuppressedNames, loadUsage, makeSerialQueue, markAgentCreated, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, readEvolutionEvents, readEvolutionTimeline, recordMutation, redactSecrets, relatedSkillNames, renderCuratorReportMarkdown, resolveOrigins, retainEventArchives, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, transactIo, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, verifyPromptBundle, yamlPlainScalarNeedsQuotes };
|
|
4403
|
+
export { AUTHORING_DESCRIPTION_BAR, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, LOW_QUALITY_THRESHOLD, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, QUALITY_WEIGHTS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, advanceReview, appendEvolutionEvent, applyCuratorFields, applyCuratorLifecycleFields, applyCuratorMetaFields, assessStructureHealth, authoringFeedback, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpUse, bumpView, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, createGateSet, duplicateHeadings, emptyRecord, evaluateThreat, eventsFile, evolutionHome, evolutionIoAdapter, findDriftSignal, foldCuratorFields, foldTurn, frontmatterBlock, frontmatterYamlUnsafeValues, getRecord, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadSuppressedNames, loadUsage, makeSerialQueue, markAgentCreated, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, readEvolutionEvents, readEvolutionTimeline, recordMutation, redactSecrets, relatedSkillNames, renderCuratorReportMarkdown, resolveOrigins, resolveSkillsRoot, retainEventArchives, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, transactIo, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, verifyPromptBundle, yamlPlainScalarNeedsQuotes };
|
package/lib/types/events.d.ts
CHANGED
|
@@ -42,11 +42,23 @@ export interface EvolutionSkillMutatedEvent {
|
|
|
42
42
|
file?: string;
|
|
43
43
|
archivedPath?: string;
|
|
44
44
|
}
|
|
45
|
+
/** 0.3.18 (E-6): a turn-end review pipeline failure was caught (never an
|
|
46
|
+
* unhandled rejection); this event lets operators/observability see it. The
|
|
47
|
+
* reason is already logged by the emitter — the event is a timestamped signal. */
|
|
48
|
+
export interface EvolutionReviewErrorEvent {
|
|
49
|
+
sessionId: string;
|
|
50
|
+
}
|
|
45
51
|
declare module '@deepseek-ai/cordis' {
|
|
46
52
|
interface Events {
|
|
47
53
|
'evolution/review-scheduled'(event: EvolutionReviewScheduledEvent): void;
|
|
48
54
|
'evolution/plan-applied'(event: EvolutionPlanAppliedEvent): void;
|
|
49
55
|
'evolution/skill-mutated'(event: EvolutionSkillMutatedEvent): void;
|
|
56
|
+
/** 0.3.18 (E-71): explicit catalog refresh request (`/evolution skills
|
|
57
|
+
* refresh`). Out-of-band tree edits (manual, git) may bypass the mutation
|
|
58
|
+
* event; listeners drop caches and invalidate downstream catalogs. No
|
|
59
|
+
* payload — it is a bare "re-read" signal, never a mutation record. */
|
|
60
|
+
'evolution/skills-refresh'(): void;
|
|
61
|
+
'evolution/review-error'(event: EvolutionReviewErrorEvent): void;
|
|
50
62
|
}
|
|
51
63
|
}
|
|
52
64
|
//# sourceMappingURL=events.d.ts.map
|
package/lib/types/io.d.ts
CHANGED
|
@@ -36,6 +36,14 @@ export interface EvolutionIoLike {
|
|
|
36
36
|
* the path does not exist). Consumers treat `null` as "let it through".
|
|
37
37
|
*/
|
|
38
38
|
isSymlink?(this: void, path: string): Promise<boolean | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Optional mtime-generation probe (0.3.18, E-71): the path's mtime in
|
|
41
|
+
* milliseconds since epoch, or `null` when unknown (unsupported backend,
|
|
42
|
+
* missing path, stat failure). Consumers use it as a cheap invalidation
|
|
43
|
+
* stamp for a cached directory listing; a backend without it keeps
|
|
44
|
+
* event-driven invalidation only.
|
|
45
|
+
*/
|
|
46
|
+
mtime?(this: void, path: string): Promise<number | null>;
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* Run `task` inside `io.transact` when the backend provides it; otherwise fall
|
|
@@ -24,6 +24,13 @@ export interface SkillHealthThresholds {
|
|
|
24
24
|
export declare const DEFAULT_HEALTH_THRESHOLDS: SkillHealthThresholds;
|
|
25
25
|
/** Stamp regex shared by health assessment and the maintenance probe (single source, 011). */
|
|
26
26
|
export declare const HEALTH_STAMP_RE: RegExp;
|
|
27
|
+
/**
|
|
28
|
+
* Bodies below this size skip stamp-density assessment: a few dates or shas
|
|
29
|
+
* in a short body are ordinary documentation, not log-like content. With the
|
|
30
|
+
* 1KB density floor a 3-date sentence in a small skill measured 3.0/KB and
|
|
31
|
+
* warned on a perfectly healthy body (audit 2026-08-31 X1).
|
|
32
|
+
*/
|
|
33
|
+
export declare const MIN_STAMP_BODY_CHARS = 2000;
|
|
27
34
|
export type SkillHealthVerdict = 'healthy' | 'warn' | 'needs-restructure';
|
|
28
35
|
/** Facts a caller already has; assessors never do IO. */
|
|
29
36
|
export interface SkillHealthSnapshot {
|
|
@@ -32,6 +32,9 @@ export interface SkillActionResult {
|
|
|
32
32
|
/** Frontmatter keys auto-quoted for catalog-loadable YAML (0.3.11) — set
|
|
33
33
|
* only when the write path modified the block. */
|
|
34
34
|
normalizedFrontmatterFields?: string[];
|
|
35
|
+
/** 0.3.18 (E-68): patch produced byte-identical content (old===new) — no
|
|
36
|
+
* write, no audit, no mutation event; callers must not count a patch. */
|
|
37
|
+
noop?: boolean;
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* One section move of a restructure proposal (008 batch B): a body section
|
|
@@ -81,6 +84,14 @@ export interface ArchiveOptions {
|
|
|
81
84
|
allowBundled?: boolean;
|
|
82
85
|
}
|
|
83
86
|
export declare function skillsRoot(env?: NodeJS.ProcessEnv): string;
|
|
87
|
+
/** 0.3.18 (S4.1, E-30): the ONE root resolution for every member that reads
|
|
88
|
+
* the skills tree — tool-skill-manage / evolution-skill-catalog / skill-usage
|
|
89
|
+
* / evolution-learning-graph used to each resolve `config.root || skillsRoot()`
|
|
90
|
+
* (and the graph ignored config entirely). Empty/whitespace config falls
|
|
91
|
+
* through to the default; callers pass their raw Config. */
|
|
92
|
+
export declare function resolveSkillsRoot(config?: {
|
|
93
|
+
root?: string;
|
|
94
|
+
}): string;
|
|
84
95
|
/**
|
|
85
96
|
* Map a requesting session onto the two origin surfaces (rc.44 plan M2-2.3):
|
|
86
97
|
* the APPROVAL surface treats every delegated subagent as the autonomous
|
package/package.json
CHANGED