memorix 1.3.3 → 1.3.4
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 +14 -0
- package/dist/cli/index.js +1162 -1098
- package/dist/index.d.ts +513 -0
- package/dist/index.js +14751 -14044
- package/dist/maintenance-runner.js +105 -52
- package/dist/media-video-runner.js +105 -52
- package/dist/memcode-runtime/CHANGELOG.md +14 -0
- package/dist/sdk.d.ts +5 -513
- package/dist/sdk.js +186 -75
- package/dist/vector-backfill-runner.js +105 -52
- package/docs/AGENT_OPERATOR_PLAYBOOK.md +4 -3
- package/package.json +1 -1
- package/plugins/claude/memorix/.claude-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/media.ts +10 -2
- package/src/cli/commands/serve-http.ts +7 -38
- package/src/cli/commands/serve-shared.ts +18 -46
- package/src/cli/commands/serve.ts +3 -41
- package/src/cli/commands/setup.ts +24 -21
- package/src/cli/mcp-root-path.ts +36 -0
- package/src/index.ts +37 -55
- package/src/media/asset-store.ts +74 -6
- package/src/media/attachment.ts +12 -9
- package/src/media/media-store.ts +38 -4
- package/src/media/video-jobs.ts +39 -14
- package/src/memory/observations.ts +21 -2
- package/src/orchestrate/adapters/spawn-helper.ts +2 -0
- package/src/server/tool-profile.ts +7 -4
- package/src/server.ts +6 -2
|
@@ -3065,8 +3065,8 @@ async function acquireLock(lockPath) {
|
|
|
3065
3065
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
3066
3066
|
if (code === "EEXIST" || code === "EPERM") {
|
|
3067
3067
|
try {
|
|
3068
|
-
const
|
|
3069
|
-
if (Date.now() -
|
|
3068
|
+
const stat4 = await fs3.stat(lockPath);
|
|
3069
|
+
if (Date.now() - stat4.mtimeMs > LOCK_STALE_MS) {
|
|
3070
3070
|
await fs3.unlink(lockPath).catch(() => {
|
|
3071
3071
|
});
|
|
3072
3072
|
continue;
|
|
@@ -7922,6 +7922,10 @@ var init_media_store = __esm({
|
|
|
7922
7922
|
`).run(projectId, assetId).changes ?? 0);
|
|
7923
7923
|
this.db.prepare("DELETE FROM media_derivations WHERE project_id = ? AND asset_id = ?").run(projectId, assetId);
|
|
7924
7924
|
this.db.prepare("DELETE FROM media_embeddings WHERE project_id = ? AND asset_id = ?").run(projectId, assetId);
|
|
7925
|
+
this.db.prepare(`
|
|
7926
|
+
UPDATE media_jobs SET asset_id = NULL, updated_at = ?
|
|
7927
|
+
WHERE project_id = ? AND asset_id = ?
|
|
7928
|
+
`).run(Date.now(), projectId, assetId);
|
|
7925
7929
|
const result = this.db.prepare(`
|
|
7926
7930
|
UPDATE media_assets SET deleted_at = ?, updated_at = ?
|
|
7927
7931
|
WHERE project_id = ? AND id = ? AND deleted_at IS NULL
|
|
@@ -8096,16 +8100,28 @@ var init_media_store = __esm({
|
|
|
8096
8100
|
return row ? rowToJob2(row) : void 0;
|
|
8097
8101
|
}
|
|
8098
8102
|
updateJob(projectId, id, input) {
|
|
8103
|
+
const updated = this.updateJobInternal(projectId, id, input, false);
|
|
8104
|
+
if (!updated) throw new Error(`Media job not found: ${id}`);
|
|
8105
|
+
return updated;
|
|
8106
|
+
}
|
|
8107
|
+
/**
|
|
8108
|
+
* Atomically preserve a user cancellation against a worker that was already
|
|
8109
|
+
* downloading or attaching media when the cancellation arrived.
|
|
8110
|
+
*/
|
|
8111
|
+
updateJobIfNotCancelled(projectId, id, input) {
|
|
8112
|
+
return this.updateJobInternal(projectId, id, input, true);
|
|
8113
|
+
}
|
|
8114
|
+
updateJobInternal(projectId, id, input, rejectCancelled) {
|
|
8099
8115
|
const existing = this.getJob(projectId, id);
|
|
8100
|
-
if (!existing)
|
|
8116
|
+
if (!existing) return void 0;
|
|
8101
8117
|
const now3 = Date.now();
|
|
8102
8118
|
const attempts = existing.attempts + (input.incrementAttempts ? 1 : 0);
|
|
8103
8119
|
const completedAt = input.status === "completed" ? now3 : null;
|
|
8104
|
-
this.db.prepare(`
|
|
8120
|
+
const result = this.db.prepare(`
|
|
8105
8121
|
UPDATE media_jobs
|
|
8106
8122
|
SET status = ?, provider_task_id = COALESCE(?, provider_task_id), asset_id = COALESCE(?, asset_id),
|
|
8107
8123
|
last_error = ?, attempts = ?, updated_at = ?, completed_at = ?
|
|
8108
|
-
WHERE project_id = ? AND id = ?
|
|
8124
|
+
WHERE project_id = ? AND id = ? ${rejectCancelled ? "AND status <> 'cancelled'" : ""}
|
|
8109
8125
|
`).run(
|
|
8110
8126
|
input.status,
|
|
8111
8127
|
input.providerTaskId ?? null,
|
|
@@ -8117,6 +8133,7 @@ var init_media_store = __esm({
|
|
|
8117
8133
|
projectId,
|
|
8118
8134
|
id
|
|
8119
8135
|
);
|
|
8136
|
+
if (Number(result.changes ?? 0) !== 1) return void 0;
|
|
8120
8137
|
return this.getJob(projectId, id);
|
|
8121
8138
|
}
|
|
8122
8139
|
cancelJob(projectId, id) {
|
|
@@ -8162,6 +8179,7 @@ async function attachMediaAssetToObservation(input) {
|
|
|
8162
8179
|
`MIME type: ${asset.mimeType}`,
|
|
8163
8180
|
...input.facts ?? []
|
|
8164
8181
|
];
|
|
8182
|
+
const store = new MediaStore(input.dataDir);
|
|
8165
8183
|
const result = await storeObservation({
|
|
8166
8184
|
entityName: input.entityName?.trim() || sourceLabel2.replace(/\.[^.]+$/, "") || "media-asset",
|
|
8167
8185
|
type: "discovery",
|
|
@@ -8174,13 +8192,15 @@ async function attachMediaAssetToObservation(input) {
|
|
|
8174
8192
|
sourceDetail: "explicit",
|
|
8175
8193
|
...input.visibility ? { visibility: input.visibility } : {},
|
|
8176
8194
|
...input.createdByAgentId ? { createdByAgentId: input.createdByAgentId } : {},
|
|
8177
|
-
...input.visibilityReader ? { visibilityReader: input.visibilityReader } : {}
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8195
|
+
...input.visibilityReader ? { visibilityReader: input.visibilityReader } : {},
|
|
8196
|
+
onPersisted: (observation) => {
|
|
8197
|
+
store.linkAsset({
|
|
8198
|
+
projectId: input.projectId,
|
|
8199
|
+
assetId: asset.id,
|
|
8200
|
+
observationId: observation.id,
|
|
8201
|
+
role: input.role ?? "attachment"
|
|
8202
|
+
});
|
|
8203
|
+
}
|
|
8184
8204
|
});
|
|
8185
8205
|
return result.observation;
|
|
8186
8206
|
}
|
|
@@ -8206,7 +8226,7 @@ var init_types2 = __esm({
|
|
|
8206
8226
|
|
|
8207
8227
|
// src/media/asset-store.ts
|
|
8208
8228
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
8209
|
-
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, rename, rm, writeFile as writeFile3 } from "fs/promises";
|
|
8229
|
+
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename, rm, stat, writeFile as writeFile3 } from "fs/promises";
|
|
8210
8230
|
import path10 from "path";
|
|
8211
8231
|
function mediaRoot(dataDir) {
|
|
8212
8232
|
return path10.resolve(dataDir, "media");
|
|
@@ -59319,7 +59339,7 @@ var require_node_domexception = __commonJS({
|
|
|
59319
59339
|
// node_modules/fetch-blob/from.js
|
|
59320
59340
|
import { statSync as statSync2, createReadStream, promises as fs7 } from "fs";
|
|
59321
59341
|
import { basename } from "path";
|
|
59322
|
-
var import_node_domexception,
|
|
59342
|
+
var import_node_domexception, stat2, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
59323
59343
|
var init_from = __esm({
|
|
59324
59344
|
"node_modules/fetch-blob/from.js"() {
|
|
59325
59345
|
"use strict";
|
|
@@ -59327,23 +59347,23 @@ var init_from = __esm({
|
|
|
59327
59347
|
import_node_domexception = __toESM(require_node_domexception(), 1);
|
|
59328
59348
|
init_file();
|
|
59329
59349
|
init_fetch_blob();
|
|
59330
|
-
({ stat } = fs7);
|
|
59350
|
+
({ stat: stat2 } = fs7);
|
|
59331
59351
|
blobFromSync = (path19, type) => fromBlob(statSync2(path19), path19, type);
|
|
59332
|
-
blobFrom = (path19, type) =>
|
|
59333
|
-
fileFrom = (path19, type) =>
|
|
59352
|
+
blobFrom = (path19, type) => stat2(path19).then((stat4) => fromBlob(stat4, path19, type));
|
|
59353
|
+
fileFrom = (path19, type) => stat2(path19).then((stat4) => fromFile(stat4, path19, type));
|
|
59334
59354
|
fileFromSync = (path19, type) => fromFile(statSync2(path19), path19, type);
|
|
59335
|
-
fromBlob = (
|
|
59355
|
+
fromBlob = (stat4, path19, type = "") => new fetch_blob_default([new BlobDataItem({
|
|
59336
59356
|
path: path19,
|
|
59337
|
-
size:
|
|
59338
|
-
lastModified:
|
|
59357
|
+
size: stat4.size,
|
|
59358
|
+
lastModified: stat4.mtimeMs,
|
|
59339
59359
|
start: 0
|
|
59340
59360
|
})], { type });
|
|
59341
|
-
fromFile = (
|
|
59361
|
+
fromFile = (stat4, path19, type = "") => new file_default([new BlobDataItem({
|
|
59342
59362
|
path: path19,
|
|
59343
|
-
size:
|
|
59344
|
-
lastModified:
|
|
59363
|
+
size: stat4.size,
|
|
59364
|
+
lastModified: stat4.mtimeMs,
|
|
59345
59365
|
start: 0
|
|
59346
|
-
})], basename(path19), { type, lastModified:
|
|
59366
|
+
})], basename(path19), { type, lastModified: stat4.mtimeMs });
|
|
59347
59367
|
BlobDataItem = class _BlobDataItem {
|
|
59348
59368
|
#path;
|
|
59349
59369
|
#start;
|
|
@@ -59366,7 +59386,7 @@ var init_from = __esm({
|
|
|
59366
59386
|
});
|
|
59367
59387
|
}
|
|
59368
59388
|
async *stream() {
|
|
59369
|
-
const { mtimeMs } = await
|
|
59389
|
+
const { mtimeMs } = await stat2(this.#path);
|
|
59370
59390
|
if (mtimeMs > this.lastModified) {
|
|
59371
59391
|
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");
|
|
59372
59392
|
}
|
|
@@ -141532,10 +141552,17 @@ function sourceLabel(request, providerTaskId) {
|
|
|
141532
141552
|
}
|
|
141533
141553
|
async function finishWithAsset(input) {
|
|
141534
141554
|
const { dataDir, projectId, store, mediaJob, request, providerTask, dependencies } = input;
|
|
141535
|
-
let
|
|
141555
|
+
let activeJob = store.getJob(projectId, mediaJob.id);
|
|
141556
|
+
if (!activeJob || terminal(activeJob)) return { action: "complete" };
|
|
141557
|
+
let asset = activeJob.assetId ? store.getAsset(projectId, activeJob.assetId) : void 0;
|
|
141536
141558
|
if (!asset) {
|
|
141537
141559
|
if (!providerTask.downloadUrl) throw new Error("Succeeded MiniMax video task did not include a download URL");
|
|
141538
|
-
store.
|
|
141560
|
+
const downloading = store.updateJobIfNotCancelled(projectId, activeJob.id, {
|
|
141561
|
+
status: "downloading",
|
|
141562
|
+
providerTaskId: providerTask.taskId
|
|
141563
|
+
});
|
|
141564
|
+
if (!downloading) return { action: "complete" };
|
|
141565
|
+
activeJob = downloading;
|
|
141539
141566
|
const bytes = await (dependencies.download ?? ((downloadInput) => downloadProviderMedia(downloadInput)))({
|
|
141540
141567
|
url: providerTask.downloadUrl,
|
|
141541
141568
|
maxBytes: request.maxBytes
|
|
@@ -141552,21 +141579,30 @@ async function finishWithAsset(input) {
|
|
|
141552
141579
|
maxBytes: request.maxBytes
|
|
141553
141580
|
});
|
|
141554
141581
|
asset = imported.asset;
|
|
141582
|
+
const persistedAsset = store.updateJobIfNotCancelled(projectId, activeJob.id, {
|
|
141583
|
+
status: "downloading",
|
|
141584
|
+
providerTaskId: providerTask.taskId,
|
|
141585
|
+
assetId: asset.id
|
|
141586
|
+
});
|
|
141587
|
+
if (!persistedAsset) return { action: "complete" };
|
|
141588
|
+
activeJob = persistedAsset;
|
|
141555
141589
|
}
|
|
141556
|
-
if (
|
|
141590
|
+
if (activeJob.attachOnComplete) {
|
|
141591
|
+
activeJob = store.getJob(projectId, activeJob.id);
|
|
141592
|
+
if (!activeJob || terminal(activeJob)) return { action: "complete" };
|
|
141557
141593
|
const hasAttachment = store.listLinks(projectId, asset.id).some((link) => link.role === "attachment" && link.observationId !== void 0);
|
|
141558
141594
|
if (!hasAttachment) {
|
|
141559
141595
|
await (dependencies.attach ?? attachMediaAssetToObservation)({
|
|
141560
141596
|
dataDir,
|
|
141561
141597
|
projectId,
|
|
141562
141598
|
asset,
|
|
141563
|
-
title:
|
|
141599
|
+
title: activeJob.observationTitle ?? `MiniMax video: ${asset.sourceLabel ?? asset.id}`,
|
|
141564
141600
|
narrative: `Generated with ${request.provider}/${request.model}. Prompt: ${request.prompt}`,
|
|
141565
141601
|
concepts: ["generated-video", "minimax", request.model]
|
|
141566
141602
|
});
|
|
141567
141603
|
}
|
|
141568
141604
|
}
|
|
141569
|
-
store.
|
|
141605
|
+
store.updateJobIfNotCancelled(projectId, activeJob.id, {
|
|
141570
141606
|
status: "completed",
|
|
141571
141607
|
providerTaskId: providerTask.taskId,
|
|
141572
141608
|
assetId: asset.id
|
|
@@ -141576,10 +141612,12 @@ async function finishWithAsset(input) {
|
|
|
141576
141612
|
function retryAfterProviderError(store, projectId, mediaJob, maintenanceJob, error) {
|
|
141577
141613
|
const message = safeError2(error);
|
|
141578
141614
|
if (maintenanceJob.attempts >= maintenanceJob.maxAttempts) {
|
|
141579
|
-
store.
|
|
141615
|
+
store.updateJobIfNotCancelled(projectId, mediaJob.id, { status: "failed", lastError: message, incrementAttempts: true });
|
|
141616
|
+
return { action: "complete" };
|
|
141617
|
+
}
|
|
141618
|
+
if (!store.updateJobIfNotCancelled(projectId, mediaJob.id, { status: "retry", lastError: message, incrementAttempts: true })) {
|
|
141580
141619
|
return { action: "complete" };
|
|
141581
141620
|
}
|
|
141582
|
-
store.updateJob(projectId, mediaJob.id, { status: "retry", lastError: message, incrementAttempts: true });
|
|
141583
141621
|
return { action: "reschedule", delayMs: MINI_MAX_VIDEO_POLL_MS, status: "retry", lastError: message };
|
|
141584
141622
|
}
|
|
141585
141623
|
function queueMiniMaxVideoGeneration(input) {
|
|
@@ -141620,22 +141658,25 @@ async function runMiniMaxVideoGenerationJob(maintenanceJob, context, dependencie
|
|
|
141620
141658
|
if (mediaJob.kind !== "minimax-video-generation") throw new Error(`Unsupported media job kind: ${mediaJob.kind}`);
|
|
141621
141659
|
const request = parseStoredRequest(mediaJob.request);
|
|
141622
141660
|
if (!mediaJob.providerTaskId) {
|
|
141623
|
-
store.
|
|
141661
|
+
if (!store.updateJobIfNotCancelled(context.projectId, mediaJob.id, { status: "submitting", incrementAttempts: true })) {
|
|
141662
|
+
return { action: "complete" };
|
|
141663
|
+
}
|
|
141624
141664
|
let submitted;
|
|
141625
141665
|
try {
|
|
141626
141666
|
submitted = await (dependencies.createTask ?? createMiniMaxVideoTask)(toVideoRequest(request));
|
|
141627
141667
|
} catch (error) {
|
|
141628
|
-
store.
|
|
141668
|
+
store.updateJobIfNotCancelled(context.projectId, mediaJob.id, { status: "failed", lastError: safeError2(error) });
|
|
141629
141669
|
return { action: "complete" };
|
|
141630
141670
|
}
|
|
141631
141671
|
if (submitted.status === "failed") {
|
|
141632
|
-
store.
|
|
141672
|
+
store.updateJobIfNotCancelled(context.projectId, mediaJob.id, { status: "failed", providerTaskId: submitted.taskId, lastError: submitted.error });
|
|
141633
141673
|
return { action: "complete" };
|
|
141634
141674
|
}
|
|
141635
|
-
const pending = store.
|
|
141675
|
+
const pending = store.updateJobIfNotCancelled(context.projectId, mediaJob.id, {
|
|
141636
141676
|
status: submitted.status === "succeeded" ? "downloading" : "provider-pending",
|
|
141637
141677
|
providerTaskId: submitted.taskId
|
|
141638
141678
|
});
|
|
141679
|
+
if (!pending) return { action: "complete" };
|
|
141639
141680
|
if (submitted.status === "succeeded") {
|
|
141640
141681
|
try {
|
|
141641
141682
|
return await finishWithAsset({
|
|
@@ -141663,11 +141704,13 @@ async function runMiniMaxVideoGenerationJob(maintenanceJob, context, dependencie
|
|
|
141663
141704
|
return retryAfterProviderError(store, context.projectId, mediaJob, maintenanceJob, error);
|
|
141664
141705
|
}
|
|
141665
141706
|
if (task.status === "pending") {
|
|
141666
|
-
store.
|
|
141707
|
+
if (!store.updateJobIfNotCancelled(context.projectId, mediaJob.id, { status: "provider-pending", providerTaskId: task.taskId })) {
|
|
141708
|
+
return { action: "complete" };
|
|
141709
|
+
}
|
|
141667
141710
|
return { action: "reschedule", delayMs: MINI_MAX_VIDEO_POLL_MS, resetAttempts: true, clearLastError: true };
|
|
141668
141711
|
}
|
|
141669
141712
|
if (task.status === "failed") {
|
|
141670
|
-
store.
|
|
141713
|
+
store.updateJobIfNotCancelled(context.projectId, mediaJob.id, { status: "failed", providerTaskId: task.taskId, lastError: task.error, incrementAttempts: true });
|
|
141671
141714
|
return { action: "complete" };
|
|
141672
141715
|
}
|
|
141673
141716
|
try {
|
|
@@ -142950,7 +142993,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
142950
142993
|
const rel = normalizeCodePath(relative(projectRoot, abs));
|
|
142951
142994
|
try {
|
|
142952
142995
|
const text = readFileSync6(abs, "utf-8");
|
|
142953
|
-
const
|
|
142996
|
+
const stat4 = fileStat ?? statSync3(abs);
|
|
142954
142997
|
const file = {
|
|
142955
142998
|
id: makeCodeFileId(projectId, rel),
|
|
142956
142999
|
projectId,
|
|
@@ -142959,8 +143002,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
142959
143002
|
contentHash: hashText(text),
|
|
142960
143003
|
// Preserve filesystem precision. Rounding here made same-size edits in
|
|
142961
143004
|
// a short Windows timestamp window indistinguishable to refresh.
|
|
142962
|
-
mtimeMs: Number(
|
|
142963
|
-
sizeBytes: Number(
|
|
143005
|
+
mtimeMs: Number(stat4.mtimeMs),
|
|
143006
|
+
sizeBytes: Number(stat4.size),
|
|
142964
143007
|
indexedAt
|
|
142965
143008
|
};
|
|
142966
143009
|
return {
|
|
@@ -142987,18 +143030,18 @@ async function indexProjectLite(options) {
|
|
|
142987
143030
|
let skippedOversizedFiles = 0;
|
|
142988
143031
|
let unreadableFiles = 0;
|
|
142989
143032
|
for (const abs of paths) {
|
|
142990
|
-
let
|
|
143033
|
+
let stat4;
|
|
142991
143034
|
try {
|
|
142992
|
-
|
|
143035
|
+
stat4 = statSync3(abs);
|
|
142993
143036
|
} catch {
|
|
142994
143037
|
unreadableFiles++;
|
|
142995
143038
|
continue;
|
|
142996
143039
|
}
|
|
142997
|
-
if (Number(
|
|
143040
|
+
if (Number(stat4.size) > maxFileBytes) {
|
|
142998
143041
|
skippedOversizedFiles++;
|
|
142999
143042
|
continue;
|
|
143000
143043
|
}
|
|
143001
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
143044
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat4);
|
|
143002
143045
|
if (!attempt.delta) {
|
|
143003
143046
|
if (attempt.unreadable) unreadableFiles++;
|
|
143004
143047
|
continue;
|
|
@@ -143026,16 +143069,16 @@ async function refreshProjectLite(store, options) {
|
|
|
143026
143069
|
for (const abs of paths) {
|
|
143027
143070
|
const rel = normalizeCodePath(relative(options.projectRoot, abs));
|
|
143028
143071
|
seenPaths.add(rel);
|
|
143029
|
-
let
|
|
143072
|
+
let stat4;
|
|
143030
143073
|
try {
|
|
143031
|
-
|
|
143074
|
+
stat4 = statSync3(abs);
|
|
143032
143075
|
} catch {
|
|
143033
143076
|
unreadableFiles++;
|
|
143034
143077
|
continue;
|
|
143035
143078
|
}
|
|
143036
143079
|
const existing = existingByPath.get(rel);
|
|
143037
|
-
const mtimeMs = Number(
|
|
143038
|
-
const sizeBytes = Number(
|
|
143080
|
+
const mtimeMs = Number(stat4.mtimeMs);
|
|
143081
|
+
const sizeBytes = Number(stat4.size);
|
|
143039
143082
|
if (sizeBytes > maxFileBytes) {
|
|
143040
143083
|
skippedOversizedFiles++;
|
|
143041
143084
|
if (existing) oversizedExistingFileIds.add(existing.id);
|
|
@@ -143045,7 +143088,7 @@ async function refreshProjectLite(store, options) {
|
|
|
143045
143088
|
unchangedFiles++;
|
|
143046
143089
|
continue;
|
|
143047
143090
|
}
|
|
143048
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
143091
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat4);
|
|
143049
143092
|
if (!attempt.delta) {
|
|
143050
143093
|
if (attempt.unreadable) unreadableFiles++;
|
|
143051
143094
|
continue;
|
|
@@ -146486,7 +146529,9 @@ async function storeObservation(input) {
|
|
|
146486
146529
|
if (input.visibilityReader && !canManageObservation(existing, input.visibilityReader)) {
|
|
146487
146530
|
throw new Error("Cannot update a memory outside this session's write scope.");
|
|
146488
146531
|
}
|
|
146489
|
-
|
|
146532
|
+
const observation2 = await upsertObservation(existing, input, now3);
|
|
146533
|
+
await input.onPersisted?.(observation2);
|
|
146534
|
+
return { observation: observation2, upserted: true };
|
|
146490
146535
|
}
|
|
146491
146536
|
}
|
|
146492
146537
|
const contentForExtraction = [input.title, input.narrative, ...input.facts ?? []].join(" ");
|
|
@@ -146511,6 +146556,7 @@ async function storeObservation(input) {
|
|
|
146511
146556
|
let doc;
|
|
146512
146557
|
let upsertedInsideLock = false;
|
|
146513
146558
|
let reloadCacheAfterCommit = false;
|
|
146559
|
+
let persistedCallbackInvoked = false;
|
|
146514
146560
|
const assignAndPersist = async () => {
|
|
146515
146561
|
if (projectDir) {
|
|
146516
146562
|
const store = getObservationStore();
|
|
@@ -146566,6 +146612,8 @@ async function storeObservation(input) {
|
|
|
146566
146612
|
writeGeneration: transactionGeneration + 1
|
|
146567
146613
|
};
|
|
146568
146614
|
await tx.insert(observation);
|
|
146615
|
+
await input.onPersisted?.(observation);
|
|
146616
|
+
persistedCallbackInvoked = true;
|
|
146569
146617
|
await tx.saveIdCounter(id + 1);
|
|
146570
146618
|
});
|
|
146571
146619
|
observation.writeGeneration = store.getGeneration();
|
|
@@ -146615,6 +146663,8 @@ async function storeObservation(input) {
|
|
|
146615
146663
|
writeGeneration: 0
|
|
146616
146664
|
};
|
|
146617
146665
|
observations.push(observation);
|
|
146666
|
+
await input.onPersisted?.(observation);
|
|
146667
|
+
persistedCallbackInvoked = true;
|
|
146618
146668
|
}
|
|
146619
146669
|
doc = {
|
|
146620
146670
|
id: makeOramaObservationId(input.projectId, observation.id),
|
|
@@ -146646,8 +146696,11 @@ async function storeObservation(input) {
|
|
|
146646
146696
|
};
|
|
146647
146697
|
await assignAndPersist();
|
|
146648
146698
|
if (upsertedInsideLock) {
|
|
146649
|
-
|
|
146699
|
+
const updated = await upsertObservation(observation, input, now3);
|
|
146700
|
+
await input.onPersisted?.(updated);
|
|
146701
|
+
return { observation: updated, upserted: true };
|
|
146650
146702
|
}
|
|
146703
|
+
if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
|
|
146651
146704
|
await bindObservationCodeRefsBestEffort(observation);
|
|
146652
146705
|
queueObservationQualification(observation);
|
|
146653
146706
|
if (resolveObservationVisibility(observation) === "project") {
|