@lmzhen/dsh-evolution-core 0.1.0-rc.45 → 0.1.0-rc.46
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 +93 -21
- package/lib/types/curator.d.ts +4 -3
- package/lib/types/gates.d.ts +38 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/prompts.d.ts +5 -5
- package/lib/types/skill-store.d.ts +14 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -316,6 +316,53 @@ const DEFAULT_USER_CHAR_LIMIT = 1375;
|
|
|
316
316
|
const DEFAULT_CONSOLIDATION_FAILURES = 3;
|
|
317
317
|
const DEFAULT_SKILL_CONTENT_CHARS = 1e5;
|
|
318
318
|
//#endregion
|
|
319
|
+
//#region lib/types/gates.js
|
|
320
|
+
/**
|
|
321
|
+
* The control-plane protection sets, held once and queried everywhere
|
|
322
|
+
* (decision B, rc.44 plan M2): the lifecycle engine, the scope view, the LLM
|
|
323
|
+
* nomination gate and the control-plane consolidate all answer "is this name
|
|
324
|
+
* off limits — and why" from the same instance, so the gate sets can never
|
|
325
|
+
* drift apart the way the three pre-rc.46 implementations did.
|
|
326
|
+
*
|
|
327
|
+
* Scope boundary: a GateSet covers NAME-SET protections only. Marker-based
|
|
328
|
+
* protections (pinned / bundled / hub-installed) are file markers resolved by
|
|
329
|
+
* `SkillLibrary.writeProtection` / `deleteProtection` — they depend on the
|
|
330
|
+
* filesystem and the write origin, not on a name list.
|
|
331
|
+
* @module @lmzhen/dsh-evolution-core
|
|
332
|
+
*/
|
|
333
|
+
var EvolutionGateSet = class {
|
|
334
|
+
exclude;
|
|
335
|
+
referenced;
|
|
336
|
+
suppressed;
|
|
337
|
+
constructor(inputs = {}) {
|
|
338
|
+
this.exclude = inputs.exclude ?? /* @__PURE__ */ new Set();
|
|
339
|
+
this.referenced = inputs.referenced ?? /* @__PURE__ */ new Set();
|
|
340
|
+
this.suppressed = inputs.suppressed ?? /* @__PURE__ */ new Set();
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* The first protection blocking this name, or null. Any hit blocks — the
|
|
344
|
+
* order is diagnostic only, so a name in two sets reports the first.
|
|
345
|
+
*/
|
|
346
|
+
blockReason(name) {
|
|
347
|
+
if (this.exclude.has(name)) return "excluded";
|
|
348
|
+
if (this.referenced.has(name)) return "referenced";
|
|
349
|
+
if (this.suppressed.has(name)) return "suppressed";
|
|
350
|
+
if (PROTECTED_BUILTIN_SKILLS.has(name)) return "protected-builtin";
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
isBlocked(name) {
|
|
354
|
+
return this.blockReason(name) !== null;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
/** Build a GateSet from the curator-style config field names. */
|
|
358
|
+
function createGateSet(config) {
|
|
359
|
+
return new EvolutionGateSet({
|
|
360
|
+
exclude: config.excludeSkillNames,
|
|
361
|
+
referenced: config.referencedSkillNames,
|
|
362
|
+
suppressed: config.suppressedNames
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
//#endregion
|
|
319
366
|
//#region lib/types/curator.js
|
|
320
367
|
/**
|
|
321
368
|
* Deterministic skill curator: active → stale → archived transitions.
|
|
@@ -385,13 +432,10 @@ function parseCuratorNominations(text) {
|
|
|
385
432
|
* view so the two can never disagree: records failing ANY of these gates are
|
|
386
433
|
* outside the managed scope.
|
|
387
434
|
*/
|
|
388
|
-
function lifecycleCandidate(name, record, config, bundled) {
|
|
435
|
+
function lifecycleCandidate(name, record, config, bundled, gates = createGateSet(config)) {
|
|
389
436
|
if (record.pinned) return false;
|
|
390
|
-
if (
|
|
391
|
-
if (config.suppressedNames?.has(name)) return false;
|
|
392
|
-
if (config.referencedSkillNames?.has(name)) return false;
|
|
437
|
+
if (gates.isBlocked(name)) return false;
|
|
393
438
|
if (!(record.created_by === "agent" || config.manageUnmanaged === true) && !(config.pruneBuiltins === true && bundled)) return false;
|
|
394
|
-
if (PROTECTED_BUILTIN_SKILLS.has(name)) return false;
|
|
395
439
|
if (record.state === "archived") return false;
|
|
396
440
|
return true;
|
|
397
441
|
}
|
|
@@ -401,21 +445,22 @@ function lifecycleCandidate(name, record, config, bundled) {
|
|
|
401
445
|
* curator pass may touch. `protectedNames` carries the marker info the usage
|
|
402
446
|
* records lack (bundled / hub-installed / pinned from `SkillLibrary.list()`).
|
|
403
447
|
*/
|
|
404
|
-
function computeScopeView(usage, config, protectedNames) {
|
|
448
|
+
function computeScopeView(usage, config, protectedNames, gates) {
|
|
405
449
|
const managed = [];
|
|
406
450
|
const watched = [];
|
|
407
451
|
const qualityWarned = [];
|
|
408
452
|
const exempted = [];
|
|
409
453
|
const protectedSet = /* @__PURE__ */ new Set();
|
|
454
|
+
const gateSet = gates ?? createGateSet(config);
|
|
410
455
|
for (const [name, record] of usage) {
|
|
411
|
-
if (
|
|
456
|
+
if (gateSet.exclude.has(name) || gateSet.referenced.has(name)) {
|
|
412
457
|
exempted.push(name);
|
|
413
458
|
continue;
|
|
414
459
|
}
|
|
415
460
|
const bundled = config.bundledNames?.has(name) === true;
|
|
416
|
-
const suppressed =
|
|
461
|
+
const suppressed = gateSet.suppressed.has(name);
|
|
417
462
|
if (record.pinned || bundled || suppressed || protectedNames?.has(name) === true) protectedSet.add(name);
|
|
418
|
-
if (lifecycleCandidate(name, record, config, bundled)) {
|
|
463
|
+
if (lifecycleCandidate(name, record, config, bundled, gateSet)) {
|
|
419
464
|
managed.push(name);
|
|
420
465
|
if (record.state === "stale" || record.quality_warn === true) watched.push(name);
|
|
421
466
|
if (record.quality_warn === true) qualityWarned.push(name);
|
|
@@ -432,15 +477,16 @@ function computeScopeView(usage, config, protectedNames) {
|
|
|
432
477
|
function daysSince(iso, created, now) {
|
|
433
478
|
return (now - new Date(iso ?? created).getTime()) / 864e5;
|
|
434
479
|
}
|
|
435
|
-
function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Date()) {
|
|
480
|
+
function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Date(), gates) {
|
|
436
481
|
const result = {
|
|
437
482
|
transitions: [],
|
|
438
483
|
archive: [],
|
|
439
484
|
reactivate: [],
|
|
440
485
|
markStale: []
|
|
441
486
|
};
|
|
487
|
+
const gateSet = gates ?? createGateSet(config);
|
|
442
488
|
for (const [name, record] of usage) {
|
|
443
|
-
if (!lifecycleCandidate(name, record, config, config.bundledNames?.has(name) === true)) continue;
|
|
489
|
+
if (!lifecycleCandidate(name, record, config, config.bundledNames?.has(name) === true, gateSet)) continue;
|
|
444
490
|
const age = daysSince(null, record.created_at, now.getTime());
|
|
445
491
|
if (record.use_count === 0 && age < config.staleAfterDays) continue;
|
|
446
492
|
const idle = daysSince(latestActivityAt(record), record.created_at, now.getTime());
|
|
@@ -508,8 +554,8 @@ function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Da
|
|
|
508
554
|
* changes semantically: the bundle digest is the fail-closed signal for
|
|
509
555
|
* review workers, so a stale id across deployments must be distinguishable.
|
|
510
556
|
*/
|
|
511
|
-
const PROMPT_BUNDLE_ID = "dsh-evolution@
|
|
512
|
-
const PROMPT_BUNDLE_VERSION =
|
|
557
|
+
const PROMPT_BUNDLE_ID = "dsh-evolution@3";
|
|
558
|
+
const PROMPT_BUNDLE_VERSION = 3;
|
|
513
559
|
const MEMORY_REVIEW_PROMPT = `[Auto-review — Memory]
|
|
514
560
|
Review the conversation above and consider saving to memory if appropriate.
|
|
515
561
|
|
|
@@ -529,13 +575,15 @@ Signals that warrant action:
|
|
|
529
575
|
- A non-trivial technique, fix, workaround, or debugging path emerged.
|
|
530
576
|
- A loaded skill turned out wrong, missing, or outdated — patch it now.
|
|
531
577
|
|
|
578
|
+
Only update skills you loaded or read in THIS session; never touch skills you have not read.
|
|
579
|
+
|
|
532
580
|
Preference order:
|
|
533
581
|
1. Patch a skill that was loaded or read this session.
|
|
534
582
|
2. Patch an existing umbrella skill.
|
|
535
583
|
3. Add references/, templates/, or scripts/ support under an existing skill.
|
|
536
584
|
4. Create a new class-level umbrella skill only when nothing fits.
|
|
537
585
|
|
|
538
|
-
Protected skills (bundled/hub-installed) must not be edited. Pinned skills may
|
|
586
|
+
Protected skills (bundled/hub-installed) must not be edited. Pinned skills are read-only to the background review: the pinned write guard refuses background changes, so only the foreground may update or archive them.
|
|
539
587
|
|
|
540
588
|
Do NOT capture:
|
|
541
589
|
- Environment-dependent failures (missing binaries, unconfigured credentials).
|
|
@@ -551,7 +599,7 @@ Review the conversation above and update two things.
|
|
|
551
599
|
|
|
552
600
|
**Memory**: who the user is. Save durable user preferences, personal details, and expectations with the memory tool.
|
|
553
601
|
|
|
554
|
-
**Skills**: how to do this class of task. Be ACTIVE. Follow the same class-level umbrella policy, preference order, protected-skill rules, and do-not-capture list as a skill review.
|
|
602
|
+
**Skills**: how to do this class of task. Be ACTIVE. Only update skills you loaded or read in THIS session. Follow the same class-level umbrella policy, preference order, protected-skill rules, and do-not-capture list as a skill review.
|
|
555
603
|
|
|
556
604
|
Act on whichever dimension has real signal. If genuinely nothing stands out on either, say "Nothing to save." and stop — but don't reach for that conclusion as a default.`;
|
|
557
605
|
const CURATOR_PROMPT = `You are the skill curator. Maintain a healthy, class-level skill library, not a flat pile of narrow one-session skills.
|
|
@@ -599,7 +647,7 @@ If you accidentally take a mutating action, say so explicitly in the summary.`;
|
|
|
599
647
|
const COMPLETION_SKILL_REVIEW_PROMPT = `[Auto-review — Skills · task complete]
|
|
600
648
|
Your current task now appears complete. Before wrapping up, review the approach and update the skill library via skill_manage.
|
|
601
649
|
|
|
602
|
-
Follow the skills review policy: be ACTIVE, prefer class-level umbrellas, patch skills loaded this session, and capture non-trivial techniques and user corrections. Do NOT capture environment-dependent failures, negative claims about tools, or one-off task narratives.
|
|
650
|
+
Follow the skills review policy: be ACTIVE, prefer class-level umbrellas, patch ONLY skills loaded or read this session, and capture non-trivial techniques and user corrections. Do NOT capture environment-dependent failures, negative claims about tools, or one-off task narratives.
|
|
603
651
|
|
|
604
652
|
Do NOT modify output files or re-run the task. If you are still mid-task, ignore this.`;
|
|
605
653
|
function reviewPrompt(kind) {
|
|
@@ -613,12 +661,12 @@ function sha256(text) {
|
|
|
613
661
|
function createPromptBundle(prompts) {
|
|
614
662
|
const canonical = JSON.stringify({
|
|
615
663
|
id: PROMPT_BUNDLE_ID,
|
|
616
|
-
version:
|
|
664
|
+
version: 3,
|
|
617
665
|
prompts: Object.fromEntries(Object.entries(prompts).sort())
|
|
618
666
|
});
|
|
619
667
|
return Object.freeze({
|
|
620
668
|
id: PROMPT_BUNDLE_ID,
|
|
621
|
-
version:
|
|
669
|
+
version: 3,
|
|
622
670
|
prompts: Object.freeze({ ...prompts }),
|
|
623
671
|
sha256: sha256(canonical)
|
|
624
672
|
});
|
|
@@ -631,10 +679,10 @@ const PROMPT_BUNDLE = createPromptBundle({
|
|
|
631
679
|
completion: COMPLETION_SKILL_REVIEW_PROMPT
|
|
632
680
|
});
|
|
633
681
|
function verifyPromptBundle(bundle = PROMPT_BUNDLE) {
|
|
634
|
-
if (bundle.id !== "dsh-evolution@
|
|
682
|
+
if (bundle.id !== "dsh-evolution@3" || bundle.version !== 3) return false;
|
|
635
683
|
const canonical = JSON.stringify({
|
|
636
684
|
id: PROMPT_BUNDLE_ID,
|
|
637
|
-
version:
|
|
685
|
+
version: 3,
|
|
638
686
|
prompts: Object.fromEntries(Object.entries(bundle.prompts).sort())
|
|
639
687
|
});
|
|
640
688
|
return bundle.sha256 === sha256(canonical);
|
|
@@ -1641,6 +1689,30 @@ const SNAPSHOT_EXTRA_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
|
1641
1689
|
function skillsRoot(env = process.env) {
|
|
1642
1690
|
return join(env.DSH_HOME ?? join(homedir(), ".dsh"), "skills");
|
|
1643
1691
|
}
|
|
1692
|
+
/**
|
|
1693
|
+
* Map a requesting session onto the two origin surfaces (rc.44 plan M2-2.3):
|
|
1694
|
+
* the APPROVAL surface treats every delegated subagent as the autonomous
|
|
1695
|
+
* review channel, while the LIBRARY surface keeps the Hermes distinction -
|
|
1696
|
+
* the review fork is 'background_review' (the pinned guard blocks its
|
|
1697
|
+
* writes) and any other subagent is 'subagent' (agent-authored, not
|
|
1698
|
+
* review-channel). `isReview` marks the caller as the background review
|
|
1699
|
+
* pipeline itself. Single source: the two tools and the review executor all
|
|
1700
|
+
* read this table instead of re-deriving it.
|
|
1701
|
+
*/
|
|
1702
|
+
function resolveOrigins(headerOrigin, isReview = false) {
|
|
1703
|
+
if (isReview) return {
|
|
1704
|
+
approval: "background_review",
|
|
1705
|
+
library: "background_review"
|
|
1706
|
+
};
|
|
1707
|
+
if (headerOrigin === "subagent") return {
|
|
1708
|
+
approval: "background_review",
|
|
1709
|
+
library: "subagent"
|
|
1710
|
+
};
|
|
1711
|
+
return {
|
|
1712
|
+
approval: "foreground",
|
|
1713
|
+
library: "foreground"
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1644
1716
|
function skillDir(root, name) {
|
|
1645
1717
|
return join(root, name);
|
|
1646
1718
|
}
|
|
@@ -2560,4 +2632,4 @@ var JsonState = class JsonState {
|
|
|
2560
2632
|
}
|
|
2561
2633
|
};
|
|
2562
2634
|
//#endregion
|
|
2563
|
-
export { COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CONSOLIDATION_FAILURES, 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, SNAPSHOT_EXTRA_NAME_RE, 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, normalizeUsageRecord, observeEvent, parseCuratorNominations, parseFrontmatter, recordMutation, relatedSkillNames, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, usageFile, validateFrontmatter, verifyPromptBundle };
|
|
2635
|
+
export { COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CONSOLIDATION_FAILURES, 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, EvolutionGateSet, 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, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, advanceReview, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpUse, bumpView, computeDedupGroups, computeLifecycleTransitions, computeQualityScores, computeScopeView, contentHash, createGateSet, emptyRecord, evaluateThreat, evolutionHome, evolutionIoAdapter, foldTurn, getRecord, latestActivityAt, lifecycleCandidate, loadMutations, loadSuppressedNames, loadUsage, markAgentCreated, memoryRoot, mutationsFile, nodeEvolutionIo, normalizeUsageRecord, observeEvent, parseCuratorNominations, parseFrontmatter, recordMutation, relatedSkillNames, resolveOrigins, reviewPrompt, saveSuppressedNames, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, suppressedFile, usageFile, validateFrontmatter, verifyPromptBundle };
|
package/lib/types/curator.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* after. File moves are performed by SkillLibrary.
|
|
7
7
|
*/
|
|
8
8
|
import type { UsageMap, UsageRecord } from './usage.ts';
|
|
9
|
+
import { EvolutionGateSet } from './gates.ts';
|
|
9
10
|
export { PROTECTED_BUILTIN_SKILLS } from './constants.ts';
|
|
10
11
|
export interface CuratorConfig {
|
|
11
12
|
staleAfterDays: number;
|
|
@@ -95,7 +96,7 @@ export declare function parseCuratorNominations(text: string): CuratorNomination
|
|
|
95
96
|
* view so the two can never disagree: records failing ANY of these gates are
|
|
96
97
|
* outside the managed scope.
|
|
97
98
|
*/
|
|
98
|
-
export declare function lifecycleCandidate(name: string, record: UsageRecord, config: CuratorConfig, bundled: boolean): boolean;
|
|
99
|
+
export declare function lifecycleCandidate(name: string, record: UsageRecord, config: CuratorConfig, bundled: boolean, gates?: EvolutionGateSet): boolean;
|
|
99
100
|
export interface ScopeView {
|
|
100
101
|
/** Skills inside the lifecycle scope right now (candidate gate + active state). */
|
|
101
102
|
managed: string[];
|
|
@@ -114,6 +115,6 @@ export interface ScopeView {
|
|
|
114
115
|
* curator pass may touch. `protectedNames` carries the marker info the usage
|
|
115
116
|
* records lack (bundled / hub-installed / pinned from `SkillLibrary.list()`).
|
|
116
117
|
*/
|
|
117
|
-
export declare function computeScopeView(usage: UsageMap, config: CuratorConfig, protectedNames?: ReadonlyMap<string, string
|
|
118
|
-
export declare function computeLifecycleTransitions(usage: UsageMap, config: CuratorConfig, now?: Date): CuratorResult;
|
|
118
|
+
export declare function computeScopeView(usage: UsageMap, config: CuratorConfig, protectedNames?: ReadonlyMap<string, string>, gates?: EvolutionGateSet): ScopeView;
|
|
119
|
+
export declare function computeLifecycleTransitions(usage: UsageMap, config: CuratorConfig, now?: Date, gates?: EvolutionGateSet): CuratorResult;
|
|
119
120
|
//# sourceMappingURL=curator.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The control-plane protection sets, held once and queried everywhere
|
|
3
|
+
* (decision B, rc.44 plan M2): the lifecycle engine, the scope view, the LLM
|
|
4
|
+
* nomination gate and the control-plane consolidate all answer "is this name
|
|
5
|
+
* off limits — and why" from the same instance, so the gate sets can never
|
|
6
|
+
* drift apart the way the three pre-rc.46 implementations did.
|
|
7
|
+
*
|
|
8
|
+
* Scope boundary: a GateSet covers NAME-SET protections only. Marker-based
|
|
9
|
+
* protections (pinned / bundled / hub-installed) are file markers resolved by
|
|
10
|
+
* `SkillLibrary.writeProtection` / `deleteProtection` — they depend on the
|
|
11
|
+
* filesystem and the write origin, not on a name list.
|
|
12
|
+
* @module @deepseek-ai/dsh-evolution-core
|
|
13
|
+
*/
|
|
14
|
+
export type GateReason = 'excluded' | 'referenced' | 'suppressed' | 'protected-builtin';
|
|
15
|
+
export interface GateSetInputs {
|
|
16
|
+
exclude?: ReadonlySet<string> | undefined;
|
|
17
|
+
referenced?: ReadonlySet<string> | undefined;
|
|
18
|
+
suppressed?: ReadonlySet<string> | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare class EvolutionGateSet {
|
|
21
|
+
readonly exclude: ReadonlySet<string>;
|
|
22
|
+
readonly referenced: ReadonlySet<string>;
|
|
23
|
+
readonly suppressed: ReadonlySet<string>;
|
|
24
|
+
constructor(inputs?: GateSetInputs);
|
|
25
|
+
/**
|
|
26
|
+
* The first protection blocking this name, or null. Any hit blocks — the
|
|
27
|
+
* order is diagnostic only, so a name in two sets reports the first.
|
|
28
|
+
*/
|
|
29
|
+
blockReason(name: string): GateReason | null;
|
|
30
|
+
isBlocked(name: string): boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Build a GateSet from the curator-style config field names. */
|
|
33
|
+
export declare function createGateSet(config: {
|
|
34
|
+
excludeSkillNames?: ReadonlySet<string>;
|
|
35
|
+
referencedSkillNames?: ReadonlySet<string>;
|
|
36
|
+
suppressedNames?: ReadonlySet<string>;
|
|
37
|
+
}): EvolutionGateSet;
|
|
38
|
+
//# sourceMappingURL=gates.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
package/lib/types/prompts.d.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* changes semantically: the bundle digest is the fail-closed signal for
|
|
4
4
|
* review workers, so a stale id across deployments must be distinguishable.
|
|
5
5
|
*/
|
|
6
|
-
export declare const PROMPT_BUNDLE_ID = "dsh-evolution@
|
|
7
|
-
export declare const PROMPT_BUNDLE_VERSION =
|
|
6
|
+
export declare const PROMPT_BUNDLE_ID = "dsh-evolution@3";
|
|
7
|
+
export declare const PROMPT_BUNDLE_VERSION = 3;
|
|
8
8
|
export declare const MEMORY_REVIEW_PROMPT = "[Auto-review \u2014 Memory]\nReview the conversation above and consider saving to memory if appropriate.\n\nFocus on:\n1. Has the user revealed things about themselves \u2014 persona, desires, preferences, or personal details worth remembering?\n2. Has the user expressed expectations about how you should behave, their work style, or ways they want you to operate?\n\nIf something stands out, save it using the memory tool.\nIf nothing is worth saving, just say \"Nothing to save.\" and stop.";
|
|
9
|
-
export declare const SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skills]\nReview the conversation above and update the skill library. Be ACTIVE \u2014 most sessions produce at least one skill update, even if small.\n\nTarget shape: CLASS-LEVEL skills with a rich SKILL.md and a references/ directory for session-specific detail. Not a flat list of narrow one-session skills.\n\nSignals that warrant action:\n- The user corrected your style, tone, format, verbosity, workflow, or approach.\n- A non-trivial technique, fix, workaround, or debugging path emerged.\n- A loaded skill turned out wrong, missing, or outdated \u2014 patch it now.\n\nPreference order:\n1. Patch a skill that was loaded or read this session.\n2. Patch an existing umbrella skill.\n3. Add references/, templates/, or scripts/ support under an existing skill.\n4. Create a new class-level umbrella skill only when nothing fits.\n\nProtected skills (bundled/hub-installed) must not be edited. Pinned skills may
|
|
10
|
-
export declare const COMBINED_REVIEW_PROMPT = "[Auto-review]\nReview the conversation above and update two things.\n\n**Memory**: who the user is. Save durable user preferences, personal details, and expectations with the memory tool.\n\n**Skills**: how to do this class of task. Be ACTIVE. Follow the same class-level umbrella policy, preference order, protected-skill rules, and do-not-capture list as a skill review.\n\nAct on whichever dimension has real signal. If genuinely nothing stands out on either, say \"Nothing to save.\" and stop \u2014 but don't reach for that conclusion as a default.";
|
|
9
|
+
export declare const SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skills]\nReview the conversation above and update the skill library. Be ACTIVE \u2014 most sessions produce at least one skill update, even if small.\n\nTarget shape: CLASS-LEVEL skills with a rich SKILL.md and a references/ directory for session-specific detail. Not a flat list of narrow one-session skills.\n\nSignals that warrant action:\n- The user corrected your style, tone, format, verbosity, workflow, or approach.\n- A non-trivial technique, fix, workaround, or debugging path emerged.\n- A loaded skill turned out wrong, missing, or outdated \u2014 patch it now.\n\nOnly update skills you loaded or read in THIS session; never touch skills you have not read.\n\nPreference order:\n1. Patch a skill that was loaded or read this session.\n2. Patch an existing umbrella skill.\n3. Add references/, templates/, or scripts/ support under an existing skill.\n4. Create a new class-level umbrella skill only when nothing fits.\n\nProtected skills (bundled/hub-installed) must not be edited. Pinned skills are read-only to the background review: the pinned write guard refuses background changes, so only the foreground may update or archive them.\n\nDo NOT capture:\n- Environment-dependent failures (missing binaries, unconfigured credentials).\n- Negative claims about tools (\"browser tools do not work\").\n- Transient errors that resolved during the session.\n- One-off task narratives.\n\nIf a tool failed because of setup state, capture the FIX under an existing setup skill \u2014 never \"this tool does not work\" as a standalone constraint.\n\n\"Nothing to save.\" is a real option but should NOT be the default.";
|
|
10
|
+
export declare const COMBINED_REVIEW_PROMPT = "[Auto-review]\nReview the conversation above and update two things.\n\n**Memory**: who the user is. Save durable user preferences, personal details, and expectations with the memory tool.\n\n**Skills**: how to do this class of task. Be ACTIVE. Only update skills you loaded or read in THIS session. Follow the same class-level umbrella policy, preference order, protected-skill rules, and do-not-capture list as a skill review.\n\nAct on whichever dimension has real signal. If genuinely nothing stands out on either, say \"Nothing to save.\" and stop \u2014 but don't reach for that conclusion as a default.";
|
|
11
11
|
export declare const CURATOR_PROMPT = "You are the skill curator. Maintain a healthy, class-level skill library, not a flat pile of narrow one-session skills.\n\nThe goal is a LIBRARY OF CLASS-LEVEL INSTRUCTIONS. A skill collection of many narrow skills where each captures one session's specific bug is a FAILURE of the library. An agent searching skills matches on descriptions, not exact names; one broad umbrella with labeled subsections beats five narrow siblings for discoverability.\n\nRight target shape: class-level skills with rich SKILL.md + references/, templates/, scripts/ support files for session-specific detail.\n\nHard rules:\n1. NEVER hard-delete a skill. Archive (moving to .archive/) is the maximum destructive action; archives are recoverable, deletion is not.\n2. Do not touch bundled, hub-installed, pinned, or scheduled-task-referenced (`referenced`) skills. Referenced skills MAY be consolidated into an umbrella, but never simply pruned.\n3. Do not archive recently-created or never-used skills without strong evidence. \"use=0\" is NOT evidence either way \u2014 it only means the trigger has not come up yet.\n4. Do NOT reject consolidation on the grounds that \"each skill has a distinct trigger\". The right bar is: would a human maintainer write this as N separate skills, or one skill with N labeled subsections? When the answer is the latter, merge.\n5. Judge overlap on CONTENT, not on usage counters.\n6. Before archiving a merged skill, ensure its unique content was preserved in the umbrella.\n\nHow to work:\n1. Scan the candidate list. Identify PREFIX CLUSTERS \u2014 skills sharing a first word or domain keyword (expect 10-25 clusters).\n2. For each cluster with 2+ members, ask \"what is the UMBRELLA CLASS these skills serve?\" and consolidate:\n a. MERGE INTO AN EXISTING UMBRELLA (patch a labeled section for each sibling's unique insight, then archive the siblings).\n b. CREATE A NEW UMBRELLA SKILL.md covering the shared workflow with short labeled subsections, then archive the absorbed siblings.\n c. DEMOTE session-specific detail to references/, templates/, or scripts/ under the umbrella.\n3. Keep the umbrella body tight and scannable: exact commands, verbatim paths, ~100-200 lines; never invent flags or APIs.\n\nProduce a YAML summary with exactly this shape:\nconsolidations:\n - from: <old-skill-name>\n into: <umbrella-skill-name>\n reason: <one short sentence>\nprunings:\n - name: <skill-name>\n reason: <one short sentence>\nNominate a pruning only when archival is clearly safe (stale AND genuinely obsolete or fully absorbed elsewhere).";
|
|
12
12
|
export declare const CURATOR_DRY_RUN_BANNER = "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nDRY-RUN \u2014 REPORT ONLY. DO NOT MUTATE THE SKILL LIBRARY.\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nThis is a PREVIEW pass. Follow every instruction above EXCEPT:\n \u2022 Do NOT call skill_manage with action=create, update, patch, delete, write_file, or remove_file.\n \u2022 Do NOT move, copy, or rewrite any file under the skills tree.\n\nYour output IS the deliverable: produce the exact same human-readable summary and YAML block you would on a live run, describing the actions you WOULD take. A reviewer will decide whether to approve a live run.\n\nIf you accidentally take a mutating action, say so explicitly in the summary.";
|
|
13
|
-
export declare const COMPLETION_SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skills \u00B7 task complete]\nYour current task now appears complete. Before wrapping up, review the approach and update the skill library via skill_manage.\n\nFollow the skills review policy: be ACTIVE, prefer class-level umbrellas, patch skills loaded this session, and capture non-trivial techniques and user corrections. Do NOT capture environment-dependent failures, negative claims about tools, or one-off task narratives.\n\nDo NOT modify output files or re-run the task. If you are still mid-task, ignore this.";
|
|
13
|
+
export declare const COMPLETION_SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skills \u00B7 task complete]\nYour current task now appears complete. Before wrapping up, review the approach and update the skill library via skill_manage.\n\nFollow the skills review policy: be ACTIVE, prefer class-level umbrellas, patch ONLY skills loaded or read this session, and capture non-trivial techniques and user corrections. Do NOT capture environment-dependent failures, negative claims about tools, or one-off task narratives.\n\nDo NOT modify output files or re-run the task. If you are still mid-task, ignore this.";
|
|
14
14
|
export declare function reviewPrompt(kind: 'memory' | 'skill' | 'combined'): string;
|
|
15
15
|
export interface PromptBundle {
|
|
16
16
|
id: string;
|
|
@@ -60,6 +60,20 @@ export interface ArchiveOptions {
|
|
|
60
60
|
allowBundled?: boolean;
|
|
61
61
|
}
|
|
62
62
|
export declare function skillsRoot(env?: NodeJS.ProcessEnv): string;
|
|
63
|
+
/**
|
|
64
|
+
* Map a requesting session onto the two origin surfaces (rc.44 plan M2-2.3):
|
|
65
|
+
* the APPROVAL surface treats every delegated subagent as the autonomous
|
|
66
|
+
* review channel, while the LIBRARY surface keeps the Hermes distinction -
|
|
67
|
+
* the review fork is 'background_review' (the pinned guard blocks its
|
|
68
|
+
* writes) and any other subagent is 'subagent' (agent-authored, not
|
|
69
|
+
* review-channel). `isReview` marks the caller as the background review
|
|
70
|
+
* pipeline itself. Single source: the two tools and the review executor all
|
|
71
|
+
* read this table instead of re-deriving it.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveOrigins(headerOrigin: string | undefined, isReview?: boolean): {
|
|
74
|
+
approval: 'foreground' | 'background_review';
|
|
75
|
+
library: WriteOrigin;
|
|
76
|
+
};
|
|
63
77
|
export interface Frontmatter {
|
|
64
78
|
name?: string;
|
|
65
79
|
description?: string;
|
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.46",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|