@lmzhen/dsh-evolution-core 0.3.67 → 0.3.69
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 +766 -232
- package/lib/types/constants.d.ts +14 -0
- package/lib/types/curator.d.ts +21 -1
- package/lib/types/events.d.ts +10 -0
- package/lib/types/evolution-events.d.ts +9 -6
- package/lib/types/io.d.ts +65 -0
- package/lib/types/memory-store.d.ts +79 -13
- package/lib/types/prompts.d.ts +6 -6
- package/lib/types/skill-store.d.ts +101 -22
- package/lib/types/threats.d.ts +3 -0
- package/package.json +1 -1
|
@@ -113,21 +113,31 @@ export declare function skillsRoot(env?: NodeJS.ProcessEnv): string;
|
|
|
113
113
|
export declare function resolveSkillsRoot(config?: {
|
|
114
114
|
root?: string | undefined;
|
|
115
115
|
}): string;
|
|
116
|
-
/** E-7 (v18): every family row reads ONE root key. `root` is
|
|
117
|
-
* `skillsRoot`
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
116
|
+
/** E-7 (v18) → V27 G2.4 (M-08): every family row reads ONE root key. `root` is
|
|
117
|
+
* canonical; the `skillsRoot` alias was honoured for one minor version and its
|
|
118
|
+
* window closed at 0.3.65 — it is now two releases past expiry, so this
|
|
119
|
+
* resolver no longer reads it at all. A deployment that still sets the alias
|
|
120
|
+
* must fail LOUDLY at load (see {@link assertSkillsRootAliasRetired}): silently
|
|
121
|
+
* ignoring a config key leaves the deployment pointing at a root nobody reads,
|
|
122
|
+
* which is the worst form of compatibility.
|
|
123
|
+
* @param config - the raw plugin config.
|
|
124
|
+
* @returns the effective root (empty when the key is unset or blank).
|
|
123
125
|
*/
|
|
124
126
|
export declare function resolveRootConfig(config?: {
|
|
125
127
|
root?: string | undefined;
|
|
126
|
-
skillsRoot?: string | undefined;
|
|
127
128
|
}): {
|
|
128
129
|
root: string;
|
|
129
|
-
usedDeprecatedAlias: boolean;
|
|
130
130
|
};
|
|
131
|
+
/** V27 G2.4 (M-08): the retirement gate for the expired `skillsRoot` alias.
|
|
132
|
+
* Called at each plugin's load boundary (before the root is resolved), it turns
|
|
133
|
+
* a stale key into an explicit load error naming the replacement — the
|
|
134
|
+
* fail-loud form the plan requires instead of a silent no-op.
|
|
135
|
+
* @param config - the raw plugin config (the alias field stays DECLARED in each
|
|
136
|
+
* schema so the loader can hand it here instead of dropping it).
|
|
137
|
+
*/
|
|
138
|
+
export declare function assertSkillsRootAliasRetired(config?: {
|
|
139
|
+
skillsRoot?: string | undefined;
|
|
140
|
+
}): void;
|
|
131
141
|
/**
|
|
132
142
|
* Map a requesting session onto the two origin surfaces (rc.44 plan M2-2.3):
|
|
133
143
|
* the APPROVAL surface treats every delegated subagent as the autonomous
|
|
@@ -156,10 +166,17 @@ export interface Frontmatter {
|
|
|
156
166
|
}
|
|
157
167
|
/**
|
|
158
168
|
* Shared frontmatter block detection (P3-3 single owner): opening line `---`
|
|
159
|
-
* and closing line exactly
|
|
160
|
-
* `
|
|
169
|
+
* and closing line exactly `---`. Used by `parseFrontmatter`,
|
|
170
|
+
* `frontmatterCatalogInvalid` and `normalizeFrontmatter` so the three can
|
|
161
171
|
* never disagree about where the block ends (the loose `indexOf('\n---')`
|
|
162
172
|
* form matched `\n----` and was replaced by this strict line rule).
|
|
173
|
+
*
|
|
174
|
+
* V27 G2.1: both fence lines are matched EXACTLY, tolerating only a trailing
|
|
175
|
+
* `\r` — the same rule the upstream filesystem catalog uses
|
|
176
|
+
* (`skill-filesystem.parseFrontmatter`). The former `.trim()` comparison
|
|
177
|
+
* accepted ` --- `, so an indented fence loaded in the family while the
|
|
178
|
+
* platform ignored the file: family visibility split from platform visibility,
|
|
179
|
+
* which is exactly what a strict-YAML frontmatter is supposed to prevent.
|
|
163
180
|
*/
|
|
164
181
|
export declare function frontmatterBlock(content: string): {
|
|
165
182
|
block: string;
|
|
@@ -167,10 +184,51 @@ export declare function frontmatterBlock(content: string): {
|
|
|
167
184
|
end: number;
|
|
168
185
|
nl: string;
|
|
169
186
|
} | null;
|
|
170
|
-
|
|
187
|
+
/**
|
|
188
|
+
* One frontmatter read (V27 G2.1): the values, the body, and every signal the
|
|
189
|
+
* strict-YAML platform catalog derives from the same block. Returned by
|
|
190
|
+
* {@link parseFrontmatter} so a caller never has to parse the block twice to
|
|
191
|
+
* reach a description and the catalog verdict.
|
|
192
|
+
*/
|
|
193
|
+
export interface FrontmatterRead {
|
|
171
194
|
frontmatter: Frontmatter;
|
|
172
195
|
body: string;
|
|
173
|
-
|
|
196
|
+
/** Raw entries whose UNQUOTED value the strict catalog cannot load as
|
|
197
|
+
* written. Quotes are included, so a value already normalized by the write
|
|
198
|
+
* path (`normalizeFrontmatter`) is never re-flagged. */
|
|
199
|
+
unsafeValues: Array<{
|
|
200
|
+
key: string;
|
|
201
|
+
value: string;
|
|
202
|
+
}>;
|
|
203
|
+
/** Whether the frontmatter is not valid AS WRITTEN for the strict platform
|
|
204
|
+
* catalog: the strict parser rejects the block, or an unquoted value would
|
|
205
|
+
* read as something other than its text (a dropped ` # ` comment, a
|
|
206
|
+
* number/bool shorthand the catalog refuses as a string field). The write
|
|
207
|
+
* path quotes such a value on its next edit. */
|
|
208
|
+
catalogInvalid: boolean;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parse a SKILL.md: its frontmatter values and body, or `null` when the file
|
|
212
|
+
* has no frontmatter block or no body. Every consumer of frontmatter values
|
|
213
|
+
* goes through here — the write path's validation, `list()`'s published
|
|
214
|
+
* description, `relatedSkillNames` and the audit — so all of them read the same
|
|
215
|
+
* bytes the same way.
|
|
216
|
+
*
|
|
217
|
+
* @param content - the SKILL.md text.
|
|
218
|
+
* @returns the read, or `null` when there is no block or no body.
|
|
219
|
+
*/
|
|
220
|
+
export declare function parseFrontmatter(content: string): FrontmatterRead | null;
|
|
221
|
+
/**
|
|
222
|
+
* Whether this file's frontmatter is valid as written for the strict platform
|
|
223
|
+
* catalog (see `FrontmatterRead.catalogInvalid`). Body-independent (a body-less
|
|
224
|
+
* file is still judged), and derived from the same read as `parseFrontmatter` —
|
|
225
|
+
* so the audit's verdict and the values the family publishes for one file can
|
|
226
|
+
* never disagree (V27 G2.1).
|
|
227
|
+
*
|
|
228
|
+
* @param content - the SKILL.md text.
|
|
229
|
+
* @returns `true` when the strict parser rejects the block or an unquoted value would read as something else.
|
|
230
|
+
*/
|
|
231
|
+
export declare function frontmatterCatalogInvalid(content: string): boolean;
|
|
174
232
|
/** YAML plain-scalar hazards that make an UNQUOTED frontmatter value
|
|
175
233
|
* unloadable to the platform catalog (strict YAML parser): `: ` (mapping
|
|
176
234
|
* separator), ` #` (comment start), a trailing `:` (a mapping marker),
|
|
@@ -186,15 +244,6 @@ export declare function parseFrontmatter(content: string): {
|
|
|
186
244
|
* with the real YAML parser (see normalizeFrontmatter), so an incomplete
|
|
187
245
|
* approximation can never corrupt a multiline flow value (P3-4). */
|
|
188
246
|
export declare function yamlPlainScalarNeedsQuotes(value: string): boolean;
|
|
189
|
-
/** Raw-line scan of the frontmatter block: entries whose UNQUOTED value is
|
|
190
|
-
* YAML-unsafe for the strict platform catalog. Operates on the ORIGINAL line
|
|
191
|
-
* value (quotes included), so a value already wrapped by
|
|
192
|
-
* `normalizeFrontmatter` is never re-flagged — one source with the write
|
|
193
|
-
* path. Single-line entries only; lines with embedded line breaks skip. */
|
|
194
|
-
export declare function frontmatterYamlUnsafeValues(content: string): Array<{
|
|
195
|
-
key: string;
|
|
196
|
-
value: string;
|
|
197
|
-
}>;
|
|
198
247
|
export interface FrontmatterNormalizeResult {
|
|
199
248
|
content: string;
|
|
200
249
|
changed: boolean;
|
|
@@ -291,6 +340,17 @@ export declare class SkillLibrary {
|
|
|
291
340
|
* never inflates the mutation-maturity counter.
|
|
292
341
|
*/
|
|
293
342
|
private runSingleWrite;
|
|
343
|
+
/**
|
|
344
|
+
* v28 G1.1 (EVO-IO-02): shared compensating cleanup for a locked write that
|
|
345
|
+
* found no SKILL.md — remove the possibly-resurrected directory ONLY when it
|
|
346
|
+
* holds nothing but this path's own write-lock file. The BR-5 rule from
|
|
347
|
+
* setPinnedCore/createCore applies unchanged: a concurrent mover can land a
|
|
348
|
+
* full directory between the list probe and the remove, so anything beyond
|
|
349
|
+
* the lock file (support files, a fresh restore) must never be recursed
|
|
350
|
+
* away. Best-effort: a failed cleanup leaves the "not found" result
|
|
351
|
+
* unchanged (the operator-facing ghost-dir refusal is fail-loud already).
|
|
352
|
+
*/
|
|
353
|
+
private cleanupGhostDir;
|
|
294
354
|
/** Notify the mutation observer after a successful write; observers must never fail the mutation. */
|
|
295
355
|
private notifyMutation;
|
|
296
356
|
/** V10-03 (P2-18): ScanOptions shared by every write-path threat check —
|
|
@@ -300,6 +360,15 @@ export declare class SkillLibrary {
|
|
|
300
360
|
* label (scanContentThreats already embeds it) plus the self-heal hint, so a
|
|
301
361
|
* false-positive rewrite direction is actionable instead of a dead end. */
|
|
302
362
|
private contentThreatBlock;
|
|
363
|
+
/**
|
|
364
|
+
* v30 REV-03: read a support file's bytes for staleness anchoring (the
|
|
365
|
+
* write/remove replay guard). Same validation as writeSupportFile; a
|
|
366
|
+
* missing file (or a directory squatting on the path) reads as `null`, any
|
|
367
|
+
* other failure RETHROWS — the callers are the staging/replay anchors, and
|
|
368
|
+
* a swallowed error would silently downgrade the anchor to
|
|
369
|
+
* last-writer-wins.
|
|
370
|
+
*/
|
|
371
|
+
readSupportFile(name: string, filePath: string): Promise<string | null>;
|
|
303
372
|
list(): Promise<SkillSummary[]>;
|
|
304
373
|
read(rawName: string): Promise<string | null>;
|
|
305
374
|
/**
|
|
@@ -508,6 +577,16 @@ export declare class SkillLibrary {
|
|
|
508
577
|
* 64 chars each (the name-rule maximum — real skill names always fit).
|
|
509
578
|
*/
|
|
510
579
|
private sanitizeSkippedNames;
|
|
580
|
+
/**
|
|
581
|
+
* V27 G0.4 (core-a-01): the per-entry gate `skipped` already has. A corrupted
|
|
582
|
+
* or hand-edited manifest could carry `extras: [123]`: the array check passed,
|
|
583
|
+
* `SNAPSHOT_EXTRA_NAME_RE.test(123)` coerced the number to the string "123"
|
|
584
|
+
* and matched, and the value then threw `TypeError` inside `path.join` — which
|
|
585
|
+
* `readSnapshotExtras` reached only AFTER a whole-tree restore had committed.
|
|
586
|
+
* Extras are path components under `extras/`, so they take the entry gate too;
|
|
587
|
+
* bounded like `skipped` so a hostile manifest cannot grow the read set.
|
|
588
|
+
*/
|
|
589
|
+
private sanitizeExtraNames;
|
|
511
590
|
readSnapshotManifest(path: string): Promise<SnapshotManifest | null>;
|
|
512
591
|
/** Keep only the newest N snapshots (Hermes keep=5 parity); older ones are removed outright. */
|
|
513
592
|
private retainSnapshots;
|
package/lib/types/threats.d.ts
CHANGED
|
@@ -28,6 +28,9 @@ export interface ThreatFinding {
|
|
|
28
28
|
* benign phrasing (e.g. a skill that legitimately opens with "You are now a ...")
|
|
29
29
|
* can exclude that label by name here. This is opt-in and never widens strict
|
|
30
30
|
* scope; it only permits callers to drop a known-innocent match.
|
|
31
|
+
* V27 G-1: an exclusion drops the FINDING for that label — it never removes the
|
|
32
|
+
* de-obfuscation the other patterns are matched against, so exempting the
|
|
33
|
+
* unicode rules cannot re-open a splitting bypass.
|
|
31
34
|
*/
|
|
32
35
|
export interface ScanOptions {
|
|
33
36
|
/** Pattern labels to skip during this scan. */
|
package/package.json
CHANGED