@lmzhen/dsh-evolution-core 0.4.1 → 0.5.0

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.
@@ -368,6 +368,18 @@ export declare class SkillLibrary {
368
368
  * promises the present branch is complete (011 §7 enrichment, probe reads).
369
369
  */
370
370
  listSupportFiles(rawName: string): Promise<Probe<string[]>>;
371
+ /**
372
+ * V4 (design §16.6): exact character counts of the support files that can
373
+ * POSSIBLY exceed the content cap. The pre-filter is BYTE size, and that is
374
+ * sound rather than approximate: a UTF-16 code unit never costs less than one
375
+ * UTF-8 byte, so a file whose bytes are within the cap provably cannot exceed
376
+ * the cap in characters. The returned map is therefore COMPLETE for the
377
+ * oversize question without reading the small files.
378
+ * @param rawName - the skill's name.
379
+ * @returns path -> character count (possibly empty), or null when the listing or
380
+ * a size probe cannot answer — unknown is never an empty map.
381
+ */
382
+ supportFileChars(rawName: string): Promise<Record<string, number> | null>;
371
383
  /**
372
384
  * Structure-health facts for one skill (rc.73 A1, 008 design): body
373
385
  * chars/density from SKILL.md, support groups from countSupportDirs, plus
@@ -465,6 +477,17 @@ export declare class SkillLibrary {
465
477
  * recovery. A non-lock body shape is left alone (user file). */
466
478
  private refuseLiveLockOrSweep;
467
479
  archive(rawName: string, options?: ArchiveOptions): Promise<SkillActionResult>;
480
+ /**
481
+ * V2 (design §16.7): what an apply-mode consolidation would do for ONE source,
482
+ * computed BEFORE any side effect. `blocked` means behaviour is exactly the
483
+ * plan-mode refusal (with the reason named); `apply` carries the rewritten body
484
+ * and the support files that must be copied into the target.
485
+ * @param source - the moving skill's name.
486
+ * @param targetName - the destination skill's name.
487
+ * @param body - the moving body (frontmatter stripped).
488
+ * @returns the decision plus the note to append to a refusal.
489
+ */
490
+ private planSourceRehoming;
468
491
  /**
469
492
  * Merge the bodies of `sources` into `target` and archive the sources with
470
493
  * an absorbed-into marker. Hermes-style consolidation: overlapping skills
@@ -482,6 +505,14 @@ export declare class SkillLibrary {
482
505
  * `target/references/<source>.md` and archives the source — the demote path
483
506
  * (009-II). A source body with support-directory links is refused there too
484
507
  * (the references file would carry links whose files were archived).
508
+ *
509
+ * V2 (design §16.7) lifts that refusal when `referenceRewrite:'apply'` and the
510
+ * plan proves the move is safe: the support files the body NEEDS are copied into
511
+ * the target under their own paths (renamed only on a collision) and the body's
512
+ * references are rewritten to match, in the same commit. Anything the plan
513
+ * cannot place — a cited file the source no longer has, an unreadable listing —
514
+ * still refuses, and the refusal names it. The archived source keeps whatever
515
+ * the body did not need.
485
516
  */
486
517
  consolidate(target: string, sources: string[], origin?: WriteOrigin, options?: {
487
518
  mode?: 'append' | 'reference';
@@ -528,6 +559,19 @@ export declare class SkillLibrary {
528
559
  * Backends without the mtime probe skip pruning (no false deletes on
529
560
  * unknown age).
530
561
  */
562
+ /**
563
+ * 0.5.0 V1 (design §16.6-④): the retention window's READ half. Names every
564
+ * archived entry past the window without touching it — the report path the
565
+ * default policy uses, and the input the curator's run report carries.
566
+ * @returns the expired entry names ([] when the backend has no mtime probe,
567
+ * because an unknown age must never read as expired).
568
+ */
569
+ expiredArchives(): Promise<string[] | null>;
570
+ /** V4 (design §16.6): support-file char policy, resolved at the call site. */
571
+ supportFileCharPolicy(): 'report' | 'enforce';
572
+ /** Retention policy resolved at the call site (absent limits object = report).
573
+ * Public so a run report can say WHICH policy produced its numbers. */
574
+ archiveRetentionPolicy(): 'report' | 'prune';
531
575
  private pruneExpiredArchives;
532
576
  /**
533
577
  * Snapshot the recoverable skills state: active tree, usage/suppression
@@ -615,8 +659,8 @@ export interface NewSkillLibraryOptions {
615
659
  threatExemptLabels?: readonly string[] | undefined;
616
660
  }
617
661
  export declare function newSkillLibrary(options: NewSkillLibraryOptions): SkillLibrary;
618
- export { DEFAULT_SKILL_LIMITS } from './limits.ts';
619
- export type { SkillLimits } from './limits.ts';
662
+ export { DEFAULT_SKILL_LIMITS, DEFAULT_CITATION_POLICY, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_SUPPORT_FILE_CHAR_POLICY, POLICY_STAGE_DEFAULTS, policyStageLimits, } from './limits.ts';
663
+ export type { SkillLimits, CitationPolicy, ReferenceRewritePolicy, ArchiveRetentionPolicy, SupportFileCharPolicy, PolicyStageFields, } from './limits.ts';
620
664
  export { authoringFeedback, frontmatterBlock, frontmatterCatalogInvalid, normalizeFrontmatter, parseFrontmatter, relatedSkillNames, validateFrontmatter, yamlPlainScalarNeedsQuotes } from './frontmatter.ts';
621
665
  export type { AuthoringFeedback, Frontmatter, FrontmatterNormalizeResult, FrontmatterRead, PlatformStringSplit } from './frontmatter.ts';
622
666
  //# sourceMappingURL=skill-store.d.ts.map
@@ -186,6 +186,29 @@ export declare function isSkillReadToolName(name: string): boolean;
186
186
  * counts as a read: the platform settles every started sub-dispatch, so pending
187
187
  * is a live-window state, not a failure.
188
188
  */
189
+ /** Tool names whose dispatch reads one FILE — the deployment's file tool
190
+ * (default `read`). A differently named tool is configured, not guessed. */
191
+ export declare const DEFAULT_SUPPORT_READ_TOOL_NAMES: readonly string[];
192
+ /** One support-file read attributed to a skill (design §5.5). */
193
+ export interface SupportReadHit {
194
+ skill: string;
195
+ /** Skill-root-relative path, e.g. `references/design-x.md`. */
196
+ rel: string;
197
+ }
198
+ /**
199
+ * Read one dispatch as a SUPPORT-FILE read attributed to a skill: a read of
200
+ * `<root>/<skill>/<support dir>/…` is demand evidence for that one file, the
201
+ * way `skillReadNameOf` is demand evidence for a whole body.
202
+ * @param signal - a settled dispatch.
203
+ * @param options - the deployment's file-tool names and its skills root; an
204
+ * empty root falls back to the `/skills/` marker in the path.
205
+ * @returns the skill name and the skill-root-relative path, or `null` when the
206
+ * dispatch is not a support-file read. Pure: no IO, no service lookup.
207
+ */
208
+ export declare function supportFileReadOf(signal: ToolDispatchSignal, options: {
209
+ toolNames: readonly string[];
210
+ root: string;
211
+ }): SupportReadHit | null;
189
212
  export declare function skillReadNameOf(signal: ToolDispatchSignal): string | undefined;
190
213
  /**
191
214
  * Fold one session log into its deduplicated dispatches.
@@ -28,6 +28,11 @@ export interface UsageRecord {
28
28
  * relevant again. */
29
29
  feedback_score?: number | undefined;
30
30
  feedback_warn?: boolean | undefined;
31
+ /** Demand evidence per SUPPORT FILE (design §5.5): how many observed reads
32
+ * landed on each `references/…`-style path of this skill. Absent on every
33
+ * record written before this field existed, and on skills whose support
34
+ * files were never read — absence means "no evidence", never "zero demand". */
35
+ support_reads?: Record<string, number> | undefined;
31
36
  }
32
37
  export type UsageMap = Map<string, UsageRecord>;
33
38
  export declare function usageFile(root: string): string;
@@ -44,6 +49,8 @@ export declare function emptyRecord(): UsageRecord;
44
49
  * Pure — exported for unit tests; `loadUsage` is the production caller.
45
50
  */
46
51
  export declare function normalizeUsageRecord(record: unknown): UsageRecord;
52
+ /** Sidecar bound: a pathological path set must not grow the usage file forever. */
53
+ export declare const MAX_SUPPORT_READ_PATHS = 200;
47
54
  export declare function loadUsage(root: string, io?: EvolutionIoLike): Promise<UsageMap>;
48
55
  /**
49
56
  * Atomic read-modify-write on the usage sidecar (rc.50 P2-2): `task` receives
@@ -100,8 +107,19 @@ export declare function getRecord(map: UsageMap, name: string): UsageRecord;
100
107
  export declare function bumpView(map: UsageMap, name: string, when?: Date): void;
101
108
  export declare function bumpUse(map: UsageMap, name: string, when?: Date): void;
102
109
  export declare function bumpPatch(map: UsageMap, name: string, when?: Date): void;
110
+ /** Count one observed support-file read (design §5.5). The map is created on
111
+ * first evidence only — a skill with no support reads keeps the field absent. */
112
+ export declare function bumpSupportRead(map: UsageMap, name: string, rel: string, when?: Date): void;
103
113
  export declare function markAgentCreated(map: UsageMap, name: string): void;
104
114
  export declare function latestActivityAt(record: UsageRecord): string | null;
115
+ /** Days between an ISO timestamp (falling back to `created`) and `now`. An
116
+ * unparseable date counts as 0 days: NaN silently froze every age comparison
117
+ * (A2-9). */
118
+ export declare function daysSinceIso(iso: string | null, created: string, nowMs: number): number;
119
+ /** Idle days of one skill since its lifecycle age anchor (`last activity ??
120
+ * created_at`) — the SAME anchor the curator's transitions use, so the
121
+ * maintenance view and the lifecycle can never disagree about staleness. */
122
+ export declare function idleDays(record: UsageRecord, now?: Date): number;
105
123
  /**
106
124
  * Whether the library has ANY observed read evidence (C observation window):
107
125
  * reads were invisible to the usage sidecar before A2, so `view_count` zero
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.4.1",
4
+ "version": "0.5.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },