@plur-ai/core 0.6.0 → 0.7.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.
- package/dist/index.d.ts +60 -17
- package/dist/index.js +230 -35
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -545,13 +545,60 @@ declare const PackManifestSchema: z.ZodObject<{
|
|
|
545
545
|
}>;
|
|
546
546
|
type PackManifest = z.infer<typeof PackManifestSchema>;
|
|
547
547
|
|
|
548
|
+
interface InstallResult {
|
|
549
|
+
installed: number;
|
|
550
|
+
name: string;
|
|
551
|
+
conflicts: ConflictItem[];
|
|
552
|
+
}
|
|
553
|
+
interface ConflictItem {
|
|
554
|
+
pack_engram_id: string;
|
|
555
|
+
pack_statement: string;
|
|
556
|
+
existing_engram_id: string;
|
|
557
|
+
existing_statement: string;
|
|
558
|
+
type: 'contradiction' | 'duplicate';
|
|
559
|
+
}
|
|
560
|
+
declare function installPack(packsDir: string, source: string, existingEngrams?: Engram[]): InstallResult;
|
|
561
|
+
interface UninstallResult {
|
|
562
|
+
name: string;
|
|
563
|
+
removed: boolean;
|
|
564
|
+
engram_count: number;
|
|
565
|
+
}
|
|
566
|
+
declare function uninstallPack(packsDir: string, name: string): UninstallResult;
|
|
548
567
|
interface PackInfo {
|
|
549
568
|
name: string;
|
|
550
569
|
path: string;
|
|
551
570
|
engram_count: number;
|
|
552
571
|
manifest?: PackManifest;
|
|
572
|
+
integrity?: string;
|
|
553
573
|
}
|
|
554
574
|
declare function listPacks(packsDir: string): PackInfo[];
|
|
575
|
+
interface ExportOptions {
|
|
576
|
+
name: string;
|
|
577
|
+
version: string;
|
|
578
|
+
description?: string;
|
|
579
|
+
creator?: string;
|
|
580
|
+
domain?: string;
|
|
581
|
+
scope?: string;
|
|
582
|
+
tags?: string[];
|
|
583
|
+
type?: string;
|
|
584
|
+
}
|
|
585
|
+
interface PrivacyScanResult {
|
|
586
|
+
clean: boolean;
|
|
587
|
+
issues: PrivacyIssue[];
|
|
588
|
+
}
|
|
589
|
+
interface PrivacyIssue {
|
|
590
|
+
engram_id: string;
|
|
591
|
+
type: 'secret' | 'private_visibility' | 'personal_path' | 'email' | 'ip_address';
|
|
592
|
+
detail: string;
|
|
593
|
+
}
|
|
594
|
+
interface ExportResult {
|
|
595
|
+
path: string;
|
|
596
|
+
engram_count: number;
|
|
597
|
+
privacy: PrivacyScanResult;
|
|
598
|
+
match_terms: string[];
|
|
599
|
+
integrity: string;
|
|
600
|
+
}
|
|
601
|
+
declare function exportPack(engrams: Engram[], outputDir: string, manifest: ExportOptions): ExportResult;
|
|
555
602
|
|
|
556
603
|
interface SyncStatus {
|
|
557
604
|
initialized: boolean;
|
|
@@ -804,14 +851,14 @@ declare const StructuralTemplateSchema: z.ZodObject<{
|
|
|
804
851
|
goal_type: string;
|
|
805
852
|
constraint_type: string;
|
|
806
853
|
outcome_type: string;
|
|
807
|
-
structure_type: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
854
|
+
structure_type: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform";
|
|
808
855
|
freeform_structure?: string | undefined;
|
|
809
856
|
}, {
|
|
810
857
|
template: string;
|
|
811
858
|
goal_type: string;
|
|
812
859
|
constraint_type: string;
|
|
813
860
|
outcome_type: string;
|
|
814
|
-
structure_type?: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
861
|
+
structure_type?: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform" | undefined;
|
|
815
862
|
freeform_structure?: string | undefined;
|
|
816
863
|
}>;
|
|
817
864
|
declare const EvidenceEntrySchema: z.ZodObject<{
|
|
@@ -904,14 +951,14 @@ declare const MetaFieldSchema: z.ZodObject<{
|
|
|
904
951
|
goal_type: string;
|
|
905
952
|
constraint_type: string;
|
|
906
953
|
outcome_type: string;
|
|
907
|
-
structure_type: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
954
|
+
structure_type: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform";
|
|
908
955
|
freeform_structure?: string | undefined;
|
|
909
956
|
}, {
|
|
910
957
|
template: string;
|
|
911
958
|
goal_type: string;
|
|
912
959
|
constraint_type: string;
|
|
913
960
|
outcome_type: string;
|
|
914
|
-
structure_type?: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
961
|
+
structure_type?: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform" | undefined;
|
|
915
962
|
freeform_structure?: string | undefined;
|
|
916
963
|
}>;
|
|
917
964
|
evidence: z.ZodArray<z.ZodObject<{
|
|
@@ -1003,7 +1050,7 @@ declare const MetaFieldSchema: z.ZodObject<{
|
|
|
1003
1050
|
goal_type: string;
|
|
1004
1051
|
constraint_type: string;
|
|
1005
1052
|
outcome_type: string;
|
|
1006
|
-
structure_type: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
1053
|
+
structure_type: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform";
|
|
1007
1054
|
freeform_structure?: string | undefined;
|
|
1008
1055
|
};
|
|
1009
1056
|
evidence: {
|
|
@@ -1042,7 +1089,7 @@ declare const MetaFieldSchema: z.ZodObject<{
|
|
|
1042
1089
|
goal_type: string;
|
|
1043
1090
|
constraint_type: string;
|
|
1044
1091
|
outcome_type: string;
|
|
1045
|
-
structure_type?: "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "
|
|
1092
|
+
structure_type?: "recursive" | "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "freeform" | undefined;
|
|
1046
1093
|
freeform_structure?: string | undefined;
|
|
1047
1094
|
};
|
|
1048
1095
|
evidence: {
|
|
@@ -1385,22 +1432,18 @@ declare class Plur {
|
|
|
1385
1432
|
timeline(query?: TimelineQuery): Episode[];
|
|
1386
1433
|
/** Rule-based extraction of engram candidates from content. */
|
|
1387
1434
|
ingest(content: string, options?: IngestOptions): IngestCandidate[];
|
|
1388
|
-
/** Install a pack from a source path. */
|
|
1389
|
-
installPack(source: string):
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
/** Export engrams as a shareable pack. */
|
|
1435
|
+
/** Install a pack from a source path. Detects conflicts with existing engrams. */
|
|
1436
|
+
installPack(source: string): ReturnType<typeof installPack>;
|
|
1437
|
+
/** Uninstall a pack by name. */
|
|
1438
|
+
uninstallPack(name: string): ReturnType<typeof uninstallPack>;
|
|
1439
|
+
/** Export engrams as a shareable pack with privacy scanning and integrity hash. */
|
|
1394
1440
|
exportPack(engrams: Engram[], outputDir: string, manifest: {
|
|
1395
1441
|
name: string;
|
|
1396
1442
|
version: string;
|
|
1397
1443
|
description?: string;
|
|
1398
1444
|
creator?: string;
|
|
1399
|
-
}):
|
|
1400
|
-
|
|
1401
|
-
engram_count: number;
|
|
1402
|
-
};
|
|
1403
|
-
/** List all installed packs. */
|
|
1445
|
+
}): ReturnType<typeof exportPack>;
|
|
1446
|
+
/** List all installed packs (with integrity hashes). */
|
|
1404
1447
|
listPacks(): ReturnType<typeof listPacks>;
|
|
1405
1448
|
/** Sync engrams to git. Initializes repo on first call, commits + push/pull on subsequent calls. */
|
|
1406
1449
|
sync(remote?: string): SyncResult;
|
package/dist/index.js
CHANGED
|
@@ -1062,25 +1062,110 @@ async function expandedSearch(engrams, query, limit, llm, storagePath) {
|
|
|
1062
1062
|
// src/packs.ts
|
|
1063
1063
|
import * as fs2 from "fs";
|
|
1064
1064
|
import * as path from "path";
|
|
1065
|
+
import * as crypto from "crypto";
|
|
1065
1066
|
import yaml4 from "js-yaml";
|
|
1066
|
-
|
|
1067
|
+
|
|
1068
|
+
// src/secrets.ts
|
|
1069
|
+
var SECRET_PATTERNS = [
|
|
1070
|
+
{ name: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/ },
|
|
1071
|
+
{ name: "aws_secret_key", regex: /(?:aws_secret_access_key|secret_access_key)\s*[=:]\s*[A-Za-z0-9/+=]{40}/i },
|
|
1072
|
+
{ name: "generic_api_key", regex: /(?:^|[^a-z])(sk|pk)[-_][a-z0-9]{20,}/i },
|
|
1073
|
+
{ name: "api_key_assignment", regex: /(?:api[_-]?key|api[_-]?secret|secret[_-]?key)\s*[=:]\s*\S{20,}/i },
|
|
1074
|
+
{ name: "password_assignment", regex: /password\s*[=:]\s*\S{8,}/i },
|
|
1075
|
+
{ name: "connection_string", regex: /(?:postgres|mysql|mongodb|redis):\/\/\S+/ },
|
|
1076
|
+
{ name: "jwt", regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}/ },
|
|
1077
|
+
{ name: "private_key", regex: /-----BEGIN\s+\S+\s+PRIVATE KEY-----/ },
|
|
1078
|
+
{ name: "bearer_token", regex: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/ }
|
|
1079
|
+
];
|
|
1080
|
+
function detectSecrets(text) {
|
|
1081
|
+
const matches = [];
|
|
1082
|
+
for (const { name, regex } of SECRET_PATTERNS) {
|
|
1083
|
+
const m = text.match(regex);
|
|
1084
|
+
if (m) {
|
|
1085
|
+
matches.push({ pattern: name, match: m[0].slice(0, 20) + "..." });
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return matches;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// src/packs.ts
|
|
1092
|
+
function detectConflicts2(newEngrams, existingEngrams) {
|
|
1093
|
+
const conflicts = [];
|
|
1094
|
+
for (const ne of newEngrams) {
|
|
1095
|
+
for (const ee of existingEngrams) {
|
|
1096
|
+
const nNorm = ne.statement.toLowerCase().replace(/\s+/g, " ").trim();
|
|
1097
|
+
const eNorm = ee.statement.toLowerCase().replace(/\s+/g, " ").trim();
|
|
1098
|
+
if (nNorm === eNorm) {
|
|
1099
|
+
conflicts.push({
|
|
1100
|
+
pack_engram_id: ne.id,
|
|
1101
|
+
pack_statement: ne.statement.slice(0, 120),
|
|
1102
|
+
existing_engram_id: ee.id,
|
|
1103
|
+
existing_statement: ee.statement.slice(0, 120),
|
|
1104
|
+
type: "duplicate"
|
|
1105
|
+
});
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
if (ne.domain && ee.domain && ne.domain === ee.domain) {
|
|
1109
|
+
const nHasNever = /\b(never|don't|do not|avoid|stop)\b/i.test(ne.statement);
|
|
1110
|
+
const eHasNever = /\b(never|don't|do not|avoid|stop)\b/i.test(ee.statement);
|
|
1111
|
+
const nHasAlways = /\b(always|must|should|prefer|use)\b/i.test(ne.statement);
|
|
1112
|
+
const eHasAlways = /\b(always|must|should|prefer|use)\b/i.test(ee.statement);
|
|
1113
|
+
if (nHasNever && eHasAlways || nHasAlways && eHasNever) {
|
|
1114
|
+
const nWords = new Set(nNorm.split(" ").filter((w) => w.length > 4));
|
|
1115
|
+
const eWords = new Set(eNorm.split(" ").filter((w) => w.length > 4));
|
|
1116
|
+
const overlap = [...nWords].filter((w) => eWords.has(w));
|
|
1117
|
+
if (overlap.length >= 2) {
|
|
1118
|
+
conflicts.push({
|
|
1119
|
+
pack_engram_id: ne.id,
|
|
1120
|
+
pack_statement: ne.statement.slice(0, 120),
|
|
1121
|
+
existing_engram_id: ee.id,
|
|
1122
|
+
existing_statement: ee.statement.slice(0, 120),
|
|
1123
|
+
type: "contradiction"
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
return conflicts;
|
|
1131
|
+
}
|
|
1132
|
+
function installPack(packsDir, source, existingEngrams) {
|
|
1067
1133
|
if (!fs2.existsSync(source)) throw new Error(`Pack source not found: ${source}`);
|
|
1068
1134
|
const sourceName = path.basename(source);
|
|
1069
1135
|
const destDir = path.join(packsDir, sourceName);
|
|
1070
1136
|
if (!fs2.existsSync(destDir)) fs2.mkdirSync(destDir, { recursive: true });
|
|
1071
1137
|
const files = fs2.readdirSync(source);
|
|
1072
|
-
let copied = 0;
|
|
1073
1138
|
for (const file of files) {
|
|
1074
1139
|
const srcPath = path.join(source, file);
|
|
1075
1140
|
const destPath = path.join(destDir, file);
|
|
1076
1141
|
if (fs2.statSync(srcPath).isFile()) {
|
|
1077
1142
|
fs2.copyFileSync(srcPath, destPath);
|
|
1078
|
-
copied++;
|
|
1079
1143
|
}
|
|
1080
1144
|
}
|
|
1081
1145
|
const engramsPath = path.join(destDir, "engrams.yaml");
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1146
|
+
const newEngrams = fs2.existsSync(engramsPath) ? loadEngrams(engramsPath) : [];
|
|
1147
|
+
const conflicts = existingEngrams ? detectConflicts2(newEngrams, existingEngrams) : [];
|
|
1148
|
+
return { installed: newEngrams.length, name: sourceName, conflicts };
|
|
1149
|
+
}
|
|
1150
|
+
function uninstallPack(packsDir, name) {
|
|
1151
|
+
let packDir = path.join(packsDir, name);
|
|
1152
|
+
if (!fs2.existsSync(packDir)) {
|
|
1153
|
+
const entries = fs2.existsSync(packsDir) ? fs2.readdirSync(packsDir) : [];
|
|
1154
|
+
const match = entries.find((e) => e.toLowerCase() === name.toLowerCase());
|
|
1155
|
+
if (match) {
|
|
1156
|
+
packDir = path.join(packsDir, match);
|
|
1157
|
+
} else {
|
|
1158
|
+
throw new Error(`Pack not found: ${name}. Use 'plur packs list' to see installed packs.`);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
const engramsPath = path.join(packDir, "engrams.yaml");
|
|
1162
|
+
let count = 0;
|
|
1163
|
+
try {
|
|
1164
|
+
count = loadEngrams(engramsPath).length;
|
|
1165
|
+
} catch {
|
|
1166
|
+
}
|
|
1167
|
+
fs2.rmSync(packDir, { recursive: true, force: true });
|
|
1168
|
+
return { name, removed: true, engram_count: count };
|
|
1084
1169
|
}
|
|
1085
1170
|
function listPacks(packsDir) {
|
|
1086
1171
|
if (!fs2.existsSync(packsDir)) return [];
|
|
@@ -1094,7 +1179,8 @@ function listPacks(packsDir) {
|
|
|
1094
1179
|
name: pack.manifest.name,
|
|
1095
1180
|
path: packDir,
|
|
1096
1181
|
engram_count: pack.engrams.length,
|
|
1097
|
-
manifest: pack.manifest
|
|
1182
|
+
manifest: pack.manifest,
|
|
1183
|
+
integrity: computePackHash(packDir)
|
|
1098
1184
|
});
|
|
1099
1185
|
} catch {
|
|
1100
1186
|
const engramsPath = path.join(packDir, "engrams.yaml");
|
|
@@ -1108,7 +1194,83 @@ function listPacks(packsDir) {
|
|
|
1108
1194
|
}
|
|
1109
1195
|
return result;
|
|
1110
1196
|
}
|
|
1197
|
+
var PERSONAL_PATH_RE = /(?:\/Users\/\w+|\/home\/\w+|~\/|C:\\Users\\\w+)/;
|
|
1198
|
+
var EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
1199
|
+
var IP_RE = /\b(?:10|172\.(?:1[6-9]|2\d|3[01])|192\.168)\.\d{1,3}\.\d{1,3}\b/;
|
|
1200
|
+
function scanPrivacy(engrams) {
|
|
1201
|
+
const issues = [];
|
|
1202
|
+
for (const e of engrams) {
|
|
1203
|
+
if (e.visibility === "private") {
|
|
1204
|
+
issues.push({
|
|
1205
|
+
engram_id: e.id,
|
|
1206
|
+
type: "private_visibility",
|
|
1207
|
+
detail: `Engram marked as private \u2014 skipped from export`
|
|
1208
|
+
});
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
const text = `${e.statement} ${e.rationale ?? ""} ${e.source ?? ""}`;
|
|
1212
|
+
const secrets = detectSecrets(text);
|
|
1213
|
+
for (const s of secrets) {
|
|
1214
|
+
issues.push({
|
|
1215
|
+
engram_id: e.id,
|
|
1216
|
+
type: "secret",
|
|
1217
|
+
detail: `${s.pattern}: ${s.match}`
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
if (PERSONAL_PATH_RE.test(text)) {
|
|
1221
|
+
issues.push({
|
|
1222
|
+
engram_id: e.id,
|
|
1223
|
+
type: "personal_path",
|
|
1224
|
+
detail: `Contains personal path: ${text.match(PERSONAL_PATH_RE)?.[0]}`
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
const emailMatch = text.match(EMAIL_RE);
|
|
1228
|
+
if (emailMatch) {
|
|
1229
|
+
issues.push({
|
|
1230
|
+
engram_id: e.id,
|
|
1231
|
+
type: "email",
|
|
1232
|
+
detail: `Contains email: ${emailMatch[0]}`
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
const ipMatch = text.match(IP_RE);
|
|
1236
|
+
if (ipMatch) {
|
|
1237
|
+
issues.push({
|
|
1238
|
+
engram_id: e.id,
|
|
1239
|
+
type: "ip_address",
|
|
1240
|
+
detail: `Contains private IP: ${ipMatch[0]}`
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return { clean: issues.length === 0, issues };
|
|
1245
|
+
}
|
|
1246
|
+
function deriveMatchTerms(engrams) {
|
|
1247
|
+
const termCounts = /* @__PURE__ */ new Map();
|
|
1248
|
+
for (const e of engrams) {
|
|
1249
|
+
if (e.tags) {
|
|
1250
|
+
for (const t of e.tags) {
|
|
1251
|
+
termCounts.set(t, (termCounts.get(t) || 0) + 1);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
if (e.domain) {
|
|
1255
|
+
for (const part of e.domain.split(".")) {
|
|
1256
|
+
if (part.length > 2) {
|
|
1257
|
+
termCounts.set(part, (termCounts.get(part) || 0) + 1);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
if (e.type) {
|
|
1262
|
+
termCounts.set(e.type, (termCounts.get(e.type) || 0) + 1);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return [...termCounts.entries()].filter(([, count]) => count >= 2).sort((a, b) => b[1] - a[1]).slice(0, 20).map(([term]) => term);
|
|
1266
|
+
}
|
|
1111
1267
|
function exportPack(engrams, outputDir, manifest) {
|
|
1268
|
+
const allPrivacy = scanPrivacy(engrams);
|
|
1269
|
+
const blockedIds = new Set(
|
|
1270
|
+
allPrivacy.issues.filter((i) => i.type === "secret" || i.type === "private_visibility").map((i) => i.engram_id)
|
|
1271
|
+
);
|
|
1272
|
+
const safeEngrams = engrams.filter((e) => !blockedIds.has(e.id));
|
|
1273
|
+
const matchTerms = deriveMatchTerms(safeEngrams);
|
|
1112
1274
|
if (!fs2.existsSync(outputDir)) fs2.mkdirSync(outputDir, { recursive: true });
|
|
1113
1275
|
const frontmatter = yaml4.dump({
|
|
1114
1276
|
name: manifest.name,
|
|
@@ -1117,8 +1279,8 @@ function exportPack(engrams, outputDir, manifest) {
|
|
|
1117
1279
|
creator: manifest.creator,
|
|
1118
1280
|
metadata: {
|
|
1119
1281
|
injection_policy: "on_match",
|
|
1120
|
-
match_terms:
|
|
1121
|
-
engram_count:
|
|
1282
|
+
match_terms: matchTerms,
|
|
1283
|
+
engram_count: safeEngrams.length
|
|
1122
1284
|
}
|
|
1123
1285
|
});
|
|
1124
1286
|
fs2.writeFileSync(
|
|
@@ -1131,32 +1293,60 @@ ${frontmatter}---
|
|
|
1131
1293
|
${manifest.description || ""}
|
|
1132
1294
|
`
|
|
1133
1295
|
);
|
|
1134
|
-
const
|
|
1296
|
+
const exportEngrams = safeEngrams.map((e) => {
|
|
1297
|
+
const cleaned = { ...e };
|
|
1298
|
+
if (cleaned.relations) {
|
|
1299
|
+
cleaned.relations = {
|
|
1300
|
+
...cleaned.relations,
|
|
1301
|
+
conflicts: [],
|
|
1302
|
+
related: []
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
if (cleaned.associations) {
|
|
1306
|
+
cleaned.associations = [];
|
|
1307
|
+
}
|
|
1308
|
+
if (cleaned.knowledge_anchors) {
|
|
1309
|
+
cleaned.knowledge_anchors = [];
|
|
1310
|
+
}
|
|
1311
|
+
if (cleaned.activation) {
|
|
1312
|
+
cleaned.activation = {
|
|
1313
|
+
...cleaned.activation,
|
|
1314
|
+
frequency: 0,
|
|
1315
|
+
retrieval_strength: 0.7
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
if (cleaned.feedback_signals) {
|
|
1319
|
+
cleaned.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
|
|
1320
|
+
}
|
|
1321
|
+
return cleaned;
|
|
1322
|
+
});
|
|
1323
|
+
const content = yaml4.dump({ engrams: exportEngrams }, { lineWidth: 120, noRefs: true, quotingType: '"' });
|
|
1135
1324
|
fs2.writeFileSync(path.join(outputDir, "engrams.yaml"), content);
|
|
1136
|
-
|
|
1325
|
+
const integrity = computePackHash(outputDir);
|
|
1326
|
+
fs2.writeFileSync(path.join(outputDir, "INTEGRITY"), `sha256:${integrity}
|
|
1327
|
+
`);
|
|
1328
|
+
return {
|
|
1329
|
+
path: outputDir,
|
|
1330
|
+
engram_count: safeEngrams.length,
|
|
1331
|
+
privacy: allPrivacy,
|
|
1332
|
+
match_terms: matchTerms,
|
|
1333
|
+
integrity: `sha256:${integrity}`
|
|
1334
|
+
};
|
|
1137
1335
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
{ name: "connection_string", regex: /(?:postgres|mysql|mongodb|redis):\/\/\S+/ },
|
|
1147
|
-
{ name: "jwt", regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}/ },
|
|
1148
|
-
{ name: "private_key", regex: /-----BEGIN\s+\S+\s+PRIVATE KEY-----/ },
|
|
1149
|
-
{ name: "bearer_token", regex: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/ }
|
|
1150
|
-
];
|
|
1151
|
-
function detectSecrets(text) {
|
|
1152
|
-
const matches = [];
|
|
1153
|
-
for (const { name, regex } of SECRET_PATTERNS) {
|
|
1154
|
-
const m = text.match(regex);
|
|
1155
|
-
if (m) {
|
|
1156
|
-
matches.push({ pattern: name, match: m[0].slice(0, 20) + "..." });
|
|
1157
|
-
}
|
|
1336
|
+
function computePackHash(packDir) {
|
|
1337
|
+
const hash = crypto.createHash("sha256");
|
|
1338
|
+
const skillMd = path.join(packDir, "SKILL.md");
|
|
1339
|
+
const manifestYaml = path.join(packDir, "manifest.yaml");
|
|
1340
|
+
if (fs2.existsSync(skillMd)) {
|
|
1341
|
+
hash.update(fs2.readFileSync(skillMd));
|
|
1342
|
+
} else if (fs2.existsSync(manifestYaml)) {
|
|
1343
|
+
hash.update(fs2.readFileSync(manifestYaml));
|
|
1158
1344
|
}
|
|
1159
|
-
|
|
1345
|
+
const engramsPath = path.join(packDir, "engrams.yaml");
|
|
1346
|
+
if (fs2.existsSync(engramsPath)) {
|
|
1347
|
+
hash.update(fs2.readFileSync(engramsPath));
|
|
1348
|
+
}
|
|
1349
|
+
return hash.digest("hex");
|
|
1160
1350
|
}
|
|
1161
1351
|
|
|
1162
1352
|
// src/meta/sanitize.ts
|
|
@@ -2555,15 +2745,20 @@ var Plur = class {
|
|
|
2555
2745
|
}
|
|
2556
2746
|
return candidates;
|
|
2557
2747
|
}
|
|
2558
|
-
/** Install a pack from a source path. */
|
|
2748
|
+
/** Install a pack from a source path. Detects conflicts with existing engrams. */
|
|
2559
2749
|
installPack(source) {
|
|
2560
|
-
|
|
2750
|
+
const existing = this._loadAllEngrams();
|
|
2751
|
+
return installPack(this.paths.packs, source, existing);
|
|
2752
|
+
}
|
|
2753
|
+
/** Uninstall a pack by name. */
|
|
2754
|
+
uninstallPack(name) {
|
|
2755
|
+
return uninstallPack(this.paths.packs, name);
|
|
2561
2756
|
}
|
|
2562
|
-
/** Export engrams as a shareable pack. */
|
|
2757
|
+
/** Export engrams as a shareable pack with privacy scanning and integrity hash. */
|
|
2563
2758
|
exportPack(engrams, outputDir, manifest) {
|
|
2564
2759
|
return exportPack(engrams, outputDir, manifest);
|
|
2565
2760
|
}
|
|
2566
|
-
/** List all installed packs. */
|
|
2761
|
+
/** List all installed packs (with integrity hashes). */
|
|
2567
2762
|
listPacks() {
|
|
2568
2763
|
return listPacks(this.paths.packs);
|
|
2569
2764
|
}
|