@joshuaswarren/openclaw-engram 8.3.20 → 8.3.21
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 +203 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10562,7 +10562,7 @@ title: ${opts.title.replace(/\n/g, " ").slice(0, 200)}
|
|
|
10562
10562
|
};
|
|
10563
10563
|
|
|
10564
10564
|
// src/compounding/engine.ts
|
|
10565
|
-
import { mkdir as mkdir15, readFile as readFile15, writeFile as writeFile14 } from "fs/promises";
|
|
10565
|
+
import { mkdir as mkdir15, readFile as readFile15, readdir as readdir10, writeFile as writeFile14 } from "fs/promises";
|
|
10566
10566
|
import path21 from "path";
|
|
10567
10567
|
import os4 from "os";
|
|
10568
10568
|
function isoWeekId(d) {
|
|
@@ -10574,6 +10574,22 @@ function isoWeekId(d) {
|
|
|
10574
10574
|
const yyyy = dt.getUTCFullYear();
|
|
10575
10575
|
return `${yyyy}-W${String(week).padStart(2, "0")}`;
|
|
10576
10576
|
}
|
|
10577
|
+
function isoMonthId(d) {
|
|
10578
|
+
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}`;
|
|
10579
|
+
}
|
|
10580
|
+
function monthIdFromIsoWeek(weekId) {
|
|
10581
|
+
const match = weekId.match(/^(\d{4})-W(\d{2})$/);
|
|
10582
|
+
if (!match) return isoMonthId(/* @__PURE__ */ new Date());
|
|
10583
|
+
const year = Number(match[1]);
|
|
10584
|
+
const week = Number(match[2]);
|
|
10585
|
+
const jan4 = new Date(Date.UTC(year, 0, 4));
|
|
10586
|
+
const jan4Day = jan4.getUTCDay() || 7;
|
|
10587
|
+
const isoWeekOneMonday = new Date(jan4);
|
|
10588
|
+
isoWeekOneMonday.setUTCDate(jan4.getUTCDate() - (jan4Day - 1));
|
|
10589
|
+
const monday = new Date(isoWeekOneMonday);
|
|
10590
|
+
monday.setUTCDate(isoWeekOneMonday.getUTCDate() + (week - 1) * 7);
|
|
10591
|
+
return isoMonthId(monday);
|
|
10592
|
+
}
|
|
10577
10593
|
function sharedContextDir(config) {
|
|
10578
10594
|
if (typeof config.sharedContextDir === "string" && config.sharedContextDir.length > 0) {
|
|
10579
10595
|
return config.sharedContextDir;
|
|
@@ -10586,10 +10602,20 @@ var CompoundingEngine = class {
|
|
|
10586
10602
|
this.weeklyDir = path21.join(config.memoryDir, "compounding", "weekly");
|
|
10587
10603
|
this.mistakesPath = path21.join(config.memoryDir, "compounding", "mistakes.json");
|
|
10588
10604
|
this.feedbackInboxPath = path21.join(sharedContextDir(config), "feedback", "inbox.jsonl");
|
|
10605
|
+
this.identityAnchorPath = path21.join(config.memoryDir, "identity", "identity-anchor.md");
|
|
10606
|
+
this.identityIncidentsDir = path21.join(config.memoryDir, "identity", "incidents");
|
|
10607
|
+
this.identityAuditWeeklyDir = path21.join(config.memoryDir, "identity", "audits", "weekly");
|
|
10608
|
+
this.identityAuditMonthlyDir = path21.join(config.memoryDir, "identity", "audits", "monthly");
|
|
10609
|
+
this.identityImprovementLoopsPath = path21.join(config.memoryDir, "identity", "improvement-loops.md");
|
|
10589
10610
|
}
|
|
10590
10611
|
weeklyDir;
|
|
10591
10612
|
mistakesPath;
|
|
10592
10613
|
feedbackInboxPath;
|
|
10614
|
+
identityAnchorPath;
|
|
10615
|
+
identityIncidentsDir;
|
|
10616
|
+
identityAuditWeeklyDir;
|
|
10617
|
+
identityAuditMonthlyDir;
|
|
10618
|
+
identityImprovementLoopsPath;
|
|
10593
10619
|
async ensureDirs() {
|
|
10594
10620
|
await mkdir15(this.weeklyDir, { recursive: true });
|
|
10595
10621
|
await mkdir15(path21.dirname(this.mistakesPath), { recursive: true });
|
|
@@ -10599,13 +10625,77 @@ var CompoundingEngine = class {
|
|
|
10599
10625
|
const weekId = opts?.weekId ?? isoWeekId(/* @__PURE__ */ new Date());
|
|
10600
10626
|
const entries = await this.readFeedbackEntriesForWeek(weekId);
|
|
10601
10627
|
const mistakes = this.buildMistakes(entries);
|
|
10628
|
+
const continuity = await this.readContinuityAuditReferences(weekId);
|
|
10602
10629
|
const reportPath = path21.join(this.weeklyDir, `${weekId}.md`);
|
|
10603
|
-
const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns);
|
|
10630
|
+
const md = this.formatWeeklyReport(weekId, entries, mistakes.patterns, continuity);
|
|
10604
10631
|
await writeFile14(reportPath, md, "utf-8");
|
|
10605
10632
|
await writeFile14(this.mistakesPath, JSON.stringify(mistakes, null, 2) + "\n", "utf-8");
|
|
10606
10633
|
log.info(`compounding: wrote weekly=${reportPath} mistakes=${this.mistakesPath}`);
|
|
10607
10634
|
return { weekId, reportPath, mistakesCount: mistakes.patterns.length };
|
|
10608
10635
|
}
|
|
10636
|
+
async synthesizeContinuityAudit(opts) {
|
|
10637
|
+
const period = opts?.period === "monthly" ? "monthly" : "weekly";
|
|
10638
|
+
const key = opts?.key?.trim() || (period === "weekly" ? isoWeekId(/* @__PURE__ */ new Date()) : isoMonthId(/* @__PURE__ */ new Date()));
|
|
10639
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
10640
|
+
const [anchorPresent, improvementLoopPresent, incidents, mistakes] = await Promise.all([
|
|
10641
|
+
this.readNonEmptyFile(this.identityAnchorPath),
|
|
10642
|
+
this.readNonEmptyFile(this.identityImprovementLoopsPath),
|
|
10643
|
+
this.readContinuityIncidents(),
|
|
10644
|
+
this.readMistakes()
|
|
10645
|
+
]);
|
|
10646
|
+
const openIncidents = incidents.filter((i) => i.state === "open");
|
|
10647
|
+
const closedIncidents = incidents.filter((i) => i.state === "closed");
|
|
10648
|
+
const hardeningCandidates = [];
|
|
10649
|
+
if (!anchorPresent) {
|
|
10650
|
+
hardeningCandidates.push("Create/update identity anchor baseline and verify recovery injection path.");
|
|
10651
|
+
}
|
|
10652
|
+
if (openIncidents.length > 0) {
|
|
10653
|
+
hardeningCandidates.push(
|
|
10654
|
+
`Close or downgrade ${openIncidents.length} open continuity incident${openIncidents.length === 1 ? "" : "s"}.`
|
|
10655
|
+
);
|
|
10656
|
+
}
|
|
10657
|
+
if (!improvementLoopPresent) {
|
|
10658
|
+
hardeningCandidates.push("Initialize continuity improvement-loops register with cadence and kill conditions.");
|
|
10659
|
+
}
|
|
10660
|
+
if ((mistakes?.patterns.length ?? 0) > 0) {
|
|
10661
|
+
hardeningCandidates.push("Review latest compounding mistakes and convert one pattern into preventive continuity rule.");
|
|
10662
|
+
}
|
|
10663
|
+
const nextAction = hardeningCandidates[0] ?? "No critical drift detected; keep weekly/monthly continuity audit cadence.";
|
|
10664
|
+
const lines = [
|
|
10665
|
+
`# Continuity Audit \u2014 ${period} ${key}`,
|
|
10666
|
+
"",
|
|
10667
|
+
`Generated: ${nowIso}`,
|
|
10668
|
+
`Scope: ${period}`,
|
|
10669
|
+
"",
|
|
10670
|
+
"## Signal Summary",
|
|
10671
|
+
`- Identity anchor present: ${anchorPresent ? "yes" : "no"}`,
|
|
10672
|
+
`- Improvement-loop register present: ${improvementLoopPresent ? "yes" : "no"}`,
|
|
10673
|
+
`- Open incidents: ${openIncidents.length}`,
|
|
10674
|
+
`- Closed incidents: ${closedIncidents.length}`,
|
|
10675
|
+
`- Compounding mistake patterns: ${mistakes?.patterns.length ?? 0}`,
|
|
10676
|
+
"",
|
|
10677
|
+
"## Drift Checks",
|
|
10678
|
+
`- Identity anchor drift: ${anchorPresent ? "pass" : "needs attention"}`,
|
|
10679
|
+
`- Incident backlog: ${openIncidents.length === 0 ? "pass" : "needs attention"}`,
|
|
10680
|
+
`- Improvement-loop coverage: ${improvementLoopPresent ? "pass" : "needs attention"}`,
|
|
10681
|
+
"",
|
|
10682
|
+
"## Stale Rule Detection",
|
|
10683
|
+
`- Open incidents older than closure window: ${openIncidents.length > 0 ? "possible" : "none detected"}`,
|
|
10684
|
+
`- Preventive rule coverage on closed incidents: ${closedIncidents.some((i) => (i.preventiveRule ?? "").trim().length > 0) ? "present" : "not detected"}`,
|
|
10685
|
+
"",
|
|
10686
|
+
"## Next Hardening Action",
|
|
10687
|
+
`- ${nextAction}`,
|
|
10688
|
+
"",
|
|
10689
|
+
"## Open Incident IDs",
|
|
10690
|
+
...openIncidents.length > 0 ? openIncidents.slice(0, 20).map((i) => `- ${i.id}`) : ["- (none)"],
|
|
10691
|
+
""
|
|
10692
|
+
];
|
|
10693
|
+
const dir = period === "weekly" ? this.identityAuditWeeklyDir : this.identityAuditMonthlyDir;
|
|
10694
|
+
await mkdir15(dir, { recursive: true });
|
|
10695
|
+
const reportPath = path21.join(dir, `${key}.md`);
|
|
10696
|
+
await writeFile14(reportPath, lines.join("\n"), "utf-8");
|
|
10697
|
+
return { period, key, reportPath };
|
|
10698
|
+
}
|
|
10609
10699
|
async readMistakes() {
|
|
10610
10700
|
try {
|
|
10611
10701
|
const raw = await readFile15(this.mistakesPath, "utf-8");
|
|
@@ -10650,7 +10740,7 @@ var CompoundingEngine = class {
|
|
|
10650
10740
|
const uniq = Array.from(new Set(patterns)).slice(0, 500);
|
|
10651
10741
|
return { updatedAt: (/* @__PURE__ */ new Date()).toISOString(), patterns: uniq };
|
|
10652
10742
|
}
|
|
10653
|
-
formatWeeklyReport(weekId, entries, patterns) {
|
|
10743
|
+
formatWeeklyReport(weekId, entries, patterns, continuity) {
|
|
10654
10744
|
const byAgent = /* @__PURE__ */ new Map();
|
|
10655
10745
|
for (const e of entries) {
|
|
10656
10746
|
const list = byAgent.get(e.agent) ?? [];
|
|
@@ -10689,8 +10779,61 @@ var CompoundingEngine = class {
|
|
|
10689
10779
|
for (const p of patterns.slice(0, 100)) lines.push(`- ${p}`);
|
|
10690
10780
|
}
|
|
10691
10781
|
lines.push("");
|
|
10782
|
+
if (this.config.continuityAuditEnabled) {
|
|
10783
|
+
lines.push("## Continuity Audits");
|
|
10784
|
+
if (continuity.weeklyPath) {
|
|
10785
|
+
lines.push(`- weekly: ${continuity.weeklyPath}`);
|
|
10786
|
+
} else {
|
|
10787
|
+
lines.push(`- weekly: (missing for ${weekId})`);
|
|
10788
|
+
}
|
|
10789
|
+
if (continuity.monthlyPath) {
|
|
10790
|
+
lines.push(`- monthly: ${continuity.monthlyPath}`);
|
|
10791
|
+
} else {
|
|
10792
|
+
lines.push(`- monthly: (missing for ${continuity.monthId})`);
|
|
10793
|
+
}
|
|
10794
|
+
lines.push("");
|
|
10795
|
+
}
|
|
10692
10796
|
return lines.join("\n");
|
|
10693
10797
|
}
|
|
10798
|
+
async readNonEmptyFile(filePath) {
|
|
10799
|
+
try {
|
|
10800
|
+
const raw = await readFile15(filePath, "utf-8");
|
|
10801
|
+
return raw.trim().length > 0;
|
|
10802
|
+
} catch {
|
|
10803
|
+
return false;
|
|
10804
|
+
}
|
|
10805
|
+
}
|
|
10806
|
+
async readContinuityIncidents() {
|
|
10807
|
+
const incidents = [];
|
|
10808
|
+
try {
|
|
10809
|
+
const names = await readdir10(this.identityIncidentsDir);
|
|
10810
|
+
const files = names.filter((n) => n.endsWith(".md")).sort().reverse();
|
|
10811
|
+
for (const file of files) {
|
|
10812
|
+
const filePath = path21.join(this.identityIncidentsDir, file);
|
|
10813
|
+
try {
|
|
10814
|
+
const raw = await readFile15(filePath, "utf-8");
|
|
10815
|
+
const parsed = parseContinuityIncident(raw);
|
|
10816
|
+
if (parsed) incidents.push(parsed);
|
|
10817
|
+
} catch {
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
} catch {
|
|
10821
|
+
}
|
|
10822
|
+
return incidents;
|
|
10823
|
+
}
|
|
10824
|
+
async readContinuityAuditReferences(weekId) {
|
|
10825
|
+
const monthId = monthIdFromIsoWeek(weekId);
|
|
10826
|
+
const weeklyPath = path21.join(this.identityAuditWeeklyDir, `${weekId}.md`);
|
|
10827
|
+
const monthlyPath = path21.join(this.identityAuditMonthlyDir, `${monthId}.md`);
|
|
10828
|
+
const weeklyExists = await this.readNonEmptyFile(weeklyPath);
|
|
10829
|
+
const monthlyExists = await this.readNonEmptyFile(monthlyPath);
|
|
10830
|
+
return {
|
|
10831
|
+
weekId,
|
|
10832
|
+
monthId,
|
|
10833
|
+
weeklyPath: weeklyExists ? weeklyPath : null,
|
|
10834
|
+
monthlyPath: monthlyExists ? monthlyPath : null
|
|
10835
|
+
};
|
|
10836
|
+
}
|
|
10694
10837
|
};
|
|
10695
10838
|
|
|
10696
10839
|
// src/orchestrator.ts
|
|
@@ -14011,6 +14154,57 @@ ${formatted}`
|
|
|
14011
14154
|
},
|
|
14012
14155
|
{ name: "memory_search" }
|
|
14013
14156
|
);
|
|
14157
|
+
api.registerTool(
|
|
14158
|
+
{
|
|
14159
|
+
name: "continuity_audit_generate",
|
|
14160
|
+
label: "Generate Continuity Audit",
|
|
14161
|
+
description: "Generate a deterministic identity continuity audit report (weekly/monthly) and persist it under identity/audits.",
|
|
14162
|
+
parameters: Type.Object({
|
|
14163
|
+
period: Type.Optional(
|
|
14164
|
+
Type.String({
|
|
14165
|
+
enum: ["weekly", "monthly"],
|
|
14166
|
+
description: "Audit period. Defaults to weekly."
|
|
14167
|
+
})
|
|
14168
|
+
),
|
|
14169
|
+
key: Type.Optional(
|
|
14170
|
+
Type.String({
|
|
14171
|
+
description: "Optional period key (weekly: YYYY-Www, monthly: YYYY-MM). Defaults to current period."
|
|
14172
|
+
})
|
|
14173
|
+
)
|
|
14174
|
+
}),
|
|
14175
|
+
async execute(_toolCallId, params) {
|
|
14176
|
+
if (!orchestrator.config.identityContinuityEnabled) {
|
|
14177
|
+
return toolResult(
|
|
14178
|
+
"Identity continuity is disabled. Enable `identityContinuityEnabled: true` to generate continuity audits."
|
|
14179
|
+
);
|
|
14180
|
+
}
|
|
14181
|
+
if (!orchestrator.config.continuityAuditEnabled) {
|
|
14182
|
+
return toolResult(
|
|
14183
|
+
"Continuity audits are disabled. Enable `continuityAuditEnabled: true` to generate continuity audits."
|
|
14184
|
+
);
|
|
14185
|
+
}
|
|
14186
|
+
if (!orchestrator.compounding) {
|
|
14187
|
+
return toolResult(
|
|
14188
|
+
"Compounding engine is disabled. Enable `compoundingEnabled: true` to generate continuity audits."
|
|
14189
|
+
);
|
|
14190
|
+
}
|
|
14191
|
+
const period = params.period === "monthly" ? "monthly" : "weekly";
|
|
14192
|
+
const key = typeof params.key === "string" ? params.key : void 0;
|
|
14193
|
+
const audit = await orchestrator.compounding.synthesizeContinuityAudit({
|
|
14194
|
+
period,
|
|
14195
|
+
key
|
|
14196
|
+
});
|
|
14197
|
+
return toolResult(
|
|
14198
|
+
`OK
|
|
14199
|
+
|
|
14200
|
+
period: ${audit.period}
|
|
14201
|
+
key: ${audit.key}
|
|
14202
|
+
report: ${audit.reportPath}`
|
|
14203
|
+
);
|
|
14204
|
+
}
|
|
14205
|
+
},
|
|
14206
|
+
{ name: "continuity_audit_generate" }
|
|
14207
|
+
);
|
|
14014
14208
|
api.registerTool(
|
|
14015
14209
|
{
|
|
14016
14210
|
name: "continuity_incident_open",
|
|
@@ -15045,7 +15239,7 @@ mistakes: ${res.mistakesCount} patterns`
|
|
|
15045
15239
|
|
|
15046
15240
|
// src/cli.ts
|
|
15047
15241
|
import path33 from "path";
|
|
15048
|
-
import { access as access2, readFile as readFile22, readdir as
|
|
15242
|
+
import { access as access2, readFile as readFile22, readdir as readdir13, unlink as unlink3 } from "fs/promises";
|
|
15049
15243
|
|
|
15050
15244
|
// src/transfer/export-json.ts
|
|
15051
15245
|
import path25 from "path";
|
|
@@ -15057,7 +15251,7 @@ var EXPORT_SCHEMA_VERSION = 1;
|
|
|
15057
15251
|
|
|
15058
15252
|
// src/transfer/fs-utils.ts
|
|
15059
15253
|
import { createHash as createHash6 } from "crypto";
|
|
15060
|
-
import { mkdir as mkdir17, readdir as
|
|
15254
|
+
import { mkdir as mkdir17, readdir as readdir11, readFile as readFile17, stat as stat3, writeFile as writeFile16 } from "fs/promises";
|
|
15061
15255
|
import path24 from "path";
|
|
15062
15256
|
async function sha256File(filePath) {
|
|
15063
15257
|
const buf = await readFile17(filePath);
|
|
@@ -15080,7 +15274,7 @@ async function readJsonFile(filePath) {
|
|
|
15080
15274
|
async function listFilesRecursive(rootDir) {
|
|
15081
15275
|
const out = [];
|
|
15082
15276
|
async function walk(dir) {
|
|
15083
|
-
const entries = await
|
|
15277
|
+
const entries = await readdir11(dir, { withFileTypes: true });
|
|
15084
15278
|
for (const ent of entries) {
|
|
15085
15279
|
const fp = path24.join(dir, ent.name);
|
|
15086
15280
|
if (ent.isDirectory()) {
|
|
@@ -15208,7 +15402,7 @@ async function looksLikeEngramMdExport(fromDir) {
|
|
|
15208
15402
|
|
|
15209
15403
|
// src/transfer/backup.ts
|
|
15210
15404
|
import path27 from "path";
|
|
15211
|
-
import { mkdir as mkdir20, readdir as
|
|
15405
|
+
import { mkdir as mkdir20, readdir as readdir12, rm as rm2 } from "fs/promises";
|
|
15212
15406
|
function timestampDirName(now) {
|
|
15213
15407
|
return now.toISOString().replace(/[:.]/g, "-");
|
|
15214
15408
|
}
|
|
@@ -15229,7 +15423,7 @@ async function backupMemoryDir(opts) {
|
|
|
15229
15423
|
return backupDir;
|
|
15230
15424
|
}
|
|
15231
15425
|
async function enforceRetention(outDirAbs, retentionDays) {
|
|
15232
|
-
const entries = await
|
|
15426
|
+
const entries = await readdir12(outDirAbs, { withFileTypes: true });
|
|
15233
15427
|
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
15234
15428
|
for (const ent of entries) {
|
|
15235
15429
|
if (!ent.isDirectory()) continue;
|
|
@@ -15598,7 +15792,7 @@ async function readAllMemoryFiles(memoryDir) {
|
|
|
15598
15792
|
const walk = async (dir) => {
|
|
15599
15793
|
let entries;
|
|
15600
15794
|
try {
|
|
15601
|
-
entries = await
|
|
15795
|
+
entries = await readdir13(dir, { withFileTypes: true });
|
|
15602
15796
|
} catch {
|
|
15603
15797
|
return;
|
|
15604
15798
|
}
|