@lmzhen/dsh-evolution-core 0.3.80 → 0.3.82
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 +673 -480
- package/lib/types/drift-signals.d.ts +3 -2
- package/lib/types/events.d.ts +2 -1
- package/lib/types/evolution-events.d.ts +24 -15
- package/lib/types/frontmatter.d.ts +169 -0
- package/lib/types/fuzzy-match.d.ts +18 -0
- package/lib/types/gates.d.ts +3 -2
- package/lib/types/instance-scope.d.ts +21 -2
- package/lib/types/io.d.ts +31 -2
- package/lib/types/limits.d.ts +15 -0
- package/lib/types/opt-in.d.ts +34 -4
- package/lib/types/skill-health.d.ts +3 -2
- package/lib/types/skill-store.d.ts +5 -156
- package/lib/types/threats.d.ts +3 -2
- package/lib/types/tool-dispatch.d.ts +12 -2
- package/lib/types/usage.d.ts +2 -1
- package/lib/types/write-inventory.d.ts +15 -3
- package/package.json +1 -1
- package/persisted-write-inventory.json +3 -4
|
@@ -34,16 +34,10 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import { transactIo, type EvolutionIoLike } from './io.ts';
|
|
36
36
|
import { type Probe } from './probe.ts';
|
|
37
|
+
import type { SkillLimits } from './limits.ts';
|
|
37
38
|
import { type MutationRecord } from './mutations.ts';
|
|
38
39
|
import { type SkillHealthAssessment, type SkillHealthThresholds } from './skill-health.ts';
|
|
39
40
|
import type { EvolutionSkillMutatedEvent } from './events.ts';
|
|
40
|
-
export interface SkillLimits {
|
|
41
|
-
maxNameLength: number;
|
|
42
|
-
maxDescriptionLength: number;
|
|
43
|
-
maxSkillContentChars: number;
|
|
44
|
-
maxSkillFileBytes: number;
|
|
45
|
-
}
|
|
46
|
-
export declare const DEFAULT_SKILL_LIMITS: SkillLimits;
|
|
47
41
|
export interface SkillSummary {
|
|
48
42
|
name: string;
|
|
49
43
|
description: string;
|
|
@@ -246,155 +240,6 @@ export declare function resolveExecOrigins(exec: EvolutionExecOriginView | undef
|
|
|
246
240
|
* consumers that must probe markers without re-deriving the name (curator's
|
|
247
241
|
* archive-copy bundled probe, 0.3.26 V4-02). */
|
|
248
242
|
export declare function markerEntryName(marker: 'bundled' | 'hub-installed' | 'pinned' | 'hermes-managed'): string;
|
|
249
|
-
export interface Frontmatter {
|
|
250
|
-
name?: string;
|
|
251
|
-
description?: string;
|
|
252
|
-
[key: string]: unknown;
|
|
253
|
-
}
|
|
254
|
-
export declare function frontmatterBlock(content: string): {
|
|
255
|
-
block: string;
|
|
256
|
-
lines: string[];
|
|
257
|
-
end: number;
|
|
258
|
-
nl: string;
|
|
259
|
-
} | null;
|
|
260
|
-
/**
|
|
261
|
-
* One frontmatter read (V27 G2.1): the values, the body, and every signal the
|
|
262
|
-
* strict-YAML platform catalog derives from the same block. Returned by
|
|
263
|
-
* {@link parseFrontmatter} so a caller never has to parse the block twice to
|
|
264
|
-
* reach a description and the catalog verdict.
|
|
265
|
-
*/
|
|
266
|
-
export interface FrontmatterRead {
|
|
267
|
-
frontmatter: Frontmatter;
|
|
268
|
-
body: string;
|
|
269
|
-
/** Raw entries whose UNQUOTED value the strict catalog cannot load as
|
|
270
|
-
* written. Quotes are included, so a value already normalized by the write
|
|
271
|
-
* path (`normalizeFrontmatter`) is never re-flagged. */
|
|
272
|
-
unsafeValues: Array<{
|
|
273
|
-
key: string;
|
|
274
|
-
value: string;
|
|
275
|
-
}>;
|
|
276
|
-
/** Whether the frontmatter is not valid AS WRITTEN for the strict platform
|
|
277
|
-
* catalog: the strict parser rejects the block, or an unquoted value would
|
|
278
|
-
* read as something other than its text (a dropped ` # ` comment, a
|
|
279
|
-
* number/bool shorthand the catalog refuses as a string field), or a
|
|
280
|
-
* platform string field carries a non-string value. The write path quotes
|
|
281
|
-
* such a value on its next edit. */
|
|
282
|
-
catalogInvalid: boolean;
|
|
283
|
-
/** Platform string fields (`name`/`description`/`whenToUse`) whose YAML value
|
|
284
|
-
* is not a string: the strict catalog reads such a field as ABSENT and, for an
|
|
285
|
-
* absent name/description, ignores the whole file (P2-9/v37). */
|
|
286
|
-
platformStringSplit: PlatformStringSplit[];
|
|
287
|
-
}
|
|
288
|
-
/** One `name`/`description`/`whenToUse` entry the strict catalog cannot read as
|
|
289
|
-
* a string, with the YAML kind the parser found. */
|
|
290
|
-
export interface PlatformStringSplit {
|
|
291
|
-
key: string;
|
|
292
|
-
/** The YAML type read for this field. `scalar` covers number/boolean (the
|
|
293
|
-
* E-47 auto-quote repair handles those); `sequence`/`mapping` are the shapes
|
|
294
|
-
* no rewrite can repair without inventing text — see `validateFrontmatter`. */
|
|
295
|
-
kind: 'sequence' | 'mapping' | 'scalar' | 'null';
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Parse a SKILL.md: its frontmatter values and body, or `null` when the file
|
|
299
|
-
* has no frontmatter block or no body. Every consumer of frontmatter values
|
|
300
|
-
* goes through here — the write path's validation, `list()`'s published
|
|
301
|
-
* description, `relatedSkillNames` and the audit — so all of them read the same
|
|
302
|
-
* bytes the same way.
|
|
303
|
-
*
|
|
304
|
-
* @param content - the SKILL.md text.
|
|
305
|
-
* @returns the read, or `null` when there is no block or no body.
|
|
306
|
-
*/
|
|
307
|
-
export declare function parseFrontmatter(content: string): FrontmatterRead | null;
|
|
308
|
-
/**
|
|
309
|
-
* Whether this file's frontmatter is valid as written for the strict platform
|
|
310
|
-
* catalog (see `FrontmatterRead.catalogInvalid`). Body-independent (a body-less
|
|
311
|
-
* file is still judged), and derived from the same read as `parseFrontmatter` —
|
|
312
|
-
* so the audit's verdict and the values the family publishes for one file can
|
|
313
|
-
* never disagree (V27 G2.1).
|
|
314
|
-
*
|
|
315
|
-
* @param content - the SKILL.md text.
|
|
316
|
-
* @returns `true` when the strict parser rejects the block or an unquoted value would read as something else.
|
|
317
|
-
*/
|
|
318
|
-
export declare function frontmatterCatalogInvalid(content: string): boolean;
|
|
319
|
-
/** YAML plain-scalar hazards that make an UNQUOTED frontmatter value
|
|
320
|
-
* unloadable to the platform catalog (strict YAML parser): `: ` (mapping
|
|
321
|
-
* separator), ` #` (comment start), a trailing `:` (a mapping marker),
|
|
322
|
-
* or a leading YAML indicator. The evolution `parseFrontmatter` is
|
|
323
|
-
* deliberately lenient, so violations silently split family-visibility from
|
|
324
|
-
* platform-visibility (0.3.11 inkos-harness case: the description carried
|
|
325
|
-
* "…: " and the catalog dropped the whole skill). Already-quoted values and
|
|
326
|
-
* well-formed flow collections (`[a, b]` / `{a: b}`) are considered safe.
|
|
327
|
-
* 0.3.16 (E-47): null/bool/number-shaped plain scalars are flagged too — they
|
|
328
|
-
* parse as booleans/numbers on the platform while the family keeps the string
|
|
329
|
-
* (a `description: true` split-brain).
|
|
330
|
-
* This rule is only the FAST PATH — the write path re-verifies every rewrite
|
|
331
|
-
* with the real YAML parser (see normalizeFrontmatter), so an incomplete
|
|
332
|
-
* approximation can never corrupt a multiline flow value (P3-4). */
|
|
333
|
-
export declare function yamlPlainScalarNeedsQuotes(value: string): boolean;
|
|
334
|
-
export interface FrontmatterNormalizeResult {
|
|
335
|
-
content: string;
|
|
336
|
-
changed: boolean;
|
|
337
|
-
/** Frontmatter keys whose values were auto-quoted. */
|
|
338
|
-
fields: string[];
|
|
339
|
-
/** Values that cannot be auto-quoted safely (control characters, or a
|
|
340
|
-
* rewrite that failed the real-parser verification — a multiline flow
|
|
341
|
-
* collection line etc. is left untouched and reported here, so the write
|
|
342
|
-
* path rejects instead of silently damaging a value; 0.3.14). */
|
|
343
|
-
issues: string[];
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Normalize a SKILL.md frontmatter block into catalog-loadable YAML: values
|
|
347
|
-
* that YAML forbids unquoted get quotes — double quotes normally, single
|
|
348
|
-
* quotes (with `''` doubling) when the value contains `"` or `\` (both legal
|
|
349
|
-
* unescaped inside single-quoted YAML). Idempotent; only single-line
|
|
350
|
-
* `key: value` entries are touched; body text is never modified; line-ending
|
|
351
|
-
* style is preserved. **Every rewrite is re-verified with the real YAML
|
|
352
|
-
* parser** (js-yaml — the same parser the platform catalog uses): if the
|
|
353
|
-
* rewritten block no longer parses, or a rewritten value's parsed content
|
|
354
|
-
* differs from the original, the rewrite is rolled back and reported in
|
|
355
|
-
* `issues` (fail-loud, never a silent value corruption — P3-4).
|
|
356
|
-
*
|
|
357
|
-
* V10-02 (P2-3): the rewrite decision is PER LINE — each entry parses its own
|
|
358
|
-
* value, so a duplicated key can never route one entry's unsafe value into a
|
|
359
|
-
* different line's rewrite (the old key→Map lookup rewrote the FIRST (safe)
|
|
360
|
-
* line with the SECOND line's quoted value, and the last-wins YAML reader
|
|
361
|
-
* masked the damage). A duplicated key is itself invalid input and is
|
|
362
|
-
* reported in `issues` (the write path refuses) instead of being rewritten.
|
|
363
|
-
*/
|
|
364
|
-
export declare function normalizeFrontmatter(content: string): FrontmatterNormalizeResult;
|
|
365
|
-
/**
|
|
366
|
-
* Skill names referenced by a SKILL.md's `related_skills` frontmatter
|
|
367
|
-
* (B-line G3, rc.44): the single parsing source for the quality references
|
|
368
|
-
* factor and the learning-graph edges. The DSH frontmatter parser keeps the
|
|
369
|
-
* YAML value as a string (`"[a, b]"`), so names are scanned out of it; each
|
|
370
|
-
* must satisfy the skill-name shape and the referencing skill itself is
|
|
371
|
-
* excluded. Pure and deduplicated.
|
|
372
|
-
*/
|
|
373
|
-
export declare function relatedSkillNames(content: string, exclude?: string): string[];
|
|
374
|
-
export declare function validateFrontmatter(content: string, expectedName?: string, limits?: SkillLimits,
|
|
375
|
-
/** On-disk bytes, so a NET SHRINK of an over-limit file is allowed (S1.2). */
|
|
376
|
-
current?: string | null): string | null;
|
|
377
|
-
/** Hermes authoring quality bar for descriptions — see constants.ts
|
|
378
|
-
* (0.3.16 T-4 moved the single source there; the public re-export sits behind
|
|
379
|
-
* the package root, which re-exports constants anyway). */
|
|
380
|
-
export interface AuthoringFeedback {
|
|
381
|
-
/** Frontmatter description length in characters (0 when absent). */
|
|
382
|
-
descriptionChars: number;
|
|
383
|
-
/** Whether the description exceeds the authoring bar (60) while still passing the platform limit. */
|
|
384
|
-
over60: boolean;
|
|
385
|
-
/** Whether the description contains a colon (the standard requires double-quote wrapping). */
|
|
386
|
-
hasColon: boolean;
|
|
387
|
-
/** Advice lines appended to mutation success messages. */
|
|
388
|
-
lines: string[];
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Advisory authoring feedback (P0): evaluate frontmatter against the
|
|
392
|
-
* authoring bar WITHOUT changing platform validation semantics. The bar is
|
|
393
|
-
* the quality target, `validateFrontmatter`'s limits are the compatibility
|
|
394
|
-
* floor, and this bridge layer tells the model when its text would be
|
|
395
|
-
* truncated or route-poor instead of silently shipping it.
|
|
396
|
-
*/
|
|
397
|
-
export declare function authoringFeedback(frontmatter: Frontmatter): AuthoringFeedback;
|
|
398
243
|
/** A1-6 (v18): the regex alone admits `references/nul.md` (a Windows device
|
|
399
244
|
* stem), which the support-file layer refuses. Restructure must use the same
|
|
400
245
|
* rule, or it creates an orphan the later patch/write/remove paths refuse.
|
|
@@ -747,4 +592,8 @@ export interface NewSkillLibraryOptions {
|
|
|
747
592
|
threatExemptLabels?: readonly string[] | undefined;
|
|
748
593
|
}
|
|
749
594
|
export declare function newSkillLibrary(options: NewSkillLibraryOptions): SkillLibrary;
|
|
595
|
+
export { DEFAULT_SKILL_LIMITS } from './limits.ts';
|
|
596
|
+
export type { SkillLimits } from './limits.ts';
|
|
597
|
+
export { authoringFeedback, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from './frontmatter.ts';
|
|
598
|
+
export type { AuthoringFeedback, Frontmatter, FrontmatterNormalizeResult, FrontmatterRead, PlatformStringSplit } from './frontmatter.ts';
|
|
750
599
|
//# sourceMappingURL=skill-store.d.ts.map
|
package/lib/types/threats.d.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* REPORT findings: they stay visible to operators and tests but never reject a
|
|
14
14
|
* write. Blocking them turned every emoji into a security event.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
type ThreatScope = 'all' | 'context' | 'strict';
|
|
17
|
+
interface ThreatFinding {
|
|
18
18
|
label: string;
|
|
19
19
|
category: string;
|
|
20
20
|
scope: ThreatScope;
|
|
@@ -74,4 +74,5 @@ export declare function scanContentThreats(text: string, maxScanChars?: number,
|
|
|
74
74
|
* returns the scan message verbatim, so the hint rides along there too.
|
|
75
75
|
*/
|
|
76
76
|
export declare const THREAT_EXEMPTION_HINT = " A deployment that needs a specific label can exempt it via threatExemptLabels (see the README env/dial reference).";
|
|
77
|
+
export {};
|
|
77
78
|
//# sourceMappingURL=threats.d.ts.map
|
|
@@ -105,6 +105,16 @@ export declare class ToolDispatchNormalizer {
|
|
|
105
105
|
constructor(options?: {
|
|
106
106
|
maxTracked?: number;
|
|
107
107
|
});
|
|
108
|
+
/**
|
|
109
|
+
* v43 audit (FLOW4-4): the ledger key. A normalizer shared by every session
|
|
110
|
+
* (skill-usage's live listener holds ONE process-wide instance) used the bare
|
|
111
|
+
* call id, so two sessions that produced the same id — PTC sub-call ids are
|
|
112
|
+
* short, and an id-less payload falls back to a type+payload key that is not
|
|
113
|
+
* unique by construction — collided: the second session's read was absorbed as
|
|
114
|
+
* "already seen" and never counted, and a settle in one session flipped the
|
|
115
|
+
* other's `ok`. Callers that span sessions pass the session id as `scope`.
|
|
116
|
+
*/
|
|
117
|
+
private keyOf;
|
|
108
118
|
/**
|
|
109
119
|
* Absorb one session event.
|
|
110
120
|
* @param event - the event to absorb; any non-dispatch event is ignored.
|
|
@@ -115,7 +125,7 @@ export declare class ToolDispatchNormalizer {
|
|
|
115
125
|
advance(event: {
|
|
116
126
|
type: string;
|
|
117
127
|
data?: unknown;
|
|
118
|
-
}): ToolDispatchSignal | null;
|
|
128
|
+
}, scope?: string): ToolDispatchSignal | null;
|
|
119
129
|
/**
|
|
120
130
|
* S2-P2-12: the SETTLE channel. \`advance\` answers \`null\` for the paired
|
|
121
131
|
* event that settles an already-emitted dispatch, so a consumer that must act
|
|
@@ -129,7 +139,7 @@ export declare class ToolDispatchNormalizer {
|
|
|
129
139
|
settledSignalOf(event: {
|
|
130
140
|
type: string;
|
|
131
141
|
data?: unknown;
|
|
132
|
-
}): ToolDispatchSignal | null;
|
|
142
|
+
}, scope?: string): ToolDispatchSignal | null;
|
|
133
143
|
/** Oldest-first eviction once the ledger (or the settle markers) overflows. */
|
|
134
144
|
private evict;
|
|
135
145
|
/** Every emitted dispatch, in first-seen order. */
|
package/lib/types/usage.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Format-compatible with Hermes Agent / hermes-claw core fields.
|
|
4
4
|
*/
|
|
5
5
|
import { type EvolutionIoLike } from './io.ts';
|
|
6
|
-
|
|
6
|
+
type SkillState = 'active' | 'stale' | 'archived';
|
|
7
7
|
export interface UsageRecord {
|
|
8
8
|
created_by: string | null;
|
|
9
9
|
use_count: number;
|
|
@@ -127,4 +127,5 @@ export declare function saveSuppressedNames(root: string, names: ReadonlySet<str
|
|
|
127
127
|
* sharing DSH_HOME cannot interleave its RMW. Best-effort posture unchanged.
|
|
128
128
|
*/
|
|
129
129
|
export declare function updateSuppressedNames(root: string, io: EvolutionIoLike, task: (names: Set<string>) => void | Promise<void>): Promise<void>;
|
|
130
|
+
export {};
|
|
130
131
|
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @module @lmzhen/dsh-evolution-core/src/write-inventory
|
|
17
17
|
*/
|
|
18
18
|
/** How concurrent writers of one site are kept apart. */
|
|
19
|
-
|
|
19
|
+
type WriteSerialization = 'transact' | 'write-lock' | 'instance-claim';
|
|
20
20
|
/** One declared persisted write site. */
|
|
21
21
|
export interface PersistedWriteSite {
|
|
22
22
|
/** Stable id; referenced by the gate's failure text and by the specs. */
|
|
@@ -43,8 +43,19 @@ export declare const INSTANCE_KEYS: {
|
|
|
43
43
|
/** The per-home curator: report writing + the retention sweep. */
|
|
44
44
|
readonly curator: "evolution-curator";
|
|
45
45
|
};
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The declared persisted write sites, in file order.
|
|
48
|
+
*
|
|
49
|
+
* v43 audit (S2-3 / P1-10): this used to be a module-scope readFileSync plus
|
|
50
|
+
* parse, so an unshipped asset threw AT IMPORT — one absent file took the whole
|
|
51
|
+
* family's load down (0.3.79 shipped a tarball without this asset and every
|
|
52
|
+
* package failed to load). The read is lazy now: importing the package never
|
|
53
|
+
* fails on this asset, while the first caller still gets a loud, descriptive
|
|
54
|
+
* failure instead of an empty table ("no declared write sites" would silently
|
|
55
|
+
* disable rule N20).
|
|
56
|
+
* @returns the sites, in file order.
|
|
57
|
+
*/
|
|
58
|
+
export declare function persistedWriteSites(): readonly PersistedWriteSite[];
|
|
48
59
|
/** Sites serialized by the per-home instance claim, with their instance keys. */
|
|
49
60
|
export declare function instanceClaimedWriteSites(): readonly (PersistedWriteSite & {
|
|
50
61
|
readonly instance: string;
|
|
@@ -52,4 +63,5 @@ export declare function instanceClaimedWriteSites(): readonly (PersistedWriteSit
|
|
|
52
63
|
/** One declared site by id. An undeclared id throws — a stale caller must fail
|
|
53
64
|
* loud rather than read "nothing is declared". */
|
|
54
65
|
export declare function persistedWriteSite(id: string): PersistedWriteSite;
|
|
66
|
+
export {};
|
|
55
67
|
//# sourceMappingURL=write-inventory.d.ts.map
|
package/package.json
CHANGED
|
@@ -61,11 +61,10 @@
|
|
|
61
61
|
"id": "curator-reports",
|
|
62
62
|
"path": "<evolutionHome>/reports/curator-*.json",
|
|
63
63
|
"writer": "evolution-curator/src/index.ts",
|
|
64
|
-
"serializedBy": "
|
|
65
|
-
"marker": "
|
|
66
|
-
"instance": "evolution-curator",
|
|
64
|
+
"serializedBy": "transact",
|
|
65
|
+
"marker": "transactIo(this.io, reportsSweepLockTarget()",
|
|
67
66
|
"state": [],
|
|
68
|
-
"note": "Curator run reports + their retention sweep.
|
|
67
|
+
"note": "Curator run reports + their retention sweep. The sweep is a multi-step list + delete-beyond-the-window over a DIRECTORY, so it has no per-file lock: v43 FLOW2-1 put it inside the IO backend's cross-process write lock (transactIo) on a per-home lock target, <evolutionHome>/reports/.retention (lock file <target>.lock, pid:token body). The former declaration here was instance-claim, which is in-process ONLY (instance-scope.ts is a module-scope Map). Two curator ROWS in one process still cannot sweep at once (the loser yields on that claim), and report writes are name-unique per runId. Trigger for the remaining gap: a second PROCESS sharing DSH_HOME now WAITS on the lock instead of sweeping concurrently, and on a backend without transact there is no lock at all, so the sweep degrades to best-effort idempotent deletes."
|
|
69
68
|
},
|
|
70
69
|
{
|
|
71
70
|
"id": "skill-tree",
|