@lmzhen/dsh-evolution-core 0.1.0-rc.25 → 0.1.0-rc.27
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 +94 -9
- package/lib/types/curator.d.ts +23 -1
- package/lib/types/prompts.d.ts +1 -1
- package/lib/types/skill-store.d.ts +9 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -308,6 +308,50 @@ function parseCuratorNominations(text) {
|
|
|
308
308
|
consolidations: consolidations.filter((item) => valid(item.from) && valid(item.into))
|
|
309
309
|
};
|
|
310
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* The lifecycle-candidate gate, shared by the transition engine and the scope
|
|
313
|
+
* view so the two can never disagree: records failing ANY of these gates are
|
|
314
|
+
* outside the managed scope.
|
|
315
|
+
*/
|
|
316
|
+
function lifecycleCandidate(name, record, config, bundled) {
|
|
317
|
+
if (record.pinned) return false;
|
|
318
|
+
if (config.excludeSkillNames?.has(name)) return false;
|
|
319
|
+
if (config.suppressedNames?.has(name)) return false;
|
|
320
|
+
if (config.referencedSkillNames?.has(name)) return false;
|
|
321
|
+
if (!(record.created_by === "agent" || config.manageUnmanaged === true) && !(config.pruneBuiltins === true && bundled)) return false;
|
|
322
|
+
if (PROTECTED_BUILTIN_SKILLS.has(name)) return false;
|
|
323
|
+
if (record.state === "archived") return false;
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Read-only scope classification, derived from the SAME gate the transition
|
|
328
|
+
* engine uses (`lifecycleCandidate`), so the view always predicts what a
|
|
329
|
+
* curator pass may touch.
|
|
330
|
+
*/
|
|
331
|
+
function computeScopeView(usage, config) {
|
|
332
|
+
const managed = [];
|
|
333
|
+
const watched = [];
|
|
334
|
+
const exempted = [];
|
|
335
|
+
const protectedNames = [];
|
|
336
|
+
for (const [name, record] of usage) {
|
|
337
|
+
if (config.excludeSkillNames?.has(name) || config.referencedSkillNames?.has(name)) {
|
|
338
|
+
exempted.push(name);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const bundled = config.bundledNames?.has(name) === true;
|
|
342
|
+
if (record.pinned || bundled || config.suppressedNames?.has(name) === true) protectedNames.push(name);
|
|
343
|
+
if (lifecycleCandidate(name, record, config, bundled)) {
|
|
344
|
+
managed.push(name);
|
|
345
|
+
if (record.state === "stale" || record.quality_warn === true) watched.push(name);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
managed: managed.sort(),
|
|
350
|
+
watched: watched.sort(),
|
|
351
|
+
exempted: exempted.sort(),
|
|
352
|
+
protected: protectedNames.sort()
|
|
353
|
+
};
|
|
354
|
+
}
|
|
311
355
|
function daysSince(iso, created, now) {
|
|
312
356
|
return (now - new Date(iso ?? created).getTime()) / 864e5;
|
|
313
357
|
}
|
|
@@ -319,14 +363,7 @@ function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Da
|
|
|
319
363
|
markStale: []
|
|
320
364
|
};
|
|
321
365
|
for (const [name, record] of usage) {
|
|
322
|
-
if (record.
|
|
323
|
-
if (config.excludeSkillNames?.has(name)) continue;
|
|
324
|
-
if (config.suppressedNames?.has(name)) continue;
|
|
325
|
-
if (config.referencedSkillNames?.has(name)) continue;
|
|
326
|
-
const bundled = config.bundledNames?.has(name) === true;
|
|
327
|
-
if (!(record.created_by === "agent" || config.manageUnmanaged === true) && !(config.pruneBuiltins === true && bundled)) continue;
|
|
328
|
-
if (PROTECTED_BUILTIN_SKILLS.has(name)) continue;
|
|
329
|
-
if (record.state === "archived") continue;
|
|
366
|
+
if (!lifecycleCandidate(name, record, config, config.bundledNames?.has(name) === true)) continue;
|
|
330
367
|
const age = daysSince(null, record.created_at, now.getTime());
|
|
331
368
|
if (record.use_count === 0 && age < config.staleAfterDays) continue;
|
|
332
369
|
const idle = daysSince(latestActivityAt(record), record.created_at, now.getTime());
|
|
@@ -533,6 +570,7 @@ Frontmatter:
|
|
|
533
570
|
- author: always the literal value "Hermes". NEVER fill it from the environment, git config, or any identity you can probe.
|
|
534
571
|
- platforms: declare [macos], [linux], and/or [windows] only when the skill is genuinely OS-bound; omit for portable skills.
|
|
535
572
|
- metadata.hermes.tags: a few Capitalized, Relevant, Tags.
|
|
573
|
+
- metadata.hermes.related_skills: [a, b] — name sibling skills this one builds on or is referenced by (optional; feeds the quality references factor).
|
|
536
574
|
|
|
537
575
|
Body section order (omit only when empty):
|
|
538
576
|
1. "# <Human Title>" then a 2-3 sentence intro: what it does, what it does NOT do, key dependency stance.
|
|
@@ -1685,6 +1723,11 @@ var SkillLibrary = class {
|
|
|
1685
1723
|
const dir = skillDir(this.root, name);
|
|
1686
1724
|
return await this.io.exists(markerPath(dir, "bundled"));
|
|
1687
1725
|
}
|
|
1726
|
+
/** Whether the skill carries the pinned marker (the marker is the factual source; usage.pinned mirrors it). */
|
|
1727
|
+
async isPinned(name) {
|
|
1728
|
+
const dir = skillDir(this.root, name);
|
|
1729
|
+
return await this.io.exists(markerPath(dir, "pinned"));
|
|
1730
|
+
}
|
|
1688
1731
|
/** Count non-empty support subdirectories (richness input for quality scoring). */
|
|
1689
1732
|
async countSupportDirs(name) {
|
|
1690
1733
|
const dir = skillDir(this.root, name);
|
|
@@ -1720,6 +1763,48 @@ var SkillLibrary = class {
|
|
|
1720
1763
|
async listMutations() {
|
|
1721
1764
|
return await loadMutations(this.root, this.io);
|
|
1722
1765
|
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Pin or unpin a skill (`.pinned` marker). Pinned skills are protected from
|
|
1768
|
+
* deletion, from background-review writes, and from the lifecycle — a
|
|
1769
|
+
* protective mutation, so the autonomous pipeline may never call it. The
|
|
1770
|
+
* marker write is the only state change; content is untouched.
|
|
1771
|
+
*/
|
|
1772
|
+
async setPinned(name, pinned, origin = "foreground") {
|
|
1773
|
+
const normalized = name.trim();
|
|
1774
|
+
if (!SKILL_NAME_RE.test(normalized) || normalized.length > this.limits.maxNameLength) return {
|
|
1775
|
+
ok: false,
|
|
1776
|
+
message: `Invalid skill name "${normalized}". Use lowercase letters, digits, and hyphens (<= ${this.limits.maxNameLength}).`
|
|
1777
|
+
};
|
|
1778
|
+
if (origin === "background_review") return {
|
|
1779
|
+
ok: false,
|
|
1780
|
+
message: "Only the foreground (user or the main agent) may pin or unpin skills."
|
|
1781
|
+
};
|
|
1782
|
+
const dir = skillDir(this.root, normalized);
|
|
1783
|
+
const marker = markerPath(dir, "pinned");
|
|
1784
|
+
const existing = await this.io.exists(marker);
|
|
1785
|
+
if (pinned && existing) return {
|
|
1786
|
+
ok: true,
|
|
1787
|
+
message: `Skill "${normalized}" is already pinned.`,
|
|
1788
|
+
path: dir
|
|
1789
|
+
};
|
|
1790
|
+
if (!pinned && !existing) return {
|
|
1791
|
+
ok: true,
|
|
1792
|
+
message: `Skill "${normalized}" is not pinned; nothing to do.`,
|
|
1793
|
+
path: dir
|
|
1794
|
+
};
|
|
1795
|
+
if (!await this.io.exists(join(dir, "SKILL.md"))) return {
|
|
1796
|
+
ok: false,
|
|
1797
|
+
message: `Skill "${normalized}" not found.`
|
|
1798
|
+
};
|
|
1799
|
+
if (pinned) await this.io.writeText(marker, "");
|
|
1800
|
+
else await this.io.remove(marker);
|
|
1801
|
+
await this.audit(normalized, pinned ? "pin" : "unpin", null, null, pinned ? "pinned" : "unpinned");
|
|
1802
|
+
return {
|
|
1803
|
+
ok: true,
|
|
1804
|
+
message: pinned ? `Skill "${normalized}" pinned: protected from deletion, background review, and the lifecycle.` : `Skill "${normalized}" unpinned.`,
|
|
1805
|
+
path: dir
|
|
1806
|
+
};
|
|
1807
|
+
}
|
|
1723
1808
|
async create(name, content, origin) {
|
|
1724
1809
|
const normalized = name.trim();
|
|
1725
1810
|
if (!SKILL_NAME_RE.test(normalized) || normalized.length > this.limits.maxNameLength) return {
|
|
@@ -2185,4 +2270,4 @@ var JsonState = class JsonState {
|
|
|
2185
2270
|
}
|
|
2186
2271
|
};
|
|
2187
2272
|
//#endregion
|
|
2188
|
-
export { COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_INTERVAL_HOURS, 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, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, JsonState, LOW_QUALITY_THRESHOLD, MAX_DESCRIPTION_LENGTH, 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, SKILL_NAME_RE, SKILL_REVIEW_PROMPT, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, advanceReview, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpUse, bumpView, computeDedupGroups, computeLifecycleTransitions, computeQualityScores, contentHash, emptyRecord, evaluateThreat, evolutionHome, evolutionIoAdapter, foldTurn, getRecord, latestActivityAt, loadMutations, loadSuppressedNames, loadUsage, markAgentCreated, memoryRoot, mutationsFile, nodeEvolutionIo, observeEvent, parseCuratorNominations, parseFrontmatter, recordMutation, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, usageFile, validateFrontmatter, verifyPromptBundle };
|
|
2273
|
+
export { COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_INTERVAL_HOURS, 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, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, JsonState, LOW_QUALITY_THRESHOLD, MAX_DESCRIPTION_LENGTH, 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, SKILL_NAME_RE, SKILL_REVIEW_PROMPT, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, advanceReview, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpUse, bumpView, computeDedupGroups, computeLifecycleTransitions, computeQualityScores, computeScopeView, contentHash, emptyRecord, evaluateThreat, evolutionHome, evolutionIoAdapter, foldTurn, getRecord, latestActivityAt, lifecycleCandidate, loadMutations, loadSuppressedNames, loadUsage, markAgentCreated, memoryRoot, mutationsFile, nodeEvolutionIo, observeEvent, parseCuratorNominations, parseFrontmatter, recordMutation, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, usageFile, validateFrontmatter, verifyPromptBundle };
|
package/lib/types/curator.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Deterministic skill curator: active → stale → archived transitions.
|
|
3
3
|
* Pure function; file moves are performed by SkillLibrary.
|
|
4
4
|
*/
|
|
5
|
-
import type { UsageMap } from './usage.ts';
|
|
5
|
+
import type { UsageMap, UsageRecord } from './usage.ts';
|
|
6
6
|
export { PROTECTED_BUILTIN_SKILLS } from './constants.ts';
|
|
7
7
|
export interface CuratorConfig {
|
|
8
8
|
staleAfterDays: number;
|
|
@@ -87,5 +87,27 @@ export interface CuratorNominations {
|
|
|
87
87
|
* is re-validated against the tree before any file move happens downstream.
|
|
88
88
|
*/
|
|
89
89
|
export declare function parseCuratorNominations(text: string): CuratorNominations;
|
|
90
|
+
/**
|
|
91
|
+
* The lifecycle-candidate gate, shared by the transition engine and the scope
|
|
92
|
+
* view so the two can never disagree: records failing ANY of these gates are
|
|
93
|
+
* outside the managed scope.
|
|
94
|
+
*/
|
|
95
|
+
export declare function lifecycleCandidate(name: string, record: UsageRecord, config: CuratorConfig, bundled: boolean): boolean;
|
|
96
|
+
export interface ScopeView {
|
|
97
|
+
/** Skills inside the lifecycle scope right now (candidate gate + active state). */
|
|
98
|
+
managed: string[];
|
|
99
|
+
/** Managed skills already flagged stale or quality-warned — the ones to watch. */
|
|
100
|
+
watched: string[];
|
|
101
|
+
/** Explicitly exempted by excludeSkillNames / referencedSkillNames. */
|
|
102
|
+
exempted: string[];
|
|
103
|
+
/** Carrying a protection marker (pinned / bundled / hub-installed). */
|
|
104
|
+
protected: string[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Read-only scope classification, derived from the SAME gate the transition
|
|
108
|
+
* engine uses (`lifecycleCandidate`), so the view always predicts what a
|
|
109
|
+
* curator pass may touch.
|
|
110
|
+
*/
|
|
111
|
+
export declare function computeScopeView(usage: UsageMap, config: CuratorConfig): ScopeView;
|
|
90
112
|
export declare function computeLifecycleTransitions(usage: UsageMap, config: CuratorConfig, now?: Date): CuratorResult;
|
|
91
113
|
//# sourceMappingURL=curator.d.ts.map
|
package/lib/types/prompts.d.ts
CHANGED
|
@@ -20,5 +20,5 @@ export interface PromptBundle {
|
|
|
20
20
|
}
|
|
21
21
|
export declare const PROMPT_BUNDLE: PromptBundle;
|
|
22
22
|
export declare function verifyPromptBundle(bundle?: PromptBundle): boolean;
|
|
23
|
-
export declare const DSH_AUTHORING_STANDARDS = "Follow the Hermes skill-authoring standards, translated to DSH tools.\n\nFrontmatter:\n- name: lowercase-hyphenated, <=64 chars, no spaces.\n- description: ONE sentence, <=60 characters, ends with a period. State the capability, not the implementation. No marketing words. Do NOT repeat the skill name. Count the characters before saving.\n- version: 0.1.0\n- author: always the literal value \"Hermes\". NEVER fill it from the environment, git config, or any identity you can probe.\n- platforms: declare [macos], [linux], and/or [windows] only when the skill is genuinely OS-bound; omit for portable skills.\n- metadata.hermes.tags: a few Capitalized, Relevant, Tags.\n\nBody section order (omit only when empty):\n1. \"# <Human Title>\" then a 2-3 sentence intro: what it does, what it does NOT do, key dependency stance.\n2. \"## When to Use\" \u2014 concrete trigger phrases.\n3. \"## Prerequisites\" \u2014 exact env vars, install steps, credentials.\n4. \"## How to Run\" \u2014 canonical invocation framed through DSH tools.\n5. \"## Quick Reference\" \u2014 flat command/endpoint list.\n6. \"## Procedure\" \u2014 numbered steps with copy-paste-exact commands.\n7. \"## Pitfalls\" \u2014 known limits and rate limits.\n8. \"## Verification\" \u2014 one check proving the skill worked.\n\nDSH-tool framing:\n- Reference DSH tools by name in backticks: `bash`, `str_replace_editor`, `write`, `skill`, `skill_manage`, `memory`.\n- Do not name wrapped shell utilities when a DSH tool already covers them.\n- Larger scripts belong under `scripts/` (written with `skill_manage write_file`) and are referenced from SKILL.md by relative path.\n\nQuality bar:\n- Prefer verbatim flags, paths, and APIs from the source. Never invent them.\n- Keep it tight: ~100 lines simple, ~200 complex.\n- No router/index/hub skills that only point at other skills.\n- References go in `references/`, templates in `templates/`.";
|
|
23
|
+
export declare const DSH_AUTHORING_STANDARDS = "Follow the Hermes skill-authoring standards, translated to DSH tools.\n\nFrontmatter:\n- name: lowercase-hyphenated, <=64 chars, no spaces.\n- description: ONE sentence, <=60 characters, ends with a period. State the capability, not the implementation. No marketing words. Do NOT repeat the skill name. Count the characters before saving.\n- version: 0.1.0\n- author: always the literal value \"Hermes\". NEVER fill it from the environment, git config, or any identity you can probe.\n- platforms: declare [macos], [linux], and/or [windows] only when the skill is genuinely OS-bound; omit for portable skills.\n- metadata.hermes.tags: a few Capitalized, Relevant, Tags.\n- metadata.hermes.related_skills: [a, b] \u2014 name sibling skills this one builds on or is referenced by (optional; feeds the quality references factor).\n\nBody section order (omit only when empty):\n1. \"# <Human Title>\" then a 2-3 sentence intro: what it does, what it does NOT do, key dependency stance.\n2. \"## When to Use\" \u2014 concrete trigger phrases.\n3. \"## Prerequisites\" \u2014 exact env vars, install steps, credentials.\n4. \"## How to Run\" \u2014 canonical invocation framed through DSH tools.\n5. \"## Quick Reference\" \u2014 flat command/endpoint list.\n6. \"## Procedure\" \u2014 numbered steps with copy-paste-exact commands.\n7. \"## Pitfalls\" \u2014 known limits and rate limits.\n8. \"## Verification\" \u2014 one check proving the skill worked.\n\nDSH-tool framing:\n- Reference DSH tools by name in backticks: `bash`, `str_replace_editor`, `write`, `skill`, `skill_manage`, `memory`.\n- Do not name wrapped shell utilities when a DSH tool already covers them.\n- Larger scripts belong under `scripts/` (written with `skill_manage write_file`) and are referenced from SKILL.md by relative path.\n\nQuality bar:\n- Prefer verbatim flags, paths, and APIs from the source. Never invent them.\n- Keep it tight: ~100 lines simple, ~200 complex.\n- No router/index/hub skills that only point at other skills.\n- References go in `references/`, templates in `templates/`.";
|
|
24
24
|
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -64,12 +64,21 @@ export declare class SkillLibrary {
|
|
|
64
64
|
isManaged(name: string): Promise<boolean>;
|
|
65
65
|
/** Whether the skill carries the bundled marker (curator prune-builtins eligibility). */
|
|
66
66
|
isBundled(name: string): Promise<boolean>;
|
|
67
|
+
/** Whether the skill carries the pinned marker (the marker is the factual source; usage.pinned mirrors it). */
|
|
68
|
+
isPinned(name: string): Promise<boolean>;
|
|
67
69
|
/** Count non-empty support subdirectories (richness input for quality scoring). */
|
|
68
70
|
countSupportDirs(name: string): Promise<number>;
|
|
69
71
|
/** Best-effort audit trail entry; never blocks the mutation. */
|
|
70
72
|
private audit;
|
|
71
73
|
/** Recent mutation audit records (read-only inspection surface). */
|
|
72
74
|
listMutations(): Promise<MutationRecord[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Pin or unpin a skill (`.pinned` marker). Pinned skills are protected from
|
|
77
|
+
* deletion, from background-review writes, and from the lifecycle — a
|
|
78
|
+
* protective mutation, so the autonomous pipeline may never call it. The
|
|
79
|
+
* marker write is the only state change; content is untouched.
|
|
80
|
+
*/
|
|
81
|
+
setPinned(name: string, pinned: boolean, origin?: WriteOrigin): Promise<SkillActionResult>;
|
|
73
82
|
create(name: string, content: string, origin: 'foreground' | 'background_review'): Promise<SkillActionResult>;
|
|
74
83
|
update(name: string, content: string, origin?: WriteOrigin): Promise<SkillActionResult>;
|
|
75
84
|
patch(name: string, oldString: string, newString: string, filePath?: string, replaceAll?: boolean, origin?: WriteOrigin): Promise<SkillActionResult>;
|
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.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.27",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|