@joshuaswarren/openclaw-engram 8.3.17 → 8.3.18
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.js +235 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4317,6 +4317,104 @@ function confidenceTier(score) {
|
|
|
4317
4317
|
}
|
|
4318
4318
|
var SPECULATIVE_TTL_DAYS = 30;
|
|
4319
4319
|
|
|
4320
|
+
// src/identity-continuity.ts
|
|
4321
|
+
function parseFrontmatterValue(raw) {
|
|
4322
|
+
try {
|
|
4323
|
+
return JSON.parse(raw);
|
|
4324
|
+
} catch {
|
|
4325
|
+
return raw;
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
function parseFrontmatter(raw) {
|
|
4329
|
+
const parsed = {};
|
|
4330
|
+
for (const line of raw.split("\n")) {
|
|
4331
|
+
const idx = line.indexOf(":");
|
|
4332
|
+
if (idx <= 0) continue;
|
|
4333
|
+
const key = line.slice(0, idx).trim();
|
|
4334
|
+
const value = line.slice(idx + 1).trim();
|
|
4335
|
+
parsed[key] = parseFrontmatterValue(value);
|
|
4336
|
+
}
|
|
4337
|
+
return parsed;
|
|
4338
|
+
}
|
|
4339
|
+
function emitSection(lines, title, value) {
|
|
4340
|
+
if (!value || value.trim().length === 0) return;
|
|
4341
|
+
lines.push(`## ${title}`, "", value.trim(), "");
|
|
4342
|
+
}
|
|
4343
|
+
function parseSection(body, title) {
|
|
4344
|
+
const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4345
|
+
const re = new RegExp(`## ${escaped}\\n\\n([\\s\\S]*?)(?=\\n## |$)`);
|
|
4346
|
+
const match = body.match(re);
|
|
4347
|
+
if (!match) return void 0;
|
|
4348
|
+
const value = match[1].trim();
|
|
4349
|
+
return value.length > 0 ? value : void 0;
|
|
4350
|
+
}
|
|
4351
|
+
function serializeContinuityIncident(incident) {
|
|
4352
|
+
const lines = [
|
|
4353
|
+
"---",
|
|
4354
|
+
`id: ${JSON.stringify(incident.id)}`,
|
|
4355
|
+
`state: ${JSON.stringify(incident.state)}`,
|
|
4356
|
+
`openedAt: ${JSON.stringify(incident.openedAt)}`,
|
|
4357
|
+
`updatedAt: ${JSON.stringify(incident.updatedAt)}`
|
|
4358
|
+
];
|
|
4359
|
+
if (incident.closedAt) lines.push(`closedAt: ${JSON.stringify(incident.closedAt)}`);
|
|
4360
|
+
if (incident.triggerWindow) lines.push(`triggerWindow: ${JSON.stringify(incident.triggerWindow)}`);
|
|
4361
|
+
lines.push("---", "");
|
|
4362
|
+
emitSection(lines, "Symptom", incident.symptom);
|
|
4363
|
+
emitSection(lines, "Suspected Cause", incident.suspectedCause);
|
|
4364
|
+
emitSection(lines, "Fix Applied", incident.fixApplied);
|
|
4365
|
+
emitSection(lines, "Verification Result", incident.verificationResult);
|
|
4366
|
+
emitSection(lines, "Preventive Rule", incident.preventiveRule);
|
|
4367
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
4368
|
+
}
|
|
4369
|
+
function parseContinuityIncident(raw) {
|
|
4370
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
4371
|
+
if (!match) return null;
|
|
4372
|
+
const frontmatter = parseFrontmatter(match[1]);
|
|
4373
|
+
const body = match[2] ?? "";
|
|
4374
|
+
const id = typeof frontmatter.id === "string" ? frontmatter.id : "";
|
|
4375
|
+
const stateRaw = frontmatter.state;
|
|
4376
|
+
const state = stateRaw === "closed" ? "closed" : stateRaw === "open" ? "open" : "open";
|
|
4377
|
+
const openedAt = typeof frontmatter.openedAt === "string" ? frontmatter.openedAt : "";
|
|
4378
|
+
const updatedAt = typeof frontmatter.updatedAt === "string" ? frontmatter.updatedAt : openedAt;
|
|
4379
|
+
const symptom = parseSection(body, "Symptom");
|
|
4380
|
+
if (!id || !openedAt || !updatedAt || !symptom) return null;
|
|
4381
|
+
return {
|
|
4382
|
+
id,
|
|
4383
|
+
state,
|
|
4384
|
+
openedAt,
|
|
4385
|
+
updatedAt,
|
|
4386
|
+
triggerWindow: typeof frontmatter.triggerWindow === "string" ? frontmatter.triggerWindow : void 0,
|
|
4387
|
+
symptom,
|
|
4388
|
+
suspectedCause: parseSection(body, "Suspected Cause"),
|
|
4389
|
+
fixApplied: parseSection(body, "Fix Applied"),
|
|
4390
|
+
verificationResult: parseSection(body, "Verification Result"),
|
|
4391
|
+
preventiveRule: parseSection(body, "Preventive Rule"),
|
|
4392
|
+
closedAt: typeof frontmatter.closedAt === "string" ? frontmatter.closedAt : void 0
|
|
4393
|
+
};
|
|
4394
|
+
}
|
|
4395
|
+
function createContinuityIncidentRecord(id, input, nowIso) {
|
|
4396
|
+
return {
|
|
4397
|
+
id,
|
|
4398
|
+
state: "open",
|
|
4399
|
+
openedAt: nowIso,
|
|
4400
|
+
updatedAt: nowIso,
|
|
4401
|
+
triggerWindow: input.triggerWindow?.trim() || void 0,
|
|
4402
|
+
symptom: input.symptom.trim(),
|
|
4403
|
+
suspectedCause: input.suspectedCause?.trim() || void 0
|
|
4404
|
+
};
|
|
4405
|
+
}
|
|
4406
|
+
function closeContinuityIncidentRecord(incident, closure, nowIso) {
|
|
4407
|
+
return {
|
|
4408
|
+
...incident,
|
|
4409
|
+
state: "closed",
|
|
4410
|
+
updatedAt: nowIso,
|
|
4411
|
+
closedAt: nowIso,
|
|
4412
|
+
fixApplied: closure.fixApplied.trim(),
|
|
4413
|
+
verificationResult: closure.verificationResult.trim(),
|
|
4414
|
+
preventiveRule: closure.preventiveRule?.trim() || incident.preventiveRule
|
|
4415
|
+
};
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4320
4418
|
// src/storage.ts
|
|
4321
4419
|
var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
|
|
4322
4420
|
"a",
|
|
@@ -4416,7 +4514,7 @@ function serializeFrontmatter(fm) {
|
|
|
4416
4514
|
lines.push("---");
|
|
4417
4515
|
return lines.join("\n");
|
|
4418
4516
|
}
|
|
4419
|
-
function
|
|
4517
|
+
function parseFrontmatter2(raw) {
|
|
4420
4518
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
4421
4519
|
if (!match) return null;
|
|
4422
4520
|
const fmBlock = match[1];
|
|
@@ -4804,6 +4902,24 @@ var StorageManager = class _StorageManager {
|
|
|
4804
4902
|
get artifactsDir() {
|
|
4805
4903
|
return path4.join(this.baseDir, "artifacts");
|
|
4806
4904
|
}
|
|
4905
|
+
get identityDir() {
|
|
4906
|
+
return path4.join(this.baseDir, "identity");
|
|
4907
|
+
}
|
|
4908
|
+
get identityAnchorPath() {
|
|
4909
|
+
return path4.join(this.identityDir, "identity-anchor.md");
|
|
4910
|
+
}
|
|
4911
|
+
get identityIncidentsDir() {
|
|
4912
|
+
return path4.join(this.identityDir, "incidents");
|
|
4913
|
+
}
|
|
4914
|
+
get identityAuditsWeeklyDir() {
|
|
4915
|
+
return path4.join(this.identityDir, "audits", "weekly");
|
|
4916
|
+
}
|
|
4917
|
+
get identityAuditsMonthlyDir() {
|
|
4918
|
+
return path4.join(this.identityDir, "audits", "monthly");
|
|
4919
|
+
}
|
|
4920
|
+
get identityImprovementLoopsPath() {
|
|
4921
|
+
return path4.join(this.identityDir, "improvement-loops.md");
|
|
4922
|
+
}
|
|
4807
4923
|
get profilePath() {
|
|
4808
4924
|
return path4.join(this.baseDir, "profile.md");
|
|
4809
4925
|
}
|
|
@@ -4839,6 +4955,10 @@ var StorageManager = class _StorageManager {
|
|
|
4839
4955
|
await mkdir2(this.stateDir, { recursive: true });
|
|
4840
4956
|
await mkdir2(this.questionsDir, { recursive: true });
|
|
4841
4957
|
await mkdir2(this.artifactsDir, { recursive: true });
|
|
4958
|
+
await mkdir2(this.identityDir, { recursive: true });
|
|
4959
|
+
await mkdir2(this.identityIncidentsDir, { recursive: true });
|
|
4960
|
+
await mkdir2(this.identityAuditsWeeklyDir, { recursive: true });
|
|
4961
|
+
await mkdir2(this.identityAuditsMonthlyDir, { recursive: true });
|
|
4842
4962
|
await mkdir2(path4.join(this.baseDir, "config"), { recursive: true });
|
|
4843
4963
|
}
|
|
4844
4964
|
async writeMemory(category, content, options = {}) {
|
|
@@ -5114,7 +5234,7 @@ ${sanitized.text}
|
|
|
5114
5234
|
} else if (entry.name.endsWith(".md")) {
|
|
5115
5235
|
try {
|
|
5116
5236
|
const raw = await readFile2(fullPath, "utf-8");
|
|
5117
|
-
const parsed =
|
|
5237
|
+
const parsed = parseFrontmatter2(raw);
|
|
5118
5238
|
if (parsed) {
|
|
5119
5239
|
memories.push({
|
|
5120
5240
|
path: fullPath,
|
|
@@ -5150,7 +5270,7 @@ ${sanitized.text}
|
|
|
5150
5270
|
} else if (entry.name.endsWith(".md")) {
|
|
5151
5271
|
try {
|
|
5152
5272
|
const raw = await readFile2(fullPath, "utf-8");
|
|
5153
|
-
const parsed =
|
|
5273
|
+
const parsed = parseFrontmatter2(raw);
|
|
5154
5274
|
if (parsed) {
|
|
5155
5275
|
memories.push({
|
|
5156
5276
|
path: fullPath,
|
|
@@ -5172,7 +5292,7 @@ ${sanitized.text}
|
|
|
5172
5292
|
async readMemoryByPath(filePath) {
|
|
5173
5293
|
try {
|
|
5174
5294
|
const raw = await readFile2(filePath, "utf-8");
|
|
5175
|
-
const parsed =
|
|
5295
|
+
const parsed = parseFrontmatter2(raw);
|
|
5176
5296
|
if (!parsed) return null;
|
|
5177
5297
|
return { path: filePath, frontmatter: parsed.frontmatter, content: parsed.content };
|
|
5178
5298
|
} catch {
|
|
@@ -5448,6 +5568,86 @@ ${memory.content}
|
|
|
5448
5568
|
return null;
|
|
5449
5569
|
}
|
|
5450
5570
|
}
|
|
5571
|
+
async writeIdentityAnchor(content) {
|
|
5572
|
+
await this.ensureDirectories();
|
|
5573
|
+
await writeFile2(this.identityAnchorPath, content, "utf-8");
|
|
5574
|
+
}
|
|
5575
|
+
async readIdentityAnchor() {
|
|
5576
|
+
try {
|
|
5577
|
+
return await readFile2(this.identityAnchorPath, "utf-8");
|
|
5578
|
+
} catch {
|
|
5579
|
+
return null;
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
async appendContinuityIncident(input) {
|
|
5583
|
+
await this.ensureDirectories();
|
|
5584
|
+
const now = /* @__PURE__ */ new Date();
|
|
5585
|
+
const nowIso = now.toISOString();
|
|
5586
|
+
const date = nowIso.slice(0, 10);
|
|
5587
|
+
const id = this.generateId("incident");
|
|
5588
|
+
const incident = createContinuityIncidentRecord(id, input, nowIso);
|
|
5589
|
+
const filePath = path4.join(this.identityIncidentsDir, `${date}-${id}.md`);
|
|
5590
|
+
await writeFile2(filePath, serializeContinuityIncident(incident), "utf-8");
|
|
5591
|
+
return { ...incident, filePath };
|
|
5592
|
+
}
|
|
5593
|
+
async readContinuityIncidents(limit = 200) {
|
|
5594
|
+
const cappedLimit = Math.max(0, Math.floor(limit));
|
|
5595
|
+
if (cappedLimit === 0) return [];
|
|
5596
|
+
try {
|
|
5597
|
+
const candidates = await this.readContinuityIncidentFileNames();
|
|
5598
|
+
const incidents = [];
|
|
5599
|
+
for (const file of candidates) {
|
|
5600
|
+
if (incidents.length >= cappedLimit) break;
|
|
5601
|
+
const filePath = path4.join(this.identityIncidentsDir, file);
|
|
5602
|
+
try {
|
|
5603
|
+
const raw = await readFile2(filePath, "utf-8");
|
|
5604
|
+
const parsed = parseContinuityIncident(raw);
|
|
5605
|
+
if (parsed) incidents.push({ ...parsed, filePath });
|
|
5606
|
+
} catch {
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
return incidents;
|
|
5610
|
+
} catch {
|
|
5611
|
+
return [];
|
|
5612
|
+
}
|
|
5613
|
+
}
|
|
5614
|
+
async closeContinuityIncident(id, closure) {
|
|
5615
|
+
const directFilePath = await this.findContinuityIncidentFilePathById(id);
|
|
5616
|
+
const target = directFilePath ? await this.readContinuityIncidentFile(directFilePath) : null;
|
|
5617
|
+
if (!target || !directFilePath) return null;
|
|
5618
|
+
if (target.state === "closed") return target;
|
|
5619
|
+
const closed = closeContinuityIncidentRecord(target, closure, (/* @__PURE__ */ new Date()).toISOString());
|
|
5620
|
+
await writeFile2(directFilePath, serializeContinuityIncident(closed), "utf-8");
|
|
5621
|
+
return { ...closed, filePath: directFilePath };
|
|
5622
|
+
}
|
|
5623
|
+
async writeIdentityAudit(period, key, content) {
|
|
5624
|
+
await this.ensureDirectories();
|
|
5625
|
+
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
5626
|
+
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
5627
|
+
const filePath = path4.join(dir, `${safeKey}.md`);
|
|
5628
|
+
await writeFile2(filePath, content, "utf-8");
|
|
5629
|
+
return filePath;
|
|
5630
|
+
}
|
|
5631
|
+
async readIdentityAudit(period, key) {
|
|
5632
|
+
try {
|
|
5633
|
+
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
5634
|
+
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
5635
|
+
return await readFile2(path4.join(dir, `${safeKey}.md`), "utf-8");
|
|
5636
|
+
} catch {
|
|
5637
|
+
return null;
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
async writeIdentityImprovementLoops(content) {
|
|
5641
|
+
await this.ensureDirectories();
|
|
5642
|
+
await writeFile2(this.identityImprovementLoopsPath, content, "utf-8");
|
|
5643
|
+
}
|
|
5644
|
+
async readIdentityImprovementLoops() {
|
|
5645
|
+
try {
|
|
5646
|
+
return await readFile2(this.identityImprovementLoopsPath, "utf-8");
|
|
5647
|
+
} catch {
|
|
5648
|
+
return null;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5451
5651
|
// ---------------------------------------------------------------------------
|
|
5452
5652
|
// Question storage
|
|
5453
5653
|
// ---------------------------------------------------------------------------
|
|
@@ -5456,6 +5656,37 @@ ${memory.content}
|
|
|
5456
5656
|
const rand = Math.random().toString(36).slice(2, 4);
|
|
5457
5657
|
return `${prefix}-${ts}-${rand}`;
|
|
5458
5658
|
}
|
|
5659
|
+
async readContinuityIncidentFileNames() {
|
|
5660
|
+
const files = await readdir(this.identityIncidentsDir);
|
|
5661
|
+
return files.filter((file) => file.endsWith(".md")).sort().reverse();
|
|
5662
|
+
}
|
|
5663
|
+
async readContinuityIncidentFile(filePath) {
|
|
5664
|
+
try {
|
|
5665
|
+
const raw = await readFile2(filePath, "utf-8");
|
|
5666
|
+
const parsed = parseContinuityIncident(raw);
|
|
5667
|
+
return parsed ? { ...parsed, filePath } : null;
|
|
5668
|
+
} catch {
|
|
5669
|
+
return null;
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
async findContinuityIncidentFilePathById(id) {
|
|
5673
|
+
const fileNames = await this.readContinuityIncidentFileNames();
|
|
5674
|
+
const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
|
|
5675
|
+
if (directMatch) return path4.join(this.identityIncidentsDir, directMatch);
|
|
5676
|
+
for (const fileName of fileNames) {
|
|
5677
|
+
const filePath = path4.join(this.identityIncidentsDir, fileName);
|
|
5678
|
+
const parsed = await this.readContinuityIncidentFile(filePath);
|
|
5679
|
+
if (parsed?.id === id) return filePath;
|
|
5680
|
+
}
|
|
5681
|
+
return null;
|
|
5682
|
+
}
|
|
5683
|
+
sanitizeIdentityAuditKey(key) {
|
|
5684
|
+
const trimmed = key.trim();
|
|
5685
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(trimmed) || trimmed.includes("..")) {
|
|
5686
|
+
throw new Error("Invalid identity audit key");
|
|
5687
|
+
}
|
|
5688
|
+
return trimmed;
|
|
5689
|
+
}
|
|
5459
5690
|
async writeQuestion(question, context, priority) {
|
|
5460
5691
|
await mkdir2(this.questionsDir, { recursive: true });
|
|
5461
5692
|
const id = this.generateId("q");
|