@remnic/core 9.3.756 → 9.3.758
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/access-admin-ops-surface.d.ts +1 -1
- package/dist/access-admin-ops-surface.js +25 -25
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.js +26 -26
- package/dist/access-cli.js +86 -85
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +1 -1
- package/dist/access-http.js +31 -31
- package/dist/access-identity-continuity-surface.d.ts +166 -0
- package/dist/access-identity-continuity-surface.js +128 -0
- package/dist/access-lcm-surface.d.ts +1 -1
- package/dist/access-lcm-surface.js +25 -25
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-mcp.js +30 -30
- package/dist/access-observe-write-surface.d.ts +1 -1
- package/dist/access-observe-write-surface.js +25 -25
- package/dist/access-operations-batch.js +27 -27
- package/dist/access-operations.d.ts +1 -1
- package/dist/access-operations.js +29 -29
- package/dist/access-recall-surface.d.ts +1 -1
- package/dist/access-recall-surface.js +25 -25
- package/dist/access-schema.js +4 -4
- package/dist/{access-service-CJwcDoQp.d.ts → access-service-Z-8CnmrW.d.ts} +3 -2
- package/dist/access-service.d.ts +1 -1
- package/dist/access-service.js +25 -25
- package/dist/access-surface-catalog.d.ts +1 -1
- package/dist/{auto-sync-RZO5ZPHR.js → auto-sync-2SOUW4JW.js} +5 -5
- package/dist/briefing.js +9 -9
- package/dist/calibration.js +2 -2
- package/dist/{capsule-crypto-FFWJ4X4A.js → capsule-crypto-CZJSLEFG.js} +2 -2
- package/dist/capsule-crypto-CZJSLEFG.js.map +1 -0
- package/dist/causal-consolidation.js +13 -13
- package/dist/{chunk-WEPWY4HB.js → chunk-2BFLDH5F.js} +2 -2
- package/dist/{chunk-JTYM4HPA.js → chunk-2MR3MFQB.js} +2 -2
- package/dist/chunk-3I4FUAVJ.js +20 -0
- package/dist/chunk-3I4FUAVJ.js.map +1 -0
- package/dist/{chunk-TH7WMHVK.js → chunk-3NN73CM7.js} +2 -2
- package/dist/{chunk-A6XCHI53.js → chunk-3QLPBCFG.js} +8 -8
- package/dist/{chunk-EJJQDP3H.js → chunk-437S3G37.js} +1 -1
- package/dist/{chunk-DWDDQLSZ.js → chunk-6C6BBBCI.js} +276 -202
- package/dist/chunk-6C6BBBCI.js.map +1 -0
- package/dist/{chunk-7XH7VJN4.js → chunk-6T4LTI2F.js} +4 -4
- package/dist/{chunk-UNV6ZGTS.js → chunk-7I2QTC2K.js} +2 -2
- package/dist/{chunk-6DA5BBLS.js → chunk-7ME6VBF7.js} +107 -107
- package/dist/{chunk-AGNBY3VG.js → chunk-APJQ6UEA.js} +4 -4
- package/dist/{chunk-GG6G2RYR.js → chunk-CJDGB3EG.js} +2 -2
- package/dist/{chunk-PRX77NPC.js → chunk-CQCCVJZO.js} +2 -2
- package/dist/{chunk-ZUDM75KG.js → chunk-DCWIQFNA.js} +4 -4
- package/dist/{chunk-7APVFQ34.js → chunk-DUQHQ3TL.js} +294 -238
- package/dist/chunk-DUQHQ3TL.js.map +1 -0
- package/dist/{chunk-EF3VFQC4.js → chunk-EOTTKLPJ.js} +2 -2
- package/dist/{chunk-TCKP4EHY.js → chunk-FLVL4L3L.js} +2 -2
- package/dist/{chunk-NLXKSM46.js → chunk-HO3VUUGI.js} +2 -2
- package/dist/{chunk-4I45UZ4V.js → chunk-IBAU2RZN.js} +2 -2
- package/dist/{chunk-OLAVQS6S.js → chunk-ILB2MFTS.js} +2 -2
- package/dist/{chunk-4AC57RCM.js → chunk-IWI2ICTF.js} +4 -4
- package/dist/{chunk-5VWRYFQE.js → chunk-K2DJQOE3.js} +2 -2
- package/dist/{chunk-BTH6MQJT.js → chunk-LQDA67TT.js} +2 -2
- package/dist/{chunk-PBZQVVLG.js → chunk-LX4ZWRGD.js} +2 -2
- package/dist/{chunk-3I2IASNK.js → chunk-M5QKGHCR.js} +2 -2
- package/dist/{chunk-PPAEJXVF.js → chunk-NNL4LJAD.js} +2 -2
- package/dist/{chunk-TXV3I2O6.js → chunk-ODC4HOUZ.js} +2 -2
- package/dist/{chunk-7CFGXWYX.js → chunk-PJ5AG6D4.js} +2 -2
- package/dist/{chunk-EVVLGYHR.js → chunk-QEAOKI4U.js} +3 -3
- package/dist/{chunk-ZUHD6XZZ.js → chunk-QJUZAUAD.js} +32 -32
- package/dist/{chunk-REZ4TUD2.js → chunk-QKOTOUVR.js} +3 -3
- package/dist/{chunk-NG2NHB4C.js → chunk-QOGXUNWL.js} +2 -2
- package/dist/{chunk-YMGQXBPS.js → chunk-RF6BZHOD.js} +2 -2
- package/dist/{chunk-6DXXIXED.js → chunk-RQNV75HR.js} +2 -2
- package/dist/{chunk-GBXP62CL.js → chunk-TMXTQCJ7.js} +4 -4
- package/dist/{chunk-ZW5SZ3TH.js → chunk-TVWF3GNF.js} +8 -8
- package/dist/{chunk-5J4OL7TJ.js → chunk-VUA4S7P6.js} +4 -4
- package/dist/{chunk-PS572XYO.js → chunk-XQT5GSWU.js} +2 -2
- package/dist/{chunk-H2T4OJNI.js → chunk-YQYG24C6.js} +4 -4
- package/dist/{chunk-2OZ2JEUP.js → chunk-YTU7WKYN.js} +2 -2
- package/dist/{chunk-Y4TAFMUE.js → chunk-ZFYML7C3.js} +2 -2
- package/dist/{chunk-5ZKT7WTR.js → chunk-ZLOD23PD.js} +5 -5
- package/dist/{cli-cZyANcmY.d.ts → cli-C5pCwszN.d.ts} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +52 -52
- package/dist/compounding/engine.js +9 -9
- package/dist/config-record.d.ts +11 -0
- package/dist/config-record.js +8 -0
- package/dist/config-record.js.map +1 -0
- package/dist/connectors/codex-materialize-runner.js +9 -9
- package/dist/connectors/index.js +9 -9
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/conversation-index/backend.js +2 -2
- package/dist/entity-retrieval.js +9 -9
- package/dist/extraction-faithfulness.js +3 -3
- package/dist/extraction-judge.js +3 -3
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.js +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +124 -120
- package/dist/lcm/index.js +3 -3
- package/dist/maintenance/memory-governance.js +9 -9
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
- package/dist/maintenance/rebuild-memory-projection.js +10 -10
- package/dist/mcp-memory-inspector-app.d.ts +1 -1
- package/dist/namespaces/migrate.js +16 -16
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.js +9 -9
- package/dist/operator-toolkit.js +21 -21
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/orchestrator.js +85 -84
- package/dist/recall-planner-llm.js +2 -2
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +9 -9
- package/dist/semantic-consolidation.js +10 -10
- package/dist/semantic-rule-promotion.js +9 -9
- package/dist/semantic-rule-verifier.js +9 -9
- package/dist/storage.d.ts +3 -4
- package/dist/storage.js +8 -8
- package/dist/summarizer.js +3 -3
- package/dist/transfer/backup.js +3 -3
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/verified-recall.js +9 -9
- package/package.json +2 -2
- package/src/access-identity-continuity-surface.test.ts +374 -0
- package/src/access-identity-continuity-surface.ts +322 -0
- package/src/access-service.ts +23 -171
- package/src/config-record.ts +25 -0
- package/src/index.ts +1 -0
- package/src/storage/identity-continuity-store.ts +223 -0
- package/src/storage.ts +25 -142
- package/dist/chunk-7APVFQ34.js.map +0 -1
- package/dist/chunk-DWDDQLSZ.js.map +0 -1
- /package/dist/{capsule-crypto-FFWJ4X4A.js.map → access-identity-continuity-surface.js.map} +0 -0
- /package/dist/{auto-sync-RZO5ZPHR.js.map → auto-sync-2SOUW4JW.js.map} +0 -0
- /package/dist/{chunk-WEPWY4HB.js.map → chunk-2BFLDH5F.js.map} +0 -0
- /package/dist/{chunk-JTYM4HPA.js.map → chunk-2MR3MFQB.js.map} +0 -0
- /package/dist/{chunk-TH7WMHVK.js.map → chunk-3NN73CM7.js.map} +0 -0
- /package/dist/{chunk-A6XCHI53.js.map → chunk-3QLPBCFG.js.map} +0 -0
- /package/dist/{chunk-EJJQDP3H.js.map → chunk-437S3G37.js.map} +0 -0
- /package/dist/{chunk-7XH7VJN4.js.map → chunk-6T4LTI2F.js.map} +0 -0
- /package/dist/{chunk-UNV6ZGTS.js.map → chunk-7I2QTC2K.js.map} +0 -0
- /package/dist/{chunk-6DA5BBLS.js.map → chunk-7ME6VBF7.js.map} +0 -0
- /package/dist/{chunk-AGNBY3VG.js.map → chunk-APJQ6UEA.js.map} +0 -0
- /package/dist/{chunk-GG6G2RYR.js.map → chunk-CJDGB3EG.js.map} +0 -0
- /package/dist/{chunk-PRX77NPC.js.map → chunk-CQCCVJZO.js.map} +0 -0
- /package/dist/{chunk-ZUDM75KG.js.map → chunk-DCWIQFNA.js.map} +0 -0
- /package/dist/{chunk-EF3VFQC4.js.map → chunk-EOTTKLPJ.js.map} +0 -0
- /package/dist/{chunk-TCKP4EHY.js.map → chunk-FLVL4L3L.js.map} +0 -0
- /package/dist/{chunk-NLXKSM46.js.map → chunk-HO3VUUGI.js.map} +0 -0
- /package/dist/{chunk-4I45UZ4V.js.map → chunk-IBAU2RZN.js.map} +0 -0
- /package/dist/{chunk-OLAVQS6S.js.map → chunk-ILB2MFTS.js.map} +0 -0
- /package/dist/{chunk-4AC57RCM.js.map → chunk-IWI2ICTF.js.map} +0 -0
- /package/dist/{chunk-5VWRYFQE.js.map → chunk-K2DJQOE3.js.map} +0 -0
- /package/dist/{chunk-BTH6MQJT.js.map → chunk-LQDA67TT.js.map} +0 -0
- /package/dist/{chunk-PBZQVVLG.js.map → chunk-LX4ZWRGD.js.map} +0 -0
- /package/dist/{chunk-3I2IASNK.js.map → chunk-M5QKGHCR.js.map} +0 -0
- /package/dist/{chunk-PPAEJXVF.js.map → chunk-NNL4LJAD.js.map} +0 -0
- /package/dist/{chunk-TXV3I2O6.js.map → chunk-ODC4HOUZ.js.map} +0 -0
- /package/dist/{chunk-7CFGXWYX.js.map → chunk-PJ5AG6D4.js.map} +0 -0
- /package/dist/{chunk-EVVLGYHR.js.map → chunk-QEAOKI4U.js.map} +0 -0
- /package/dist/{chunk-ZUHD6XZZ.js.map → chunk-QJUZAUAD.js.map} +0 -0
- /package/dist/{chunk-REZ4TUD2.js.map → chunk-QKOTOUVR.js.map} +0 -0
- /package/dist/{chunk-NG2NHB4C.js.map → chunk-QOGXUNWL.js.map} +0 -0
- /package/dist/{chunk-YMGQXBPS.js.map → chunk-RF6BZHOD.js.map} +0 -0
- /package/dist/{chunk-6DXXIXED.js.map → chunk-RQNV75HR.js.map} +0 -0
- /package/dist/{chunk-GBXP62CL.js.map → chunk-TMXTQCJ7.js.map} +0 -0
- /package/dist/{chunk-ZW5SZ3TH.js.map → chunk-TVWF3GNF.js.map} +0 -0
- /package/dist/{chunk-5J4OL7TJ.js.map → chunk-VUA4S7P6.js.map} +0 -0
- /package/dist/{chunk-PS572XYO.js.map → chunk-XQT5GSWU.js.map} +0 -0
- /package/dist/{chunk-H2T4OJNI.js.map → chunk-YQYG24C6.js.map} +0 -0
- /package/dist/{chunk-2OZ2JEUP.js.map → chunk-YTU7WKYN.js.map} +0 -0
- /package/dist/{chunk-Y4TAFMUE.js.map → chunk-ZFYML7C3.js.map} +0 -0
- /package/dist/{chunk-5ZKT7WTR.js.map → chunk-ZLOD23PD.js.map} +0 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity-continuity persistence extracted from StorageManager.
|
|
3
|
+
*
|
|
4
|
+
* The host keeps the public API while this store owns anchors, incidents,
|
|
5
|
+
* audits, and improvement-loop files. Dependencies stay live through
|
|
6
|
+
* `selfDeps`, preserving secure-store and catalog-write behavior.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readdir } from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import {
|
|
12
|
+
closeContinuityIncidentRecord,
|
|
13
|
+
createContinuityIncidentRecord,
|
|
14
|
+
parseContinuityImprovementLoops,
|
|
15
|
+
parseContinuityIncident,
|
|
16
|
+
reviewContinuityLoopInMarkdown,
|
|
17
|
+
serializeContinuityIncident,
|
|
18
|
+
upsertContinuityLoopInMarkdown,
|
|
19
|
+
} from "../identity-continuity.js";
|
|
20
|
+
import { SecureStoreLockedError } from "../secure-store/secure-fs.js";
|
|
21
|
+
import type {
|
|
22
|
+
ContinuityImprovementLoop,
|
|
23
|
+
ContinuityIncidentCloseInput,
|
|
24
|
+
ContinuityIncidentOpenInput,
|
|
25
|
+
ContinuityIncidentRecord,
|
|
26
|
+
ContinuityLoopReviewInput,
|
|
27
|
+
ContinuityLoopUpsertInput,
|
|
28
|
+
} from "../types.js";
|
|
29
|
+
import { isErrnoCode } from "../utils/errno.js";
|
|
30
|
+
|
|
31
|
+
export interface IdentityContinuityStoreDeps {
|
|
32
|
+
ensureDirectories(): Promise<void>;
|
|
33
|
+
generateId(prefix?: string): string;
|
|
34
|
+
readonly identityAnchorPath: string;
|
|
35
|
+
readonly identityIncidentsDir: string;
|
|
36
|
+
readonly identityAuditsWeeklyDir: string;
|
|
37
|
+
readonly identityAuditsMonthlyDir: string;
|
|
38
|
+
readonly identityImprovementLoopsPath: string;
|
|
39
|
+
readStorageSecureFile(filePath: string): Promise<string>;
|
|
40
|
+
writeStorageSecureFile(filePath: string, content: string | Buffer): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class IdentityContinuityStore {
|
|
44
|
+
constructor(private readonly deps: IdentityContinuityStoreDeps) {}
|
|
45
|
+
|
|
46
|
+
async writeIdentityAnchor(content: string): Promise<void> {
|
|
47
|
+
await this.deps.ensureDirectories();
|
|
48
|
+
await this.deps.writeStorageSecureFile(this.deps.identityAnchorPath, content);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async readIdentityAnchor(): Promise<string | null> {
|
|
52
|
+
try {
|
|
53
|
+
return await this.deps.readStorageSecureFile(this.deps.identityAnchorPath);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async appendContinuityIncident(input: ContinuityIncidentOpenInput): Promise<ContinuityIncidentRecord> {
|
|
61
|
+
await this.deps.ensureDirectories();
|
|
62
|
+
const now = new Date();
|
|
63
|
+
const nowIso = now.toISOString();
|
|
64
|
+
const date = nowIso.slice(0, 10);
|
|
65
|
+
const id = this.deps.generateId("incident");
|
|
66
|
+
const incident = createContinuityIncidentRecord(id, input, nowIso);
|
|
67
|
+
const filePath = path.join(this.deps.identityIncidentsDir, `${date}-${id}.md`);
|
|
68
|
+
await this.deps.writeStorageSecureFile(filePath, serializeContinuityIncident(incident));
|
|
69
|
+
return { ...incident, filePath };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async readContinuityIncidents(
|
|
73
|
+
limit = 200,
|
|
74
|
+
state: "open" | "closed" | "all" = "all"
|
|
75
|
+
): Promise<ContinuityIncidentRecord[]> {
|
|
76
|
+
const normalizedLimit = Number.isFinite(limit) ? Math.floor(limit) : 0;
|
|
77
|
+
const cappedLimit = Math.max(0, normalizedLimit);
|
|
78
|
+
if (cappedLimit === 0) return [];
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const candidates = await this.readContinuityIncidentFileNames();
|
|
82
|
+
const incidents: ContinuityIncidentRecord[] = [];
|
|
83
|
+
|
|
84
|
+
for (const file of candidates) {
|
|
85
|
+
if (incidents.length >= cappedLimit) break;
|
|
86
|
+
const filePath = path.join(this.deps.identityIncidentsDir, file);
|
|
87
|
+
try {
|
|
88
|
+
const raw = await this.deps.readStorageSecureFile(filePath);
|
|
89
|
+
const parsed = parseContinuityIncident(raw);
|
|
90
|
+
if (!parsed) continue;
|
|
91
|
+
if (state !== "all" && parsed.state !== state) continue;
|
|
92
|
+
incidents.push({ ...parsed, filePath });
|
|
93
|
+
} catch (err) {
|
|
94
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
95
|
+
// Fail-open on malformed/missing files.
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return incidents;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
101
|
+
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async closeContinuityIncident(
|
|
107
|
+
id: string,
|
|
108
|
+
closure: ContinuityIncidentCloseInput
|
|
109
|
+
): Promise<ContinuityIncidentRecord | null> {
|
|
110
|
+
const directFilePath = await this.findContinuityIncidentFilePathById(id);
|
|
111
|
+
const target = directFilePath ? await this.readContinuityIncidentFile(directFilePath) : null;
|
|
112
|
+
if (!target || !directFilePath) return null;
|
|
113
|
+
if (target.state === "closed") return target;
|
|
114
|
+
|
|
115
|
+
const closed = closeContinuityIncidentRecord(target, closure, new Date().toISOString());
|
|
116
|
+
await this.deps.writeStorageSecureFile(directFilePath, serializeContinuityIncident(closed));
|
|
117
|
+
return { ...closed, filePath: directFilePath };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async writeIdentityAudit(period: "weekly" | "monthly", key: string, content: string): Promise<string> {
|
|
121
|
+
await this.deps.ensureDirectories();
|
|
122
|
+
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
123
|
+
const dir = period === "weekly" ? this.deps.identityAuditsWeeklyDir : this.deps.identityAuditsMonthlyDir;
|
|
124
|
+
const filePath = path.join(dir, `${safeKey}.md`);
|
|
125
|
+
await this.deps.writeStorageSecureFile(filePath, content);
|
|
126
|
+
return filePath;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async readIdentityAudit(period: "weekly" | "monthly", key: string): Promise<string | null> {
|
|
130
|
+
try {
|
|
131
|
+
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
132
|
+
const dir = period === "weekly" ? this.deps.identityAuditsWeeklyDir : this.deps.identityAuditsMonthlyDir;
|
|
133
|
+
return await this.deps.readStorageSecureFile(path.join(dir, `${safeKey}.md`));
|
|
134
|
+
} catch (err) {
|
|
135
|
+
if (err instanceof Error && err.message === "Invalid identity audit key") return null;
|
|
136
|
+
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async writeIdentityImprovementLoops(content: string): Promise<void> {
|
|
142
|
+
await this.deps.ensureDirectories();
|
|
143
|
+
await this.deps.writeStorageSecureFile(this.deps.identityImprovementLoopsPath, content);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async readIdentityImprovementLoops(): Promise<string | null> {
|
|
147
|
+
try {
|
|
148
|
+
return await this.deps.readStorageSecureFile(this.deps.identityImprovementLoopsPath);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async readIdentityImprovementLoopRegister(): Promise<ContinuityImprovementLoop[]> {
|
|
156
|
+
const raw = await this.readIdentityImprovementLoops();
|
|
157
|
+
if (!raw) return [];
|
|
158
|
+
return parseContinuityImprovementLoops(raw);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async upsertIdentityImprovementLoop(input: ContinuityLoopUpsertInput): Promise<ContinuityImprovementLoop> {
|
|
162
|
+
const nowIso = new Date().toISOString();
|
|
163
|
+
const raw = await this.readIdentityImprovementLoops();
|
|
164
|
+
const { markdown, loop } = upsertContinuityLoopInMarkdown(raw, input, nowIso);
|
|
165
|
+
await this.writeIdentityImprovementLoops(markdown);
|
|
166
|
+
return loop;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async reviewIdentityImprovementLoop(
|
|
170
|
+
id: string,
|
|
171
|
+
input: ContinuityLoopReviewInput
|
|
172
|
+
): Promise<ContinuityImprovementLoop | null> {
|
|
173
|
+
const raw = await this.readIdentityImprovementLoops();
|
|
174
|
+
const { markdown, loop } = reviewContinuityLoopInMarkdown(raw, id, input, new Date().toISOString());
|
|
175
|
+
if (!loop) return null;
|
|
176
|
+
await this.writeIdentityImprovementLoops(markdown);
|
|
177
|
+
return loop;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private async readContinuityIncidentFileNames(): Promise<string[]> {
|
|
181
|
+
const files = await readdir(this.deps.identityIncidentsDir);
|
|
182
|
+
return files
|
|
183
|
+
.filter((file) => file.endsWith(".md"))
|
|
184
|
+
.sort()
|
|
185
|
+
.reverse();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private async readContinuityIncidentFile(filePath: string): Promise<ContinuityIncidentRecord | null> {
|
|
189
|
+
try {
|
|
190
|
+
const raw = await this.deps.readStorageSecureFile(filePath);
|
|
191
|
+
const parsed = parseContinuityIncident(raw);
|
|
192
|
+
return parsed ? { ...parsed, filePath } : null;
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async findContinuityIncidentFilePathById(id: string): Promise<string | null> {
|
|
200
|
+
const fileNames = await this.readContinuityIncidentFileNames();
|
|
201
|
+
const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
|
|
202
|
+
if (directMatch) {
|
|
203
|
+
const directPath = path.join(this.deps.identityIncidentsDir, directMatch);
|
|
204
|
+
const parsed = await this.readContinuityIncidentFile(directPath);
|
|
205
|
+
if (parsed?.id === id) return directPath;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const fileName of fileNames) {
|
|
209
|
+
const filePath = path.join(this.deps.identityIncidentsDir, fileName);
|
|
210
|
+
const parsed = await this.readContinuityIncidentFile(filePath);
|
|
211
|
+
if (parsed?.id === id) return filePath;
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private sanitizeIdentityAuditKey(key: string): string {
|
|
217
|
+
const trimmed = key.trim();
|
|
218
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(trimmed) || trimmed.includes("..")) {
|
|
219
|
+
throw new Error("Invalid identity audit key");
|
|
220
|
+
}
|
|
221
|
+
return trimmed;
|
|
222
|
+
}
|
|
223
|
+
}
|
package/src/storage.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { log } from "./logger.js";
|
|
|
7
7
|
import { MemoryReadStore } from "./storage/memory-read-store.js";
|
|
8
8
|
import { selfDeps } from "./orchestration/self-deps.js";
|
|
9
9
|
import { EntityStore } from "./storage/entity-store.js";
|
|
10
|
+
import { IdentityContinuityStore } from "./storage/identity-continuity-store.js";
|
|
10
11
|
import { isErrnoCode } from "./utils/errno.js";
|
|
11
12
|
import { RECALL_FALLBACK_DIRS, getCategoryDir, categoryDirName } from "./utils/category-dir.js";
|
|
12
13
|
import { assertPathInsideRoot } from "./utils/path-containment.js";
|
|
@@ -113,15 +114,6 @@ import {
|
|
|
113
114
|
normalizeProjectionPreview,
|
|
114
115
|
normalizeProjectionTags,
|
|
115
116
|
} from "./memory-projection-format.js";
|
|
116
|
-
import {
|
|
117
|
-
closeContinuityIncidentRecord,
|
|
118
|
-
createContinuityIncidentRecord,
|
|
119
|
-
parseContinuityIncident,
|
|
120
|
-
parseContinuityImprovementLoops,
|
|
121
|
-
reviewContinuityLoopInMarkdown,
|
|
122
|
-
serializeContinuityIncident,
|
|
123
|
-
upsertContinuityLoopInMarkdown,
|
|
124
|
-
} from "./identity-continuity.js";
|
|
125
117
|
import { parseFlexibleIsoTimestamp } from "./utils/iso-timestamp.js";
|
|
126
118
|
// stripCitation import removed: legacy rebuild fallback was replaced by a
|
|
127
119
|
// skip-with-warning strategy (Finding 1 — Uhol). See ensureFactHashIndexAuthoritative.
|
|
@@ -2560,6 +2552,18 @@ export class StorageManager {
|
|
|
2560
2552
|
return this._entityStore;
|
|
2561
2553
|
}
|
|
2562
2554
|
|
|
2555
|
+
/** IdentityContinuityStore (storage.ts decomposition). Lazy; selfDeps live wiring. */
|
|
2556
|
+
private _identityContinuityStore: IdentityContinuityStore | undefined;
|
|
2557
|
+
|
|
2558
|
+
private get identityContinuityStore(): IdentityContinuityStore {
|
|
2559
|
+
if (!this._identityContinuityStore) {
|
|
2560
|
+
this._identityContinuityStore = new IdentityContinuityStore(
|
|
2561
|
+
selfDeps<ConstructorParameters<typeof IdentityContinuityStore>[0]>(this),
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
return this._identityContinuityStore;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2563
2567
|
get dir(): string {
|
|
2564
2568
|
return this.baseDir;
|
|
2565
2569
|
}
|
|
@@ -5355,137 +5359,60 @@ export class StorageManager {
|
|
|
5355
5359
|
}
|
|
5356
5360
|
|
|
5357
5361
|
async writeIdentityAnchor(content: string): Promise<void> {
|
|
5358
|
-
|
|
5359
|
-
await this.writeStorageSecureFile(this.identityAnchorPath, content);
|
|
5362
|
+
return this.identityContinuityStore.writeIdentityAnchor(content);
|
|
5360
5363
|
}
|
|
5361
5364
|
|
|
5362
5365
|
async readIdentityAnchor(): Promise<string | null> {
|
|
5363
|
-
|
|
5364
|
-
return await this.readStorageSecureFile(this.identityAnchorPath);
|
|
5365
|
-
} catch (err) {
|
|
5366
|
-
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
5367
|
-
return null;
|
|
5368
|
-
}
|
|
5366
|
+
return this.identityContinuityStore.readIdentityAnchor();
|
|
5369
5367
|
}
|
|
5370
5368
|
|
|
5371
5369
|
async appendContinuityIncident(input: ContinuityIncidentOpenInput): Promise<ContinuityIncidentRecord> {
|
|
5372
|
-
|
|
5373
|
-
const now = new Date();
|
|
5374
|
-
const nowIso = now.toISOString();
|
|
5375
|
-
const date = nowIso.slice(0, 10);
|
|
5376
|
-
const id = this.generateId("incident");
|
|
5377
|
-
const incident = createContinuityIncidentRecord(id, input, nowIso);
|
|
5378
|
-
const filePath = path.join(this.identityIncidentsDir, `${date}-${id}.md`);
|
|
5379
|
-
await this.writeStorageSecureFile(filePath, serializeContinuityIncident(incident));
|
|
5380
|
-
return { ...incident, filePath };
|
|
5370
|
+
return this.identityContinuityStore.appendContinuityIncident(input);
|
|
5381
5371
|
}
|
|
5382
5372
|
|
|
5383
5373
|
async readContinuityIncidents(
|
|
5384
5374
|
limit: number = 200,
|
|
5385
5375
|
state: "open" | "closed" | "all" = "all",
|
|
5386
5376
|
): Promise<ContinuityIncidentRecord[]> {
|
|
5387
|
-
|
|
5388
|
-
const cappedLimit = Math.max(0, normalizedLimit);
|
|
5389
|
-
if (cappedLimit === 0) return [];
|
|
5390
|
-
|
|
5391
|
-
try {
|
|
5392
|
-
const candidates = await this.readContinuityIncidentFileNames();
|
|
5393
|
-
const incidents: ContinuityIncidentRecord[] = [];
|
|
5394
|
-
|
|
5395
|
-
for (const file of candidates) {
|
|
5396
|
-
if (incidents.length >= cappedLimit) break;
|
|
5397
|
-
const filePath = path.join(this.identityIncidentsDir, file);
|
|
5398
|
-
try {
|
|
5399
|
-
const raw = await this.readStorageSecureFile(filePath);
|
|
5400
|
-
const parsed = parseContinuityIncident(raw);
|
|
5401
|
-
if (!parsed) continue;
|
|
5402
|
-
if (state !== "all" && parsed.state !== state) continue;
|
|
5403
|
-
incidents.push({ ...parsed, filePath });
|
|
5404
|
-
} catch (err) {
|
|
5405
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
5406
|
-
// Fail-open on malformed/missing files.
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
return incidents;
|
|
5410
|
-
} catch (err) {
|
|
5411
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
5412
|
-
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
5413
|
-
return [];
|
|
5414
|
-
}
|
|
5377
|
+
return this.identityContinuityStore.readContinuityIncidents(limit, state);
|
|
5415
5378
|
}
|
|
5416
5379
|
|
|
5417
5380
|
async closeContinuityIncident(
|
|
5418
5381
|
id: string,
|
|
5419
5382
|
closure: ContinuityIncidentCloseInput,
|
|
5420
5383
|
): Promise<ContinuityIncidentRecord | null> {
|
|
5421
|
-
|
|
5422
|
-
const target = directFilePath ? await this.readContinuityIncidentFile(directFilePath) : null;
|
|
5423
|
-
if (!target || !directFilePath) return null;
|
|
5424
|
-
if (target.state === "closed") return target;
|
|
5425
|
-
|
|
5426
|
-
const closed = closeContinuityIncidentRecord(target, closure, new Date().toISOString());
|
|
5427
|
-
await this.writeStorageSecureFile(directFilePath, serializeContinuityIncident(closed));
|
|
5428
|
-
return { ...closed, filePath: directFilePath };
|
|
5384
|
+
return this.identityContinuityStore.closeContinuityIncident(id, closure);
|
|
5429
5385
|
}
|
|
5430
5386
|
|
|
5431
5387
|
async writeIdentityAudit(period: "weekly" | "monthly", key: string, content: string): Promise<string> {
|
|
5432
|
-
|
|
5433
|
-
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
5434
|
-
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
5435
|
-
const filePath = path.join(dir, `${safeKey}.md`);
|
|
5436
|
-
await this.writeStorageSecureFile(filePath, content);
|
|
5437
|
-
return filePath;
|
|
5388
|
+
return this.identityContinuityStore.writeIdentityAudit(period, key, content);
|
|
5438
5389
|
}
|
|
5439
5390
|
|
|
5440
5391
|
async readIdentityAudit(period: "weekly" | "monthly", key: string): Promise<string | null> {
|
|
5441
|
-
|
|
5442
|
-
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
5443
|
-
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
5444
|
-
return await this.readStorageSecureFile(path.join(dir, `${safeKey}.md`));
|
|
5445
|
-
} catch (err) {
|
|
5446
|
-
if (err instanceof Error && err.message === "Invalid identity audit key") return null;
|
|
5447
|
-
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
5448
|
-
return null;
|
|
5449
|
-
}
|
|
5392
|
+
return this.identityContinuityStore.readIdentityAudit(period, key);
|
|
5450
5393
|
}
|
|
5451
5394
|
|
|
5452
5395
|
async writeIdentityImprovementLoops(content: string): Promise<void> {
|
|
5453
|
-
|
|
5454
|
-
await this.writeStorageSecureFile(this.identityImprovementLoopsPath, content);
|
|
5396
|
+
return this.identityContinuityStore.writeIdentityImprovementLoops(content);
|
|
5455
5397
|
}
|
|
5456
5398
|
|
|
5457
5399
|
async readIdentityImprovementLoops(): Promise<string | null> {
|
|
5458
|
-
|
|
5459
|
-
return await this.readStorageSecureFile(this.identityImprovementLoopsPath);
|
|
5460
|
-
} catch (err) {
|
|
5461
|
-
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
5462
|
-
return null;
|
|
5463
|
-
}
|
|
5400
|
+
return this.identityContinuityStore.readIdentityImprovementLoops();
|
|
5464
5401
|
}
|
|
5465
5402
|
|
|
5466
5403
|
async readIdentityImprovementLoopRegister(): Promise<ContinuityImprovementLoop[]> {
|
|
5467
|
-
|
|
5468
|
-
if (!raw) return [];
|
|
5469
|
-
return parseContinuityImprovementLoops(raw);
|
|
5404
|
+
return this.identityContinuityStore.readIdentityImprovementLoopRegister();
|
|
5470
5405
|
}
|
|
5471
5406
|
|
|
5472
5407
|
async upsertIdentityImprovementLoop(input: ContinuityLoopUpsertInput): Promise<ContinuityImprovementLoop> {
|
|
5473
|
-
|
|
5474
|
-
const raw = await this.readIdentityImprovementLoops();
|
|
5475
|
-
const { markdown, loop } = upsertContinuityLoopInMarkdown(raw, input, nowIso);
|
|
5476
|
-
await this.writeIdentityImprovementLoops(markdown);
|
|
5477
|
-
return loop;
|
|
5408
|
+
return this.identityContinuityStore.upsertIdentityImprovementLoop(input);
|
|
5478
5409
|
}
|
|
5479
5410
|
|
|
5480
5411
|
async reviewIdentityImprovementLoop(
|
|
5481
5412
|
id: string,
|
|
5482
5413
|
input: ContinuityLoopReviewInput,
|
|
5483
5414
|
): Promise<ContinuityImprovementLoop | null> {
|
|
5484
|
-
|
|
5485
|
-
const { markdown, loop } = reviewContinuityLoopInMarkdown(raw, id, input, new Date().toISOString());
|
|
5486
|
-
if (!loop) return null;
|
|
5487
|
-
await this.writeIdentityImprovementLoops(markdown);
|
|
5488
|
-
return loop;
|
|
5415
|
+
return this.identityContinuityStore.reviewIdentityImprovementLoop(id, input);
|
|
5489
5416
|
}
|
|
5490
5417
|
|
|
5491
5418
|
// ---------------------------------------------------------------------------
|
|
@@ -5498,50 +5425,6 @@ export class StorageManager {
|
|
|
5498
5425
|
return `${prefix}-${ts}-${rand}`;
|
|
5499
5426
|
}
|
|
5500
5427
|
|
|
5501
|
-
private async readContinuityIncidentFileNames(): Promise<string[]> {
|
|
5502
|
-
const files = await readdir(this.identityIncidentsDir);
|
|
5503
|
-
return files
|
|
5504
|
-
.filter((file) => file.endsWith(".md"))
|
|
5505
|
-
.sort()
|
|
5506
|
-
.reverse();
|
|
5507
|
-
}
|
|
5508
|
-
|
|
5509
|
-
private async readContinuityIncidentFile(filePath: string): Promise<ContinuityIncidentRecord | null> {
|
|
5510
|
-
try {
|
|
5511
|
-
const raw = await this.readStorageSecureFile(filePath);
|
|
5512
|
-
const parsed = parseContinuityIncident(raw);
|
|
5513
|
-
return parsed ? { ...parsed, filePath } : null;
|
|
5514
|
-
} catch (err) {
|
|
5515
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
5516
|
-
return null;
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
|
-
|
|
5520
|
-
private async findContinuityIncidentFilePathById(id: string): Promise<string | null> {
|
|
5521
|
-
const fileNames = await this.readContinuityIncidentFileNames();
|
|
5522
|
-
const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
|
|
5523
|
-
if (directMatch) {
|
|
5524
|
-
const directPath = path.join(this.identityIncidentsDir, directMatch);
|
|
5525
|
-
const parsed = await this.readContinuityIncidentFile(directPath);
|
|
5526
|
-
if (parsed?.id === id) return directPath;
|
|
5527
|
-
}
|
|
5528
|
-
|
|
5529
|
-
for (const fileName of fileNames) {
|
|
5530
|
-
const filePath = path.join(this.identityIncidentsDir, fileName);
|
|
5531
|
-
const parsed = await this.readContinuityIncidentFile(filePath);
|
|
5532
|
-
if (parsed?.id === id) return filePath;
|
|
5533
|
-
}
|
|
5534
|
-
return null;
|
|
5535
|
-
}
|
|
5536
|
-
|
|
5537
|
-
private sanitizeIdentityAuditKey(key: string): string {
|
|
5538
|
-
const trimmed = key.trim();
|
|
5539
|
-
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(trimmed) || trimmed.includes("..")) {
|
|
5540
|
-
throw new Error("Invalid identity audit key");
|
|
5541
|
-
}
|
|
5542
|
-
return trimmed;
|
|
5543
|
-
}
|
|
5544
|
-
|
|
5545
5428
|
async writeQuestion(
|
|
5546
5429
|
question: string,
|
|
5547
5430
|
context: string,
|