@lmzhen/dsh-evolution-core 0.3.81 → 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.
@@ -29,7 +29,7 @@ export interface DriftSkillSnapshot {
29
29
  catalogInvalid?: boolean | undefined;
30
30
  }
31
31
  /** verdict=over means "relatively positioned above the threshold", never a violation. */
32
- export type DriftVerdict = 'pass' | 'over' | 'unknown';
32
+ type DriftVerdict = 'pass' | 'over' | 'unknown';
33
33
  export interface DriftSignal {
34
34
  id: string;
35
35
  verdict: DriftVerdict;
@@ -40,7 +40,7 @@ export interface DriftSignal {
40
40
  /** Extra evidence (matched shapes, line numbers, group members). */
41
41
  detail?: string | undefined;
42
42
  }
43
- export interface DriftSkillAssessment {
43
+ interface DriftSkillAssessment {
44
44
  name: string;
45
45
  signals: ReadonlyArray<DriftSignal>;
46
46
  /** Passthrough from the snapshot (0.3.11): protection marker, catalog loadability. */
@@ -80,4 +80,5 @@ export declare function narrowNameMatches(name: string): string[];
80
80
  export declare function computeDriftSignals(snapshots: ReadonlyArray<DriftSkillSnapshot>): DriftReport;
81
81
  /** Convenience: fetch one signal from an assessment or library list. */
82
82
  export declare function findDriftSignal(signals: ReadonlyArray<DriftSignal>, id: string): DriftSignal | undefined;
83
+ export {};
83
84
  //# sourceMappingURL=drift-signals.d.ts.map
@@ -73,7 +73,7 @@ export interface EvolutionSkillMutatedEvent {
73
73
  /** 0.3.18 (E-6): a turn-end review pipeline failure was caught (never an
74
74
  * unhandled rejection); this event lets operators/observability see it. The
75
75
  * reason is already logged by the emitter — the event is a timestamped signal. */
76
- export interface EvolutionReviewErrorEvent {
76
+ interface EvolutionReviewErrorEvent {
77
77
  sessionId: string;
78
78
  }
79
79
  declare module '@deepseek-ai/cordis' {
@@ -89,4 +89,5 @@ declare module '@deepseek-ai/cordis' {
89
89
  'evolution/review-error'(event: EvolutionReviewErrorEvent): void;
90
90
  }
91
91
  }
92
+ export {};
92
93
  //# sourceMappingURL=events.d.ts.map
@@ -75,7 +75,7 @@ export interface EvolutionEvent {
75
75
  /** The durable-write shape of one event: `feedback` REQUIRES a `target` —
76
76
  * the fold key the aggregate is keyed by (P2-10). The other tags keep every
77
77
  * field optional, exactly as the runtime payload gate treats them. */
78
- export type EvolutionEventInput = (Omit<EvolutionEvent, 'seq' | 'at' | 'target'> & {
78
+ type EvolutionEventInput = (Omit<EvolutionEvent, 'seq' | 'at' | 'target'> & {
79
79
  type: 'feedback';
80
80
  target: string;
81
81
  }) | (Omit<EvolutionEvent, 'seq' | 'at'> & {
@@ -128,28 +128,37 @@ export declare function appendEvolutionEvent(io: EvolutionIoLike, path: string,
128
128
  * Best-effort per removal; exported for the retention test.
129
129
  */
130
130
  export declare function retainEventArchives(io: EvolutionIoLike, path: string): Promise<void>;
131
- export interface EventLogRead {
131
+ interface EventLogRead {
132
132
  events: EvolutionEvent[];
133
- /** True when the body is not valid JSON (syntax-level damage): refused on
134
- * append, bytes untouched. Well-formed JSON with a damaged `events` field
135
- * is REPLACEABLE garbage reads as empty and is rewritten at the next
136
- * append (rc.70 F-1: read and append agree on the same boundary). A READ
137
- * error (EISDIR etc.) also flags malformed the file is unusable either
138
- * way and is never overwritten (the append read would fail identically). */
133
+ /** True when THIS read DROPPED events the file may hold, so the result must
134
+ * never be treated as the complete truth for that file. Three causes flag it:
135
+ * syntax-level damage and a READ error (EISDIR/EACCES) both refused on
136
+ * append with their bytes untouched and, since C-events-dispatch-1 (v43
137
+ * audit), a body whose `version` this reader cannot interpret: F-338 keeps
138
+ * such a body un-reshaped and never rewritten down, but its records ARE
139
+ * missing from the read. A well-formed body with a damaged `events` field
140
+ * stays UNflagged — REPLACEABLE garbage that reads as empty and is rewritten
141
+ * at the next append (rc.70 F-1: read and append agree on the same boundary). */
139
142
  malformed: boolean;
140
143
  }
141
- /** Read the event log; a missing/whitespace-only file reads as empty,
142
- * corrupt content is flagged (and refused on append). A well-formed future-
143
- * version body is v1-incompatible and reads as empty, NOT malformed (F-338:
144
- * the reader must never mis-shape a newer format; the append path refuses it
145
- * up front so the original bytes survive). */
144
+ /** Read the event log; a missing/whitespace-only file reads as empty, corrupt
145
+ * content is flagged (and refused on append). A well-formed future-version body
146
+ * is v1-incompatible: it reads as EMPTY and is now flagged malformed as well
147
+ * (C-events-dispatch-1, v43). F-338's own guarantees are untouched the reader
148
+ * never mis-shapes a newer format and the append path refuses it up front, so
149
+ * the original bytes survive — while the flag reports what the old reader hid:
150
+ * every record that body holds is dropped from this read. */
146
151
  export declare function readEvolutionEvents(io: EvolutionIoLike, path: string): Promise<EventLogRead>;
147
152
  /**
148
153
  * Read the full timeline (rc.71): active log + all archives, merged by seq
149
154
  * (active copy wins, duplicates only arise from the rotation crash window),
150
155
  * sorted ascending. Per-file malformed flag as in `readEvolutionEvents`; a
151
- * malformed (or unreadable) ARCHIVE is skipped it never bricks the boot and
152
- * it is still flagged.
156
+ * flagged ARCHIVE (unreadable, damaged, or a future-version body this reader
157
+ * cannot interpret) is SKIPPED — it never bricks the boot, the returned events
158
+ * simply LACK that seq band, and `malformed` is the only signal that they do
159
+ * (C-events-dispatch-1, v43: the flag is the consumer's contract; a truncated
160
+ * timeline must never be folded back as if it were complete).
153
161
  */
154
162
  export declare function readEvolutionTimeline(io: EvolutionIoLike, path: string, archives?: readonly string[]): Promise<EventLogRead>;
163
+ export {};
155
164
  //# sourceMappingURL=evolution-events.d.ts.map
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Frontmatter parsing, normalization and validation for skill Markdown files.
3
+ *
4
+ * Split out of skill-store.ts (S2-1): pure functions over file text, no store
5
+ * state. skill-store.ts re-exports the same names it exported before the split,
6
+ * so the package export surface is unchanged.
7
+ */
8
+ import type { SkillLimits } from './limits.ts';
9
+ export interface Frontmatter {
10
+ name?: string;
11
+ description?: string;
12
+ [key: string]: unknown;
13
+ }
14
+ export declare function frontmatterBlock(content: string): {
15
+ block: string;
16
+ lines: string[];
17
+ end: number;
18
+ nl: string;
19
+ } | null;
20
+ /**
21
+ * One frontmatter read (V27 G2.1): the values, the body, and every signal the
22
+ * strict-YAML platform catalog derives from the same block. Returned by
23
+ * {@link parseFrontmatter} so a caller never has to parse the block twice to
24
+ * reach a description and the catalog verdict.
25
+ */
26
+ export interface FrontmatterRead {
27
+ frontmatter: Frontmatter;
28
+ body: string;
29
+ /** Raw entries whose UNQUOTED value the strict catalog cannot load as
30
+ * written. Quotes are included, so a value already normalized by the write
31
+ * path (`normalizeFrontmatter`) is never re-flagged. */
32
+ unsafeValues: Array<{
33
+ key: string;
34
+ value: string;
35
+ }>;
36
+ /** Whether the frontmatter is not valid AS WRITTEN for the strict platform
37
+ * catalog: the strict parser rejects the block, or an unquoted value would
38
+ * read as something other than its text (a dropped ` # ` comment, a
39
+ * number/bool shorthand the catalog refuses as a string field), or a
40
+ * platform string field carries a non-string value. The write path quotes
41
+ * such a value on its next edit. */
42
+ catalogInvalid: boolean;
43
+ /** Platform string fields (`name`/`description`/`whenToUse`) whose YAML value
44
+ * is not a string: the strict catalog reads such a field as ABSENT and, for an
45
+ * absent name/description, ignores the whole file (P2-9/v37). */
46
+ platformStringSplit: PlatformStringSplit[];
47
+ }
48
+ /** One `name`/`description`/`whenToUse` entry the strict catalog cannot read as
49
+ * a string, with the YAML kind the parser found. */
50
+ export interface PlatformStringSplit {
51
+ key: string;
52
+ /** The YAML type read for this field. `scalar` covers number/boolean (the
53
+ * E-47 auto-quote repair handles those); `sequence`/`mapping` are the shapes
54
+ * no rewrite can repair without inventing text — see `validateFrontmatter`. */
55
+ kind: 'sequence' | 'mapping' | 'scalar' | 'null';
56
+ }
57
+ /**
58
+ * Parse a SKILL.md: its frontmatter values and body, or `null` when the file
59
+ * has no frontmatter block or no body. Every consumer of frontmatter values
60
+ * goes through here — the write path's validation, `list()`'s published
61
+ * description, `relatedSkillNames` and the audit — so all of them read the same
62
+ * bytes the same way.
63
+ *
64
+ * @param content - the SKILL.md text.
65
+ * @returns the read, or `null` when there is no block or no body.
66
+ */
67
+ export declare function parseFrontmatter(content: string): FrontmatterRead | null;
68
+ /**
69
+ * Whether this file's frontmatter is valid as written for the strict platform
70
+ * catalog (see `FrontmatterRead.catalogInvalid`). Body-independent (a body-less
71
+ * file is still judged), and derived from the same read as `parseFrontmatter` —
72
+ * so the audit's verdict and the values the family publishes for one file can
73
+ * never disagree (V27 G2.1).
74
+ *
75
+ * @param content - the SKILL.md text.
76
+ * @returns `true` when the strict parser rejects the block or an unquoted value would read as something else.
77
+ */
78
+ export declare function frontmatterCatalogInvalid(content: string): boolean;
79
+ /** YAML plain-scalar hazards that make an UNQUOTED frontmatter value
80
+ * unloadable to the platform catalog (strict YAML parser): `: ` (mapping
81
+ * separator), ` #` (comment start), a trailing `:` (a mapping marker),
82
+ * or a leading YAML indicator. The evolution `parseFrontmatter` is
83
+ * deliberately lenient, so violations silently split family-visibility from
84
+ * platform-visibility (0.3.11 inkos-harness case: the description carried
85
+ * "…: " and the catalog dropped the whole skill). Already-quoted values and
86
+ * well-formed flow collections (`[a, b]` / `{a: b}`) are considered safe.
87
+ * 0.3.16 (E-47): null/bool/number-shaped plain scalars are flagged too — they
88
+ * parse as booleans/numbers on the platform while the family keeps the string
89
+ * (a `description: true` split-brain).
90
+ * This rule is only the FAST PATH — the write path re-verifies every rewrite
91
+ * with the real YAML parser (see normalizeFrontmatter), so an incomplete
92
+ * approximation can never corrupt a multiline flow value (P3-4). */
93
+ export declare function yamlPlainScalarNeedsQuotes(value: string): boolean;
94
+ export interface FrontmatterNormalizeResult {
95
+ content: string;
96
+ changed: boolean;
97
+ /** Frontmatter keys whose values were auto-quoted. */
98
+ fields: string[];
99
+ /** Values that cannot be auto-quoted safely (control characters, or a
100
+ * rewrite that failed the real-parser verification — a multiline flow
101
+ * collection line etc. is left untouched and reported here, so the write
102
+ * path rejects instead of silently damaging a value; 0.3.14). */
103
+ issues: string[];
104
+ }
105
+ /**
106
+ * Normalize a SKILL.md frontmatter block into catalog-loadable YAML: values
107
+ * that YAML forbids unquoted get quotes — double quotes normally, single
108
+ * quotes (with `''` doubling) when the value contains `"` or `\` (both legal
109
+ * unescaped inside single-quoted YAML). Idempotent; only single-line
110
+ * `key: value` entries are touched; body text is never modified; line-ending
111
+ * style is preserved. **Every rewrite is re-verified with the real YAML
112
+ * parser** (js-yaml — the same parser the platform catalog uses): if the
113
+ * rewritten block no longer parses, or a rewritten value's parsed content
114
+ * differs from the original, the rewrite is rolled back and reported in
115
+ * `issues` (fail-loud, never a silent value corruption — P3-4).
116
+ *
117
+ * V10-02 (P2-3): the rewrite decision is PER LINE — each entry parses its own
118
+ * value, so a duplicated key can never route one entry's unsafe value into a
119
+ * different line's rewrite (the old key→Map lookup rewrote the FIRST (safe)
120
+ * line with the SECOND line's quoted value, and the last-wins YAML reader
121
+ * masked the damage). A duplicated key is itself invalid input and is
122
+ * reported in `issues` (the write path refuses) instead of being rewritten.
123
+ */
124
+ export declare function normalizeFrontmatter(content: string): FrontmatterNormalizeResult;
125
+ /**
126
+ * Skill names referenced by a SKILL.md's `related_skills` frontmatter
127
+ * (B-line G3, rc.44): the single parsing source for the quality references
128
+ * factor and the learning-graph edges. The DSH frontmatter parser keeps the
129
+ * YAML value as a string (`"[a, b]"`), so names are scanned out of it; each
130
+ * must satisfy the skill-name shape and the referencing skill itself is
131
+ * excluded. Pure and deduplicated.
132
+ */
133
+ export declare function relatedSkillNames(content: string, exclude?: string): string[];
134
+ /** Whether `content` would exceed `limit` once written. */
135
+ export declare function exceedsContentLimit(content: string, limit: number): boolean;
136
+ /** S1.2: the repair path — a write that makes an already-over-limit file smaller.
137
+ * Only a NET SHRINK is exempt; an equal or larger write stays refused. */
138
+ export declare function shrinksOverLimit(next: string, current: string | null | undefined, limit: number): boolean;
139
+ export declare function validateFrontmatter(content: string, expectedName?: string, limits?: SkillLimits,
140
+ /** On-disk bytes, so a NET SHRINK of an over-limit file is allowed (S1.2). */
141
+ current?: string | null): string | null;
142
+ /** Hermes authoring quality bar for descriptions — see constants.ts
143
+ * (0.3.16 T-4 moved the single source there; the public re-export sits behind
144
+ * the package root, which re-exports constants anyway). */
145
+ export interface AuthoringFeedback {
146
+ /** Frontmatter description length in characters (0 when absent). */
147
+ descriptionChars: number;
148
+ /** Whether the description exceeds the authoring bar (60) while still passing the platform limit. */
149
+ over60: boolean;
150
+ /** Whether the description contains a colon (the standard requires double-quote wrapping). */
151
+ hasColon: boolean;
152
+ /** Advice lines appended to mutation success messages. */
153
+ lines: string[];
154
+ }
155
+ /**
156
+ * Advisory authoring feedback (P0): evaluate frontmatter against the
157
+ * authoring bar WITHOUT changing platform validation semantics. The bar is
158
+ * the quality target, `validateFrontmatter`'s limits are the compatibility
159
+ * floor, and this bridge layer tells the model when its text would be
160
+ * truncated or route-poor instead of silently shipping it.
161
+ */
162
+ export declare function authoringFeedback(frontmatter: Frontmatter): AuthoringFeedback;
163
+ /** A1-15 (v18) / P2-2 (v19): the io layer marks an error `committed: true` when
164
+ * the rename landed and only the directory fsync failed. Every single-file
165
+ * writer must treat that as "written, durability unconfirmed" — never as a
166
+ * plain failure (which a caller would retry, or a two-phase caller roll back).
167
+ * v28 G2.1 (EVO-IO-05): this is a delegation to the seam's own
168
+ * `isCommittedWarning` — the marker predicate has exactly one definition. */
169
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Fuzzy string matching and replacement for patch/restructure edits of skill files.
3
+ *
4
+ * Split out of skill-store.ts (S2-1): pure text functions with no store state.
5
+ * The store imports the scan, the budgets and the replace entry points directly;
6
+ * none of them is re-exported, so the package export surface is unchanged.
7
+ */
8
+ /** V6-17 (0.3.37): the fuzzy-patch scan is O(n·m) with no input bound; a
9
+ * non-exact anchor past these budgets would block the event loop (measured
10
+ * ~6s at 20k×20k). Exact matches go through the fast `includes` path and stay
11
+ * allowed regardless of size. */
12
+ export declare const FUZZY_MAX_PATTERN_CHARS = 4096;
13
+ export declare const FUZZY_MAX_WORK = 8000000;
14
+ /** Trim leading whitespace of the first line and trailing whitespace of the last line. */
15
+ export declare function trimPatternBoundaries(pattern: string): string;
16
+ export declare function fuzzyPatch(content: string, oldString: string, newString: string, replaceAll?: boolean): string | null;
17
+ /** Deterministic section-extraction plan facts; the caller owns the IO and the append semantics. */
18
+ //# sourceMappingURL=fuzzy-match.d.ts.map
@@ -11,8 +11,8 @@
11
11
  * filesystem and the write origin, not on a name list.
12
12
  * @module @lmzhen/dsh-evolution-core
13
13
  */
14
- export type GateReason = 'excluded' | 'referenced' | 'suppressed' | 'protected-builtin';
15
- export interface GateSetInputs {
14
+ type GateReason = 'excluded' | 'referenced' | 'suppressed' | 'protected-builtin';
15
+ interface GateSetInputs {
16
16
  exclude?: ReadonlySet<string> | undefined;
17
17
  referenced?: ReadonlySet<string> | undefined;
18
18
  suppressed?: ReadonlySet<string> | undefined;
@@ -35,4 +35,5 @@ export declare function createGateSet(config: {
35
35
  referencedSkillNames?: ReadonlySet<string>;
36
36
  suppressedNames?: ReadonlySet<string>;
37
37
  }): EvolutionGateSet;
38
+ export {};
38
39
  //# sourceMappingURL=gates.d.ts.map
@@ -14,10 +14,27 @@
14
14
  * the sidecar directory, so two instances resolving different homes (an
15
15
  * isolated test fixture, a second DSH_HOME) do not contend, while two rows on
16
16
  * one profile do.
17
+ *
18
+ * ## Scope (v43 FLOW2-1) — this registry is PER PROCESS
19
+ *
20
+ * `claims` below is a module-scope Map: two ROWS over one home in ONE process
21
+ * contend, while the SAME home in another process gets its own Map and is
22
+ * granted the key. That is by construction, not a gap to close here — the
23
+ * cross-process half of the contract is the IO backend's write lock
24
+ * (`transactIo`, core/io.ts), which serializes a per-target read-modify-write.
25
+ * The FLOW2-1 finding was three call sites reading a GRANTED claim as "no other
26
+ * process can be doing this work", so the caller contract is stated here:
27
+ * - granted means "no other row OF THIS PROCESS owns the key";
28
+ * - `instanceHolder()` answers "who holds it HERE"; `undefined` also covers
29
+ * "held by another process";
30
+ * - a foreign holder's LIVENESS cannot be decided from a claim at all (no pid
31
+ * is recorded here): a consumer that needs that decision must carry a pid in
32
+ * its own credential and probe it (`isProcessAlive`, core/io.ts), or state
33
+ * that its action is destructive.
17
34
  * @module @lmzhen/dsh-evolution-core/src/instance-scope
18
35
  */
19
36
  /** Outcome of a claim. `holder` is the current owner either way. */
20
- export interface InstanceClaimResult {
37
+ interface InstanceClaimResult {
21
38
  readonly granted: boolean;
22
39
  readonly key: string;
23
40
  readonly holder: string;
@@ -30,6 +47,8 @@ export declare function instanceClaimKey(home: string, key: string): string;
30
47
  export declare function claimInstance(home: string, key: string, owner: string): InstanceClaimResult;
31
48
  /** Release only the claim `owner` took — never another instance's. */
32
49
  export declare function releaseInstance(home: string, key: string, owner: string): void;
33
- /** The current holder of `key` at `home`, or undefined. */
50
+ /** The current holder of `key` at `home`, IN THIS PROCESS, or undefined
51
+ * (which also covers "another process holds it" — v43 FLOW2-1). */
34
52
  export declare function instanceHolder(home: string, key: string): string | undefined;
53
+ export {};
35
54
  //# sourceMappingURL=instance-scope.d.ts.map
package/lib/types/io.d.ts CHANGED
@@ -68,6 +68,34 @@ export interface EvolutionIoLike {
68
68
  * node backend's V5-03 short-circuit).
69
69
  */
70
70
  export declare function transactIo(io: EvolutionIoLike, path: string, task: (current: string | null) => string | null | Promise<string | null>): Promise<void>;
71
+ /**
72
+ * V43 F-4 (S0-6): the shared "the transaction really invoked the task" guard.
73
+ * A backend that implements `transact` but never calls `task` resolves
74
+ * cleanly, so every caller that reads the outcome out of the task itself (a
75
+ * result slot filled inside it, a `Promise<void>` save path) reported success
76
+ * for a write that never happened — the silent-lost-write family the inline
77
+ * C-01 (memory-store) and V6-19 (skill-store) guards cover one call site at a
78
+ * time. Wrap the task handed to `transactIo`/`io.transact` and probe after
79
+ * the call: `invoked()` for a path that owns a structured refusal, or
80
+ * `assertInvoked()` for a void-returning path with no result channel (the
81
+ * family's fail-loud discipline, same wording as skill-store's guard).
82
+ *
83
+ * The wrapper is an identity pass-through — neither the backend nor the task
84
+ * sees a difference — and a task that IS invoked but skips the write (a
85
+ * dedupe no-op) counts as invoked: the probe answers "did the write path get
86
+ * to decide", not "did bytes change".
87
+ * @param what - the write being attempted, named in the thrown message
88
+ */
89
+ export interface TransactTaskGuard {
90
+ /** Wrap the task handed to the transact backend, marking its invocation. */
91
+ wrap<A, R>(task: (current: A) => R): (current: A) => R;
92
+ /** Did the backend invoke the wrapped task? */
93
+ invoked(): boolean;
94
+ /** Throw when the backend never invoked it (nothing was written). */
95
+ assertInvoked(): void;
96
+ }
97
+ /** Build a {@link TransactTaskGuard} for one write path. See its doc. */
98
+ export declare function transactTaskGuard(what: string): TransactTaskGuard;
71
99
  /** Lazy adapter over an IO provider registry, shared by every evolution consumer. */
72
100
  export declare function evolutionIoAdapter(provider: () => EvolutionIoLike): EvolutionIoLike;
73
101
  /**
@@ -181,9 +209,9 @@ export declare const LOCK_TEAR_TAKEOVER_MS = 3600000;
181
209
  */
182
210
  export declare function isCommittedWarning(error: unknown): boolean;
183
211
  /** V27 G1.1: the takeover branches, as a value. */
184
- export type TakeoverDecision = 'none' | 'dead' | 'empty' | 'corrupt';
212
+ type TakeoverDecision = 'none' | 'dead' | 'empty' | 'corrupt';
185
213
  /** V27 G1.1: one lock observation, plus the liveness probe for its pid. */
186
- export interface TakeoverProbe {
214
+ interface TakeoverProbe {
187
215
  /** Raw lock body. An empty string means the file exists with no content. */
188
216
  body: string;
189
217
  /** Lock mtime in epoch ms. */
@@ -220,4 +248,5 @@ export declare function decideTakeover(probe: TakeoverProbe): TakeoverDecision;
220
248
  * exceed the default budget and fail loud.
221
249
  */
222
250
  export declare function nodeEvolutionIo(lockAttempts?: number): EvolutionIoLike;
251
+ export {};
223
252
  //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Skill content limits: the byte/char budgets every write path validates against.
3
+ *
4
+ * Split out of skill-store.ts (S2-1) so the frontmatter validators and the
5
+ * store share one declaration site. Re-exported by skill-store.ts: the package
6
+ * export surface is unchanged.
7
+ */
8
+ export interface SkillLimits {
9
+ maxNameLength: number;
10
+ maxDescriptionLength: number;
11
+ maxSkillContentChars: number;
12
+ maxSkillFileBytes: number;
13
+ }
14
+ export declare const DEFAULT_SKILL_LIMITS: SkillLimits;
15
+ //# sourceMappingURL=limits.d.ts.map
@@ -21,9 +21,19 @@
21
21
  * `sessionScoped` is what a deployment declares: true means "act only on a
22
22
  * session that carries the family's model tools", which is the right question in
23
23
  * BOTH install forms — at profile root every session carries them, inside a
24
- * variant preset only the sessions that selected one do. The shipped bundles set
25
- * it; a bare library mount and the host-only infrastructure mode leave it false
26
- * and keep the historical "every session" behavior.
24
+ * variant preset only the sessions that selected one do. The shipped bundles all
25
+ * set it, evolution-host included (S0-4 / v43 G-1); a bare library mount leaves
26
+ * it false and keeps the historical "every session" behavior. The host-only
27
+ * install thus matches nothing unless the model tool packages are mounted some
28
+ * other way, because that bundle mounts no model tool row.
29
+ *
30
+ * S0-4 (v43 J-1 / G-1): the gate's false used to be SILENT, which left exactly
31
+ * those deployments — host-only, or an overlay that disables tool-memory /
32
+ * tool-skill-manage — indistinguishable from an ordinary per-session skip while
33
+ * review injection and skill-usage telemetry stayed off for every session. The
34
+ * witness below records what the gate saw, the first scoped miss with no match
35
+ * ever leaves ONE warn per process, and `scopedProbeReport()` is the read side
36
+ * `/evolution doctor` renders as `scoped rows × probe`.
27
37
  * @module
28
38
  */
29
39
  import type { Context } from '@deepseek-ai/cordis';
@@ -35,6 +45,25 @@ import type { Context } from '@deepseek-ai/cordis';
35
45
  * a family session. Two names, not one: a deployment may disable either row.
36
46
  */
37
47
  export declare const FAMILY_SESSION_TOOL_NAMES: readonly string[];
48
+ /** What the session-scoped gate has seen in this process. */
49
+ export interface ScopedProbeReport {
50
+ /** `hit` — at least one session carried the family tools; `never-hit` — the
51
+ * gate evaluated sessions and rejected every one; `idle` — it has not been
52
+ * asked yet (no session event reached a scoped consumer since startup). */
53
+ verdict: 'hit' | 'never-hit' | 'idle';
54
+ /** Scoped evaluations that resolved true. */
55
+ hits: number;
56
+ /** Scoped evaluations that resolved false. */
57
+ misses: number;
58
+ }
59
+ /**
60
+ * Read the witness for a diagnostic surface (`/evolution doctor`). Read-only: it
61
+ * neither evaluates the probe nor consumes the one-time warn, so a report run
62
+ * cannot change what the next miss would have logged.
63
+ * @returns the verdict with both counts, zeroed in a process where the gate has
64
+ * not run.
65
+ */
66
+ export declare function scopedProbeReport(): ScopedProbeReport;
38
67
  /**
39
68
  * Does this session's scope see the family's model tools?
40
69
  *
@@ -56,7 +85,8 @@ export declare function sessionSeesFamilyTools(ctx: Context, sessionId: string):
56
85
  * @returns true when the consumer may act on this session. A deployment that did
57
86
  * not declare session scoping always answers true (the historical behavior);
58
87
  * a scoped one answers true only for a session that carries the family's model
59
- * tools.
88
+ * tools. Each scoped answer updates the process witness, and the first miss with
89
+ * no match ever leaves one warn (see {@link noteScopedProbeMiss}).
60
90
  */
61
91
  export declare function sessionAudited(ctx: Context, sessionId: string, sessionScoped: boolean | undefined): boolean;
62
92
  //# sourceMappingURL=opt-in.d.ts.map
@@ -54,7 +54,7 @@ export type SkillHealthVerdict = 'healthy' | 'warn' | 'needs-restructure';
54
54
  * and `snapshotFromLibrary` feed `read()` verbatim. The field names predate
55
55
  * that convention; the thresholds are calibrated against the whole file, so a
56
56
  * caller must not strip frontmatter before measuring. */
57
- export interface SkillHealthSnapshot {
57
+ interface SkillHealthSnapshot {
58
58
  skillName: string;
59
59
  bodyChars: number;
60
60
  bodyText?: string | undefined;
@@ -65,7 +65,7 @@ export interface SkillHealthSnapshot {
65
65
  /** Usage-side view count, when the caller has it (A2 churn dimension). */
66
66
  readCount?: number | undefined;
67
67
  }
68
- export interface SkillHealthDim {
68
+ interface SkillHealthDim {
69
69
  bodyChars: number;
70
70
  stampDensityPerKb: number | null;
71
71
  supportGroups: number;
@@ -79,4 +79,5 @@ export interface SkillHealthAssessment {
79
79
  reasons: string[];
80
80
  }
81
81
  export declare function assessStructureHealth(snapshot: SkillHealthSnapshot, thresholds?: SkillHealthThresholds): SkillHealthAssessment;
82
+ export {};
82
83
  //# sourceMappingURL=skill-health.d.ts.map