@memorax/memorax-code 0.1.7 → 0.1.8
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/README.md +36 -5
- package/bin/memorax-code-setup.mjs +0 -3
- package/docs/configuration.md +1 -3
- package/docs/troubleshooting.md +9 -8
- package/lib/memorax-code-backend/dist/app/backend-server.js +2 -29
- package/lib/memorax-code-backend/dist/app/memory-observability.js +1 -4
- package/lib/memorax-code-backend/dist/app/state.js +1 -12
- package/lib/memorax-code-backend/dist/clients/claude/transcript-turn.js +0 -182
- package/lib/memorax-code-backend/dist/clients/opencode/message-turn.js +68 -2
- package/lib/memorax-code-backend/dist/lifecycle/backend/service.js +0 -5
- package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +1 -14
- package/lib/memorax-code-backend/dist/memory/automatic-writeback.js +8 -5
- package/lib/memorax-code-backend/dist/memory/project.js +4 -26
- package/lib/memorax-code-backend/dist/memory/quota-notice.js +79 -19
- package/lib/memorax-code-backend/dist/provider/memorax/adapter.js +1 -4
- package/lib/memorax-code-backend/dist/provider/memorax/http.js +0 -28
- package/lib/memorax-code-backend/dist/transport/http/request.js +1 -39
- package/lib/memorax-code-backend/package.json +2 -3
- package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +0 -6
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +1 -1
- package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +0 -6
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +1 -1
- package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +1 -1
- package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
- package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
- package/lib/memorax-code-codex-adapter/package.json +1 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/SKILL.md +0 -6
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +1 -1
- package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +1 -1
- package/lib/memorax-code-dsh-adapter/package.json +1 -1
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/SKILL.md +0 -6
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +1 -1
- package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +1 -1
- package/lib/memorax-code-opencode-adapter/package.json +1 -1
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/SKILL.md +0 -6
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +1 -1
- package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +1 -1
- package/lib/memorax-code-opencode-adapter/src/plugin.mjs +121 -16
- package/lib/memorax-code-opencode-adapter/src/repo-memory-server-runner.mjs +2 -0
- package/package.json +1 -1
- package/lib/memorax-code-backend/dist/clients/codex/effective-prompt.js +0 -54
- package/lib/memorax-code-backend/dist/memory/writeback-reconciler.js +0 -244
- package/lib/memorax-code-backend/dist/memory/writeback-task-projection.js +0 -377
- package/lib/memorax-code-backend/dist/repository/readiness.js +0 -188
- package/lib/memorax-code-backend/dist/shared/incremental-jsonl-projection.js +0 -271
- package/lib/memorax-code-backend/dist/viewer/history/claude-transcript.js +0 -648
- package/lib/memorax-code-backend/dist/viewer/history/session-title.js +0 -93
- package/lib/memorax-code-backend/dist/viewer/http/public-routes.js +0 -146
- package/lib/memorax-code-backend/dist/viewer/model.js +0 -1
- package/lib/memorax-code-backend/dist/viewer/projection/activity.js +0 -113
- package/lib/memorax-code-backend/dist/viewer/projection/cache.js +0 -69
- package/lib/memorax-code-backend/dist/viewer/projection/event-identity.js +0 -3
- package/lib/memorax-code-backend/dist/viewer/projection/history.js +0 -79
- package/lib/memorax-code-backend/dist/viewer/projection/observability.js +0 -8
- package/lib/memorax-code-backend/dist/viewer/projection/redaction.js +0 -52
- package/lib/memorax-code-backend/dist/viewer/projection/turn-reference.js +0 -12
- package/lib/memorax-code-backend/dist/viewer/projection/user.js +0 -168
- package/lib/memorax-code-backend/dist/viewer/projection/writeback-status.js +0 -97
- package/lib/memorax-code-backend/dist/viewer/store.js +0 -991
- package/lib/memorax-code-backend/dist/viewer/ui/icon.js +0 -1
- package/lib/memorax-code-backend/dist/viewer/ui/logo.js +0 -1
- package/lib/memorax-code-backend/dist/viewer/ui/user-html.js +0 -117
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { open, readFile, readdir, stat } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
const projections = new Map();
|
|
5
|
-
const HASH_CHUNK_BYTES = 64 * 1024;
|
|
6
|
-
export async function readIncrementalJsonlProjection(options) {
|
|
7
|
-
return (await readIncrementalJsonlProjectionSnapshot(options)).values;
|
|
8
|
-
}
|
|
9
|
-
export async function readIncrementalJsonlProjectionSnapshot(options) {
|
|
10
|
-
const projectionKey = options.namespace
|
|
11
|
-
? `${options.namespace}\u0000${options.root}\u0000${options.filename}`
|
|
12
|
-
: `${options.root}\u0000${options.filename}`;
|
|
13
|
-
let projection = projections.get(projectionKey);
|
|
14
|
-
if (projection && projection.identity !== options.identity)
|
|
15
|
-
projection = undefined;
|
|
16
|
-
if (!projection) {
|
|
17
|
-
projection = { identity: options.identity, files: new Map(), values: [] };
|
|
18
|
-
projections.set(projectionKey, projection);
|
|
19
|
-
}
|
|
20
|
-
if (projection.refresh)
|
|
21
|
-
return projection.refresh;
|
|
22
|
-
const refresh = refreshProjection(projection, options);
|
|
23
|
-
projection.refresh = refresh;
|
|
24
|
-
try {
|
|
25
|
-
return await refresh;
|
|
26
|
-
}
|
|
27
|
-
finally {
|
|
28
|
-
if (projection.refresh === refresh)
|
|
29
|
-
projection.refresh = undefined;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export function clearIncrementalJsonlProjections() {
|
|
33
|
-
projections.clear();
|
|
34
|
-
}
|
|
35
|
-
async function refreshProjection(projection, options) {
|
|
36
|
-
let directories;
|
|
37
|
-
try {
|
|
38
|
-
directories = (await readdir(options.root, { withFileTypes: true }))
|
|
39
|
-
.filter((entry) => entry.isDirectory())
|
|
40
|
-
.map((entry) => entry.name);
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
if (projection.files.size > 0 || projection.values.length > 0) {
|
|
44
|
-
projection.files.clear();
|
|
45
|
-
projection.values = [];
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
values: projection.values,
|
|
49
|
-
complete: error.code === "ENOENT",
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
const activeDirectories = new Set(directories);
|
|
53
|
-
let rebuild = false;
|
|
54
|
-
let complete = true;
|
|
55
|
-
for (const cachedDirectory of projection.files.keys()) {
|
|
56
|
-
if (activeDirectories.has(cachedDirectory))
|
|
57
|
-
continue;
|
|
58
|
-
projection.files.delete(cachedDirectory);
|
|
59
|
-
rebuild = true;
|
|
60
|
-
}
|
|
61
|
-
if (options.refreshEntry) {
|
|
62
|
-
for (const file of projection.files.values()) {
|
|
63
|
-
const retryEntries = [];
|
|
64
|
-
for (const entry of file.retryEntries) {
|
|
65
|
-
if (options.refreshEntry(entry))
|
|
66
|
-
rebuild = true;
|
|
67
|
-
if (entry.retryKey)
|
|
68
|
-
retryEntries.push(entry);
|
|
69
|
-
}
|
|
70
|
-
file.retryEntries = retryEntries;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const appended = [];
|
|
74
|
-
for (const directory of directories) {
|
|
75
|
-
const path = join(options.root, directory, options.filename);
|
|
76
|
-
const cached = projection.files.get(directory);
|
|
77
|
-
let metadata;
|
|
78
|
-
try {
|
|
79
|
-
metadata = await stat(path);
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
const missing = error.code === "ENOENT";
|
|
83
|
-
if (cached && missing) {
|
|
84
|
-
projection.files.delete(directory);
|
|
85
|
-
rebuild = true;
|
|
86
|
-
}
|
|
87
|
-
if (!missing)
|
|
88
|
-
complete = false;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (!metadata.isFile()) {
|
|
92
|
-
complete = false;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
if (cached
|
|
96
|
-
&& metadata.size === cached.byteLength
|
|
97
|
-
&& metadata.mtimeMs === cached.modifiedAtMs
|
|
98
|
-
&& metadata.ctimeMs === cached.changedAtMs
|
|
99
|
-
&& metadata.ino === cached.inode) {
|
|
100
|
-
if (!cached.complete)
|
|
101
|
-
complete = false;
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
let buffer;
|
|
105
|
-
let verifiedPrefixHash;
|
|
106
|
-
let rangeStart;
|
|
107
|
-
let appendOnly = false;
|
|
108
|
-
try {
|
|
109
|
-
if (cached && metadata.ino === cached.inode && metadata.size > cached.byteLength) {
|
|
110
|
-
verifiedPrefixHash = await hashFilePrefix(path, cached.byteLength);
|
|
111
|
-
appendOnly = verifiedPrefixHash.copy().digest("hex") === cached.contentHash;
|
|
112
|
-
if (appendOnly) {
|
|
113
|
-
buffer = await readFileRange(path, cached.byteLength, metadata.size);
|
|
114
|
-
rangeStart = cached.byteLength;
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
buffer = await readFile(path);
|
|
118
|
-
rangeStart = 0;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
buffer = await readFile(path);
|
|
123
|
-
rangeStart = 0;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
complete = false;
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
const parsed = parseJsonlChunk(buffer, directory, options.project);
|
|
131
|
-
const readComplete = buffer.length === metadata.size - rangeStart;
|
|
132
|
-
const consumedComplete = (appendOnly ? cached.consumedComplete : true)
|
|
133
|
-
&& parsed.consumedComplete
|
|
134
|
-
&& readComplete;
|
|
135
|
-
const fileComplete = (appendOnly ? cached.consumedComplete : true)
|
|
136
|
-
&& parsed.complete
|
|
137
|
-
&& readComplete;
|
|
138
|
-
if (!fileComplete)
|
|
139
|
-
complete = false;
|
|
140
|
-
const entries = appendOnly ? [...cached.entries, ...parsed.entries] : parsed.entries;
|
|
141
|
-
const parsedRetryEntries = parsed.entries.filter((entry) => entry.retryKey);
|
|
142
|
-
const retryEntries = appendOnly
|
|
143
|
-
? [...cached.retryEntries, ...parsedRetryEntries]
|
|
144
|
-
: parsedRetryEntries;
|
|
145
|
-
const byteLength = rangeStart + parsed.consumedByteLength;
|
|
146
|
-
projection.files.set(directory, {
|
|
147
|
-
byteLength,
|
|
148
|
-
modifiedAtMs: metadata.mtimeMs,
|
|
149
|
-
changedAtMs: metadata.ctimeMs,
|
|
150
|
-
inode: metadata.ino,
|
|
151
|
-
contentHash: appendOnly
|
|
152
|
-
? verifiedPrefixHash.update(buffer.subarray(0, parsed.consumedByteLength)).digest("hex")
|
|
153
|
-
: hashBuffer(buffer.subarray(0, parsed.consumedByteLength)),
|
|
154
|
-
complete: fileComplete,
|
|
155
|
-
consumedComplete,
|
|
156
|
-
entries,
|
|
157
|
-
retryEntries,
|
|
158
|
-
});
|
|
159
|
-
if (appendOnly || !cached)
|
|
160
|
-
appended.push(...parsed.entries.map(({ value }) => value));
|
|
161
|
-
else
|
|
162
|
-
rebuild = true;
|
|
163
|
-
}
|
|
164
|
-
if (rebuild) {
|
|
165
|
-
projection.values = [...projection.files.values()]
|
|
166
|
-
.flatMap((file) => file.entries.map(({ value }) => value))
|
|
167
|
-
.sort(options.compare);
|
|
168
|
-
}
|
|
169
|
-
else if (appended.length > 0) {
|
|
170
|
-
const chronological = appended.sort(options.compare);
|
|
171
|
-
const last = projection.values.at(-1);
|
|
172
|
-
projection.values = !last || options.compare(last, chronological[0]) <= 0
|
|
173
|
-
? [...projection.values, ...chronological]
|
|
174
|
-
: [...projection.values, ...chronological].sort(options.compare);
|
|
175
|
-
}
|
|
176
|
-
return { values: projection.values, complete };
|
|
177
|
-
}
|
|
178
|
-
async function readFileRange(path, start, end) {
|
|
179
|
-
const handle = await open(path, "r");
|
|
180
|
-
try {
|
|
181
|
-
const buffer = Buffer.allocUnsafe(end - start);
|
|
182
|
-
let offset = 0;
|
|
183
|
-
while (offset < buffer.length) {
|
|
184
|
-
const { bytesRead } = await handle.read(buffer, offset, buffer.length - offset, start + offset);
|
|
185
|
-
if (bytesRead === 0)
|
|
186
|
-
break;
|
|
187
|
-
offset += bytesRead;
|
|
188
|
-
}
|
|
189
|
-
return buffer.subarray(0, offset);
|
|
190
|
-
}
|
|
191
|
-
finally {
|
|
192
|
-
await handle.close();
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function parseJsonlChunk(buffer, directory, project) {
|
|
196
|
-
const entries = [];
|
|
197
|
-
let consumedByteLength = 0;
|
|
198
|
-
let complete = true;
|
|
199
|
-
let consumedComplete = true;
|
|
200
|
-
let lineStart = 0;
|
|
201
|
-
while (lineStart < buffer.length) {
|
|
202
|
-
const newline = buffer.indexOf(0x0a, lineStart);
|
|
203
|
-
const lineComplete = newline !== -1;
|
|
204
|
-
const lineEnd = lineComplete ? newline : buffer.length;
|
|
205
|
-
const line = buffer.subarray(lineStart, lineEnd).toString("utf8");
|
|
206
|
-
if (lineComplete)
|
|
207
|
-
consumedByteLength = lineEnd + 1;
|
|
208
|
-
if (!line.trim()) {
|
|
209
|
-
if (!lineComplete)
|
|
210
|
-
consumedByteLength = buffer.length;
|
|
211
|
-
lineStart = lineEnd + 1;
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
let value;
|
|
215
|
-
try {
|
|
216
|
-
value = JSON.parse(line);
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
complete = false;
|
|
220
|
-
if (lineComplete)
|
|
221
|
-
consumedComplete = false;
|
|
222
|
-
if (!lineComplete)
|
|
223
|
-
break;
|
|
224
|
-
lineStart = lineEnd + 1;
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
if (!lineComplete)
|
|
228
|
-
consumedByteLength = buffer.length;
|
|
229
|
-
try {
|
|
230
|
-
const entry = project(value, directory);
|
|
231
|
-
if (entry)
|
|
232
|
-
entries.push(entry);
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
complete = false;
|
|
236
|
-
consumedComplete = false;
|
|
237
|
-
}
|
|
238
|
-
if (!lineComplete)
|
|
239
|
-
break;
|
|
240
|
-
lineStart = lineEnd + 1;
|
|
241
|
-
}
|
|
242
|
-
return {
|
|
243
|
-
entries,
|
|
244
|
-
consumedByteLength,
|
|
245
|
-
complete,
|
|
246
|
-
consumedComplete,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
async function hashFilePrefix(path, end) {
|
|
250
|
-
const handle = await open(path, "r");
|
|
251
|
-
const hash = createHash("sha256");
|
|
252
|
-
try {
|
|
253
|
-
const buffer = Buffer.allocUnsafe(Math.min(HASH_CHUNK_BYTES, end));
|
|
254
|
-
let position = 0;
|
|
255
|
-
while (position < end) {
|
|
256
|
-
const length = Math.min(buffer.length, end - position);
|
|
257
|
-
const { bytesRead } = await handle.read(buffer, 0, length, position);
|
|
258
|
-
if (bytesRead === 0)
|
|
259
|
-
break;
|
|
260
|
-
hash.update(buffer.subarray(0, bytesRead));
|
|
261
|
-
position += bytesRead;
|
|
262
|
-
}
|
|
263
|
-
return hash;
|
|
264
|
-
}
|
|
265
|
-
finally {
|
|
266
|
-
await handle.close();
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
function hashBuffer(buffer) {
|
|
270
|
-
return createHash("sha256").update(buffer).digest("hex");
|
|
271
|
-
}
|