@remnic/core 9.3.629 → 9.3.631
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-cli.js +15 -13
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +5 -4
- package/dist/access-http.js +7 -6
- package/dist/access-mcp.d.ts +5 -4
- package/dist/access-mcp.js +6 -5
- package/dist/{access-service-BdThkfIE.d.ts → access-service-C9_EpVHd.d.ts} +2 -2
- package/dist/access-service.d.ts +5 -4
- package/dist/access-service.js +5 -4
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/auto-sync-RFADEHIQ.js +75 -0
- package/dist/auto-sync-RFADEHIQ.js.map +1 -0
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -2
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -3
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-532VCWYW.js → chunk-242XFZ36.js} +2 -2
- package/dist/{chunk-XXO5TI3B.js → chunk-32U3N7H5.js} +3 -3
- package/dist/{chunk-KB4MFBF5.js → chunk-3RDYU3JS.js} +3 -3
- package/dist/{chunk-57QXN2CS.js → chunk-4S3N6HFG.js} +2 -2
- package/dist/{chunk-OLNNOHBC.js → chunk-5PT5I6JQ.js} +20 -14
- package/dist/{chunk-OLNNOHBC.js.map → chunk-5PT5I6JQ.js.map} +1 -1
- package/dist/{chunk-GE7Q7KXP.js → chunk-7A2QKUUA.js} +2 -2
- package/dist/{chunk-KKTXCFD7.js → chunk-7H5WCPBS.js} +95 -11
- package/dist/{chunk-KKTXCFD7.js.map → chunk-7H5WCPBS.js.map} +1 -1
- package/dist/{chunk-3MNBW7R7.js → chunk-C4KKM62E.js} +2 -2
- package/dist/{chunk-NKCW223V.js → chunk-CMN5AWAZ.js} +2 -2
- package/dist/{chunk-JXHMAQYT.js → chunk-DOBJH4I6.js} +4 -4
- package/dist/{chunk-TZDSNIRO.js → chunk-IFVFQRZ2.js} +5 -5
- package/dist/{chunk-LQYTQCXM.js → chunk-JCLECECB.js} +2 -2
- package/dist/chunk-KVDUDYEN.js +1164 -0
- package/dist/chunk-KVDUDYEN.js.map +1 -0
- package/dist/{chunk-QDV6VAD4.js → chunk-LEG7XWS2.js} +2 -2
- package/dist/chunk-M7XQSUBB.js +280 -0
- package/dist/chunk-M7XQSUBB.js.map +1 -0
- package/dist/{chunk-N5RGXWLQ.js → chunk-PUEAEQSN.js} +2 -2
- package/dist/{chunk-UGHUNQ74.js → chunk-QYGIQ5NM.js} +212 -417
- package/dist/chunk-QYGIQ5NM.js.map +1 -0
- package/dist/{chunk-JKCDQBDW.js → chunk-UXFOGILU.js} +2 -2
- package/dist/{chunk-MVQN73GT.js → chunk-VTR3MNYF.js} +2 -2
- package/dist/{chunk-KVFYTRMV.js → chunk-W25I7G6U.js} +2 -2
- package/dist/{chunk-3GLCUPXP.js → chunk-WLZBVYC6.js} +192 -889
- package/dist/chunk-WLZBVYC6.js.map +1 -0
- package/dist/{chunk-3R2UZV3U.js → chunk-X7EJF46S.js} +2 -2
- package/dist/{chunk-54KDA6UK.js → chunk-XG4NAWAV.js} +3 -3
- package/dist/{chunk-P2D2MM47.js → chunk-YROCXMCK.js} +2 -2
- package/dist/{cli-DAsHklrf.d.ts → cli-CuVEQWKr.d.ts} +3 -3
- package/dist/cli.d.ts +6 -5
- package/dist/cli.js +18 -17
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -2
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -2
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -2
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -3
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +49 -45
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +4 -3
- package/dist/mcp-memory-inspector-app.d.ts +5 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +4 -3
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -2
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +7 -6
- package/dist/{orchestrator-BexeSJ2j.d.ts → orchestrator-CoqytbK_.d.ts} +102 -10
- package/dist/orchestrator.d.ts +4 -3
- package/dist/orchestrator.js +12 -10
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-PwkzNfdK.d.ts → semantic-consolidation-BPs6BURk.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -3
- package/dist/semantic-rule-promotion.js +3 -2
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +3 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +38 -2
- package/dist/storage.js +6 -3
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/{types-BCF2wqKa.d.ts → types-CpMPD8xl.d.ts} +59 -11
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -2
- package/package.json +1 -1
- package/src/orchestrator.ts +74 -0
- package/src/storage.ts +100 -0
- package/src/wearables/auto-sync.test.ts +181 -0
- package/src/wearables/auto-sync.ts +129 -0
- package/src/wearables/cli.ts +6 -0
- package/src/wearables/config.test.ts +90 -11
- package/src/wearables/config.ts +113 -11
- package/src/wearables/memory-gen.test.ts +416 -1
- package/src/wearables/memory-gen.ts +381 -23
- package/src/wearables/pipeline.test.ts +396 -5
- package/src/wearables/pipeline.ts +174 -22
- package/src/wearables/service.test.ts +172 -0
- package/src/wearables/service.ts +84 -3
- package/src/wearables/storage-io.test.ts +81 -0
- package/src/wearables/trust.test.ts +123 -0
- package/src/wearables/trust.ts +168 -0
- package/src/wearables/types.ts +57 -9
- package/dist/chunk-3GLCUPXP.js.map +0 -1
- package/dist/chunk-UGHUNQ74.js.map +0 -1
- /package/dist/{chunk-532VCWYW.js.map → chunk-242XFZ36.js.map} +0 -0
- /package/dist/{chunk-XXO5TI3B.js.map → chunk-32U3N7H5.js.map} +0 -0
- /package/dist/{chunk-KB4MFBF5.js.map → chunk-3RDYU3JS.js.map} +0 -0
- /package/dist/{chunk-57QXN2CS.js.map → chunk-4S3N6HFG.js.map} +0 -0
- /package/dist/{chunk-GE7Q7KXP.js.map → chunk-7A2QKUUA.js.map} +0 -0
- /package/dist/{chunk-3MNBW7R7.js.map → chunk-C4KKM62E.js.map} +0 -0
- /package/dist/{chunk-NKCW223V.js.map → chunk-CMN5AWAZ.js.map} +0 -0
- /package/dist/{chunk-JXHMAQYT.js.map → chunk-DOBJH4I6.js.map} +0 -0
- /package/dist/{chunk-TZDSNIRO.js.map → chunk-IFVFQRZ2.js.map} +0 -0
- /package/dist/{chunk-LQYTQCXM.js.map → chunk-JCLECECB.js.map} +0 -0
- /package/dist/{chunk-QDV6VAD4.js.map → chunk-LEG7XWS2.js.map} +0 -0
- /package/dist/{chunk-N5RGXWLQ.js.map → chunk-PUEAEQSN.js.map} +0 -0
- /package/dist/{chunk-JKCDQBDW.js.map → chunk-UXFOGILU.js.map} +0 -0
- /package/dist/{chunk-MVQN73GT.js.map → chunk-VTR3MNYF.js.map} +0 -0
- /package/dist/{chunk-KVFYTRMV.js.map → chunk-W25I7G6U.js.map} +0 -0
- /package/dist/{chunk-3R2UZV3U.js.map → chunk-X7EJF46S.js.map} +0 -0
- /package/dist/{chunk-54KDA6UK.js.map → chunk-XG4NAWAV.js.map} +0 -0
- /package/dist/{chunk-P2D2MM47.js.map → chunk-YROCXMCK.js.map} +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WEARABLES_DIR_NAME,
|
|
3
|
+
isValidTranscriptDate
|
|
4
|
+
} from "./chunk-M7XQSUBB.js";
|
|
1
5
|
import {
|
|
2
6
|
isErrnoCode
|
|
3
7
|
} from "./chunk-5UZXUTVO.js";
|
|
@@ -77,274 +81,8 @@ import {
|
|
|
77
81
|
// src/storage.ts
|
|
78
82
|
import { access, readdir, readFile, stat, writeFile, mkdir, unlink, appendFile, open } from "fs/promises";
|
|
79
83
|
import { appendFileSync, createReadStream, mkdirSync, statSync } from "fs";
|
|
80
|
-
import { createHash as createHash2 } from "crypto";
|
|
81
|
-
import path2 from "path";
|
|
82
|
-
|
|
83
|
-
// src/wearables/day-store.ts
|
|
84
84
|
import { createHash } from "crypto";
|
|
85
|
-
|
|
86
|
-
// src/wearables/speakers.ts
|
|
87
|
-
import { promises as fsPromises } from "fs";
|
|
88
|
-
import * as path from "path";
|
|
89
|
-
var DEFAULT_SELF_NAME = "Me";
|
|
90
|
-
function emptySpeakerRegistry() {
|
|
91
|
-
return { version: 1, selfName: DEFAULT_SELF_NAME, speakers: {} };
|
|
92
|
-
}
|
|
93
|
-
function speakersFilePath(memoryDir) {
|
|
94
|
-
return path.join(memoryDir, "state", "wearables", "speakers.json");
|
|
95
|
-
}
|
|
96
|
-
async function loadSpeakerRegistry(memoryDir) {
|
|
97
|
-
const filePath = speakersFilePath(memoryDir);
|
|
98
|
-
let raw;
|
|
99
|
-
try {
|
|
100
|
-
raw = await fsPromises.readFile(filePath, "utf-8");
|
|
101
|
-
} catch (err) {
|
|
102
|
-
if (err.code === "ENOENT") {
|
|
103
|
-
return emptySpeakerRegistry();
|
|
104
|
-
}
|
|
105
|
-
throw err;
|
|
106
|
-
}
|
|
107
|
-
let parsed;
|
|
108
|
-
try {
|
|
109
|
-
parsed = JSON.parse(raw);
|
|
110
|
-
} catch (err) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`wearables speakers file is not valid JSON (state/wearables/speakers.json): ${err instanceof Error ? err.message : String(err)}`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof parsed.speakers !== "object" || parsed.speakers === null) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
'wearables speakers file has an unexpected shape (state/wearables/speakers.json); expected {"version":1,"selfName":"...","speakers":{}}'
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
const registry = parsed;
|
|
121
|
-
return {
|
|
122
|
-
version: 1,
|
|
123
|
-
selfName: typeof registry.selfName === "string" && registry.selfName.trim().length > 0 ? registry.selfName.trim() : DEFAULT_SELF_NAME,
|
|
124
|
-
speakers: registry.speakers
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
async function saveSpeakerRegistry(memoryDir, registry) {
|
|
128
|
-
const filePath = speakersFilePath(memoryDir);
|
|
129
|
-
await fsPromises.mkdir(path.dirname(filePath), { recursive: true });
|
|
130
|
-
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
131
|
-
await fsPromises.writeFile(
|
|
132
|
-
tmpPath,
|
|
133
|
-
`${JSON.stringify(registry, null, 2)}
|
|
134
|
-
`,
|
|
135
|
-
"utf-8"
|
|
136
|
-
);
|
|
137
|
-
try {
|
|
138
|
-
await fsPromises.rename(tmpPath, filePath);
|
|
139
|
-
} catch (err) {
|
|
140
|
-
await fsPromises.unlink(tmpPath).catch(() => void 0);
|
|
141
|
-
throw err;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function speakerRegistryKey(sourceId, speakerKey) {
|
|
145
|
-
return `${sourceId}:${speakerKey}`;
|
|
146
|
-
}
|
|
147
|
-
function resolveSpeaker(sourceId, segment, registry) {
|
|
148
|
-
const override = registry.speakers[speakerRegistryKey(sourceId, segment.speakerKey)];
|
|
149
|
-
if (override) {
|
|
150
|
-
const isSelf = override.isSelf === true;
|
|
151
|
-
return {
|
|
152
|
-
label: isSelf ? `${override.name} (you)` : override.name,
|
|
153
|
-
isSelf
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
if (segment.isWearer === true) {
|
|
157
|
-
return { label: `${registry.selfName} (you)`, isSelf: true };
|
|
158
|
-
}
|
|
159
|
-
if (typeof segment.speakerName === "string" && segment.speakerName.trim().length > 0) {
|
|
160
|
-
return { label: segment.speakerName.trim(), isSelf: false };
|
|
161
|
-
}
|
|
162
|
-
const key = segment.speakerKey.trim();
|
|
163
|
-
if (/^\d+$/.test(key)) {
|
|
164
|
-
return { label: `Speaker ${key}`, isSelf: false };
|
|
165
|
-
}
|
|
166
|
-
return { label: key.length > 0 ? key : "Unknown speaker", isSelf: false };
|
|
167
|
-
}
|
|
168
|
-
function distinctSpeakerLabels(sourceId, segments, registry) {
|
|
169
|
-
const labels = [];
|
|
170
|
-
const seen = /* @__PURE__ */ new Set();
|
|
171
|
-
for (const segment of segments) {
|
|
172
|
-
const { label } = resolveSpeaker(sourceId, segment, registry);
|
|
173
|
-
if (!seen.has(label)) {
|
|
174
|
-
seen.add(label);
|
|
175
|
-
labels.push(label);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return labels;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// src/wearables/day-store.ts
|
|
182
|
-
var WEARABLES_DIR_NAME = "wearables";
|
|
183
|
-
var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
184
|
-
function isValidTranscriptDate(date) {
|
|
185
|
-
if (!DATE_PATTERN.test(date)) return false;
|
|
186
|
-
const parsed = /* @__PURE__ */ new Date(`${date}T00:00:00Z`);
|
|
187
|
-
return !Number.isNaN(parsed.getTime()) && parsed.toISOString().slice(0, 10) === date;
|
|
188
|
-
}
|
|
189
|
-
function hashTranscriptBody(body) {
|
|
190
|
-
return createHash("sha256").update(body, "utf-8").digest("hex");
|
|
191
|
-
}
|
|
192
|
-
function formatClockTime(iso, timezone) {
|
|
193
|
-
if (!iso) return "--:--";
|
|
194
|
-
const ms = Date.parse(iso);
|
|
195
|
-
if (Number.isNaN(ms)) return "--:--";
|
|
196
|
-
try {
|
|
197
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
198
|
-
timeZone: timezone,
|
|
199
|
-
hour12: false,
|
|
200
|
-
hour: "2-digit",
|
|
201
|
-
minute: "2-digit"
|
|
202
|
-
}).format(new Date(ms));
|
|
203
|
-
} catch {
|
|
204
|
-
return new Date(ms).toISOString().slice(11, 16);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function conversationDurationMinutes(conversation) {
|
|
208
|
-
const start = Date.parse(conversation.startIso);
|
|
209
|
-
const end = conversation.endIso ? Date.parse(conversation.endIso) : NaN;
|
|
210
|
-
if (Number.isNaN(start) || Number.isNaN(end) || end <= start) return 0;
|
|
211
|
-
return (end - start) / 6e4;
|
|
212
|
-
}
|
|
213
|
-
function composeDayTranscriptBody(sourceId, date, timezone, conversations, registry) {
|
|
214
|
-
const lines = [];
|
|
215
|
-
lines.push(`# ${sourceId} transcript \u2014 ${date}`);
|
|
216
|
-
lines.push("");
|
|
217
|
-
const ordered = [...conversations].sort((a, b) => {
|
|
218
|
-
const aMs = Date.parse(a.startIso);
|
|
219
|
-
const bMs = Date.parse(b.startIso);
|
|
220
|
-
if (aMs < bMs) return -1;
|
|
221
|
-
if (aMs > bMs) return 1;
|
|
222
|
-
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
223
|
-
});
|
|
224
|
-
for (const conversation of ordered) {
|
|
225
|
-
const start = formatClockTime(conversation.startIso, timezone);
|
|
226
|
-
const end = formatClockTime(conversation.endIso, timezone);
|
|
227
|
-
const title = conversation.title?.trim();
|
|
228
|
-
const heading = title && title.length > 0 ? ` \xB7 ${title}` : "";
|
|
229
|
-
lines.push(`## ${start}\u2013${end}${heading} (conversation ${conversation.id})`);
|
|
230
|
-
if (conversation.location) {
|
|
231
|
-
lines.push(`*Location: ${conversation.location}*`);
|
|
232
|
-
}
|
|
233
|
-
lines.push("");
|
|
234
|
-
for (const segment of conversation.segments) {
|
|
235
|
-
const { label } = resolveSpeaker(sourceId, segment, registry);
|
|
236
|
-
const at = formatClockTime(segment.startIso, timezone);
|
|
237
|
-
lines.push(`**${label}** [${at}]: ${segment.text}`);
|
|
238
|
-
}
|
|
239
|
-
lines.push("");
|
|
240
|
-
}
|
|
241
|
-
return `${lines.join("\n").trimEnd()}
|
|
242
|
-
`;
|
|
243
|
-
}
|
|
244
|
-
function composeDayTranscriptMeta(sourceId, date, timezone, conversations, registry, body, syncedAt) {
|
|
245
|
-
const allSegments = conversations.flatMap((c) => c.segments);
|
|
246
|
-
const durationMinutes = Math.round(
|
|
247
|
-
conversations.reduce((sum, c) => sum + conversationDurationMinutes(c), 0)
|
|
248
|
-
);
|
|
249
|
-
return {
|
|
250
|
-
kind: "wearable-transcript",
|
|
251
|
-
source: sourceId,
|
|
252
|
-
date,
|
|
253
|
-
timezone,
|
|
254
|
-
conversationCount: conversations.length,
|
|
255
|
-
segmentCount: allSegments.length,
|
|
256
|
-
speakers: distinctSpeakerLabels(sourceId, allSegments, registry),
|
|
257
|
-
durationMinutes,
|
|
258
|
-
contentHash: hashTranscriptBody(body),
|
|
259
|
-
syncedAt
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
function serializeDayTranscript(meta, body) {
|
|
263
|
-
const lines = ["---"];
|
|
264
|
-
lines.push(`kind: ${meta.kind}`);
|
|
265
|
-
lines.push(`source: ${JSON.stringify(meta.source)}`);
|
|
266
|
-
lines.push(`date: ${JSON.stringify(meta.date)}`);
|
|
267
|
-
lines.push(`timezone: ${JSON.stringify(meta.timezone)}`);
|
|
268
|
-
lines.push(`conversationCount: ${meta.conversationCount}`);
|
|
269
|
-
lines.push(`segmentCount: ${meta.segmentCount}`);
|
|
270
|
-
if (meta.speakers.length === 0) {
|
|
271
|
-
lines.push("speakers: []");
|
|
272
|
-
} else {
|
|
273
|
-
lines.push("speakers:");
|
|
274
|
-
for (const speaker of meta.speakers) {
|
|
275
|
-
lines.push(` - ${JSON.stringify(speaker)}`);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
lines.push(`durationMinutes: ${meta.durationMinutes}`);
|
|
279
|
-
lines.push(`contentHash: ${JSON.stringify(meta.contentHash)}`);
|
|
280
|
-
lines.push(`syncedAt: ${JSON.stringify(meta.syncedAt)}`);
|
|
281
|
-
lines.push("---");
|
|
282
|
-
lines.push("");
|
|
283
|
-
return `${lines.join("\n")}${body}`;
|
|
284
|
-
}
|
|
285
|
-
function parseDayTranscript(raw) {
|
|
286
|
-
if (!raw.startsWith("---\n")) return null;
|
|
287
|
-
const closeIndex = raw.indexOf("\n---\n", 4);
|
|
288
|
-
if (closeIndex === -1) return null;
|
|
289
|
-
const header = raw.slice(4, closeIndex);
|
|
290
|
-
const body = raw.slice(closeIndex + 5).replace(/^\n/, "");
|
|
291
|
-
const scalars = /* @__PURE__ */ new Map();
|
|
292
|
-
const speakers = [];
|
|
293
|
-
let inSpeakers = false;
|
|
294
|
-
for (const line of header.split("\n")) {
|
|
295
|
-
if (inSpeakers) {
|
|
296
|
-
const item = line.match(/^ {2}- (.*)$/);
|
|
297
|
-
if (item) {
|
|
298
|
-
speakers.push(parseYamlScalar(item[1]));
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
inSpeakers = false;
|
|
302
|
-
}
|
|
303
|
-
if (line === "speakers:") {
|
|
304
|
-
inSpeakers = true;
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
if (line === "speakers: []") continue;
|
|
308
|
-
const match = line.match(/^([A-Za-z][A-Za-z0-9]*): (.*)$/);
|
|
309
|
-
if (match) scalars.set(match[1], parseYamlScalar(match[2]));
|
|
310
|
-
}
|
|
311
|
-
if (scalars.get("kind") !== "wearable-transcript") return null;
|
|
312
|
-
const source = scalars.get("source");
|
|
313
|
-
const date = scalars.get("date");
|
|
314
|
-
if (!source || !date) return null;
|
|
315
|
-
const meta = {
|
|
316
|
-
kind: "wearable-transcript",
|
|
317
|
-
source,
|
|
318
|
-
date,
|
|
319
|
-
timezone: scalars.get("timezone") ?? "UTC",
|
|
320
|
-
conversationCount: parseNonNegativeInt(scalars.get("conversationCount")),
|
|
321
|
-
segmentCount: parseNonNegativeInt(scalars.get("segmentCount")),
|
|
322
|
-
speakers,
|
|
323
|
-
durationMinutes: parseNonNegativeInt(scalars.get("durationMinutes")),
|
|
324
|
-
contentHash: scalars.get("contentHash") ?? "",
|
|
325
|
-
syncedAt: scalars.get("syncedAt") ?? ""
|
|
326
|
-
};
|
|
327
|
-
return { meta, body };
|
|
328
|
-
}
|
|
329
|
-
function parseYamlScalar(value) {
|
|
330
|
-
const trimmed = value.trim();
|
|
331
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length >= 2) {
|
|
332
|
-
try {
|
|
333
|
-
const parsed = JSON.parse(trimmed);
|
|
334
|
-
if (typeof parsed === "string") return parsed;
|
|
335
|
-
} catch {
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return trimmed;
|
|
339
|
-
}
|
|
340
|
-
function parseNonNegativeInt(value) {
|
|
341
|
-
if (value === void 0) return 0;
|
|
342
|
-
const parsed = Number(value);
|
|
343
|
-
if (!Number.isFinite(parsed) || parsed < 0) return 0;
|
|
344
|
-
return Math.floor(parsed);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// src/storage.ts
|
|
85
|
+
import path from "path";
|
|
348
86
|
var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
|
|
349
87
|
"a",
|
|
350
88
|
"an",
|
|
@@ -928,17 +666,17 @@ var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set([
|
|
|
928
666
|
"topic"
|
|
929
667
|
]);
|
|
930
668
|
function inferEntityTypeFromFilename(pathRel) {
|
|
931
|
-
const basename =
|
|
669
|
+
const basename = path.basename(pathRel, ".md").toLowerCase();
|
|
932
670
|
const separator = basename.indexOf("-");
|
|
933
671
|
if (separator <= 0) return void 0;
|
|
934
672
|
const candidate = basename.slice(0, separator);
|
|
935
673
|
return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
|
|
936
674
|
}
|
|
937
675
|
function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
|
|
938
|
-
const normalizedPath = pathRel.split(
|
|
676
|
+
const normalizedPath = pathRel.split(path.sep).join("/");
|
|
939
677
|
let normalizedFrontmatter = frontmatter;
|
|
940
678
|
if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
|
|
941
|
-
const basename =
|
|
679
|
+
const basename = path.basename(pathRel, ".md");
|
|
942
680
|
const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
|
|
943
681
|
const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
|
|
944
682
|
normalizedFrontmatter = {
|
|
@@ -1005,8 +743,8 @@ var ContentHashIndex = class _ContentHashIndex {
|
|
|
1005
743
|
secureStoreKeyProvider;
|
|
1006
744
|
secureStoreWriteKeyProvider;
|
|
1007
745
|
memoryDir;
|
|
1008
|
-
constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir =
|
|
1009
|
-
this.filePath =
|
|
746
|
+
constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path.dirname(stateDir)) {
|
|
747
|
+
this.filePath = path.join(stateDir, "fact-hashes.txt");
|
|
1010
748
|
this.secureStoreKeyProvider = secureStoreKeyProvider;
|
|
1011
749
|
this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
|
|
1012
750
|
this.memoryDir = memoryDir;
|
|
@@ -1053,7 +791,7 @@ var ContentHashIndex = class _ContentHashIndex {
|
|
|
1053
791
|
/** Persist index to disk if changed. */
|
|
1054
792
|
async save() {
|
|
1055
793
|
if (!this.dirty) return;
|
|
1056
|
-
await mkdir(
|
|
794
|
+
await mkdir(path.dirname(this.filePath), { recursive: true });
|
|
1057
795
|
await writeMaybeEncryptedFile(
|
|
1058
796
|
this.filePath,
|
|
1059
797
|
[...this.hashes].join("\n") + "\n",
|
|
@@ -1105,9 +843,19 @@ var ContentHashIndex = class _ContentHashIndex {
|
|
|
1105
843
|
/** Normalize content and compute SHA-256 hash. */
|
|
1106
844
|
static computeHash(content) {
|
|
1107
845
|
const normalized = _ContentHashIndex.normalizeContent(content);
|
|
1108
|
-
return
|
|
846
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
1109
847
|
}
|
|
1110
848
|
};
|
|
849
|
+
function stripAttributesSuffix(content) {
|
|
850
|
+
const trimmed = content.trimEnd();
|
|
851
|
+
if (!trimmed.endsWith("]")) return content.trim();
|
|
852
|
+
const marker = "\n[Attributes: ";
|
|
853
|
+
const markerIndex = trimmed.lastIndexOf(marker);
|
|
854
|
+
if (markerIndex === -1) return content.trim();
|
|
855
|
+
const inner = trimmed.slice(markerIndex + marker.length, -1);
|
|
856
|
+
if (inner.includes("]") || inner.includes("\n")) return content.trim();
|
|
857
|
+
return trimmed.slice(0, markerIndex).trim();
|
|
858
|
+
}
|
|
1111
859
|
function normalizeAttributePairs(pairs) {
|
|
1112
860
|
return Object.entries(pairs).map(([k, v]) => [k.trim().toLowerCase(), v.trim()]).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
1113
861
|
}
|
|
@@ -1596,7 +1344,7 @@ function fingerprintEntityStructuredFacts(entity) {
|
|
|
1596
1344
|
facts: normalizeStructuredSectionFacts(section.facts).slice().sort((left, right) => left.localeCompare(right))
|
|
1597
1345
|
})).filter((section) => section.facts.length > 0).sort((left, right) => left.key.localeCompare(right.key) || left.title.localeCompare(right.title) || left.facts.join("\n").localeCompare(right.facts.join("\n")));
|
|
1598
1346
|
if (normalizedSections.length === 0) return void 0;
|
|
1599
|
-
return
|
|
1347
|
+
return createHash("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
|
|
1600
1348
|
}
|
|
1601
1349
|
function isEntitySynthesisStale(entity) {
|
|
1602
1350
|
const structuredFactCount = countEntityStructuredFacts(entity);
|
|
@@ -2110,7 +1858,7 @@ var StorageManager = class _StorageManager {
|
|
|
2110
1858
|
void 0,
|
|
2111
1859
|
this.baseDir
|
|
2112
1860
|
);
|
|
2113
|
-
const rel =
|
|
1861
|
+
const rel = path.relative(this.baseDir, filePath).split(path.sep).join("/");
|
|
2114
1862
|
return `${rel}:${version.versionId}`;
|
|
2115
1863
|
} catch (err) {
|
|
2116
1864
|
log.warn(
|
|
@@ -2125,13 +1873,13 @@ var StorageManager = class _StorageManager {
|
|
|
2125
1873
|
}
|
|
2126
1874
|
identityFilePath(workspaceDir, namespace) {
|
|
2127
1875
|
const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
|
|
2128
|
-
if (!rawNamespace) return
|
|
1876
|
+
if (!rawNamespace) return path.join(workspaceDir, "IDENTITY.md");
|
|
2129
1877
|
const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
2130
|
-
return
|
|
1878
|
+
return path.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
|
|
2131
1879
|
}
|
|
2132
1880
|
versionFilePath(kind) {
|
|
2133
1881
|
const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : ".cold-write-version.log";
|
|
2134
|
-
return
|
|
1882
|
+
return path.join(this.stateDir, fileName);
|
|
2135
1883
|
}
|
|
2136
1884
|
bumpSharedVersion(kind, fallbackMap) {
|
|
2137
1885
|
const filePath = this.versionFilePath(kind);
|
|
@@ -2177,7 +1925,7 @@ var StorageManager = class _StorageManager {
|
|
|
2177
1925
|
// memories.
|
|
2178
1926
|
// -------------------------------------------------------------------------
|
|
2179
1927
|
get wearablesDir() {
|
|
2180
|
-
return
|
|
1928
|
+
return path.join(this.baseDir, WEARABLES_DIR_NAME);
|
|
2181
1929
|
}
|
|
2182
1930
|
/**
|
|
2183
1931
|
* Resolve the on-disk path for a source/day transcript. Throws on
|
|
@@ -2195,7 +1943,7 @@ var StorageManager = class _StorageManager {
|
|
|
2195
1943
|
`invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`
|
|
2196
1944
|
);
|
|
2197
1945
|
}
|
|
2198
|
-
return
|
|
1946
|
+
return path.join(this.wearablesDir, sourceId, `${date}.md`);
|
|
2199
1947
|
}
|
|
2200
1948
|
async writeWearableDayTranscript(sourceId, date, serialized) {
|
|
2201
1949
|
const targetPath = this.wearableTranscriptPath(sourceId, date);
|
|
@@ -2233,7 +1981,7 @@ var StorageManager = class _StorageManager {
|
|
|
2233
1981
|
if (!/^[a-z][a-z0-9-]{0,63}$/.test(source)) continue;
|
|
2234
1982
|
let entries;
|
|
2235
1983
|
try {
|
|
2236
|
-
entries = await readdir(
|
|
1984
|
+
entries = await readdir(path.join(this.wearablesDir, source));
|
|
2237
1985
|
} catch (err) {
|
|
2238
1986
|
if (err.code === "ENOENT") continue;
|
|
2239
1987
|
throw err;
|
|
@@ -2254,26 +2002,87 @@ var StorageManager = class _StorageManager {
|
|
|
2254
2002
|
});
|
|
2255
2003
|
return days;
|
|
2256
2004
|
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Locate a wearable-sourced memory by exact (trimmed) content,
|
|
2007
|
+
* ignoring the "[Attributes: ...]" suffix writeMemory appends for
|
|
2008
|
+
* structuredAttributes — callers pass the raw fact text. Used by the
|
|
2009
|
+
* smart trust pipeline to find an earlier borderline write when the
|
|
2010
|
+
* same fact re-extracts with stronger evidence.
|
|
2011
|
+
*/
|
|
2012
|
+
async findWearableMemoryByContent(content) {
|
|
2013
|
+
const needle = stripAttributesSuffix(content);
|
|
2014
|
+
const memories = await this.readAllMemories();
|
|
2015
|
+
for (const memory of memories) {
|
|
2016
|
+
if (typeof memory.frontmatter.source === "string" && memory.frontmatter.source.startsWith("wearable:") && stripAttributesSuffix(memory.content) === needle) {
|
|
2017
|
+
return { id: memory.frontmatter.id, status: memory.frontmatter.status };
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* Promote a pending_review wearable memory to active in place,
|
|
2024
|
+
* merging updated trust evidence into structuredAttributes. Returns
|
|
2025
|
+
* false when the memory is missing or no longer pending_review (a
|
|
2026
|
+
* concurrent review decision wins).
|
|
2027
|
+
*/
|
|
2028
|
+
async promoteWearableMemory(id, attributeUpdates, confidence) {
|
|
2029
|
+
const memories = await this.readAllMemories();
|
|
2030
|
+
const memory = memories.find((entry) => entry.frontmatter.id === id);
|
|
2031
|
+
if (!memory) return false;
|
|
2032
|
+
if (memory.frontmatter.status !== "pending_review") return false;
|
|
2033
|
+
return this.writeMemoryFrontmatter(memory, {
|
|
2034
|
+
status: "active",
|
|
2035
|
+
// Keep frontmatter confidence in step with the re-scored trust —
|
|
2036
|
+
// new smart writes persist trust as confidence, and a promoted
|
|
2037
|
+
// row must not keep its stale borderline value.
|
|
2038
|
+
...typeof confidence === "number" && Number.isFinite(confidence) ? { confidence: Math.min(1, Math.max(0, confidence)) } : {},
|
|
2039
|
+
structuredAttributes: {
|
|
2040
|
+
...memory.frontmatter.structuredAttributes ?? {},
|
|
2041
|
+
...attributeUpdates
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Demote a pending_review wearable memory to rejected when a re-pass
|
|
2047
|
+
* produced an explicit judge-reject verdict, merging the evidence.
|
|
2048
|
+
* Returns false when the memory is missing or no longer
|
|
2049
|
+
* pending_review — active rows are NEVER auto-demoted (operator
|
|
2050
|
+
* approvals and accrued recall signals win; contradiction scans and
|
|
2051
|
+
* supersession own active-row retirement).
|
|
2052
|
+
*/
|
|
2053
|
+
async demoteWearableMemory(id, attributeUpdates) {
|
|
2054
|
+
const memories = await this.readAllMemories();
|
|
2055
|
+
const memory = memories.find((entry) => entry.frontmatter.id === id);
|
|
2056
|
+
if (!memory) return false;
|
|
2057
|
+
if (memory.frontmatter.status !== "pending_review") return false;
|
|
2058
|
+
return this.writeMemoryFrontmatter(memory, {
|
|
2059
|
+
status: "rejected",
|
|
2060
|
+
structuredAttributes: {
|
|
2061
|
+
...memory.frontmatter.structuredAttributes ?? {},
|
|
2062
|
+
...attributeUpdates
|
|
2063
|
+
}
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2257
2066
|
get factsDir() {
|
|
2258
|
-
return
|
|
2067
|
+
return path.join(this.baseDir, "facts");
|
|
2259
2068
|
}
|
|
2260
2069
|
get correctionsDir() {
|
|
2261
|
-
return
|
|
2070
|
+
return path.join(this.baseDir, "corrections");
|
|
2262
2071
|
}
|
|
2263
2072
|
get proceduresDir() {
|
|
2264
|
-
return
|
|
2073
|
+
return path.join(this.baseDir, "procedures");
|
|
2265
2074
|
}
|
|
2266
2075
|
get reasoningTracesDir() {
|
|
2267
|
-
return
|
|
2076
|
+
return path.join(this.baseDir, "reasoning-traces");
|
|
2268
2077
|
}
|
|
2269
2078
|
get entitiesDir() {
|
|
2270
|
-
return
|
|
2079
|
+
return path.join(this.baseDir, "entities");
|
|
2271
2080
|
}
|
|
2272
2081
|
resolveEntityFilePath(name) {
|
|
2273
2082
|
if (typeof name !== "string") return null;
|
|
2274
|
-
const filePath =
|
|
2275
|
-
const relative =
|
|
2276
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
2083
|
+
const filePath = path.resolve(this.entitiesDir, `${name}.md`);
|
|
2084
|
+
const relative = path.relative(this.entitiesDir, filePath);
|
|
2085
|
+
if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
2277
2086
|
return null;
|
|
2278
2087
|
}
|
|
2279
2088
|
return filePath;
|
|
@@ -2285,10 +2094,10 @@ var StorageManager = class _StorageManager {
|
|
|
2285
2094
|
return writeMaybeEncryptedFile(filePath, content, this.resolveWriteKey(), {}, this.baseDir);
|
|
2286
2095
|
}
|
|
2287
2096
|
assertManagedStoragePath(filePath, method) {
|
|
2288
|
-
const resolved =
|
|
2289
|
-
const base =
|
|
2290
|
-
const rel =
|
|
2291
|
-
if (rel === "" || rel === ".." || rel.startsWith(`..${
|
|
2097
|
+
const resolved = path.resolve(filePath);
|
|
2098
|
+
const base = path.resolve(this.baseDir);
|
|
2099
|
+
const rel = path.relative(base, resolved);
|
|
2100
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) {
|
|
2292
2101
|
throw new Error(`${method}: file path escapes memory dir`);
|
|
2293
2102
|
}
|
|
2294
2103
|
return resolved;
|
|
@@ -2300,7 +2109,7 @@ var StorageManager = class _StorageManager {
|
|
|
2300
2109
|
async digestOfflineSyncFile(filePath) {
|
|
2301
2110
|
const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
|
|
2302
2111
|
const st = await stat(target);
|
|
2303
|
-
const relPath =
|
|
2112
|
+
const relPath = path.relative(this.baseDir, target).split(path.sep).join("/");
|
|
2304
2113
|
const cache = await this.loadOfflineSyncDigestCache();
|
|
2305
2114
|
const cached = cache.get(relPath);
|
|
2306
2115
|
if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
|
|
@@ -2314,11 +2123,11 @@ var StorageManager = class _StorageManager {
|
|
|
2314
2123
|
if (encrypted) {
|
|
2315
2124
|
const content = await readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
|
|
2316
2125
|
digest = {
|
|
2317
|
-
sha256:
|
|
2126
|
+
sha256: createHash("sha256").update(content).digest("hex"),
|
|
2318
2127
|
bytes: content.byteLength
|
|
2319
2128
|
};
|
|
2320
2129
|
} else {
|
|
2321
|
-
const hash =
|
|
2130
|
+
const hash = createHash("sha256");
|
|
2322
2131
|
let bytes = 0;
|
|
2323
2132
|
for await (const rawChunk of createReadStream(target)) {
|
|
2324
2133
|
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
@@ -2361,7 +2170,7 @@ var StorageManager = class _StorageManager {
|
|
|
2361
2170
|
const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
|
|
2362
2171
|
const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
|
|
2363
2172
|
const encrypted = record.encrypted === true;
|
|
2364
|
-
if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") ||
|
|
2173
|
+
if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
|
|
2365
2174
|
continue;
|
|
2366
2175
|
}
|
|
2367
2176
|
cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
|
|
@@ -2403,7 +2212,7 @@ var StorageManager = class _StorageManager {
|
|
|
2403
2212
|
const cache = this.offlineSyncDigestCache;
|
|
2404
2213
|
if (!cache) return;
|
|
2405
2214
|
const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
|
|
2406
|
-
await mkdir(
|
|
2215
|
+
await mkdir(path.dirname(this.offlineSyncDigestCachePath), { recursive: true });
|
|
2407
2216
|
await writeFile(
|
|
2408
2217
|
this.offlineSyncDigestCachePath,
|
|
2409
2218
|
`${JSON.stringify({ version: 1, entries })}
|
|
@@ -2457,10 +2266,10 @@ var StorageManager = class _StorageManager {
|
|
|
2457
2266
|
if (isErrnoCode(error, "ENOENT")) return;
|
|
2458
2267
|
throw error;
|
|
2459
2268
|
});
|
|
2460
|
-
if (filePath.includes(`${
|
|
2269
|
+
if (filePath.includes(`${path.sep}cold${path.sep}`)) {
|
|
2461
2270
|
this.invalidateColdMemoriesCache();
|
|
2462
2271
|
}
|
|
2463
|
-
if (filePath.includes(`${
|
|
2272
|
+
if (filePath.includes(`${path.sep}artifacts${path.sep}`)) {
|
|
2464
2273
|
this.bumpArtifactWriteVersion();
|
|
2465
2274
|
}
|
|
2466
2275
|
this.bumpMemoryStatusVersion();
|
|
@@ -2488,7 +2297,7 @@ var StorageManager = class _StorageManager {
|
|
|
2488
2297
|
}
|
|
2489
2298
|
async appendStorageSecureFileUnlocked(filePath, content) {
|
|
2490
2299
|
const writeKey = this.resolveWriteKey();
|
|
2491
|
-
await mkdir(
|
|
2300
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
2492
2301
|
if (writeKey === null) {
|
|
2493
2302
|
try {
|
|
2494
2303
|
if (isEncryptedFile(await readFile(filePath))) {
|
|
@@ -2511,16 +2320,16 @@ var StorageManager = class _StorageManager {
|
|
|
2511
2320
|
await writeMaybeEncryptedFile(filePath, `${existing}${content}`, writeKey, {}, this.baseDir);
|
|
2512
2321
|
}
|
|
2513
2322
|
get stateDir() {
|
|
2514
|
-
return
|
|
2323
|
+
return path.join(this.baseDir, "state");
|
|
2515
2324
|
}
|
|
2516
2325
|
get offlineSyncDigestCachePath() {
|
|
2517
|
-
return
|
|
2326
|
+
return path.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
|
|
2518
2327
|
}
|
|
2519
2328
|
get entitySynthesisQueuePath() {
|
|
2520
|
-
return
|
|
2329
|
+
return path.join(this.stateDir, "entity-synthesis-queue.json");
|
|
2521
2330
|
}
|
|
2522
2331
|
get factHashIndexReadyPath() {
|
|
2523
|
-
return
|
|
2332
|
+
return path.join(this.stateDir, "fact-hashes.ready");
|
|
2524
2333
|
}
|
|
2525
2334
|
async getFactHashIndex() {
|
|
2526
2335
|
if (this.factHashIndex) {
|
|
@@ -2587,7 +2396,7 @@ var StorageManager = class _StorageManager {
|
|
|
2587
2396
|
);
|
|
2588
2397
|
}
|
|
2589
2398
|
await factHashIndex.save();
|
|
2590
|
-
await mkdir(
|
|
2399
|
+
await mkdir(path.dirname(this.factHashIndexReadyPath), { recursive: true });
|
|
2591
2400
|
await writeFile(this.factHashIndexReadyPath, "v1\n", "utf-8");
|
|
2592
2401
|
this.factHashIndexAuthoritative = true;
|
|
2593
2402
|
})().finally(() => {
|
|
@@ -2596,55 +2405,55 @@ var StorageManager = class _StorageManager {
|
|
|
2596
2405
|
await this.factHashIndexAuthoritativePromise;
|
|
2597
2406
|
}
|
|
2598
2407
|
get questionsDir() {
|
|
2599
|
-
return
|
|
2408
|
+
return path.join(this.baseDir, "questions");
|
|
2600
2409
|
}
|
|
2601
2410
|
get artifactsDir() {
|
|
2602
|
-
return
|
|
2411
|
+
return path.join(this.baseDir, "artifacts");
|
|
2603
2412
|
}
|
|
2604
2413
|
get identityDir() {
|
|
2605
|
-
return
|
|
2414
|
+
return path.join(this.baseDir, "identity");
|
|
2606
2415
|
}
|
|
2607
2416
|
get identityAnchorPath() {
|
|
2608
|
-
return
|
|
2417
|
+
return path.join(this.identityDir, "identity-anchor.md");
|
|
2609
2418
|
}
|
|
2610
2419
|
get identityIncidentsDir() {
|
|
2611
|
-
return
|
|
2420
|
+
return path.join(this.identityDir, "incidents");
|
|
2612
2421
|
}
|
|
2613
2422
|
get identityAuditsWeeklyDir() {
|
|
2614
|
-
return
|
|
2423
|
+
return path.join(this.identityDir, "audits", "weekly");
|
|
2615
2424
|
}
|
|
2616
2425
|
get identityAuditsMonthlyDir() {
|
|
2617
|
-
return
|
|
2426
|
+
return path.join(this.identityDir, "audits", "monthly");
|
|
2618
2427
|
}
|
|
2619
2428
|
get identityImprovementLoopsPath() {
|
|
2620
|
-
return
|
|
2429
|
+
return path.join(this.identityDir, "improvement-loops.md");
|
|
2621
2430
|
}
|
|
2622
2431
|
get identityReflectionsPath() {
|
|
2623
|
-
return
|
|
2432
|
+
return path.join(this.identityDir, "reflections.md");
|
|
2624
2433
|
}
|
|
2625
2434
|
get profilePath() {
|
|
2626
|
-
return
|
|
2435
|
+
return path.join(this.baseDir, "profile.md");
|
|
2627
2436
|
}
|
|
2628
2437
|
get memoryActionsPath() {
|
|
2629
|
-
return
|
|
2438
|
+
return path.join(this.stateDir, "memory-actions.jsonl");
|
|
2630
2439
|
}
|
|
2631
2440
|
get memoryLifecycleLedgerPath() {
|
|
2632
|
-
return
|
|
2441
|
+
return path.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
|
|
2633
2442
|
}
|
|
2634
2443
|
get compressionGuidelinesPath() {
|
|
2635
|
-
return
|
|
2444
|
+
return path.join(this.stateDir, "compression-guidelines.md");
|
|
2636
2445
|
}
|
|
2637
2446
|
get compressionGuidelineDraftPath() {
|
|
2638
|
-
return
|
|
2447
|
+
return path.join(this.stateDir, "compression-guidelines.draft.md");
|
|
2639
2448
|
}
|
|
2640
2449
|
get compressionGuidelineStatePath() {
|
|
2641
|
-
return
|
|
2450
|
+
return path.join(this.stateDir, "compression-guideline-state.json");
|
|
2642
2451
|
}
|
|
2643
2452
|
get compressionGuidelineDraftStatePath() {
|
|
2644
|
-
return
|
|
2453
|
+
return path.join(this.stateDir, "compression-guideline-draft-state.json");
|
|
2645
2454
|
}
|
|
2646
2455
|
get behaviorSignalsPath() {
|
|
2647
|
-
return
|
|
2456
|
+
return path.join(this.stateDir, "behavior-signals.jsonl");
|
|
2648
2457
|
}
|
|
2649
2458
|
/**
|
|
2650
2459
|
* Buffer surprise telemetry ledger (issue #563 PR 3).
|
|
@@ -2657,7 +2466,7 @@ var StorageManager = class _StorageManager {
|
|
|
2657
2466
|
* governance sweeps can treat it uniformly.
|
|
2658
2467
|
*/
|
|
2659
2468
|
get bufferSurpriseLedgerPath() {
|
|
2660
|
-
return
|
|
2469
|
+
return path.join(this.stateDir, "buffer-surprise-ledger.jsonl");
|
|
2661
2470
|
}
|
|
2662
2471
|
/**
|
|
2663
2472
|
* Load user-defined entity aliases from config/aliases.json in the memory store.
|
|
@@ -2665,7 +2474,7 @@ var StorageManager = class _StorageManager {
|
|
|
2665
2474
|
* Call this once at startup (e.g. from orchestrator.initialize()).
|
|
2666
2475
|
*/
|
|
2667
2476
|
async loadAliases() {
|
|
2668
|
-
const aliasPath =
|
|
2477
|
+
const aliasPath = path.join(this.baseDir, "config", "aliases.json");
|
|
2669
2478
|
try {
|
|
2670
2479
|
const raw = await readFile(aliasPath, "utf-8");
|
|
2671
2480
|
const parsed = JSON.parse(raw);
|
|
@@ -2679,9 +2488,9 @@ var StorageManager = class _StorageManager {
|
|
|
2679
2488
|
}
|
|
2680
2489
|
async ensureDirectories() {
|
|
2681
2490
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2682
|
-
await mkdir(
|
|
2683
|
-
await mkdir(
|
|
2684
|
-
await mkdir(
|
|
2491
|
+
await mkdir(path.join(this.factsDir, today), { recursive: true });
|
|
2492
|
+
await mkdir(path.join(this.proceduresDir, today), { recursive: true });
|
|
2493
|
+
await mkdir(path.join(this.reasoningTracesDir, today), { recursive: true });
|
|
2685
2494
|
await mkdir(this.correctionsDir, { recursive: true });
|
|
2686
2495
|
await mkdir(this.entitiesDir, { recursive: true });
|
|
2687
2496
|
await mkdir(this.stateDir, { recursive: true });
|
|
@@ -2691,7 +2500,7 @@ var StorageManager = class _StorageManager {
|
|
|
2691
2500
|
await mkdir(this.identityIncidentsDir, { recursive: true });
|
|
2692
2501
|
await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
|
|
2693
2502
|
await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
|
|
2694
|
-
await mkdir(
|
|
2503
|
+
await mkdir(path.join(this.baseDir, "config"), { recursive: true });
|
|
2695
2504
|
}
|
|
2696
2505
|
async writeMemory(category, content, options = {}) {
|
|
2697
2506
|
await this.ensureDirectories();
|
|
@@ -2761,15 +2570,15 @@ ${sanitized.text}
|
|
|
2761
2570
|
`;
|
|
2762
2571
|
let filePath;
|
|
2763
2572
|
if (category === "correction") {
|
|
2764
|
-
filePath =
|
|
2573
|
+
filePath = path.join(this.correctionsDir, `${id}.md`);
|
|
2765
2574
|
} else if (category === "procedure") {
|
|
2766
|
-
await mkdir(
|
|
2767
|
-
filePath =
|
|
2575
|
+
await mkdir(path.join(this.proceduresDir, today), { recursive: true });
|
|
2576
|
+
filePath = path.join(this.proceduresDir, today, `${id}.md`);
|
|
2768
2577
|
} else if (category === "reasoning_trace") {
|
|
2769
|
-
await mkdir(
|
|
2770
|
-
filePath =
|
|
2578
|
+
await mkdir(path.join(this.reasoningTracesDir, today), { recursive: true });
|
|
2579
|
+
filePath = path.join(this.reasoningTracesDir, today, `${id}.md`);
|
|
2771
2580
|
} else {
|
|
2772
|
-
filePath =
|
|
2581
|
+
filePath = path.join(this.factsDir, today, `${id}.md`);
|
|
2773
2582
|
}
|
|
2774
2583
|
await this.snapshotBeforeWrite(filePath, "write");
|
|
2775
2584
|
await writeMaybeEncryptedFile(filePath, fileContent, this.resolveWriteKey(), {}, this.baseDir);
|
|
@@ -2884,7 +2693,7 @@ ${sanitized.text}
|
|
|
2884
2693
|
await this.ensureDirectories();
|
|
2885
2694
|
const now = /* @__PURE__ */ new Date();
|
|
2886
2695
|
const day = now.toISOString().slice(0, 10);
|
|
2887
|
-
const dir =
|
|
2696
|
+
const dir = path.join(this.artifactsDir, day);
|
|
2888
2697
|
await mkdir(dir, { recursive: true });
|
|
2889
2698
|
const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
2890
2699
|
const fm = {
|
|
@@ -2908,7 +2717,7 @@ ${sanitized.text}
|
|
|
2908
2717
|
log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
2909
2718
|
return "";
|
|
2910
2719
|
}
|
|
2911
|
-
const filePath =
|
|
2720
|
+
const filePath = path.join(dir, `${id}.md`);
|
|
2912
2721
|
await writeMaybeEncryptedFile(filePath, `${serializeFrontmatter(fm)}
|
|
2913
2722
|
|
|
2914
2723
|
${sanitized.text}
|
|
@@ -2936,7 +2745,7 @@ ${sanitized.text}
|
|
|
2936
2745
|
try {
|
|
2937
2746
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
2938
2747
|
for (const entry of entries) {
|
|
2939
|
-
const fullPath =
|
|
2748
|
+
const fullPath = path.join(dir, entry.name);
|
|
2940
2749
|
if (entry.isDirectory()) {
|
|
2941
2750
|
await readDir(fullPath);
|
|
2942
2751
|
continue;
|
|
@@ -3002,7 +2811,7 @@ ${sanitized.text}
|
|
|
3002
2811
|
log.debug(`fuzzy match: "${normalized}" \u2192 existing "${match}"`);
|
|
3003
2812
|
normalized = match;
|
|
3004
2813
|
}
|
|
3005
|
-
const filePath =
|
|
2814
|
+
const filePath = path.join(this.entitiesDir, `${normalized}.md`);
|
|
3006
2815
|
let entity = {
|
|
3007
2816
|
name,
|
|
3008
2817
|
type,
|
|
@@ -3237,7 +3046,7 @@ ${sanitized.text}
|
|
|
3237
3046
|
* per-process in-memory cache safe across process boundaries.
|
|
3238
3047
|
*/
|
|
3239
3048
|
invalidateColdMemoriesCache() {
|
|
3240
|
-
const coldRoot =
|
|
3049
|
+
const coldRoot = path.join(this.baseDir, "cold");
|
|
3241
3050
|
_StorageManager.coldMemoriesCache.delete(coldRoot);
|
|
3242
3051
|
this.bumpColdWriteVersion();
|
|
3243
3052
|
}
|
|
@@ -3265,7 +3074,7 @@ ${sanitized.text}
|
|
|
3265
3074
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
3266
3075
|
const subdirs = [];
|
|
3267
3076
|
for (const entry of entries) {
|
|
3268
|
-
const fullPath =
|
|
3077
|
+
const fullPath = path.join(dir, entry.name);
|
|
3269
3078
|
if (entry.isDirectory()) {
|
|
3270
3079
|
subdirs.push(fullPath);
|
|
3271
3080
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -3349,7 +3158,7 @@ ${sanitized.text}
|
|
|
3349
3158
|
const correctionPaths = [];
|
|
3350
3159
|
const factPaths = [];
|
|
3351
3160
|
for (const filePath of filePaths) {
|
|
3352
|
-
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${
|
|
3161
|
+
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path.sep}`)) {
|
|
3353
3162
|
correctionPaths.push(filePath);
|
|
3354
3163
|
} else {
|
|
3355
3164
|
factPaths.push(filePath);
|
|
@@ -3469,7 +3278,7 @@ ${sanitized.text}
|
|
|
3469
3278
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
3470
3279
|
const subdirs = [];
|
|
3471
3280
|
for (const entry of entries) {
|
|
3472
|
-
const fullPath =
|
|
3281
|
+
const fullPath = path.join(dir, entry.name);
|
|
3473
3282
|
if (entry.isDirectory()) {
|
|
3474
3283
|
subdirs.push(fullPath);
|
|
3475
3284
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -3498,7 +3307,7 @@ ${sanitized.text}
|
|
|
3498
3307
|
try {
|
|
3499
3308
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
3500
3309
|
for (const entry of entries) {
|
|
3501
|
-
const fullPath =
|
|
3310
|
+
const fullPath = path.join(dir, entry.name);
|
|
3502
3311
|
if (entry.isDirectory()) {
|
|
3503
3312
|
await readDir(fullPath);
|
|
3504
3313
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -3543,11 +3352,11 @@ ${sanitized.text}
|
|
|
3543
3352
|
content: parsed.content
|
|
3544
3353
|
};
|
|
3545
3354
|
}
|
|
3546
|
-
const normalizedPath = filePath.split(
|
|
3355
|
+
const normalizedPath = filePath.split(path.sep).join("/");
|
|
3547
3356
|
if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
|
|
3548
3357
|
const entity = parseEntityFile(raw, this.entitySchemas);
|
|
3549
3358
|
if (!entity.name) return null;
|
|
3550
|
-
const nameWithoutExt =
|
|
3359
|
+
const nameWithoutExt = path.basename(filePath, ".md");
|
|
3551
3360
|
const fileMtime = entity.updated || await stat(filePath).then((s) => s.mtime.toISOString()).catch(() => (/* @__PURE__ */ new Date(0)).toISOString());
|
|
3552
3361
|
return {
|
|
3553
3362
|
path: filePath,
|
|
@@ -3571,7 +3380,7 @@ ${sanitized.text}
|
|
|
3571
3380
|
}
|
|
3572
3381
|
}
|
|
3573
3382
|
resolveTierRootDir(tier) {
|
|
3574
|
-
return tier === "cold" ?
|
|
3383
|
+
return tier === "cold" ? path.join(this.baseDir, "cold") : this.baseDir;
|
|
3575
3384
|
}
|
|
3576
3385
|
resolveMemoryDateDir(memory) {
|
|
3577
3386
|
const preferred = memory.frontmatter.created || memory.frontmatter.updated;
|
|
@@ -3586,18 +3395,18 @@ ${sanitized.text}
|
|
|
3586
3395
|
buildTierMemoryPath(memory, tier) {
|
|
3587
3396
|
const root = this.resolveTierRootDir(tier);
|
|
3588
3397
|
if (this.isArtifactMemory(memory)) {
|
|
3589
|
-
return
|
|
3398
|
+
return path.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
3590
3399
|
}
|
|
3591
3400
|
if (memory.frontmatter.category === "correction") {
|
|
3592
|
-
return
|
|
3401
|
+
return path.join(root, "corrections", `${memory.frontmatter.id}.md`);
|
|
3593
3402
|
}
|
|
3594
3403
|
if (memory.frontmatter.category === "procedure") {
|
|
3595
|
-
return
|
|
3404
|
+
return path.join(root, "procedures", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
3596
3405
|
}
|
|
3597
3406
|
if (memory.frontmatter.category === "reasoning_trace") {
|
|
3598
|
-
return
|
|
3407
|
+
return path.join(root, "reasoning-traces", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
3599
3408
|
}
|
|
3600
|
-
return
|
|
3409
|
+
return path.join(root, "facts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
3601
3410
|
}
|
|
3602
3411
|
async writeMemoryFileAtomic(targetPath, memory) {
|
|
3603
3412
|
const fileContent = `${serializeFrontmatter(memory.frontmatter)}
|
|
@@ -3609,8 +3418,8 @@ ${memory.content}
|
|
|
3609
3418
|
}
|
|
3610
3419
|
async moveMemoryToPath(memory, targetPath) {
|
|
3611
3420
|
await this.writeMemoryFileAtomic(targetPath, memory);
|
|
3612
|
-
const sourcePath =
|
|
3613
|
-
const destPath =
|
|
3421
|
+
const sourcePath = path.resolve(memory.path);
|
|
3422
|
+
const destPath = path.resolve(targetPath);
|
|
3614
3423
|
if (sourcePath !== destPath) {
|
|
3615
3424
|
try {
|
|
3616
3425
|
await unlink(memory.path);
|
|
@@ -3625,8 +3434,8 @@ ${memory.content}
|
|
|
3625
3434
|
}
|
|
3626
3435
|
async migrateMemoryToTier(memory, targetTier) {
|
|
3627
3436
|
const targetPath = this.buildTierMemoryPath(memory, targetTier);
|
|
3628
|
-
const sourcePath =
|
|
3629
|
-
const destPath =
|
|
3437
|
+
const sourcePath = path.resolve(memory.path);
|
|
3438
|
+
const destPath = path.resolve(targetPath);
|
|
3630
3439
|
if (sourcePath === destPath) {
|
|
3631
3440
|
return { changed: false, targetPath };
|
|
3632
3441
|
}
|
|
@@ -3652,7 +3461,7 @@ ${memory.content}
|
|
|
3652
3461
|
return { changed: true, targetPath };
|
|
3653
3462
|
}
|
|
3654
3463
|
get archiveDir() {
|
|
3655
|
-
return
|
|
3464
|
+
return path.join(this.baseDir, "archive");
|
|
3656
3465
|
}
|
|
3657
3466
|
/**
|
|
3658
3467
|
* Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
|
|
@@ -3663,7 +3472,7 @@ ${memory.content}
|
|
|
3663
3472
|
try {
|
|
3664
3473
|
const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
|
|
3665
3474
|
const today = now.toISOString().slice(0, 10);
|
|
3666
|
-
const destDir =
|
|
3475
|
+
const destDir = path.join(this.archiveDir, today);
|
|
3667
3476
|
await mkdir(destDir, { recursive: true });
|
|
3668
3477
|
const updatedFm = {
|
|
3669
3478
|
...memory.frontmatter,
|
|
@@ -3675,7 +3484,7 @@ ${memory.content}
|
|
|
3675
3484
|
|
|
3676
3485
|
${memory.content}
|
|
3677
3486
|
`;
|
|
3678
|
-
const destPath =
|
|
3487
|
+
const destPath = path.join(destDir, path.basename(memory.path));
|
|
3679
3488
|
await writeMaybeEncryptedFile(destPath, fileContent, this.resolveWriteKey(), {}, this.baseDir);
|
|
3680
3489
|
await unlink(memory.path);
|
|
3681
3490
|
this.invalidateAllMemoriesCache();
|
|
@@ -3837,7 +3646,7 @@ ${memory.content}
|
|
|
3837
3646
|
`;
|
|
3838
3647
|
await writeMaybeEncryptedFile(memory.path, fileContent, this.resolveWriteKey(), {}, this.baseDir);
|
|
3839
3648
|
this.invalidateAllMemoriesCache();
|
|
3840
|
-
if (memory.path.includes(`${
|
|
3649
|
+
if (memory.path.includes(`${path.sep}cold${path.sep}`)) {
|
|
3841
3650
|
this.invalidateColdMemoriesCache();
|
|
3842
3651
|
}
|
|
3843
3652
|
try {
|
|
@@ -3909,7 +3718,7 @@ ${memory.content}
|
|
|
3909
3718
|
return deleted;
|
|
3910
3719
|
}
|
|
3911
3720
|
async loadBuffer() {
|
|
3912
|
-
const bufferPath =
|
|
3721
|
+
const bufferPath = path.join(this.stateDir, "buffer.json");
|
|
3913
3722
|
try {
|
|
3914
3723
|
const raw = await this.readStorageSecureFile(bufferPath);
|
|
3915
3724
|
return JSON.parse(raw);
|
|
@@ -3921,11 +3730,11 @@ ${memory.content}
|
|
|
3921
3730
|
}
|
|
3922
3731
|
async saveBuffer(state) {
|
|
3923
3732
|
await this.ensureDirectories();
|
|
3924
|
-
const bufferPath =
|
|
3733
|
+
const bufferPath = path.join(this.stateDir, "buffer.json");
|
|
3925
3734
|
await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
|
|
3926
3735
|
}
|
|
3927
3736
|
async loadMeta() {
|
|
3928
|
-
const metaPath =
|
|
3737
|
+
const metaPath = path.join(this.stateDir, "meta.json");
|
|
3929
3738
|
try {
|
|
3930
3739
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
3931
3740
|
const parsed = JSON.parse(raw);
|
|
@@ -3959,7 +3768,7 @@ ${memory.content}
|
|
|
3959
3768
|
}
|
|
3960
3769
|
async saveMeta(state) {
|
|
3961
3770
|
await this.ensureDirectories();
|
|
3962
|
-
const metaPath =
|
|
3771
|
+
const metaPath = path.join(this.stateDir, "meta.json");
|
|
3963
3772
|
await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
|
|
3964
3773
|
}
|
|
3965
3774
|
async appendMemoryActionEvents(events) {
|
|
@@ -4129,7 +3938,7 @@ ${memory.content}
|
|
|
4129
3938
|
async appendReextractJobs(events) {
|
|
4130
3939
|
if (events.length === 0) return 0;
|
|
4131
3940
|
await this.ensureDirectories();
|
|
4132
|
-
const filePath =
|
|
3941
|
+
const filePath = path.join(this.stateDir, "reextract-jobs.jsonl");
|
|
4133
3942
|
const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
4134
3943
|
try {
|
|
4135
3944
|
await this.appendStorageSecureFile(filePath, lines);
|
|
@@ -4142,7 +3951,7 @@ ${memory.content}
|
|
|
4142
3951
|
}
|
|
4143
3952
|
async readReextractJobs(limit = 200) {
|
|
4144
3953
|
const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
|
|
4145
|
-
const filePath =
|
|
3954
|
+
const filePath = path.join(this.stateDir, "reextract-jobs.jsonl");
|
|
4146
3955
|
try {
|
|
4147
3956
|
const raw = await this.readStorageSecureFile(filePath);
|
|
4148
3957
|
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
@@ -4314,7 +4123,7 @@ ${memory.content}
|
|
|
4314
4123
|
return false;
|
|
4315
4124
|
}
|
|
4316
4125
|
if (draftState.contentHash) {
|
|
4317
|
-
const contentHash =
|
|
4126
|
+
const contentHash = createHash("sha256").update(draftContent).digest("hex");
|
|
4318
4127
|
if (contentHash !== draftState.contentHash) return false;
|
|
4319
4128
|
}
|
|
4320
4129
|
await this.writeCompressionGuidelines(draftContent);
|
|
@@ -4396,7 +4205,7 @@ ${memory.content}
|
|
|
4396
4205
|
const date = nowIso.slice(0, 10);
|
|
4397
4206
|
const id = this.generateId("incident");
|
|
4398
4207
|
const incident = createContinuityIncidentRecord(id, input, nowIso);
|
|
4399
|
-
const filePath =
|
|
4208
|
+
const filePath = path.join(this.identityIncidentsDir, `${date}-${id}.md`);
|
|
4400
4209
|
await this.writeStorageSecureFile(filePath, serializeContinuityIncident(incident));
|
|
4401
4210
|
return { ...incident, filePath };
|
|
4402
4211
|
}
|
|
@@ -4409,7 +4218,7 @@ ${memory.content}
|
|
|
4409
4218
|
const incidents = [];
|
|
4410
4219
|
for (const file of candidates) {
|
|
4411
4220
|
if (incidents.length >= cappedLimit) break;
|
|
4412
|
-
const filePath =
|
|
4221
|
+
const filePath = path.join(this.identityIncidentsDir, file);
|
|
4413
4222
|
try {
|
|
4414
4223
|
const raw = await this.readStorageSecureFile(filePath);
|
|
4415
4224
|
const parsed = parseContinuityIncident(raw);
|
|
@@ -4440,7 +4249,7 @@ ${memory.content}
|
|
|
4440
4249
|
await this.ensureDirectories();
|
|
4441
4250
|
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
4442
4251
|
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
4443
|
-
const filePath =
|
|
4252
|
+
const filePath = path.join(dir, `${safeKey}.md`);
|
|
4444
4253
|
await this.writeStorageSecureFile(filePath, content);
|
|
4445
4254
|
return filePath;
|
|
4446
4255
|
}
|
|
@@ -4448,7 +4257,7 @@ ${memory.content}
|
|
|
4448
4257
|
try {
|
|
4449
4258
|
const safeKey = this.sanitizeIdentityAuditKey(key);
|
|
4450
4259
|
const dir = period === "weekly" ? this.identityAuditsWeeklyDir : this.identityAuditsMonthlyDir;
|
|
4451
|
-
return await this.readStorageSecureFile(
|
|
4260
|
+
return await this.readStorageSecureFile(path.join(dir, `${safeKey}.md`));
|
|
4452
4261
|
} catch (err) {
|
|
4453
4262
|
if (err instanceof Error && err.message === "Invalid identity audit key") return null;
|
|
4454
4263
|
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
@@ -4512,12 +4321,12 @@ ${memory.content}
|
|
|
4512
4321
|
const fileNames = await this.readContinuityIncidentFileNames();
|
|
4513
4322
|
const directMatch = fileNames.find((name) => name.endsWith(`-${id}.md`));
|
|
4514
4323
|
if (directMatch) {
|
|
4515
|
-
const directPath =
|
|
4324
|
+
const directPath = path.join(this.identityIncidentsDir, directMatch);
|
|
4516
4325
|
const parsed = await this.readContinuityIncidentFile(directPath);
|
|
4517
4326
|
if (parsed?.id === id) return directPath;
|
|
4518
4327
|
}
|
|
4519
4328
|
for (const fileName of fileNames) {
|
|
4520
|
-
const filePath =
|
|
4329
|
+
const filePath = path.join(this.identityIncidentsDir, fileName);
|
|
4521
4330
|
const parsed = await this.readContinuityIncidentFile(filePath);
|
|
4522
4331
|
if (parsed?.id === id) return filePath;
|
|
4523
4332
|
}
|
|
@@ -4547,7 +4356,7 @@ ${question}
|
|
|
4547
4356
|
|
|
4548
4357
|
**Context:** ${context}
|
|
4549
4358
|
`;
|
|
4550
|
-
const filePath =
|
|
4359
|
+
const filePath = path.join(this.questionsDir, `${id}.md`);
|
|
4551
4360
|
await writeFile(filePath, content, "utf-8");
|
|
4552
4361
|
log.debug(`wrote question ${id} to ${filePath}`);
|
|
4553
4362
|
this.invalidateQuestionsCache();
|
|
@@ -4571,7 +4380,7 @@ ${question}
|
|
|
4571
4380
|
const questions = [];
|
|
4572
4381
|
for (const file of files) {
|
|
4573
4382
|
if (!file.endsWith(".md")) continue;
|
|
4574
|
-
const filePath =
|
|
4383
|
+
const filePath = path.join(this.questionsDir, file);
|
|
4575
4384
|
const raw = await readMaybeEncryptedFile(filePath, this._secureStoreKey, this.baseDir);
|
|
4576
4385
|
const parsed = this.parseQuestionFile(raw, filePath);
|
|
4577
4386
|
if (parsed) {
|
|
@@ -4594,7 +4403,7 @@ ${question}
|
|
|
4594
4403
|
if (!match) return null;
|
|
4595
4404
|
const frontmatterStr = match[1];
|
|
4596
4405
|
const body = match[2].trim();
|
|
4597
|
-
const id = this.extractFrontmatterValue(frontmatterStr, "id") ??
|
|
4406
|
+
const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path.basename(filePath, ".md");
|
|
4598
4407
|
const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
|
|
4599
4408
|
const priority = parseFloat(
|
|
4600
4409
|
this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5"
|
|
@@ -4656,11 +4465,11 @@ ${question}
|
|
|
4656
4465
|
} catch {
|
|
4657
4466
|
}
|
|
4658
4467
|
const hygiene = opts?.hygiene;
|
|
4659
|
-
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(
|
|
4468
|
+
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path.basename(identityPath));
|
|
4660
4469
|
if (rotateEnabled) {
|
|
4661
4470
|
const maxBytes = hygiene.rotateMaxBytes;
|
|
4662
4471
|
if (existing.length > maxBytes) {
|
|
4663
|
-
const archiveDir =
|
|
4472
|
+
const archiveDir = path.join(workspaceDir, hygiene.archiveDir);
|
|
4664
4473
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
4665
4474
|
filePath: identityPath,
|
|
4666
4475
|
archiveDir,
|
|
@@ -4754,7 +4563,7 @@ ${reflection}
|
|
|
4754
4563
|
* Deduplicates by target+label.
|
|
4755
4564
|
*/
|
|
4756
4565
|
async addEntityRelationship(name, rel) {
|
|
4757
|
-
const filePath =
|
|
4566
|
+
const filePath = path.join(this.entitiesDir, `${name}.md`);
|
|
4758
4567
|
let entity;
|
|
4759
4568
|
try {
|
|
4760
4569
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -4779,7 +4588,7 @@ ${reflection}
|
|
|
4779
4588
|
* Prepends to the beginning, prunes oldest entries beyond maxEntries.
|
|
4780
4589
|
*/
|
|
4781
4590
|
async addEntityActivity(name, entry, maxEntries) {
|
|
4782
|
-
const filePath =
|
|
4591
|
+
const filePath = path.join(this.entitiesDir, `${name}.md`);
|
|
4783
4592
|
let entity;
|
|
4784
4593
|
try {
|
|
4785
4594
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -4802,7 +4611,7 @@ ${reflection}
|
|
|
4802
4611
|
* Add an alias to an entity file. Deduplicates.
|
|
4803
4612
|
*/
|
|
4804
4613
|
async addEntityAlias(name, alias) {
|
|
4805
|
-
const filePath =
|
|
4614
|
+
const filePath = path.join(this.entitiesDir, `${name}.md`);
|
|
4806
4615
|
let entity;
|
|
4807
4616
|
try {
|
|
4808
4617
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -4823,7 +4632,7 @@ ${reflection}
|
|
|
4823
4632
|
* Set or rewrite the synthesis layer of an entity file.
|
|
4824
4633
|
*/
|
|
4825
4634
|
async updateEntitySynthesis(name, synthesis, options = {}) {
|
|
4826
|
-
const filePath =
|
|
4635
|
+
const filePath = path.join(this.entitiesDir, `${name}.md`);
|
|
4827
4636
|
let entity;
|
|
4828
4637
|
try {
|
|
4829
4638
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -4861,7 +4670,7 @@ ${reflection}
|
|
|
4861
4670
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4862
4671
|
let synthesisTimelineCount;
|
|
4863
4672
|
try {
|
|
4864
|
-
const filePath =
|
|
4673
|
+
const filePath = path.join(this.entitiesDir, `${name}.md`);
|
|
4865
4674
|
const content = await this.readStorageSecureFile(filePath);
|
|
4866
4675
|
synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
|
|
4867
4676
|
} catch (err) {
|
|
@@ -4944,7 +4753,7 @@ ${reflection}
|
|
|
4944
4753
|
if (!raw) continue;
|
|
4945
4754
|
const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
|
|
4946
4755
|
if (raw.trimEnd() === serialized.trimEnd()) continue;
|
|
4947
|
-
await this.writeStorageSecureFile(
|
|
4756
|
+
await this.writeStorageSecureFile(path.join(this.entitiesDir, `${entityName}.md`), serialized);
|
|
4948
4757
|
migrated += 1;
|
|
4949
4758
|
}
|
|
4950
4759
|
if (migrated > 0) {
|
|
@@ -4980,7 +4789,7 @@ ${reflection}
|
|
|
4980
4789
|
const results = await Promise.all(
|
|
4981
4790
|
batch.map(async (entry) => {
|
|
4982
4791
|
try {
|
|
4983
|
-
return await this.readStorageSecureFile(
|
|
4792
|
+
return await this.readStorageSecureFile(path.join(this.entitiesDir, entry));
|
|
4984
4793
|
} catch (err) {
|
|
4985
4794
|
if (err instanceof SecureStoreLockedError) throw err;
|
|
4986
4795
|
if (!isErrnoCode(err, "ENOENT")) throw err;
|
|
@@ -5126,7 +4935,7 @@ ${rows.join("\n")}
|
|
|
5126
4935
|
extraSections: []
|
|
5127
4936
|
};
|
|
5128
4937
|
for (const file of files) {
|
|
5129
|
-
const filePath =
|
|
4938
|
+
const filePath = path.join(this.entitiesDir, file);
|
|
5130
4939
|
try {
|
|
5131
4940
|
const content = await this.readStorageSecureFile(filePath);
|
|
5132
4941
|
const parsed = parseEntityFile(content, this.entitySchemas);
|
|
@@ -5257,10 +5066,10 @@ ${rows.join("\n")}
|
|
|
5257
5066
|
}
|
|
5258
5067
|
mergedEntity.created = mergedEntity.created || mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
|
|
5259
5068
|
mergedEntity.updated = mergedEntity.updated || (/* @__PURE__ */ new Date()).toISOString();
|
|
5260
|
-
const canonicalPath =
|
|
5069
|
+
const canonicalPath = path.join(this.entitiesDir, `${canonical}.md`);
|
|
5261
5070
|
await this.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.entitySchemas));
|
|
5262
5071
|
for (const file of files) {
|
|
5263
|
-
const filePath =
|
|
5072
|
+
const filePath = path.join(this.entitiesDir, file);
|
|
5264
5073
|
if (filePath !== canonicalPath) {
|
|
5265
5074
|
try {
|
|
5266
5075
|
await unlink(filePath);
|
|
@@ -5359,7 +5168,7 @@ ${memory.content}
|
|
|
5359
5168
|
const filePaths = await this.collectActiveMemoryPaths();
|
|
5360
5169
|
const foundIds = /* @__PURE__ */ new Set();
|
|
5361
5170
|
for (const filePath of filePaths) {
|
|
5362
|
-
const basename =
|
|
5171
|
+
const basename = path.basename(filePath, ".md");
|
|
5363
5172
|
if (wantedIds.has(basename)) {
|
|
5364
5173
|
foundIds.add(basename);
|
|
5365
5174
|
if (foundIds.size === wantedIds.size) break;
|
|
@@ -5459,15 +5268,15 @@ ${sanitized.text}
|
|
|
5459
5268
|
`;
|
|
5460
5269
|
let filePath;
|
|
5461
5270
|
if (category === "correction") {
|
|
5462
|
-
filePath =
|
|
5271
|
+
filePath = path.join(this.correctionsDir, `${id}.md`);
|
|
5463
5272
|
} else if (category === "procedure") {
|
|
5464
|
-
await mkdir(
|
|
5465
|
-
filePath =
|
|
5273
|
+
await mkdir(path.join(this.proceduresDir, today), { recursive: true });
|
|
5274
|
+
filePath = path.join(this.proceduresDir, today, `${id}.md`);
|
|
5466
5275
|
} else if (category === "reasoning_trace") {
|
|
5467
|
-
await mkdir(
|
|
5468
|
-
filePath =
|
|
5276
|
+
await mkdir(path.join(this.reasoningTracesDir, today), { recursive: true });
|
|
5277
|
+
filePath = path.join(this.reasoningTracesDir, today, `${id}.md`);
|
|
5469
5278
|
} else {
|
|
5470
|
-
filePath =
|
|
5279
|
+
filePath = path.join(this.factsDir, today, `${id}.md`);
|
|
5471
5280
|
}
|
|
5472
5281
|
await this.writeStorageSecureFile(filePath, fileContent);
|
|
5473
5282
|
log.debug(`wrote chunk ${id} (${chunkIndex + 1}/${chunkTotal}) to ${filePath}`);
|
|
@@ -5536,14 +5345,14 @@ Reason: ${reason}`, {
|
|
|
5536
5345
|
// Memory Summarization (Phase 4A)
|
|
5537
5346
|
// ---------------------------------------------------------------------------
|
|
5538
5347
|
get summariesDir() {
|
|
5539
|
-
return
|
|
5348
|
+
return path.join(this.baseDir, "summaries");
|
|
5540
5349
|
}
|
|
5541
5350
|
/**
|
|
5542
5351
|
* Write a memory summary.
|
|
5543
5352
|
*/
|
|
5544
5353
|
async writeSummary(summary) {
|
|
5545
5354
|
await mkdir(this.summariesDir, { recursive: true });
|
|
5546
|
-
const filePath =
|
|
5355
|
+
const filePath = path.join(this.summariesDir, `${summary.id}.json`);
|
|
5547
5356
|
await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
|
|
5548
5357
|
log.debug(`wrote summary ${summary.id}`);
|
|
5549
5358
|
}
|
|
@@ -5556,7 +5365,7 @@ Reason: ${reason}`, {
|
|
|
5556
5365
|
const summaries = [];
|
|
5557
5366
|
for (const file of files) {
|
|
5558
5367
|
if (!file.endsWith(".json")) continue;
|
|
5559
|
-
const filePath =
|
|
5368
|
+
const filePath = path.join(this.summariesDir, file);
|
|
5560
5369
|
const raw = await this.readStorageSecureFile(filePath);
|
|
5561
5370
|
summaries.push(JSON.parse(raw));
|
|
5562
5371
|
}
|
|
@@ -5617,7 +5426,7 @@ ${memory.content}
|
|
|
5617
5426
|
* Save topic scores to meta.json.
|
|
5618
5427
|
*/
|
|
5619
5428
|
async saveTopics(topics) {
|
|
5620
|
-
const metaPath =
|
|
5429
|
+
const metaPath = path.join(this.stateDir, "topics.json");
|
|
5621
5430
|
await mkdir(this.stateDir, { recursive: true });
|
|
5622
5431
|
await this.writeStorageSecureFile(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
|
|
5623
5432
|
log.debug(`saved ${topics.length} topic scores`);
|
|
@@ -5626,7 +5435,7 @@ ${memory.content}
|
|
|
5626
5435
|
* Load topic scores from meta.json.
|
|
5627
5436
|
*/
|
|
5628
5437
|
async loadTopics() {
|
|
5629
|
-
const metaPath =
|
|
5438
|
+
const metaPath = path.join(this.stateDir, "topics.json");
|
|
5630
5439
|
try {
|
|
5631
5440
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
5632
5441
|
return JSON.parse(raw);
|
|
@@ -5704,23 +5513,9 @@ ${memory.content}
|
|
|
5704
5513
|
};
|
|
5705
5514
|
|
|
5706
5515
|
export {
|
|
5707
|
-
DEFAULT_SELF_NAME,
|
|
5708
|
-
emptySpeakerRegistry,
|
|
5709
|
-
speakersFilePath,
|
|
5710
|
-
loadSpeakerRegistry,
|
|
5711
|
-
saveSpeakerRegistry,
|
|
5712
|
-
speakerRegistryKey,
|
|
5713
|
-
resolveSpeaker,
|
|
5714
|
-
distinctSpeakerLabels,
|
|
5715
|
-
WEARABLES_DIR_NAME,
|
|
5716
|
-
isValidTranscriptDate,
|
|
5717
|
-
hashTranscriptBody,
|
|
5718
|
-
composeDayTranscriptBody,
|
|
5719
|
-
composeDayTranscriptMeta,
|
|
5720
|
-
serializeDayTranscript,
|
|
5721
|
-
parseDayTranscript,
|
|
5722
5516
|
normalizeEntityName,
|
|
5723
5517
|
ContentHashIndex,
|
|
5518
|
+
stripAttributesSuffix,
|
|
5724
5519
|
normalizeAttributePairs,
|
|
5725
5520
|
compareEntityTimestamps,
|
|
5726
5521
|
fingerprintEntityStructuredFacts,
|
|
@@ -5729,4 +5524,4 @@ export {
|
|
|
5729
5524
|
serializeEntityFile,
|
|
5730
5525
|
StorageManager
|
|
5731
5526
|
};
|
|
5732
|
-
//# sourceMappingURL=chunk-
|
|
5527
|
+
//# sourceMappingURL=chunk-QYGIQ5NM.js.map
|