memorix 1.6.0 → 1.6.2
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/CHANGELOG.md +46 -0
- package/dist/cli/index.js +1888 -1122
- package/dist/cli/memcode.js +12 -1
- package/dist/index.js +641 -113
- package/dist/maintenance-runner.js +618 -90
- package/dist/media-audio-runner.js +618 -90
- package/dist/media-video-runner.js +618 -90
- package/dist/memcode-runtime/CHANGELOG.md +46 -0
- package/dist/sdk.js +674 -117
- package/dist/vector-backfill-runner.js +618 -90
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +11 -3
- package/docs/API_REFERENCE.md +1 -1
- package/docs/DOCKER.md +5 -1
- package/docs/PERFORMANCE.md +17 -2
- package/docs/README.md +3 -1
- package/docs/SETUP.md +8 -2
- package/package.json +2 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/agent-integrations.ts +9 -3
- package/src/cli/commands/background.ts +34 -2
- package/src/cli/commands/doctor.ts +46 -15
- package/src/cli/commands/hook.ts +13 -1
- package/src/cli/commands/operator-shared.ts +6 -3
- package/src/cli/commands/serve-http.ts +72 -7
- package/src/cli/heap.ts +76 -0
- package/src/cli/invocation.ts +7 -4
- package/src/embedding/api-provider.ts +503 -27
- package/src/embedding/provider.ts +96 -9
- package/src/hooks/handler.ts +9 -18
- package/src/hooks/lifecycle.ts +174 -0
- package/src/memory/observations.ts +68 -18
- package/src/sdk.ts +12 -8
- package/src/store/orama-store.ts +21 -3
package/dist/index.js
CHANGED
|
@@ -1195,8 +1195,8 @@ async function acquireLock(lockPath) {
|
|
|
1195
1195
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
1196
1196
|
if (code === "EEXIST" || code === "EPERM") {
|
|
1197
1197
|
try {
|
|
1198
|
-
const
|
|
1199
|
-
if (Date.now() -
|
|
1198
|
+
const stat5 = await fs2.stat(lockPath);
|
|
1199
|
+
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
1200
1200
|
await fs2.unlink(lockPath).catch(() => {
|
|
1201
1201
|
});
|
|
1202
1202
|
continue;
|
|
@@ -3713,24 +3713,131 @@ var init_transformers_provider = __esm({
|
|
|
3713
3713
|
// src/embedding/api-provider.ts
|
|
3714
3714
|
var api_provider_exports = {};
|
|
3715
3715
|
__export(api_provider_exports, {
|
|
3716
|
-
APIEmbeddingProvider: () => APIEmbeddingProvider
|
|
3716
|
+
APIEmbeddingProvider: () => APIEmbeddingProvider,
|
|
3717
|
+
convertArrayCacheToJsonl: () => convertArrayCacheToJsonl,
|
|
3718
|
+
ensureDiskCacheLoaded: () => ensureDiskCacheLoaded,
|
|
3719
|
+
getApiEmbeddingCachePayloadBytesForTests: () => getApiEmbeddingCachePayloadBytesForTests,
|
|
3720
|
+
getApiEmbeddingDiskCacheLoadCountForTests: () => getApiEmbeddingDiskCacheLoadCountForTests,
|
|
3721
|
+
getApiEmbeddingJsonlLineCountCallsForTests: () => getApiEmbeddingJsonlLineCountCallsForTests,
|
|
3722
|
+
getApiEmbeddingMaxEntriesForDimensionsForTests: () => getApiEmbeddingMaxEntriesForDimensionsForTests,
|
|
3723
|
+
migrateJsonArrayCacheToJsonl: () => migrateJsonArrayCacheToJsonl,
|
|
3724
|
+
parseCacheJsonInWorker: () => parseCacheJsonInWorker,
|
|
3725
|
+
resetApiEmbeddingCacheForTests: () => resetApiEmbeddingCacheForTests,
|
|
3726
|
+
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
3727
|
+
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
3717
3728
|
});
|
|
3718
3729
|
import { createHash as createHash2 } from "crypto";
|
|
3719
|
-
import {
|
|
3730
|
+
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
3731
|
+
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
3720
3732
|
import { join as join3 } from "path";
|
|
3721
3733
|
import { homedir as homedir7 } from "os";
|
|
3734
|
+
import { createInterface } from "readline";
|
|
3722
3735
|
function cacheDir() {
|
|
3723
3736
|
return process.env.MEMORIX_DATA_DIR || join3(homedir7(), ".memorix", "data");
|
|
3724
3737
|
}
|
|
3725
3738
|
function cacheFile() {
|
|
3726
3739
|
return join3(cacheDir(), ".embedding-api-cache.json");
|
|
3727
3740
|
}
|
|
3741
|
+
function cacheJsonlFile() {
|
|
3742
|
+
return join3(cacheDir(), ".embedding-api-cache.jsonl");
|
|
3743
|
+
}
|
|
3728
3744
|
function dimsCacheFile() {
|
|
3729
3745
|
return join3(cacheDir(), ".embedding-dims-cache.json");
|
|
3730
3746
|
}
|
|
3731
3747
|
function cacheMetaFile() {
|
|
3732
3748
|
return join3(cacheDir(), ".embedding-api-cache-meta.json");
|
|
3733
3749
|
}
|
|
3750
|
+
function cacheStatFile() {
|
|
3751
|
+
return join3(cacheDir(), ".embedding-api-cache-stat.json");
|
|
3752
|
+
}
|
|
3753
|
+
function payloadBytes(vector) {
|
|
3754
|
+
return vector.length * BYTES_PER_DIM;
|
|
3755
|
+
}
|
|
3756
|
+
function maxCachePayloadBytes() {
|
|
3757
|
+
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
3758
|
+
if (raw) {
|
|
3759
|
+
const parsed = Number.parseInt(raw, 10);
|
|
3760
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
3761
|
+
}
|
|
3762
|
+
return MAX_CACHE_PAYLOAD_BYTES;
|
|
3763
|
+
}
|
|
3764
|
+
function maxEntriesForDimensions(dimensions) {
|
|
3765
|
+
const dim = Math.max(1, Math.floor(dimensions));
|
|
3766
|
+
const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
|
|
3767
|
+
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
3768
|
+
}
|
|
3769
|
+
function rememberDimensions(vector) {
|
|
3770
|
+
if (vector.length > 0 && (cacheDimensions === null || vector.length > cacheDimensions)) {
|
|
3771
|
+
cacheDimensions = vector.length;
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
function evictOldest() {
|
|
3775
|
+
const firstKey = cache3.keys().next().value;
|
|
3776
|
+
if (firstKey === void 0) return;
|
|
3777
|
+
const old = cache3.get(firstKey);
|
|
3778
|
+
cache3.delete(firstKey);
|
|
3779
|
+
if (old) cachePayloadBytes -= payloadBytes(old);
|
|
3780
|
+
}
|
|
3781
|
+
function evictToFit(incomingBytes, incomingDims) {
|
|
3782
|
+
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
3783
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
|
|
3784
|
+
evictOldest();
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
function isNumberArray(value) {
|
|
3788
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
3789
|
+
}
|
|
3790
|
+
function parseCacheRow(raw) {
|
|
3791
|
+
if (Array.isArray(raw)) {
|
|
3792
|
+
const hash4 = raw[0];
|
|
3793
|
+
const vector = raw[1];
|
|
3794
|
+
if (typeof hash4 === "string" && isNumberArray(vector)) {
|
|
3795
|
+
return { hash: hash4, vector };
|
|
3796
|
+
}
|
|
3797
|
+
return null;
|
|
3798
|
+
}
|
|
3799
|
+
if (raw && typeof raw === "object") {
|
|
3800
|
+
const row = raw;
|
|
3801
|
+
if (typeof row.h === "string" && isNumberArray(row.v)) {
|
|
3802
|
+
return { hash: row.h, vector: row.v };
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
return null;
|
|
3806
|
+
}
|
|
3807
|
+
function cacheInsert(hash4, value, dirty) {
|
|
3808
|
+
rememberDimensions(value);
|
|
3809
|
+
const incoming = payloadBytes(value);
|
|
3810
|
+
const existing = cache3.get(hash4);
|
|
3811
|
+
if (existing) {
|
|
3812
|
+
cachePayloadBytes -= payloadBytes(existing);
|
|
3813
|
+
cache3.delete(hash4);
|
|
3814
|
+
}
|
|
3815
|
+
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
3816
|
+
cache3.set(hash4, value);
|
|
3817
|
+
cachePayloadBytes += incoming;
|
|
3818
|
+
if (dirty) diskCacheDirty2 = true;
|
|
3819
|
+
}
|
|
3820
|
+
async function readCacheStat() {
|
|
3821
|
+
try {
|
|
3822
|
+
const data = JSON.parse(await readFile2(cacheStatFile(), "utf-8"));
|
|
3823
|
+
if (typeof data.entryCount === "number" && Number.isFinite(data.entryCount) && data.entryCount >= 0) {
|
|
3824
|
+
return {
|
|
3825
|
+
version: 1,
|
|
3826
|
+
entryCount: Math.floor(data.entryCount),
|
|
3827
|
+
dimensions: isValidDimension(data.dimensions) ? data.dimensions : null
|
|
3828
|
+
};
|
|
3829
|
+
}
|
|
3830
|
+
} catch {
|
|
3831
|
+
}
|
|
3832
|
+
return null;
|
|
3833
|
+
}
|
|
3834
|
+
async function writeCacheStat(stat5) {
|
|
3835
|
+
try {
|
|
3836
|
+
await mkdir2(cacheDir(), { recursive: true });
|
|
3837
|
+
await writeFile2(cacheStatFile(), JSON.stringify(stat5));
|
|
3838
|
+
} catch {
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3734
3841
|
function normalizeText(text2) {
|
|
3735
3842
|
return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
|
|
3736
3843
|
}
|
|
@@ -3816,29 +3923,300 @@ function toProviderInput(input, baseUrl) {
|
|
|
3816
3923
|
}
|
|
3817
3924
|
return { type: input.modality, url: input.url };
|
|
3818
3925
|
}
|
|
3926
|
+
function parseCacheJsonInWorker(filePath) {
|
|
3927
|
+
return new Promise((resolve2, reject) => {
|
|
3928
|
+
void import("worker_threads").then(({ Worker }) => {
|
|
3929
|
+
const worker = new Worker(
|
|
3930
|
+
`
|
|
3931
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
3932
|
+
const { readFileSync } = require('node:fs');
|
|
3933
|
+
try {
|
|
3934
|
+
const raw = readFileSync(workerData.filePath, 'utf8');
|
|
3935
|
+
parentPort.postMessage({ ok: true, entries: JSON.parse(raw) });
|
|
3936
|
+
} catch (err) {
|
|
3937
|
+
parentPort.postMessage({
|
|
3938
|
+
ok: false,
|
|
3939
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3940
|
+
});
|
|
3941
|
+
}
|
|
3942
|
+
`,
|
|
3943
|
+
{ eval: true, workerData: { filePath } }
|
|
3944
|
+
);
|
|
3945
|
+
worker.once("message", (msg) => {
|
|
3946
|
+
void worker.terminate();
|
|
3947
|
+
if (msg?.ok && Array.isArray(msg.entries)) {
|
|
3948
|
+
resolve2(msg.entries);
|
|
3949
|
+
return;
|
|
3950
|
+
}
|
|
3951
|
+
reject(new Error(msg?.error || "embedding cache worker parse failed"));
|
|
3952
|
+
});
|
|
3953
|
+
worker.once("error", reject);
|
|
3954
|
+
}).catch(reject);
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
function findJsonValueEnd(source) {
|
|
3958
|
+
let i2 = 0;
|
|
3959
|
+
while (i2 < source.length && /\s/.test(source[i2])) i2 += 1;
|
|
3960
|
+
if (i2 >= source.length) return -1;
|
|
3961
|
+
const start = source[i2];
|
|
3962
|
+
if (start === '"') {
|
|
3963
|
+
i2 += 1;
|
|
3964
|
+
while (i2 < source.length) {
|
|
3965
|
+
if (source[i2] === "\\") {
|
|
3966
|
+
i2 += 2;
|
|
3967
|
+
continue;
|
|
3968
|
+
}
|
|
3969
|
+
if (source[i2] === '"') return i2 + 1;
|
|
3970
|
+
i2 += 1;
|
|
3971
|
+
}
|
|
3972
|
+
return -1;
|
|
3973
|
+
}
|
|
3974
|
+
if (start === "{" || start === "[") {
|
|
3975
|
+
const close = start === "{" ? "}" : "]";
|
|
3976
|
+
let depth = 0;
|
|
3977
|
+
let inString = false;
|
|
3978
|
+
for (; i2 < source.length; i2 += 1) {
|
|
3979
|
+
const ch = source[i2];
|
|
3980
|
+
if (inString) {
|
|
3981
|
+
if (ch === "\\") {
|
|
3982
|
+
i2 += 1;
|
|
3983
|
+
continue;
|
|
3984
|
+
}
|
|
3985
|
+
if (ch === '"') inString = false;
|
|
3986
|
+
continue;
|
|
3987
|
+
}
|
|
3988
|
+
if (ch === '"') {
|
|
3989
|
+
inString = true;
|
|
3990
|
+
continue;
|
|
3991
|
+
}
|
|
3992
|
+
if (ch === start) depth += 1;
|
|
3993
|
+
else if (ch === close) {
|
|
3994
|
+
depth -= 1;
|
|
3995
|
+
if (depth === 0) return i2 + 1;
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
return -1;
|
|
3999
|
+
}
|
|
4000
|
+
const rest = source.slice(i2);
|
|
4001
|
+
const match2 = rest.match(/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/);
|
|
4002
|
+
return match2 ? i2 + match2[0].length : -1;
|
|
4003
|
+
}
|
|
4004
|
+
async function streamJsonArrayToJsonl(filePath, tmpPath) {
|
|
4005
|
+
const input = createReadStream(filePath, { encoding: "utf8" });
|
|
4006
|
+
const out = createWriteStream(tmpPath);
|
|
4007
|
+
let buf = "";
|
|
4008
|
+
let started = false;
|
|
4009
|
+
let count2 = 0;
|
|
4010
|
+
const writeLine = async (line) => {
|
|
4011
|
+
if (!out.write(line)) {
|
|
4012
|
+
await new Promise((resolve2, reject) => {
|
|
4013
|
+
out.once("drain", resolve2);
|
|
4014
|
+
out.once("error", reject);
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
4017
|
+
};
|
|
4018
|
+
try {
|
|
4019
|
+
for await (const chunk of input) {
|
|
4020
|
+
buf += chunk;
|
|
4021
|
+
if (!started) {
|
|
4022
|
+
const idx = buf.search(/\S/);
|
|
4023
|
+
if (idx < 0) continue;
|
|
4024
|
+
if (buf[idx] !== "[") throw new Error("embedding cache is not a JSON array");
|
|
4025
|
+
buf = buf.slice(idx + 1);
|
|
4026
|
+
started = true;
|
|
4027
|
+
}
|
|
4028
|
+
while (true) {
|
|
4029
|
+
buf = buf.replace(/^\s*,?\s*/, "");
|
|
4030
|
+
if (!buf) break;
|
|
4031
|
+
if (buf[0] === "]") {
|
|
4032
|
+
buf = "";
|
|
4033
|
+
break;
|
|
4034
|
+
}
|
|
4035
|
+
const end = findJsonValueEnd(buf);
|
|
4036
|
+
if (end < 0) break;
|
|
4037
|
+
const value = JSON.parse(buf.slice(0, end));
|
|
4038
|
+
buf = buf.slice(end);
|
|
4039
|
+
const row = parseCacheRow(value);
|
|
4040
|
+
if (row) {
|
|
4041
|
+
await writeLine(`${JSON.stringify({ h: row.hash, v: row.vector })}
|
|
4042
|
+
`);
|
|
4043
|
+
count2 += 1;
|
|
4044
|
+
if (count2 % 50 === 0) {
|
|
4045
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
if (buf.length > MAX_MIGRATION_VALUE_BYTES) {
|
|
4050
|
+
throw new Error("embedding cache entry too large to migrate safely");
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
} finally {
|
|
4054
|
+
await new Promise((resolve2, reject) => {
|
|
4055
|
+
out.end(() => resolve2());
|
|
4056
|
+
out.once("error", reject);
|
|
4057
|
+
});
|
|
4058
|
+
}
|
|
4059
|
+
return count2;
|
|
4060
|
+
}
|
|
4061
|
+
async function migrateJsonArrayCacheToJsonl(filePath, jsonlPath) {
|
|
4062
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
4063
|
+
try {
|
|
4064
|
+
const count2 = await streamJsonArrayToJsonl(filePath, tmpPath);
|
|
4065
|
+
await rename(tmpPath, jsonlPath);
|
|
4066
|
+
diskCacheEntryCount = count2;
|
|
4067
|
+
await writeCacheStat({
|
|
4068
|
+
version: 1,
|
|
4069
|
+
entryCount: count2,
|
|
4070
|
+
dimensions: cacheDimensions
|
|
4071
|
+
});
|
|
4072
|
+
return count2;
|
|
4073
|
+
} catch (err) {
|
|
4074
|
+
await unlink(tmpPath).catch(() => void 0);
|
|
4075
|
+
throw err;
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
function convertArrayCacheToJsonl(filePath, jsonlPath) {
|
|
4079
|
+
return migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
4080
|
+
}
|
|
4081
|
+
async function loadCacheJsonl(filePath) {
|
|
4082
|
+
const rl = createInterface({
|
|
4083
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
4084
|
+
crlfDelay: Infinity
|
|
4085
|
+
});
|
|
4086
|
+
let loaded = 0;
|
|
4087
|
+
let onDiskCount = 0;
|
|
4088
|
+
for await (const line of rl) {
|
|
4089
|
+
const trimmed = line.trim();
|
|
4090
|
+
if (!trimmed) continue;
|
|
4091
|
+
try {
|
|
4092
|
+
const row = parseCacheRow(JSON.parse(trimmed));
|
|
4093
|
+
if (!row) continue;
|
|
4094
|
+
onDiskCount += 1;
|
|
4095
|
+
cacheInsert(row.hash, row.vector, false);
|
|
4096
|
+
loaded = cache3.size;
|
|
4097
|
+
} catch {
|
|
4098
|
+
}
|
|
4099
|
+
if (onDiskCount % 250 === 0) {
|
|
4100
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
diskCacheEntryCount = onDiskCount;
|
|
4104
|
+
await writeCacheStat({
|
|
4105
|
+
version: 1,
|
|
4106
|
+
entryCount: onDiskCount,
|
|
4107
|
+
dimensions: cacheDimensions
|
|
4108
|
+
});
|
|
4109
|
+
return loaded;
|
|
4110
|
+
}
|
|
4111
|
+
async function countJsonlLines(filePath) {
|
|
4112
|
+
jsonlLineCountCalls += 1;
|
|
4113
|
+
try {
|
|
4114
|
+
const rl = createInterface({
|
|
4115
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
4116
|
+
crlfDelay: Infinity
|
|
4117
|
+
});
|
|
4118
|
+
let count2 = 0;
|
|
4119
|
+
for await (const line of rl) {
|
|
4120
|
+
if (line.trim()) count2 += 1;
|
|
4121
|
+
}
|
|
4122
|
+
return count2;
|
|
4123
|
+
} catch {
|
|
4124
|
+
return 0;
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
async function resolveOnDiskCount(jsonlPath) {
|
|
4128
|
+
if (diskCacheEntryCount > 0) return diskCacheEntryCount;
|
|
4129
|
+
const sidecar = await readCacheStat();
|
|
4130
|
+
if (sidecar) {
|
|
4131
|
+
diskCacheEntryCount = sidecar.entryCount;
|
|
4132
|
+
if (sidecar.dimensions && cacheDimensions === null) cacheDimensions = sidecar.dimensions;
|
|
4133
|
+
return sidecar.entryCount;
|
|
4134
|
+
}
|
|
4135
|
+
try {
|
|
4136
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
4137
|
+
} catch {
|
|
4138
|
+
return 0;
|
|
4139
|
+
}
|
|
4140
|
+
const counted = await countJsonlLines(jsonlPath);
|
|
4141
|
+
diskCacheEntryCount = counted;
|
|
4142
|
+
await writeCacheStat({
|
|
4143
|
+
version: 1,
|
|
4144
|
+
entryCount: counted,
|
|
4145
|
+
dimensions: cacheDimensions
|
|
4146
|
+
});
|
|
4147
|
+
return counted;
|
|
4148
|
+
}
|
|
3819
4149
|
async function loadDiskCache2() {
|
|
3820
|
-
if (diskCacheLoaded) return;
|
|
4150
|
+
if (diskCacheLoaded) return cache3.size;
|
|
4151
|
+
let loaded = 0;
|
|
3821
4152
|
try {
|
|
3822
|
-
const
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
4153
|
+
const jsonlPath = cacheJsonlFile();
|
|
4154
|
+
let hasJsonl = false;
|
|
4155
|
+
try {
|
|
4156
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
4157
|
+
hasJsonl = true;
|
|
4158
|
+
} catch {
|
|
4159
|
+
hasJsonl = false;
|
|
4160
|
+
}
|
|
4161
|
+
if (hasJsonl) {
|
|
4162
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
4163
|
+
} else {
|
|
4164
|
+
const filePath = cacheFile();
|
|
4165
|
+
await stat(filePath);
|
|
4166
|
+
await migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
4167
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
4168
|
+
}
|
|
4169
|
+
diskCacheLoadCount += 1;
|
|
4170
|
+
console.error(`[memorix] Loaded ${loaded} cached API embeddings from disk`);
|
|
3826
4171
|
} catch {
|
|
3827
4172
|
}
|
|
3828
4173
|
diskCacheLoaded = true;
|
|
4174
|
+
return loaded;
|
|
3829
4175
|
}
|
|
3830
4176
|
function startDiskCacheLoad() {
|
|
3831
4177
|
if (diskCacheLoaded || diskCacheLoadPromise) return;
|
|
3832
|
-
diskCacheLoadPromise = loadDiskCache2().catch(() => {
|
|
4178
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
3833
4179
|
});
|
|
3834
4180
|
}
|
|
3835
4181
|
async function ensureDiskCacheLoaded() {
|
|
3836
|
-
if (diskCacheLoaded) return;
|
|
3837
|
-
if (diskCacheLoadPromise) {
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
}
|
|
3841
|
-
await
|
|
4182
|
+
if (diskCacheLoaded) return cache3.size;
|
|
4183
|
+
if (!diskCacheLoadPromise) {
|
|
4184
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
4185
|
+
});
|
|
4186
|
+
}
|
|
4187
|
+
await diskCacheLoadPromise;
|
|
4188
|
+
return cache3.size;
|
|
4189
|
+
}
|
|
4190
|
+
function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
4191
|
+
return diskCacheLoadCount;
|
|
4192
|
+
}
|
|
4193
|
+
function resetApiEmbeddingCacheForTests() {
|
|
4194
|
+
cache3.clear();
|
|
4195
|
+
cachePayloadBytes = 0;
|
|
4196
|
+
cacheDimensions = null;
|
|
4197
|
+
diskCacheEntryCount = 0;
|
|
4198
|
+
diskCacheLoaded = false;
|
|
4199
|
+
diskCacheLoadPromise = null;
|
|
4200
|
+
diskCacheLoadCount = 0;
|
|
4201
|
+
diskCacheDirty2 = false;
|
|
4202
|
+
jsonlLineCountCalls = 0;
|
|
4203
|
+
}
|
|
4204
|
+
function seedApiEmbeddingCacheForTests(entries) {
|
|
4205
|
+
cache3.clear();
|
|
4206
|
+
cachePayloadBytes = 0;
|
|
4207
|
+
cacheDimensions = null;
|
|
4208
|
+
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4209
|
+
diskCacheLoaded = true;
|
|
4210
|
+
diskCacheDirty2 = true;
|
|
4211
|
+
}
|
|
4212
|
+
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4213
|
+
return cachePayloadBytes;
|
|
4214
|
+
}
|
|
4215
|
+
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4216
|
+
return jsonlLineCountCalls;
|
|
4217
|
+
}
|
|
4218
|
+
function getApiEmbeddingMaxEntriesForDimensionsForTests(dimensions) {
|
|
4219
|
+
return maxEntriesForDimensions(dimensions);
|
|
3842
4220
|
}
|
|
3843
4221
|
function dimsCacheKey(config) {
|
|
3844
4222
|
return [
|
|
@@ -3954,8 +4332,46 @@ async function saveDiskCacheNow() {
|
|
|
3954
4332
|
if (!diskCacheDirty2) return;
|
|
3955
4333
|
try {
|
|
3956
4334
|
await mkdir2(cacheDir(), { recursive: true });
|
|
3957
|
-
const
|
|
3958
|
-
await
|
|
4335
|
+
const jsonlPath = cacheJsonlFile();
|
|
4336
|
+
const existing = await resolveOnDiskCount(jsonlPath);
|
|
4337
|
+
if (existing > 0 && cache3.size < Math.ceil(existing * 0.5)) {
|
|
4338
|
+
console.error(
|
|
4339
|
+
`[memorix] Refusing to overwrite embedding cache (${existing} on disk vs ${cache3.size} in memory)`
|
|
4340
|
+
);
|
|
4341
|
+
diskCacheDirty2 = false;
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
4345
|
+
await new Promise((resolve2, reject) => {
|
|
4346
|
+
const out = createWriteStream(tmpPath);
|
|
4347
|
+
const entries = cache3.entries();
|
|
4348
|
+
const writeBatch = () => {
|
|
4349
|
+
for (let i2 = 0; i2 < 50; i2++) {
|
|
4350
|
+
const next = entries.next();
|
|
4351
|
+
if (next.done) {
|
|
4352
|
+
out.end();
|
|
4353
|
+
return;
|
|
4354
|
+
}
|
|
4355
|
+
const [hash4, vector] = next.value;
|
|
4356
|
+
if (!out.write(`${JSON.stringify({ h: hash4, v: vector })}
|
|
4357
|
+
`)) {
|
|
4358
|
+
out.once("drain", writeBatch);
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
setImmediate(writeBatch);
|
|
4363
|
+
};
|
|
4364
|
+
out.on("finish", resolve2);
|
|
4365
|
+
out.on("error", reject);
|
|
4366
|
+
writeBatch();
|
|
4367
|
+
});
|
|
4368
|
+
await rename(tmpPath, jsonlPath);
|
|
4369
|
+
diskCacheEntryCount = cache3.size;
|
|
4370
|
+
await writeCacheStat({
|
|
4371
|
+
version: 1,
|
|
4372
|
+
entryCount: cache3.size,
|
|
4373
|
+
dimensions: cacheDimensions
|
|
4374
|
+
});
|
|
3959
4375
|
diskCacheDirty2 = false;
|
|
3960
4376
|
} catch {
|
|
3961
4377
|
}
|
|
@@ -3969,12 +4385,7 @@ function scheduleDiskSave() {
|
|
|
3969
4385
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
3970
4386
|
}
|
|
3971
4387
|
function cacheSet(hash4, value) {
|
|
3972
|
-
|
|
3973
|
-
const firstKey = cache3.keys().next().value;
|
|
3974
|
-
if (firstKey !== void 0) cache3.delete(firstKey);
|
|
3975
|
-
}
|
|
3976
|
-
cache3.set(hash4, value);
|
|
3977
|
-
diskCacheDirty2 = true;
|
|
4388
|
+
cacheInsert(hash4, value, true);
|
|
3978
4389
|
}
|
|
3979
4390
|
function resolveEnvEmbeddingApiKey() {
|
|
3980
4391
|
return process.env.MEMORIX_EMBEDDING_API_KEY;
|
|
@@ -4093,18 +4504,27 @@ async function waitForRetry(waitMs, signal) {
|
|
|
4093
4504
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4094
4505
|
});
|
|
4095
4506
|
}
|
|
4096
|
-
var cache3,
|
|
4507
|
+
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES, cachePayloadBytes, cacheDimensions, diskCacheEntryCount, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, diskCacheLoadCount, jsonlLineCountCalls, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
|
|
4097
4508
|
var init_api_provider = __esm({
|
|
4098
4509
|
"src/embedding/api-provider.ts"() {
|
|
4099
4510
|
"use strict";
|
|
4100
4511
|
init_esm_shims();
|
|
4101
4512
|
init_provider();
|
|
4102
4513
|
cache3 = /* @__PURE__ */ new Map();
|
|
4103
|
-
|
|
4514
|
+
MAX_CACHE_ENTRIES = 2e5;
|
|
4515
|
+
MAX_CACHE_PAYLOAD_BYTES = 256 * 1024 * 1024;
|
|
4516
|
+
BYTES_PER_DIM = 8;
|
|
4517
|
+
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4518
|
+
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4519
|
+
cachePayloadBytes = 0;
|
|
4520
|
+
cacheDimensions = null;
|
|
4521
|
+
diskCacheEntryCount = 0;
|
|
4104
4522
|
diskCacheDirty2 = false;
|
|
4105
4523
|
diskSaveTimer = null;
|
|
4106
4524
|
diskCacheLoaded = false;
|
|
4107
4525
|
diskCacheLoadPromise = null;
|
|
4526
|
+
diskCacheLoadCount = 0;
|
|
4527
|
+
jsonlLineCountCalls = 0;
|
|
4108
4528
|
MAX_INPUT_CHARS = 32e3;
|
|
4109
4529
|
MAX_CONCURRENCY = 4;
|
|
4110
4530
|
DISK_SAVE_DEBOUNCE_MS = 5e3;
|
|
@@ -4162,7 +4582,9 @@ var init_api_provider = __esm({
|
|
|
4162
4582
|
if (config.requestedDimensions) {
|
|
4163
4583
|
console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);
|
|
4164
4584
|
}
|
|
4165
|
-
|
|
4585
|
+
if (allowNetworkProbe) {
|
|
4586
|
+
startDiskCacheLoad();
|
|
4587
|
+
}
|
|
4166
4588
|
return new _APIEmbeddingProvider(config, probeDimensions);
|
|
4167
4589
|
}
|
|
4168
4590
|
static resolveConfig() {
|
|
@@ -4438,6 +4860,7 @@ __export(provider_exports, {
|
|
|
4438
4860
|
MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
|
|
4439
4861
|
UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
|
|
4440
4862
|
getEmbeddingProvider: () => getEmbeddingProvider,
|
|
4863
|
+
getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
|
|
4441
4864
|
isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
|
|
4442
4865
|
isVectorSearchAvailable: () => isVectorSearchAvailable,
|
|
4443
4866
|
resetProvider: () => resetProvider,
|
|
@@ -4499,7 +4922,12 @@ function warnOnce(message) {
|
|
|
4499
4922
|
lastEmbeddingWarningAt = now3;
|
|
4500
4923
|
console.error(message);
|
|
4501
4924
|
}
|
|
4925
|
+
function embeddingModeToken() {
|
|
4926
|
+
return process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim() ?? "";
|
|
4927
|
+
}
|
|
4502
4928
|
function getEmbeddingMode2() {
|
|
4929
|
+
const token = embeddingModeToken();
|
|
4930
|
+
if (cachedEmbeddingMode && cachedEmbeddingModeToken === token) return cachedEmbeddingMode;
|
|
4503
4931
|
try {
|
|
4504
4932
|
let cfg;
|
|
4505
4933
|
try {
|
|
@@ -4508,10 +4936,17 @@ function getEmbeddingMode2() {
|
|
|
4508
4936
|
cfg = (init_config(), __toCommonJS(config_exports));
|
|
4509
4937
|
}
|
|
4510
4938
|
const { getEmbeddingMode: cfgMode } = cfg;
|
|
4511
|
-
|
|
4939
|
+
cachedEmbeddingMode = cfgMode();
|
|
4940
|
+
cachedEmbeddingModeToken = token;
|
|
4941
|
+
return cachedEmbeddingMode;
|
|
4512
4942
|
} catch {
|
|
4513
|
-
|
|
4514
|
-
|
|
4943
|
+
if (token === "fastembed" || token === "transformers" || token === "api" || token === "auto") {
|
|
4944
|
+
cachedEmbeddingMode = token;
|
|
4945
|
+
cachedEmbeddingModeToken = token;
|
|
4946
|
+
return token;
|
|
4947
|
+
}
|
|
4948
|
+
cachedEmbeddingMode = "off";
|
|
4949
|
+
cachedEmbeddingModeToken = token;
|
|
4515
4950
|
return "off";
|
|
4516
4951
|
}
|
|
4517
4952
|
}
|
|
@@ -4545,13 +4980,36 @@ function isTemporaryEmbeddingFailure(error) {
|
|
|
4545
4980
|
if (!(error instanceof Error)) return false;
|
|
4546
4981
|
return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
|
|
4547
4982
|
}
|
|
4983
|
+
function classifyEmbeddingFailure(error) {
|
|
4984
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4985
|
+
if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
|
|
4986
|
+
return "authorization";
|
|
4987
|
+
}
|
|
4988
|
+
if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
|
|
4989
|
+
return "billing";
|
|
4990
|
+
}
|
|
4991
|
+
if (/embedding api timeout|abort/i.test(message)) {
|
|
4992
|
+
return "timeout";
|
|
4993
|
+
}
|
|
4994
|
+
return "upstream";
|
|
4995
|
+
}
|
|
4548
4996
|
function markTemporaryFailure(reason) {
|
|
4549
4997
|
provider = null;
|
|
4550
4998
|
initPromise = null;
|
|
4551
4999
|
lastInitWasTemporaryFailure = true;
|
|
4552
5000
|
lastFailureTimestamp = Date.now();
|
|
5001
|
+
lastEmbeddingFailure = {
|
|
5002
|
+
kind: classifyEmbeddingFailure(reason),
|
|
5003
|
+
occurredAt: lastFailureTimestamp
|
|
5004
|
+
};
|
|
4553
5005
|
const message = reason instanceof Error ? reason.message : String(reason);
|
|
4554
|
-
warnOnce(`[memorix] Embedding provider
|
|
5006
|
+
warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
|
|
5007
|
+
}
|
|
5008
|
+
function markProviderReady(candidate) {
|
|
5009
|
+
provider = wrapProvider(candidate);
|
|
5010
|
+
lastInitWasTemporaryFailure = false;
|
|
5011
|
+
lastEmbeddingFailure = null;
|
|
5012
|
+
return provider;
|
|
4555
5013
|
}
|
|
4556
5014
|
async function createFastEmbedProvider() {
|
|
4557
5015
|
try {
|
|
@@ -4667,35 +5125,35 @@ async function getEmbeddingProvider(options = {}) {
|
|
|
4667
5125
|
if (mode === "fastembed") {
|
|
4668
5126
|
const initialized = await createFastEmbedProvider();
|
|
4669
5127
|
if (!initialized) return null;
|
|
4670
|
-
provider =
|
|
5128
|
+
provider = markProviderReady(initialized);
|
|
4671
5129
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
4672
5130
|
return provider;
|
|
4673
5131
|
}
|
|
4674
5132
|
if (mode === "transformers") {
|
|
4675
5133
|
const initialized = await createTransformersProvider();
|
|
4676
5134
|
if (!initialized) return null;
|
|
4677
|
-
provider =
|
|
5135
|
+
provider = markProviderReady(initialized);
|
|
4678
5136
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
4679
5137
|
return provider;
|
|
4680
5138
|
}
|
|
4681
5139
|
if (mode === "api") {
|
|
4682
5140
|
const initialized = await createAPIProvider(options);
|
|
4683
5141
|
if (!initialized) return null;
|
|
4684
|
-
provider =
|
|
5142
|
+
provider = markProviderReady(initialized);
|
|
4685
5143
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
4686
5144
|
return provider;
|
|
4687
5145
|
}
|
|
4688
5146
|
if (hasAPIEmbeddingConfig()) {
|
|
4689
5147
|
const initialized = await createAPIProvider(options);
|
|
4690
5148
|
if (initialized) {
|
|
4691
|
-
provider =
|
|
5149
|
+
provider = markProviderReady(initialized);
|
|
4692
5150
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
4693
5151
|
return provider;
|
|
4694
5152
|
}
|
|
4695
5153
|
}
|
|
4696
5154
|
const localFallback = await createLocalFallbackProvider();
|
|
4697
5155
|
if (localFallback) {
|
|
4698
|
-
provider =
|
|
5156
|
+
provider = markProviderReady(localFallback);
|
|
4699
5157
|
warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
|
|
4700
5158
|
return provider;
|
|
4701
5159
|
}
|
|
@@ -4717,18 +5175,42 @@ async function isVectorSearchAvailable() {
|
|
|
4717
5175
|
const p = await getEmbeddingProvider();
|
|
4718
5176
|
return p !== null;
|
|
4719
5177
|
}
|
|
5178
|
+
function getEmbeddingRuntimeHealth() {
|
|
5179
|
+
const mode = getEmbeddingMode2();
|
|
5180
|
+
if (mode === "off") return { status: "disabled" };
|
|
5181
|
+
if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
|
|
5182
|
+
return {
|
|
5183
|
+
status: "degraded",
|
|
5184
|
+
failure: {
|
|
5185
|
+
kind: lastEmbeddingFailure.kind,
|
|
5186
|
+
occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
|
|
5187
|
+
retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
|
|
5188
|
+
}
|
|
5189
|
+
};
|
|
5190
|
+
}
|
|
5191
|
+
if (provider) {
|
|
5192
|
+
return {
|
|
5193
|
+
status: "ready",
|
|
5194
|
+
provider: { name: provider.name, dimensions: provider.dimensions }
|
|
5195
|
+
};
|
|
5196
|
+
}
|
|
5197
|
+
return { status: "uninitialized" };
|
|
5198
|
+
}
|
|
4720
5199
|
function isEmbeddingExplicitlyDisabled() {
|
|
4721
5200
|
return getEmbeddingMode2() === "off";
|
|
4722
5201
|
}
|
|
4723
5202
|
function resetProvider() {
|
|
4724
5203
|
provider = null;
|
|
4725
5204
|
initPromise = null;
|
|
5205
|
+
cachedEmbeddingMode = null;
|
|
5206
|
+
cachedEmbeddingModeToken = null;
|
|
4726
5207
|
lastInitWasTemporaryFailure = false;
|
|
4727
5208
|
lastFailureTimestamp = 0;
|
|
5209
|
+
lastEmbeddingFailure = null;
|
|
4728
5210
|
lastEmbeddingWarning = "";
|
|
4729
5211
|
lastEmbeddingWarningAt = 0;
|
|
4730
5212
|
}
|
|
4731
|
-
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
5213
|
+
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, cachedEmbeddingMode, cachedEmbeddingModeToken, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
4732
5214
|
var init_provider = __esm({
|
|
4733
5215
|
"src/embedding/provider.ts"() {
|
|
4734
5216
|
"use strict";
|
|
@@ -4752,7 +5234,10 @@ var init_provider = __esm({
|
|
|
4752
5234
|
MAX_INLINE_EMBEDDING_BYTES = 5 * 1024 * 1024;
|
|
4753
5235
|
provider = null;
|
|
4754
5236
|
initPromise = null;
|
|
5237
|
+
cachedEmbeddingMode = null;
|
|
5238
|
+
cachedEmbeddingModeToken = null;
|
|
4755
5239
|
lastInitWasTemporaryFailure = false;
|
|
5240
|
+
lastEmbeddingFailure = null;
|
|
4756
5241
|
lastEmbeddingWarning = "";
|
|
4757
5242
|
lastEmbeddingWarningAt = 0;
|
|
4758
5243
|
WARNING_COOLDOWN_MS = 3e4;
|
|
@@ -6508,6 +6993,9 @@ async function attachCachedVectors(database, candidates) {
|
|
|
6508
6993
|
await update(database, candidates[index].id, { ...existing, embedding: vector });
|
|
6509
6994
|
} catch {
|
|
6510
6995
|
}
|
|
6996
|
+
if (index % 50 === 0) {
|
|
6997
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
6998
|
+
}
|
|
6511
6999
|
}
|
|
6512
7000
|
}
|
|
6513
7001
|
async function hydrateIndex(observations2, options = {}) {
|
|
@@ -6558,17 +7046,24 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
6558
7046
|
await insert2(database, doc);
|
|
6559
7047
|
rememberObservationDoc(doc);
|
|
6560
7048
|
inserted++;
|
|
7049
|
+
if (inserted % 50 === 0) {
|
|
7050
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
7051
|
+
}
|
|
7052
|
+
if (inserted % 200 === 0) {
|
|
7053
|
+
await new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
7054
|
+
}
|
|
6561
7055
|
} catch {
|
|
6562
7056
|
}
|
|
6563
7057
|
}
|
|
6564
|
-
deferredCachedVectorHydration = deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
7058
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
6565
7059
|
}) : null;
|
|
6566
7060
|
return inserted;
|
|
6567
7061
|
}
|
|
6568
|
-
async function hydrateIndexForStartup(observations2) {
|
|
7062
|
+
async function hydrateIndexForStartup(observations2, options = {}) {
|
|
6569
7063
|
return hydrateIndex(observations2, {
|
|
6570
7064
|
allowNetworkProbe: false,
|
|
6571
|
-
deferCachedVectors: true
|
|
7065
|
+
deferCachedVectors: true,
|
|
7066
|
+
skipCachedVectors: options.skipCachedVectors
|
|
6572
7067
|
});
|
|
6573
7068
|
}
|
|
6574
7069
|
function getDeferredCachedVectorHydration() {
|
|
@@ -9891,7 +10386,7 @@ __export(asset_store_exports, {
|
|
|
9891
10386
|
removeMediaAsset: () => removeMediaAsset
|
|
9892
10387
|
});
|
|
9893
10388
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
9894
|
-
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename, rm, stat, writeFile as writeFile3 } from "fs/promises";
|
|
10389
|
+
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
9895
10390
|
import path13 from "path";
|
|
9896
10391
|
function mediaRoot(dataDir) {
|
|
9897
10392
|
return path13.resolve(dataDir, "media");
|
|
@@ -9981,7 +10476,7 @@ async function persistFile(source, destination) {
|
|
|
9981
10476
|
const temporary = `${destination}.${randomUUID5()}.tmp`;
|
|
9982
10477
|
try {
|
|
9983
10478
|
await copyFile(source, temporary);
|
|
9984
|
-
await
|
|
10479
|
+
await rename2(temporary, destination);
|
|
9985
10480
|
return true;
|
|
9986
10481
|
} catch (error) {
|
|
9987
10482
|
if (error?.code === "EEXIST" && await destinationExists(destination)) return false;
|
|
@@ -9997,7 +10492,7 @@ async function persistBuffer(bytes, destination) {
|
|
|
9997
10492
|
const temporary = `${destination}.${randomUUID5()}.tmp`;
|
|
9998
10493
|
try {
|
|
9999
10494
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
10000
|
-
await
|
|
10495
|
+
await rename2(temporary, destination);
|
|
10001
10496
|
return true;
|
|
10002
10497
|
} catch (error) {
|
|
10003
10498
|
if (error?.code === "EEXIST" && await destinationExists(destination)) return false;
|
|
@@ -10037,11 +10532,11 @@ async function importKnownMedia(input) {
|
|
|
10037
10532
|
async function importMediaFile(input) {
|
|
10038
10533
|
const maxBytes = input.maxBytes ?? DEFAULT_MAX_MEDIA_BYTES;
|
|
10039
10534
|
const source = path13.resolve(input.filePath);
|
|
10040
|
-
const
|
|
10041
|
-
if (
|
|
10042
|
-
if (!
|
|
10043
|
-
if (
|
|
10044
|
-
if (
|
|
10535
|
+
const stat5 = await lstat(source);
|
|
10536
|
+
if (stat5.isSymbolicLink()) throw new Error("Media import does not follow symbolic links");
|
|
10537
|
+
if (!stat5.isFile()) throw new Error("Media import accepts regular files only");
|
|
10538
|
+
if (stat5.size <= 0) throw new Error("Media import rejects empty files");
|
|
10539
|
+
if (stat5.size > maxBytes) throw new Error(`Media file is too large (${stat5.size} bytes; limit ${maxBytes})`);
|
|
10045
10540
|
const header = await readHeader(source);
|
|
10046
10541
|
const detected = detectMedia(header);
|
|
10047
10542
|
const sha256 = await sha256File(source);
|
|
@@ -10049,7 +10544,7 @@ async function importMediaFile(input) {
|
|
|
10049
10544
|
dataDir: input.dataDir,
|
|
10050
10545
|
projectId: input.projectId,
|
|
10051
10546
|
sha256,
|
|
10052
|
-
bytes:
|
|
10547
|
+
bytes: stat5.size,
|
|
10053
10548
|
detected,
|
|
10054
10549
|
persist: (destination) => persistFile(source, destination),
|
|
10055
10550
|
sourceKind: input.sourceKind ?? "import",
|
|
@@ -10096,13 +10591,13 @@ async function removeMediaAsset(input) {
|
|
|
10096
10591
|
const assetPath = getMediaAssetPath(input.dataDir, asset);
|
|
10097
10592
|
const stagedPath = deletionStagingPath(mediaRoot(input.dataDir), asset.id);
|
|
10098
10593
|
await mkdir3(path13.dirname(stagedPath), { recursive: true });
|
|
10099
|
-
await
|
|
10594
|
+
await rename2(assetPath, stagedPath);
|
|
10100
10595
|
let detachedLinks;
|
|
10101
10596
|
try {
|
|
10102
10597
|
({ detachedLinks } = store.removeAssetMetadata(input.projectId, asset.id, { force: input.force }));
|
|
10103
10598
|
} catch (error) {
|
|
10104
10599
|
try {
|
|
10105
|
-
await
|
|
10600
|
+
await rename2(stagedPath, assetPath);
|
|
10106
10601
|
} catch (restoreError) {
|
|
10107
10602
|
const original = error instanceof Error ? error.message : String(error);
|
|
10108
10603
|
const restore = restoreError instanceof Error ? restoreError.message : String(restoreError);
|
|
@@ -10138,7 +10633,7 @@ async function cleanupMediaTrash(dataDir) {
|
|
|
10138
10633
|
} catch (error) {
|
|
10139
10634
|
if (error?.code === "ENOENT") continue;
|
|
10140
10635
|
try {
|
|
10141
|
-
pendingBytes += (await
|
|
10636
|
+
pendingBytes += (await stat2(candidate)).size;
|
|
10142
10637
|
} catch {
|
|
10143
10638
|
}
|
|
10144
10639
|
pendingFiles += 1;
|
|
@@ -61220,9 +61715,9 @@ var require_node_domexception = __commonJS({
|
|
|
61220
61715
|
});
|
|
61221
61716
|
|
|
61222
61717
|
// node_modules/fetch-blob/from.js
|
|
61223
|
-
import { statSync as statSync2, createReadStream, promises as fs10 } from "fs";
|
|
61718
|
+
import { statSync as statSync2, createReadStream as createReadStream2, promises as fs10 } from "fs";
|
|
61224
61719
|
import { basename } from "path";
|
|
61225
|
-
var import_node_domexception,
|
|
61720
|
+
var import_node_domexception, stat3, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
61226
61721
|
var init_from = __esm({
|
|
61227
61722
|
"node_modules/fetch-blob/from.js"() {
|
|
61228
61723
|
"use strict";
|
|
@@ -61230,23 +61725,23 @@ var init_from = __esm({
|
|
|
61230
61725
|
import_node_domexception = __toESM(require_node_domexception(), 1);
|
|
61231
61726
|
init_file();
|
|
61232
61727
|
init_fetch_blob();
|
|
61233
|
-
({ stat:
|
|
61728
|
+
({ stat: stat3 } = fs10);
|
|
61234
61729
|
blobFromSync = (path37, type) => fromBlob(statSync2(path37), path37, type);
|
|
61235
|
-
blobFrom = (path37, type) =>
|
|
61236
|
-
fileFrom = (path37, type) =>
|
|
61730
|
+
blobFrom = (path37, type) => stat3(path37).then((stat5) => fromBlob(stat5, path37, type));
|
|
61731
|
+
fileFrom = (path37, type) => stat3(path37).then((stat5) => fromFile(stat5, path37, type));
|
|
61237
61732
|
fileFromSync = (path37, type) => fromFile(statSync2(path37), path37, type);
|
|
61238
|
-
fromBlob = (
|
|
61733
|
+
fromBlob = (stat5, path37, type = "") => new fetch_blob_default([new BlobDataItem({
|
|
61239
61734
|
path: path37,
|
|
61240
|
-
size:
|
|
61241
|
-
lastModified:
|
|
61735
|
+
size: stat5.size,
|
|
61736
|
+
lastModified: stat5.mtimeMs,
|
|
61242
61737
|
start: 0
|
|
61243
61738
|
})], { type });
|
|
61244
|
-
fromFile = (
|
|
61739
|
+
fromFile = (stat5, path37, type = "") => new file_default([new BlobDataItem({
|
|
61245
61740
|
path: path37,
|
|
61246
|
-
size:
|
|
61247
|
-
lastModified:
|
|
61741
|
+
size: stat5.size,
|
|
61742
|
+
lastModified: stat5.mtimeMs,
|
|
61248
61743
|
start: 0
|
|
61249
|
-
})], basename(path37), { type, lastModified:
|
|
61744
|
+
})], basename(path37), { type, lastModified: stat5.mtimeMs });
|
|
61250
61745
|
BlobDataItem = class _BlobDataItem {
|
|
61251
61746
|
#path;
|
|
61252
61747
|
#start;
|
|
@@ -61269,11 +61764,11 @@ var init_from = __esm({
|
|
|
61269
61764
|
});
|
|
61270
61765
|
}
|
|
61271
61766
|
async *stream() {
|
|
61272
|
-
const { mtimeMs } = await
|
|
61767
|
+
const { mtimeMs } = await stat3(this.#path);
|
|
61273
61768
|
if (mtimeMs > this.lastModified) {
|
|
61274
61769
|
throw new import_node_domexception.default("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.", "NotReadableError");
|
|
61275
61770
|
}
|
|
61276
|
-
yield*
|
|
61771
|
+
yield* createReadStream2(this.#path, {
|
|
61277
61772
|
start: this.#start,
|
|
61278
61773
|
end: this.#start + this.size - 1
|
|
61279
61774
|
});
|
|
@@ -76903,7 +77398,7 @@ var init_wrapper = __esm({
|
|
|
76903
77398
|
});
|
|
76904
77399
|
|
|
76905
77400
|
// node_modules/@google/genai/dist/node/index.mjs
|
|
76906
|
-
import { createWriteStream } from "fs";
|
|
77401
|
+
import { createWriteStream as createWriteStream2 } from "fs";
|
|
76907
77402
|
import * as fs11 from "fs/promises";
|
|
76908
77403
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
76909
77404
|
import { Readable } from "stream";
|
|
@@ -94183,7 +94678,7 @@ ${underline}`);
|
|
|
94183
94678
|
if (params.downloadPath) {
|
|
94184
94679
|
const response = await downloadFile(params, apiClient);
|
|
94185
94680
|
if (response instanceof HttpResponse) {
|
|
94186
|
-
const writer =
|
|
94681
|
+
const writer = createWriteStream2(params.downloadPath);
|
|
94187
94682
|
const body = Readable.fromWeb(response.responseInternal.body);
|
|
94188
94683
|
body.pipe(writer);
|
|
94189
94684
|
await finished(writer);
|
|
@@ -144217,7 +144712,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
144217
144712
|
};
|
|
144218
144713
|
}
|
|
144219
144714
|
function toRetentionDocument(obs, accessMap) {
|
|
144220
|
-
const
|
|
144715
|
+
const access3 = accessMap?.get(obs.id);
|
|
144221
144716
|
return {
|
|
144222
144717
|
id: `obs-${obs.id}`,
|
|
144223
144718
|
observationId: obs.id,
|
|
@@ -144231,8 +144726,8 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
144231
144726
|
tokens: obs.tokens,
|
|
144232
144727
|
createdAt: obs.createdAt,
|
|
144233
144728
|
projectId: obs.projectId,
|
|
144234
|
-
accessCount:
|
|
144235
|
-
lastAccessedAt:
|
|
144729
|
+
accessCount: access3?.accessCount ?? 0,
|
|
144730
|
+
lastAccessedAt: access3?.lastAccessedAt ?? "",
|
|
144236
144731
|
status: obs.status ?? "active",
|
|
144237
144732
|
source: obs.source ?? "agent",
|
|
144238
144733
|
sourceDetail: obs.sourceDetail ?? "",
|
|
@@ -146346,7 +146841,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
146346
146841
|
const rel = normalizeCodePath(relative(projectRoot, abs));
|
|
146347
146842
|
try {
|
|
146348
146843
|
const text2 = readFileSync6(abs, "utf-8");
|
|
146349
|
-
const
|
|
146844
|
+
const stat5 = fileStat ?? statSync3(abs);
|
|
146350
146845
|
const file = {
|
|
146351
146846
|
id: makeCodeFileId(projectId, rel),
|
|
146352
146847
|
projectId,
|
|
@@ -146355,8 +146850,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
146355
146850
|
contentHash: hashText(text2),
|
|
146356
146851
|
// Preserve filesystem precision. Rounding here made same-size edits in
|
|
146357
146852
|
// a short Windows timestamp window indistinguishable to refresh.
|
|
146358
|
-
mtimeMs: Number(
|
|
146359
|
-
sizeBytes: Number(
|
|
146853
|
+
mtimeMs: Number(stat5.mtimeMs),
|
|
146854
|
+
sizeBytes: Number(stat5.size),
|
|
146360
146855
|
indexedAt
|
|
146361
146856
|
};
|
|
146362
146857
|
return {
|
|
@@ -146383,18 +146878,18 @@ async function indexProjectLite(options) {
|
|
|
146383
146878
|
let skippedOversizedFiles = 0;
|
|
146384
146879
|
let unreadableFiles = 0;
|
|
146385
146880
|
for (const abs of paths) {
|
|
146386
|
-
let
|
|
146881
|
+
let stat5;
|
|
146387
146882
|
try {
|
|
146388
|
-
|
|
146883
|
+
stat5 = statSync3(abs);
|
|
146389
146884
|
} catch {
|
|
146390
146885
|
unreadableFiles++;
|
|
146391
146886
|
continue;
|
|
146392
146887
|
}
|
|
146393
|
-
if (Number(
|
|
146888
|
+
if (Number(stat5.size) > maxFileBytes) {
|
|
146394
146889
|
skippedOversizedFiles++;
|
|
146395
146890
|
continue;
|
|
146396
146891
|
}
|
|
146397
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
146892
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
146398
146893
|
if (!attempt.delta) {
|
|
146399
146894
|
if (attempt.unreadable) unreadableFiles++;
|
|
146400
146895
|
continue;
|
|
@@ -146422,16 +146917,16 @@ async function refreshProjectLite(store, options) {
|
|
|
146422
146917
|
for (const abs of paths) {
|
|
146423
146918
|
const rel = normalizeCodePath(relative(options.projectRoot, abs));
|
|
146424
146919
|
seenPaths.add(rel);
|
|
146425
|
-
let
|
|
146920
|
+
let stat5;
|
|
146426
146921
|
try {
|
|
146427
|
-
|
|
146922
|
+
stat5 = statSync3(abs);
|
|
146428
146923
|
} catch {
|
|
146429
146924
|
unreadableFiles++;
|
|
146430
146925
|
continue;
|
|
146431
146926
|
}
|
|
146432
146927
|
const existing = existingByPath.get(rel);
|
|
146433
|
-
const mtimeMs = Number(
|
|
146434
|
-
const sizeBytes = Number(
|
|
146928
|
+
const mtimeMs = Number(stat5.mtimeMs);
|
|
146929
|
+
const sizeBytes = Number(stat5.size);
|
|
146435
146930
|
if (sizeBytes > maxFileBytes) {
|
|
146436
146931
|
skippedOversizedFiles++;
|
|
146437
146932
|
if (existing) oversizedExistingFileIds.add(existing.id);
|
|
@@ -146441,7 +146936,7 @@ async function refreshProjectLite(store, options) {
|
|
|
146441
146936
|
unchangedFiles++;
|
|
146442
146937
|
continue;
|
|
146443
146938
|
}
|
|
146444
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
146939
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
146445
146940
|
if (!attempt.delta) {
|
|
146446
146941
|
if (attempt.unreadable) unreadableFiles++;
|
|
146447
146942
|
continue;
|
|
@@ -150189,12 +150684,25 @@ __export(observations_exports, {
|
|
|
150189
150684
|
prepareSearchIndex: () => prepareSearchIndex,
|
|
150190
150685
|
probeSearchIndex: () => probeSearchIndex,
|
|
150191
150686
|
reindexObservations: () => reindexObservations,
|
|
150687
|
+
resetObservationRuntime: () => resetObservationRuntime,
|
|
150192
150688
|
resolveObservations: () => resolveObservations,
|
|
150193
150689
|
storeObservation: () => storeObservation,
|
|
150194
150690
|
suggestTopicKey: () => suggestTopicKey,
|
|
150195
150691
|
updateObservationAdmission: () => updateObservationAdmission,
|
|
150196
150692
|
withFreshObservations: () => withFreshObservations
|
|
150197
150693
|
});
|
|
150694
|
+
function resetObservationRuntime() {
|
|
150695
|
+
observations = [];
|
|
150696
|
+
nextId = 1;
|
|
150697
|
+
projectDir = null;
|
|
150698
|
+
searchIndexPrepared = false;
|
|
150699
|
+
corpusLoaded = false;
|
|
150700
|
+
loadedObservationStore = null;
|
|
150701
|
+
embeddingWriteMode = "background";
|
|
150702
|
+
embeddingWorkerProjectRoot = void 0;
|
|
150703
|
+
vectorMissingIds.clear();
|
|
150704
|
+
vectorSchemaUpgradePromise = null;
|
|
150705
|
+
}
|
|
150198
150706
|
function logEmbeddingFailureOnce(key, message) {
|
|
150199
150707
|
const now3 = Date.now();
|
|
150200
150708
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
@@ -150303,23 +150811,33 @@ async function upgradeVectorSchemaAfterFirstEmbedding(embedding) {
|
|
|
150303
150811
|
async function initObservations(dir, options = {}) {
|
|
150304
150812
|
embeddingWriteMode = options.embeddingWriteMode ?? "background";
|
|
150305
150813
|
embeddingWorkerProjectRoot = options.projectRoot;
|
|
150306
|
-
if (projectDir === dir) return;
|
|
150307
150814
|
await initObservationStore(dir);
|
|
150308
150815
|
const store = getObservationStore();
|
|
150309
|
-
|
|
150816
|
+
if (projectDir === dir && loadedObservationStore === store) {
|
|
150817
|
+
if (options.skipCorpusLoad || corpusLoaded) return;
|
|
150818
|
+
}
|
|
150310
150819
|
nextId = await store.loadIdCounter();
|
|
150311
150820
|
projectDir = dir;
|
|
150312
150821
|
searchIndexPrepared = false;
|
|
150313
150822
|
vectorSchemaUpgradePromise = null;
|
|
150823
|
+
if (options.skipCorpusLoad) {
|
|
150824
|
+
observations = [];
|
|
150825
|
+
corpusLoaded = false;
|
|
150826
|
+
loadedObservationStore = store;
|
|
150827
|
+
return;
|
|
150828
|
+
}
|
|
150829
|
+
observations = await store.loadAll();
|
|
150830
|
+
corpusLoaded = true;
|
|
150831
|
+
loadedObservationStore = store;
|
|
150314
150832
|
}
|
|
150315
150833
|
function scheduleObservationEmbedding(input) {
|
|
150316
150834
|
const { observationId: observationId2, projectId, searchableText, doc } = input;
|
|
150317
150835
|
vectorMissingIds.add(observationId2);
|
|
150836
|
+
if (isEmbeddingExplicitlyDisabled()) {
|
|
150837
|
+
vectorMissingIds.delete(observationId2);
|
|
150838
|
+
return;
|
|
150839
|
+
}
|
|
150318
150840
|
if (embeddingWriteMode === "deferred") {
|
|
150319
|
-
if (isEmbeddingExplicitlyDisabled()) {
|
|
150320
|
-
vectorMissingIds.delete(observationId2);
|
|
150321
|
-
return;
|
|
150322
|
-
}
|
|
150323
150841
|
queueVectorBackfill(projectId, {
|
|
150324
150842
|
detachedWorker: true,
|
|
150325
150843
|
projectRoot: embeddingWorkerProjectRoot
|
|
@@ -150366,7 +150884,7 @@ function scheduleObservationEmbedding(input) {
|
|
|
150366
150884
|
});
|
|
150367
150885
|
}
|
|
150368
150886
|
async function ensureFreshObservations() {
|
|
150369
|
-
if (!projectDir) return false;
|
|
150887
|
+
if (!projectDir || !corpusLoaded) return false;
|
|
150370
150888
|
try {
|
|
150371
150889
|
const store = getObservationStore();
|
|
150372
150890
|
const wasStale = await store.ensureFresh();
|
|
@@ -150407,7 +150925,7 @@ async function storeObservation(input) {
|
|
|
150407
150925
|
});
|
|
150408
150926
|
if (safeAttachments) input = { ...input, attachments: safeAttachments };
|
|
150409
150927
|
await ensureFreshObservations();
|
|
150410
|
-
if (input.topicKey) {
|
|
150928
|
+
if (input.topicKey && corpusLoaded) {
|
|
150411
150929
|
const existing = observations.find(
|
|
150412
150930
|
(o) => o.topicKey === input.topicKey && o.projectId === input.projectId
|
|
150413
150931
|
);
|
|
@@ -150504,13 +151022,17 @@ async function storeObservation(input) {
|
|
|
150504
151022
|
});
|
|
150505
151023
|
observation.writeGeneration = store.getGeneration();
|
|
150506
151024
|
if (upsertedInsideLock || reloadCacheAfterCommit) {
|
|
150507
|
-
|
|
150508
|
-
|
|
150509
|
-
|
|
150510
|
-
|
|
151025
|
+
if (corpusLoaded) {
|
|
151026
|
+
observations = await store.loadAll();
|
|
151027
|
+
nextId = await store.loadIdCounter();
|
|
151028
|
+
if (upsertedInsideLock) {
|
|
151029
|
+
observation = observations.find((candidate) => candidate.id === observation.id) ?? observation;
|
|
151030
|
+
}
|
|
151031
|
+
} else {
|
|
151032
|
+
nextId = await store.loadIdCounter();
|
|
150511
151033
|
}
|
|
150512
151034
|
} else {
|
|
150513
|
-
observations.push(observation);
|
|
151035
|
+
if (corpusLoaded) observations.push(observation);
|
|
150514
151036
|
nextId = observation.id + 1;
|
|
150515
151037
|
}
|
|
150516
151038
|
if (upsertedInsideLock) return;
|
|
@@ -150578,7 +151100,9 @@ async function storeObservation(input) {
|
|
|
150578
151100
|
createdByAgentId: input.createdByAgentId ?? "",
|
|
150579
151101
|
sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? [])
|
|
150580
151102
|
};
|
|
150581
|
-
|
|
151103
|
+
if (corpusLoaded) {
|
|
151104
|
+
await insertObservation(doc);
|
|
151105
|
+
}
|
|
150582
151106
|
};
|
|
150583
151107
|
await assignAndPersist();
|
|
150584
151108
|
if (upsertedInsideLock) {
|
|
@@ -150940,9 +151464,11 @@ async function reindexObservations() {
|
|
|
150940
151464
|
searchIndexPrepared = true;
|
|
150941
151465
|
return count2;
|
|
150942
151466
|
}
|
|
150943
|
-
async function prepareSearchIndex() {
|
|
151467
|
+
async function prepareSearchIndex(options = {}) {
|
|
150944
151468
|
if (searchIndexPrepared) return 0;
|
|
150945
|
-
const count2 = await hydrateIndexForStartup(observations
|
|
151469
|
+
const count2 = await hydrateIndexForStartup(observations, {
|
|
151470
|
+
skipCachedVectors: options.skipCachedVectors
|
|
151471
|
+
});
|
|
150946
151472
|
if (count2 === 0) {
|
|
150947
151473
|
searchIndexPrepared = true;
|
|
150948
151474
|
return 0;
|
|
@@ -151134,7 +151660,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
151134
151660
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
151135
151661
|
};
|
|
151136
151662
|
}
|
|
151137
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
151663
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
151138
151664
|
var init_observations = __esm({
|
|
151139
151665
|
"src/memory/observations.ts"() {
|
|
151140
151666
|
"use strict";
|
|
@@ -151153,6 +151679,8 @@ var init_observations = __esm({
|
|
|
151153
151679
|
projectDir = null;
|
|
151154
151680
|
searchIndexPrepared = false;
|
|
151155
151681
|
embeddingWriteMode = "background";
|
|
151682
|
+
corpusLoaded = false;
|
|
151683
|
+
loadedObservationStore = null;
|
|
151156
151684
|
vectorMissingIds = /* @__PURE__ */ new Set();
|
|
151157
151685
|
vectorBackfillRunning = false;
|
|
151158
151686
|
vectorSchemaUpgradePromise = null;
|
|
@@ -153741,8 +154269,8 @@ var init_syncer = __esm({
|
|
|
153741
154269
|
const dir = path25.dirname(pattern);
|
|
153742
154270
|
const fileGlob = path25.basename(pattern);
|
|
153743
154271
|
try {
|
|
153744
|
-
const
|
|
153745
|
-
if (!
|
|
154272
|
+
const stat5 = await fs17.stat(dir);
|
|
154273
|
+
if (!stat5.isDirectory()) {
|
|
153746
154274
|
try {
|
|
153747
154275
|
await fs17.access(pattern);
|
|
153748
154276
|
return [pattern];
|
|
@@ -159333,9 +159861,9 @@ function existingLensCandidates(rootPath, lens) {
|
|
|
159333
159861
|
const absolute = path28.join(rootPath, candidate);
|
|
159334
159862
|
try {
|
|
159335
159863
|
if (!existsSync16(absolute)) continue;
|
|
159336
|
-
const
|
|
159337
|
-
if (
|
|
159338
|
-
if (
|
|
159864
|
+
const stat5 = statSync4(absolute);
|
|
159865
|
+
if (stat5.isFile()) out.push(candidate);
|
|
159866
|
+
if (stat5.isDirectory()) out.push(candidate.replace(/\\/g, "/"));
|
|
159339
159867
|
} catch {
|
|
159340
159868
|
}
|
|
159341
159869
|
}
|
|
@@ -165155,13 +165683,13 @@ async function installHooks(agent, projectRoot, global2 = false) {
|
|
|
165155
165683
|
const agentPrev = prevFiles.filter((e2) => e2.agent === agent);
|
|
165156
165684
|
for (const entry of agentPrev) {
|
|
165157
165685
|
try {
|
|
165158
|
-
const { access:
|
|
165159
|
-
await
|
|
165686
|
+
const { access: access3, unlink: unlink3 } = await import("fs/promises");
|
|
165687
|
+
await access3(entry.path);
|
|
165160
165688
|
const basename5 = path32.basename(entry.path);
|
|
165161
165689
|
if (basename5 === "AGENTS.md" || basename5 === "GEMINI.md" || basename5 === "CONTEXT.md") {
|
|
165162
165690
|
continue;
|
|
165163
165691
|
}
|
|
165164
|
-
await
|
|
165692
|
+
await unlink3(entry.path);
|
|
165165
165693
|
await removeFile2(projectRoot, entry.path);
|
|
165166
165694
|
} catch {
|
|
165167
165695
|
}
|
|
@@ -165681,11 +166209,11 @@ import path33 from "path";
|
|
|
165681
166209
|
function resolveGitDir(projectRoot) {
|
|
165682
166210
|
const dotGit = path33.join(projectRoot, ".git");
|
|
165683
166211
|
if (!existsSync19(dotGit)) return null;
|
|
165684
|
-
const
|
|
165685
|
-
if (
|
|
166212
|
+
const stat5 = statSync5(dotGit);
|
|
166213
|
+
if (stat5.isDirectory()) {
|
|
165686
166214
|
return dotGit;
|
|
165687
166215
|
}
|
|
165688
|
-
if (
|
|
166216
|
+
if (stat5.isFile()) {
|
|
165689
166217
|
try {
|
|
165690
166218
|
const content = readFileSync13(dotGit, "utf-8").trim();
|
|
165691
166219
|
const match2 = content.match(/^gitdir:\s*(.+)$/);
|
|
@@ -166096,7 +166624,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
166096
166624
|
};
|
|
166097
166625
|
const server = existingServer ?? new McpServer({
|
|
166098
166626
|
name: "memorix",
|
|
166099
|
-
version: true ? "1.6.
|
|
166627
|
+
version: true ? "1.6.2" : "1.0.1"
|
|
166100
166628
|
});
|
|
166101
166629
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
166102
166630
|
server.registerTool = ((name, ...args) => {
|
|
@@ -170502,7 +171030,7 @@ var init_serve_shared = __esm({
|
|
|
170502
171030
|
|
|
170503
171031
|
// src/cli/version.ts
|
|
170504
171032
|
function getCliVersion() {
|
|
170505
|
-
return true ? "1.6.
|
|
171033
|
+
return true ? "1.6.2" : pkg.version;
|
|
170506
171034
|
}
|
|
170507
171035
|
var init_version3 = __esm({
|
|
170508
171036
|
"src/cli/version.ts"() {
|