@lmzhen/dsh-evolution-core 0.1.0-rc.1 → 0.1.0-rc.11
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 +159 -22
- package/lib/types/io.d.ts +0 -2
- package/lib/types/memory-store.d.ts +8 -0
- package/lib/types/skill-store.d.ts +12 -0
- package/lib/types/state-store.d.ts +7 -0
- package/lib/types/threats.d.ts +16 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -72,10 +72,6 @@ function nodeEvolutionIo() {
|
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
/** Absolute path helper kept separate so stores stay platform-correct. */
|
|
76
|
-
function childPath(parent, ...parts) {
|
|
77
|
-
return join(parent, ...parts);
|
|
78
|
-
}
|
|
79
75
|
//#endregion
|
|
80
76
|
//#region lib/types/usage.js
|
|
81
77
|
/**
|
|
@@ -417,10 +413,12 @@ const SCOPE_ORDER = {
|
|
|
417
413
|
context: 2,
|
|
418
414
|
strict: 3
|
|
419
415
|
};
|
|
416
|
+
const NO_SCAN_OPTIONS = {};
|
|
420
417
|
/**
|
|
421
418
|
* Scan text at `scope`. Patterns are cumulative: `strict` includes all scopes.
|
|
419
|
+
* `options.excludeLabels` removes matching patterns without changing `scope`.
|
|
422
420
|
*/
|
|
423
|
-
function scanThreats(text, scope = "strict", maxScanChars = 65536) {
|
|
421
|
+
function scanThreats(text, scope = "strict", maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
|
|
424
422
|
const findings = [];
|
|
425
423
|
if (ZERO_WIDTH_CHARS.test(text)) findings.push({
|
|
426
424
|
label: "unicode_zero_width",
|
|
@@ -433,8 +431,10 @@ function scanThreats(text, scope = "strict", maxScanChars = 65536) {
|
|
|
433
431
|
scope
|
|
434
432
|
});
|
|
435
433
|
const normalized = text.normalize("NFKC").slice(0, maxScanChars);
|
|
434
|
+
const excluded = new Set(options.excludeLabels ?? []);
|
|
436
435
|
for (const pattern of PATTERNS) {
|
|
437
436
|
if (SCOPE_ORDER[pattern.scope] > SCOPE_ORDER[scope]) continue;
|
|
437
|
+
if (excluded.has(pattern.label)) continue;
|
|
438
438
|
if (pattern.regex.test(normalized)) findings.push({
|
|
439
439
|
label: pattern.label,
|
|
440
440
|
category: pattern.category,
|
|
@@ -444,24 +444,24 @@ function scanThreats(text, scope = "strict", maxScanChars = 65536) {
|
|
|
444
444
|
return findings;
|
|
445
445
|
}
|
|
446
446
|
/** Blocking policy: any hit blocks. `severity` is deliberately not a gate. */
|
|
447
|
-
function evaluateThreat(text, scope = "strict", maxScanChars = 65536) {
|
|
448
|
-
const findings = scanThreats(text, scope, maxScanChars);
|
|
447
|
+
function evaluateThreat(text, scope = "strict", maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
|
|
448
|
+
const findings = scanThreats(text, scope, maxScanChars, options);
|
|
449
449
|
return {
|
|
450
450
|
blocked: findings.length > 0,
|
|
451
451
|
findings
|
|
452
452
|
};
|
|
453
453
|
}
|
|
454
454
|
/** User-facing block message for memory writes. */
|
|
455
|
-
function scanMemoryThreats(text, maxScanChars = 65536) {
|
|
456
|
-
const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars);
|
|
455
|
+
function scanMemoryThreats(text, maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
|
|
456
|
+
const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars, options);
|
|
457
457
|
if (!blocked) return null;
|
|
458
458
|
const pattern = findings.find((f) => f.category !== "unicode_obfuscation");
|
|
459
459
|
if (pattern) return `Blocked by security scan (${pattern.label}). Rephrase without instruction-like language.`;
|
|
460
460
|
return "Blocked by security scan: invisible or potentially malicious Unicode detected.";
|
|
461
461
|
}
|
|
462
462
|
/** User-facing block message for skill content writes. */
|
|
463
|
-
function scanContentThreats(text, maxScanChars = 65536) {
|
|
464
|
-
const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars);
|
|
463
|
+
function scanContentThreats(text, maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
|
|
464
|
+
const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars, options);
|
|
465
465
|
if (!blocked) return null;
|
|
466
466
|
return `Blocked by security scan (${findings[0]?.label ?? "unknown"}). This content appears to contain potentially malicious instructions.`;
|
|
467
467
|
}
|
|
@@ -762,10 +762,18 @@ var MemoryStore = class {
|
|
|
762
762
|
await this.write("memory", snapshot.memory);
|
|
763
763
|
await this.write("user", snapshot.user);
|
|
764
764
|
}
|
|
765
|
+
/**
|
|
766
|
+
* Detect on-disk drift: true when the file is not in the canonical
|
|
767
|
+
* `render(normalizeEntries(raw))` form. This catches structural anomalies
|
|
768
|
+
* the writer would quietly normalize away (empty/`§`-only entries, stray
|
|
769
|
+
* blank lines, leading/trailing delimiters) that indicate the file was
|
|
770
|
+
* edited outside MemoryStore. Purely single-canonical content reaches the
|
|
771
|
+
* same serialization and returns false, so a normal write is never flagged.
|
|
772
|
+
*/
|
|
765
773
|
async detectDrift(target) {
|
|
766
774
|
const raw = await this.io.readText(fileFor(this.root, target));
|
|
767
775
|
if (raw === null) return false;
|
|
768
|
-
return normalizeEntries(raw)
|
|
776
|
+
return render(normalizeEntries(raw)) !== raw;
|
|
769
777
|
}
|
|
770
778
|
};
|
|
771
779
|
//#endregion
|
|
@@ -1278,6 +1286,128 @@ var SkillLibrary = class {
|
|
|
1278
1286
|
path: dest
|
|
1279
1287
|
};
|
|
1280
1288
|
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Merge the bodies of `sources` into `target` and archive the sources with
|
|
1291
|
+
* an absorbed-into marker. Hermes-style consolidation: overlapping skills
|
|
1292
|
+
* collapse into one, and the originals stay recoverable under `.archive/`.
|
|
1293
|
+
*/
|
|
1294
|
+
async consolidate(target, sources) {
|
|
1295
|
+
const normalizedSources = [...new Set(sources)].filter((name) => name !== target);
|
|
1296
|
+
if (normalizedSources.length === 0) return {
|
|
1297
|
+
ok: false,
|
|
1298
|
+
message: "Consolidation requires at least one distinct source skill."
|
|
1299
|
+
};
|
|
1300
|
+
for (const name of [target, ...normalizedSources]) if (!SKILL_NAME_RE.test(name)) return {
|
|
1301
|
+
ok: false,
|
|
1302
|
+
message: `Invalid skill name "${name}". Use lowercase letters, digits, and hyphens.`
|
|
1303
|
+
};
|
|
1304
|
+
const targetDir = skillDir(this.root, target);
|
|
1305
|
+
const targetMd = await this.io.readText(join(targetDir, "SKILL.md"));
|
|
1306
|
+
if (!targetMd) return {
|
|
1307
|
+
ok: false,
|
|
1308
|
+
message: `Skill "${target}" not found.`
|
|
1309
|
+
};
|
|
1310
|
+
const targetProtection = await this.writeProtection(target);
|
|
1311
|
+
if (targetProtection) return {
|
|
1312
|
+
ok: false,
|
|
1313
|
+
message: `Skill "${target}" is protected (${targetProtection}).`
|
|
1314
|
+
};
|
|
1315
|
+
const parts = [];
|
|
1316
|
+
for (const source of normalizedSources) {
|
|
1317
|
+
const protection = await this.deleteProtection(source);
|
|
1318
|
+
if (protection) return {
|
|
1319
|
+
ok: false,
|
|
1320
|
+
message: `Skill "${source}" is protected (${protection}).`
|
|
1321
|
+
};
|
|
1322
|
+
const sourceMd = await this.io.readText(join(skillDir(this.root, source), "SKILL.md"));
|
|
1323
|
+
if (!sourceMd) return {
|
|
1324
|
+
ok: false,
|
|
1325
|
+
message: `Skill "${source}" not found.`
|
|
1326
|
+
};
|
|
1327
|
+
const parsed = parseFrontmatter(sourceMd);
|
|
1328
|
+
if (!parsed) return {
|
|
1329
|
+
ok: false,
|
|
1330
|
+
message: `Skill "${source}" has no valid frontmatter; refusing to merge.`
|
|
1331
|
+
};
|
|
1332
|
+
parts.push(`\n<!-- consolidated from ${source} at ${(/* @__PURE__ */ new Date()).toISOString()} -->\n${parsed.body.trim()}`);
|
|
1333
|
+
}
|
|
1334
|
+
const merged = targetMd.trimEnd() + parts.join("\n") + "\n";
|
|
1335
|
+
const validation = validateFrontmatter(merged, target, this.limits);
|
|
1336
|
+
if (validation) return {
|
|
1337
|
+
ok: false,
|
|
1338
|
+
message: `Consolidation rejected: ${validation}`
|
|
1339
|
+
};
|
|
1340
|
+
const threat = scanContentThreats(merged);
|
|
1341
|
+
if (threat) return {
|
|
1342
|
+
ok: false,
|
|
1343
|
+
message: threat
|
|
1344
|
+
};
|
|
1345
|
+
const archived = [];
|
|
1346
|
+
try {
|
|
1347
|
+
for (const source of normalizedSources) {
|
|
1348
|
+
const result = await this.archive(source, target);
|
|
1349
|
+
if (!result.ok) return result;
|
|
1350
|
+
archived.push(source);
|
|
1351
|
+
}
|
|
1352
|
+
await this.io.writeText(join(targetDir, "SKILL.md"), merged);
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
await this.io.writeText(join(targetDir, "SKILL.md"), targetMd).catch(() => {});
|
|
1355
|
+
for (const source of archived.reverse()) await this.restoreFromArchive(source).catch(() => {});
|
|
1356
|
+
return {
|
|
1357
|
+
ok: false,
|
|
1358
|
+
message: `Consolidation failed and was rolled back: ${error instanceof Error ? error.message : String(error)}`
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
return {
|
|
1362
|
+
ok: true,
|
|
1363
|
+
message: `Consolidated ${normalizedSources.join(", ")} into "${target}".`,
|
|
1364
|
+
path: targetDir
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Restore one skill from `.archive/` back to the active root. Hermes-style
|
|
1369
|
+
* recoverability: archival never deletes, and this is the control-plane
|
|
1370
|
+
* path back. The `.archive-reason` marker is dropped on restore.
|
|
1371
|
+
*/
|
|
1372
|
+
async restoreFromArchive(name) {
|
|
1373
|
+
if (!SKILL_NAME_RE.test(name)) return {
|
|
1374
|
+
ok: false,
|
|
1375
|
+
message: `Invalid skill name "${name}". Use lowercase letters, digits, and hyphens.`
|
|
1376
|
+
};
|
|
1377
|
+
if (await this.io.exists(join(skillDir(this.root, name), "SKILL.md"))) return {
|
|
1378
|
+
ok: false,
|
|
1379
|
+
message: `Skill "${name}" already exists in the active root; refusing to overwrite.`
|
|
1380
|
+
};
|
|
1381
|
+
const archiveRoot = join(this.root, ".archive");
|
|
1382
|
+
let entries;
|
|
1383
|
+
try {
|
|
1384
|
+
entries = await this.io.list(archiveRoot);
|
|
1385
|
+
} catch {
|
|
1386
|
+
return {
|
|
1387
|
+
ok: false,
|
|
1388
|
+
message: "No skill archive available."
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
const chosen = entries.filter((entry) => entry === name || entry.startsWith(`${name}-`)).sort().reverse()[0];
|
|
1392
|
+
if (!chosen) return {
|
|
1393
|
+
ok: false,
|
|
1394
|
+
message: `Skill "${name}" is not in .archive.`
|
|
1395
|
+
};
|
|
1396
|
+
const source = join(archiveRoot, chosen);
|
|
1397
|
+
const dest = skillDir(this.root, name);
|
|
1398
|
+
try {
|
|
1399
|
+
await this.io.rename(source, dest);
|
|
1400
|
+
} catch {
|
|
1401
|
+
await this.io.copy(source, dest);
|
|
1402
|
+
await this.io.remove(source);
|
|
1403
|
+
}
|
|
1404
|
+
if (await this.io.exists(join(dest, ".archive-reason"))) await this.io.remove(join(dest, ".archive-reason"));
|
|
1405
|
+
return {
|
|
1406
|
+
ok: true,
|
|
1407
|
+
message: `Skill "${name}" restored from .archive.`,
|
|
1408
|
+
path: dest
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1281
1411
|
async writeSupportFile(name, filePath, content) {
|
|
1282
1412
|
const dir = skillDir(this.root, name);
|
|
1283
1413
|
if (!await this.io.exists(join(dir, "SKILL.md"))) return {
|
|
@@ -1403,7 +1533,7 @@ var SkillLibrary = class {
|
|
|
1403
1533
|
function evolutionHome(env = process.env) {
|
|
1404
1534
|
return join(env.DSH_HOME ?? join(homedir(), ".dsh"), "evolution");
|
|
1405
1535
|
}
|
|
1406
|
-
var JsonState = class {
|
|
1536
|
+
var JsonState = class JsonState {
|
|
1407
1537
|
initial;
|
|
1408
1538
|
path;
|
|
1409
1539
|
value;
|
|
@@ -1412,14 +1542,24 @@ var JsonState = class {
|
|
|
1412
1542
|
this.path = join(evolutionHome(env), name);
|
|
1413
1543
|
this.value = this.loadSync();
|
|
1414
1544
|
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Deep-merge persisted state over the initial defaults. Nested plain
|
|
1547
|
+
* objects merge recursively (so a new default field added under an existing
|
|
1548
|
+
* object is preserved), while arrays and primitives take the on-disk value
|
|
1549
|
+
* wholesale. Keeps forward-compatible defaults across schema additions.
|
|
1550
|
+
*/
|
|
1551
|
+
static mergeDeep(initial, persisted) {
|
|
1552
|
+
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1553
|
+
if (!isRecord(initial) || !isRecord(persisted)) return isRecord(persisted) ? persisted : persisted == null ? initial : persisted;
|
|
1554
|
+
const out = { ...initial };
|
|
1555
|
+
for (const [key, value] of Object.entries(persisted)) out[key] = key in initial ? JsonState.mergeDeep(initial[key], value) : value;
|
|
1556
|
+
return out;
|
|
1557
|
+
}
|
|
1415
1558
|
loadSync() {
|
|
1416
1559
|
try {
|
|
1417
1560
|
const raw = readFileSync(this.path, "utf8");
|
|
1418
1561
|
const parsed = JSON.parse(raw);
|
|
1419
|
-
return
|
|
1420
|
-
...this.initial,
|
|
1421
|
-
...parsed
|
|
1422
|
-
};
|
|
1562
|
+
return JsonState.mergeDeep(this.initial, parsed);
|
|
1423
1563
|
} catch {
|
|
1424
1564
|
return { ...this.initial };
|
|
1425
1565
|
}
|
|
@@ -1443,14 +1583,11 @@ var JsonState = class {
|
|
|
1443
1583
|
async reload() {
|
|
1444
1584
|
try {
|
|
1445
1585
|
const raw = await readFile(this.path, "utf8");
|
|
1446
|
-
this.value =
|
|
1447
|
-
...this.initial,
|
|
1448
|
-
...JSON.parse(raw)
|
|
1449
|
-
};
|
|
1586
|
+
this.value = JsonState.mergeDeep(this.initial, JSON.parse(raw));
|
|
1450
1587
|
} catch {
|
|
1451
1588
|
this.value = { ...this.initial };
|
|
1452
1589
|
}
|
|
1453
1590
|
}
|
|
1454
1591
|
};
|
|
1455
1592
|
//#endregion
|
|
1456
|
-
export { COMBINED_REVIEW_PROMPT, CURATOR_PROMPT, DEFAULT_SKILL_LIMITS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, JsonState, MAX_DESCRIPTION_LENGTH, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MEMORY_REVIEW_PROMPT, MemoryStore, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROTECTED_BUILTIN_SKILLS, SKILL_NAME_RE, SKILL_REVIEW_PROMPT, SUPPORT_DIRS, SkillLibrary, advanceReview, buildCuratorRunReport, bumpPatch, bumpUse, bumpView,
|
|
1593
|
+
export { COMBINED_REVIEW_PROMPT, CURATOR_PROMPT, DEFAULT_SKILL_LIMITS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, JsonState, MAX_DESCRIPTION_LENGTH, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MEMORY_REVIEW_PROMPT, MemoryStore, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROTECTED_BUILTIN_SKILLS, SKILL_NAME_RE, SKILL_REVIEW_PROMPT, SUPPORT_DIRS, SkillLibrary, advanceReview, buildCuratorRunReport, bumpPatch, bumpUse, bumpView, computeLifecycleTransitions, emptyRecord, evaluateThreat, evolutionHome, evolutionIoAdapter, foldTurn, getRecord, latestActivityAt, loadUsage, markAgentCreated, memoryRoot, nodeEvolutionIo, observeEvent, parseFrontmatter, reviewPrompt, saveUsage, scanContentThreats, scanMemoryThreats, scanThreats, skillsRoot, usageFile, validateFrontmatter, verifyPromptBundle };
|
package/lib/types/io.d.ts
CHANGED
|
@@ -17,6 +17,4 @@ export interface EvolutionIoLike {
|
|
|
17
17
|
/** Lazy adapter over an IO provider registry, shared by every evolution consumer. */
|
|
18
18
|
export declare function evolutionIoAdapter(provider: () => EvolutionIoLike): EvolutionIoLike;
|
|
19
19
|
export declare function nodeEvolutionIo(): EvolutionIoLike;
|
|
20
|
-
/** Absolute path helper kept separate so stores stay platform-correct. */
|
|
21
|
-
export declare function childPath(parent: string, ...parts: string[]): string;
|
|
22
20
|
//# sourceMappingURL=io.d.ts.map
|
|
@@ -55,6 +55,14 @@ export declare class MemoryStore {
|
|
|
55
55
|
memory: string[];
|
|
56
56
|
user: string[];
|
|
57
57
|
}): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Detect on-disk drift: true when the file is not in the canonical
|
|
60
|
+
* `render(normalizeEntries(raw))` form. This catches structural anomalies
|
|
61
|
+
* the writer would quietly normalize away (empty/`§`-only entries, stray
|
|
62
|
+
* blank lines, leading/trailing delimiters) that indicate the file was
|
|
63
|
+
* edited outside MemoryStore. Purely single-canonical content reaches the
|
|
64
|
+
* same serialization and returns false, so a normal write is never flagged.
|
|
65
|
+
*/
|
|
58
66
|
detectDrift(target: MemoryTarget): Promise<boolean>;
|
|
59
67
|
}
|
|
60
68
|
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -58,6 +58,18 @@ export declare class SkillLibrary {
|
|
|
58
58
|
update(name: string, content: string): Promise<SkillActionResult>;
|
|
59
59
|
patch(name: string, oldString: string, newString: string, filePath?: string, replaceAll?: boolean): Promise<SkillActionResult>;
|
|
60
60
|
archive(name: string, absorbedInto?: string): Promise<SkillActionResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Merge the bodies of `sources` into `target` and archive the sources with
|
|
63
|
+
* an absorbed-into marker. Hermes-style consolidation: overlapping skills
|
|
64
|
+
* collapse into one, and the originals stay recoverable under `.archive/`.
|
|
65
|
+
*/
|
|
66
|
+
consolidate(target: string, sources: string[]): Promise<SkillActionResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Restore one skill from `.archive/` back to the active root. Hermes-style
|
|
69
|
+
* recoverability: archival never deletes, and this is the control-plane
|
|
70
|
+
* path back. The `.archive-reason` marker is dropped on restore.
|
|
71
|
+
*/
|
|
72
|
+
restoreFromArchive(name: string): Promise<SkillActionResult>;
|
|
61
73
|
writeSupportFile(name: string, filePath: string, content: string): Promise<SkillActionResult>;
|
|
62
74
|
removeSupportFile(name: string, filePath: string): Promise<SkillActionResult>;
|
|
63
75
|
snapshotAll(reason?: string): Promise<string>;
|
|
@@ -8,6 +8,13 @@ export declare class JsonState<T> {
|
|
|
8
8
|
readonly path: string;
|
|
9
9
|
private value;
|
|
10
10
|
constructor(name: string, initial: T, env?: NodeJS.ProcessEnv);
|
|
11
|
+
/**
|
|
12
|
+
* Deep-merge persisted state over the initial defaults. Nested plain
|
|
13
|
+
* objects merge recursively (so a new default field added under an existing
|
|
14
|
+
* object is preserved), while arrays and primitives take the on-disk value
|
|
15
|
+
* wholesale. Keeps forward-compatible defaults across schema additions.
|
|
16
|
+
*/
|
|
17
|
+
private static mergeDeep;
|
|
11
18
|
private loadSync;
|
|
12
19
|
get(): T;
|
|
13
20
|
set(value: T): void;
|
package/lib/types/threats.d.ts
CHANGED
|
@@ -12,17 +12,29 @@ export interface ThreatFinding {
|
|
|
12
12
|
category: string;
|
|
13
13
|
scope: ThreatScope;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Optional scan controls. Default behavior (`options` omitted) is unchanged:
|
|
17
|
+
* every in-scope pattern blocks. Adapters that need to tolerate a specific
|
|
18
|
+
* benign phrasing (e.g. a skill that legitimately opens with "You are now a ...")
|
|
19
|
+
* can exclude that label by name here. This is opt-in and never widens strict
|
|
20
|
+
* scope; it only permits callers to drop a known-innocent match.
|
|
21
|
+
*/
|
|
22
|
+
export interface ScanOptions {
|
|
23
|
+
/** Pattern labels to skip during this scan. */
|
|
24
|
+
excludeLabels?: readonly string[];
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* Scan text at `scope`. Patterns are cumulative: `strict` includes all scopes.
|
|
28
|
+
* `options.excludeLabels` removes matching patterns without changing `scope`.
|
|
17
29
|
*/
|
|
18
|
-
export declare function scanThreats(text: string, scope?: ThreatScope, maxScanChars?: number): ThreatFinding[];
|
|
30
|
+
export declare function scanThreats(text: string, scope?: ThreatScope, maxScanChars?: number, options?: ScanOptions): ThreatFinding[];
|
|
19
31
|
/** Blocking policy: any hit blocks. `severity` is deliberately not a gate. */
|
|
20
|
-
export declare function evaluateThreat(text: string, scope?: ThreatScope, maxScanChars?: number): {
|
|
32
|
+
export declare function evaluateThreat(text: string, scope?: ThreatScope, maxScanChars?: number, options?: ScanOptions): {
|
|
21
33
|
blocked: boolean;
|
|
22
34
|
findings: ThreatFinding[];
|
|
23
35
|
};
|
|
24
36
|
/** User-facing block message for memory writes. */
|
|
25
|
-
export declare function scanMemoryThreats(text: string, maxScanChars?: number): string | null;
|
|
37
|
+
export declare function scanMemoryThreats(text: string, maxScanChars?: number, options?: ScanOptions): string | null;
|
|
26
38
|
/** User-facing block message for skill content writes. */
|
|
27
|
-
export declare function scanContentThreats(text: string, maxScanChars?: number): string | null;
|
|
39
|
+
export declare function scanContentThreats(text: string, maxScanChars?: number, options?: ScanOptions): string | null;
|
|
28
40
|
//# sourceMappingURL=threats.d.ts.map
|
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.11",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|