@lmzhen/dsh-evolution-core 0.3.46 → 0.3.48
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 +26 -16
- package/lib/types/curator.d.ts +2 -2
- package/lib/types/skill-store.d.ts +6 -1
- package/lib/types/state-store.d.ts +5 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -858,8 +858,9 @@ function parseCuratorNominations(text) {
|
|
|
858
858
|
* view so the two can never disagree: records failing ANY of these gates are
|
|
859
859
|
* outside the managed scope.
|
|
860
860
|
*/
|
|
861
|
-
function lifecycleCandidate(name, record, config, bundled, gates = createGateSet(config)) {
|
|
861
|
+
function lifecycleCandidate(name, record, config, bundled, gates = createGateSet(config), protectedNames) {
|
|
862
862
|
if (record.pinned) return false;
|
|
863
|
+
if (protectedNames?.has(name) === true) return false;
|
|
863
864
|
if (gates.isBlocked(name)) return false;
|
|
864
865
|
if (!(record.created_by === "agent" || config.manageUnmanaged === true) && !(config.pruneBuiltins === true && bundled)) return false;
|
|
865
866
|
if (record.state === "archived") return false;
|
|
@@ -887,7 +888,7 @@ function computeScopeView(usage, config, protectedNames, gates) {
|
|
|
887
888
|
const suppressed = gateSet.suppressed.has(name);
|
|
888
889
|
const isBuiltin = PROTECTED_BUILTIN_SKILLS.has(name);
|
|
889
890
|
if (record.pinned || bundled || suppressed || protectedNames?.has(name) === true || isBuiltin) protectedSet.add(name);
|
|
890
|
-
if (lifecycleCandidate(name, record, config, bundled, gateSet)) {
|
|
891
|
+
if (lifecycleCandidate(name, record, config, bundled, gateSet, protectedNames)) {
|
|
891
892
|
managed.push(name);
|
|
892
893
|
if (record.state === "stale" || record.quality_warn === true) watched.push(name);
|
|
893
894
|
if (record.quality_warn === true) qualityWarned.push(name);
|
|
@@ -904,7 +905,7 @@ function computeScopeView(usage, config, protectedNames, gates) {
|
|
|
904
905
|
function daysSince(iso, created, now) {
|
|
905
906
|
return (now - new Date(iso ?? created).getTime()) / 864e5;
|
|
906
907
|
}
|
|
907
|
-
function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Date(), gates) {
|
|
908
|
+
function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Date(), gates, protectedNames) {
|
|
908
909
|
const result = {
|
|
909
910
|
transitions: [],
|
|
910
911
|
archive: [],
|
|
@@ -913,7 +914,7 @@ function computeLifecycleTransitions(usage, config, now = /* @__PURE__ */ new Da
|
|
|
913
914
|
};
|
|
914
915
|
const gateSet = gates ?? createGateSet(config);
|
|
915
916
|
for (const [name, record] of usage) {
|
|
916
|
-
if (!lifecycleCandidate(name, record, config, config.bundledNames?.has(name) === true, gateSet)) continue;
|
|
917
|
+
if (!lifecycleCandidate(name, record, config, config.bundledNames?.has(name) === true, gateSet, protectedNames)) continue;
|
|
917
918
|
const age = daysSince(null, record.created_at, now.getTime());
|
|
918
919
|
if (record.use_count === 0 && age < config.staleAfterDays) continue;
|
|
919
920
|
const idle = daysSince(latestActivityAt(record), record.created_at, now.getTime());
|
|
@@ -1770,19 +1771,19 @@ const PATTERNS = [
|
|
|
1770
1771
|
label: "exfil_curl",
|
|
1771
1772
|
category: "exfiltration",
|
|
1772
1773
|
scope: "all",
|
|
1773
|
-
regex:
|
|
1774
|
+
regex: /\bcurl\s+[^\n]{0,512}\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i
|
|
1774
1775
|
},
|
|
1775
1776
|
{
|
|
1776
1777
|
label: "exfil_wget",
|
|
1777
1778
|
category: "exfiltration",
|
|
1778
1779
|
scope: "all",
|
|
1779
|
-
regex:
|
|
1780
|
+
regex: /\bwget\s+[^\n]{0,512}\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i
|
|
1780
1781
|
},
|
|
1781
1782
|
{
|
|
1782
1783
|
label: "read_secrets",
|
|
1783
1784
|
category: "exfiltration",
|
|
1784
1785
|
scope: "all",
|
|
1785
|
-
regex:
|
|
1786
|
+
regex: /\bcat\s+[^\n]{0,512}(?:\.env|credentials|\.netrc|\.pgpass|\.npmrc|\.pypirc)/i
|
|
1786
1787
|
},
|
|
1787
1788
|
{
|
|
1788
1789
|
label: "ssh_backdoor",
|
|
@@ -2158,7 +2159,7 @@ var MemoryStore = class {
|
|
|
2158
2159
|
},
|
|
2159
2160
|
write: null
|
|
2160
2161
|
};
|
|
2161
|
-
if (hasEntryDelimiter(content)) return {
|
|
2162
|
+
if (hasEntryDelimiter(this.addDatePrefix ? `## ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}\n${content}` : content)) return {
|
|
2162
2163
|
result: {
|
|
2163
2164
|
ok: false,
|
|
2164
2165
|
message: "Fact contains the entry delimiter (§) and would split into multiple entries; rewrite it as separate facts.",
|
|
@@ -2273,7 +2274,8 @@ var MemoryStore = class {
|
|
|
2273
2274
|
},
|
|
2274
2275
|
write: null
|
|
2275
2276
|
};
|
|
2276
|
-
|
|
2277
|
+
const entryBody = this.addDatePrefix ? `## ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}\n${body}` : body;
|
|
2278
|
+
if (hasEntryDelimiter(entryBody)) return {
|
|
2277
2279
|
result: {
|
|
2278
2280
|
ok: false,
|
|
2279
2281
|
message: `Operation ${position} (add): Fact contains the entry delimiter (§) and would split into multiple entries; rewrite it as separate facts.${previewEntries(entries)}`,
|
|
@@ -2283,7 +2285,7 @@ var MemoryStore = class {
|
|
|
2283
2285
|
},
|
|
2284
2286
|
write: null
|
|
2285
2287
|
};
|
|
2286
|
-
if (!working.some((entry) => stripDatePrefix(entry) === body)) working.push(
|
|
2288
|
+
if (!working.some((entry) => stripDatePrefix(entry) === body)) working.push(entryBody);
|
|
2287
2289
|
continue;
|
|
2288
2290
|
}
|
|
2289
2291
|
const rawAction = op.action;
|
|
@@ -2695,7 +2697,7 @@ function computePrefixClusters(names) {
|
|
|
2695
2697
|
* Migrated from `evolution-review` so both channels share one implementation.
|
|
2696
2698
|
*/
|
|
2697
2699
|
const SECRET_PATTERNS = [
|
|
2698
|
-
["openai-style key",
|
|
2700
|
+
["openai-style key", /\bsk-[A-Za-z0-9_-]{16,}/g],
|
|
2699
2701
|
["aws access key", /AKIA[0-9A-Z]{16}/g],
|
|
2700
2702
|
["github token", /gh[pousr]_[A-Za-z0-9]{20,}/g],
|
|
2701
2703
|
["gitlab token", /glpat-[A-Za-z0-9_-]{16,}/g],
|
|
@@ -3042,8 +3044,13 @@ const DEFAULT_SKILL_LIMITS = {
|
|
|
3042
3044
|
};
|
|
3043
3045
|
/** Upper bound of moves per restructure proposal (validator and core agree). */
|
|
3044
3046
|
const MAX_RESTRUCTURE_MOVES = 5;
|
|
3045
|
-
/** Restructure targets are plain markdown files under references/ — no
|
|
3046
|
-
|
|
3047
|
+
/** Restructure targets are plain markdown files under references/ — no
|
|
3048
|
+
* subdirectories, no other support kind. V8-10 (0.3.47): the regex-level
|
|
3049
|
+
* `(?!.*\.\.)` keeps the restructure-created set EXACTLY the set
|
|
3050
|
+
* validateSupportPath can reopen — a `references/my..notes.md` target (double
|
|
3051
|
+
* dots) used to pass here while every later patch/write/remove on it was
|
|
3052
|
+
* refused as traversal (an orphan file the user could not touch). */
|
|
3053
|
+
const RESTRUCTURE_TARGET_RE = /^references\/[a-z0-9](?!.*\.\.)[a-z0-9._-]*\.md$/;
|
|
3047
3054
|
/** Extra file name carried inside a snapshot's `extras/` directory. */
|
|
3048
3055
|
const SNAPSHOT_EXTRA_NAME_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
3049
3056
|
function skillsRoot(env = process.env) {
|
|
@@ -4845,11 +4852,14 @@ var SkillLibrary = class {
|
|
|
4845
4852
|
*/
|
|
4846
4853
|
/**
|
|
4847
4854
|
* DSH home root: `$DSH_HOME` or `~/.dsh`. Single source of the empty-string
|
|
4848
|
-
* fallback
|
|
4849
|
-
* never to a CWD-relative path (0.3.19 W1.3, 0.3.22 F-207)
|
|
4855
|
+
* fallback — an EMPTY or WHITESPACE-ONLY DSH_HOME resolves to the default
|
|
4856
|
+
* home, never to a CWD-relative path (0.3.19 W1.3, 0.3.22 F-207);
|
|
4857
|
+
* V8-06 (0.3.47) extends the guard to whitespace (upstream home-paths:
|
|
4858
|
+
* `trim().length > 0` is the adoption test — `DSH_HOME=" "` must not produce
|
|
4859
|
+
* a sidecar under a relative "." path).
|
|
4850
4860
|
*/
|
|
4851
4861
|
function evolutionRoot(env = process.env) {
|
|
4852
|
-
return env.DSH_HOME
|
|
4862
|
+
return env.DSH_HOME?.trim() ? env.DSH_HOME : join(homedir(), ".dsh");
|
|
4853
4863
|
}
|
|
4854
4864
|
/** Evolution home path helper: `$DSH_HOME/evolution` for plugin-owned sidecar
|
|
4855
4865
|
* state (reports, activity store, feedback file, state-domain data). */
|
package/lib/types/curator.d.ts
CHANGED
|
@@ -117,7 +117,7 @@ export declare function parseCuratorNominations(text: string): CuratorNomination
|
|
|
117
117
|
* view so the two can never disagree: records failing ANY of these gates are
|
|
118
118
|
* outside the managed scope.
|
|
119
119
|
*/
|
|
120
|
-
export declare function lifecycleCandidate(name: string, record: UsageRecord, config: CuratorConfig, bundled: boolean, gates?: EvolutionGateSet): boolean;
|
|
120
|
+
export declare function lifecycleCandidate(name: string, record: UsageRecord, config: CuratorConfig, bundled: boolean, gates?: EvolutionGateSet, protectedNames?: ReadonlyMap<string, string>): boolean;
|
|
121
121
|
export interface ScopeView {
|
|
122
122
|
/** Skills inside the lifecycle scope right now (candidate gate + active state). */
|
|
123
123
|
managed: string[];
|
|
@@ -137,5 +137,5 @@ export interface ScopeView {
|
|
|
137
137
|
* records lack (bundled / hub-installed / pinned from `SkillLibrary.list()`).
|
|
138
138
|
*/
|
|
139
139
|
export declare function computeScopeView(usage: UsageMap, config: CuratorConfig, protectedNames?: ReadonlyMap<string, string>, gates?: EvolutionGateSet): ScopeView;
|
|
140
|
-
export declare function computeLifecycleTransitions(usage: UsageMap, config: CuratorConfig, now?: Date, gates?: EvolutionGateSet): CuratorResult;
|
|
140
|
+
export declare function computeLifecycleTransitions(usage: UsageMap, config: CuratorConfig, now?: Date, gates?: EvolutionGateSet, protectedNames?: ReadonlyMap<string, string>): CuratorResult;
|
|
141
141
|
//# sourceMappingURL=curator.d.ts.map
|
|
@@ -50,7 +50,12 @@ export interface SkillRestructureMove {
|
|
|
50
50
|
}
|
|
51
51
|
/** Upper bound of moves per restructure proposal (validator and core agree). */
|
|
52
52
|
export declare const MAX_RESTRUCTURE_MOVES = 5;
|
|
53
|
-
/** Restructure targets are plain markdown files under references/ — no
|
|
53
|
+
/** Restructure targets are plain markdown files under references/ — no
|
|
54
|
+
* subdirectories, no other support kind. V8-10 (0.3.47): the regex-level
|
|
55
|
+
* `(?!.*\.\.)` keeps the restructure-created set EXACTLY the set
|
|
56
|
+
* validateSupportPath can reopen — a `references/my..notes.md` target (double
|
|
57
|
+
* dots) used to pass here while every later patch/write/remove on it was
|
|
58
|
+
* refused as traversal (an orphan file the user could not touch). */
|
|
54
59
|
export declare const RESTRUCTURE_TARGET_RE: RegExp;
|
|
55
60
|
/** Extra file name carried inside a snapshot's `extras/` directory. */
|
|
56
61
|
export declare const SNAPSHOT_EXTRA_NAME_RE: RegExp;
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* DSH home root: `$DSH_HOME` or `~/.dsh`. Single source of the empty-string
|
|
7
|
-
* fallback
|
|
8
|
-
* never to a CWD-relative path (0.3.19 W1.3, 0.3.22 F-207)
|
|
7
|
+
* fallback — an EMPTY or WHITESPACE-ONLY DSH_HOME resolves to the default
|
|
8
|
+
* home, never to a CWD-relative path (0.3.19 W1.3, 0.3.22 F-207);
|
|
9
|
+
* V8-06 (0.3.47) extends the guard to whitespace (upstream home-paths:
|
|
10
|
+
* `trim().length > 0` is the adoption test — `DSH_HOME=" "` must not produce
|
|
11
|
+
* a sidecar under a relative "." path).
|
|
9
12
|
*/
|
|
10
13
|
export declare function evolutionRoot(env?: NodeJS.ProcessEnv): string;
|
|
11
14
|
/** Evolution home path helper: `$DSH_HOME/evolution` for plugin-owned sidecar
|
package/package.json
CHANGED