@memorax/memorax-code 0.1.7 → 0.1.9

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.
Files changed (70) hide show
  1. package/README.md +36 -5
  2. package/bin/memorax-code-setup.mjs +0 -3
  3. package/docs/configuration.md +1 -3
  4. package/docs/troubleshooting.md +9 -8
  5. package/lib/memorax-code-backend/dist/app/backend-server.js +2 -29
  6. package/lib/memorax-code-backend/dist/app/memory-observability.js +1 -4
  7. package/lib/memorax-code-backend/dist/app/state.js +1 -12
  8. package/lib/memorax-code-backend/dist/clients/claude/transcript-turn.js +0 -182
  9. package/lib/memorax-code-backend/dist/clients/codex/rollout-turn.js +52 -2
  10. package/lib/memorax-code-backend/dist/clients/opencode/message-turn.js +68 -2
  11. package/lib/memorax-code-backend/dist/lifecycle/backend/service.js +0 -5
  12. package/lib/memorax-code-backend/dist/lifecycle/orchestrator.js +1 -14
  13. package/lib/memorax-code-backend/dist/memory/automatic-writeback.js +8 -5
  14. package/lib/memorax-code-backend/dist/memory/project.js +4 -26
  15. package/lib/memorax-code-backend/dist/memory/quota-notice.js +79 -19
  16. package/lib/memorax-code-backend/dist/provider/memorax/adapter.js +1 -4
  17. package/lib/memorax-code-backend/dist/provider/memorax/http.js +0 -28
  18. package/lib/memorax-code-backend/dist/transport/http/request.js +1 -39
  19. package/lib/memorax-code-backend/package.json +2 -3
  20. package/lib/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  21. package/lib/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  22. package/lib/memorax-code-claude-adapter/package.json +1 -1
  23. package/lib/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +0 -6
  24. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +1 -1
  25. package/lib/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +1 -1
  26. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/.claude-plugin/plugin.json +1 -1
  27. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/hooks/runtime-shell.json +1 -1
  28. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/package.json +1 -1
  29. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/SKILL.md +0 -6
  30. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-add.md +1 -1
  31. package/lib/memorax-code-claude-marketplace/plugins/memorax-code-claude-adapter/skills/memorax-code/references/memorax-search.md +1 -1
  32. package/lib/memorax-code-codex-adapter/.codex-plugin/plugin.json +1 -1
  33. package/lib/memorax-code-codex-adapter/hooks/runtime-shell.json +1 -1
  34. package/lib/memorax-code-codex-adapter/package.json +1 -1
  35. package/lib/memorax-code-codex-adapter/skills/memorax-code/SKILL.md +0 -6
  36. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-add.md +1 -1
  37. package/lib/memorax-code-codex-adapter/skills/memorax-code/references/memorax-search.md +1 -1
  38. package/lib/memorax-code-dsh-adapter/package.json +1 -1
  39. package/lib/memorax-code-dsh-adapter/skills/memorax-code/SKILL.md +0 -6
  40. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-add.md +1 -1
  41. package/lib/memorax-code-dsh-adapter/skills/memorax-code/references/memorax-search.md +1 -1
  42. package/lib/memorax-code-opencode-adapter/package.json +1 -1
  43. package/lib/memorax-code-opencode-adapter/skills/memorax-code/SKILL.md +0 -6
  44. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-add.md +1 -1
  45. package/lib/memorax-code-opencode-adapter/skills/memorax-code/references/memorax-search.md +1 -1
  46. package/lib/memorax-code-opencode-adapter/src/plugin.mjs +121 -16
  47. package/lib/memorax-code-opencode-adapter/src/repo-memory-server-runner.mjs +2 -0
  48. package/package.json +1 -1
  49. package/lib/memorax-code-backend/dist/clients/codex/effective-prompt.js +0 -54
  50. package/lib/memorax-code-backend/dist/memory/writeback-reconciler.js +0 -244
  51. package/lib/memorax-code-backend/dist/memory/writeback-task-projection.js +0 -377
  52. package/lib/memorax-code-backend/dist/repository/readiness.js +0 -188
  53. package/lib/memorax-code-backend/dist/shared/incremental-jsonl-projection.js +0 -271
  54. package/lib/memorax-code-backend/dist/viewer/history/claude-transcript.js +0 -648
  55. package/lib/memorax-code-backend/dist/viewer/history/session-title.js +0 -93
  56. package/lib/memorax-code-backend/dist/viewer/http/public-routes.js +0 -146
  57. package/lib/memorax-code-backend/dist/viewer/model.js +0 -1
  58. package/lib/memorax-code-backend/dist/viewer/projection/activity.js +0 -113
  59. package/lib/memorax-code-backend/dist/viewer/projection/cache.js +0 -69
  60. package/lib/memorax-code-backend/dist/viewer/projection/event-identity.js +0 -3
  61. package/lib/memorax-code-backend/dist/viewer/projection/history.js +0 -79
  62. package/lib/memorax-code-backend/dist/viewer/projection/observability.js +0 -8
  63. package/lib/memorax-code-backend/dist/viewer/projection/redaction.js +0 -52
  64. package/lib/memorax-code-backend/dist/viewer/projection/turn-reference.js +0 -12
  65. package/lib/memorax-code-backend/dist/viewer/projection/user.js +0 -168
  66. package/lib/memorax-code-backend/dist/viewer/projection/writeback-status.js +0 -97
  67. package/lib/memorax-code-backend/dist/viewer/store.js +0 -991
  68. package/lib/memorax-code-backend/dist/viewer/ui/icon.js +0 -1
  69. package/lib/memorax-code-backend/dist/viewer/ui/logo.js +0 -1
  70. package/lib/memorax-code-backend/dist/viewer/ui/user-html.js +0 -117
@@ -1,377 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { readIncrementalJsonlProjection, } from "../shared/incremental-jsonl-projection.js";
3
- import { memoryProjectFromUnknown, resolveMemoryProject, } from "./project.js";
4
- import { clientTracePaths } from "../trace/config.js";
5
- import { isTraceClient, } from "../trace/context.js";
6
- const LIVE_TASK_CAPACITY = 1_024;
7
- const PENDING_WRITEBACK_STATUSES = new Set([
8
- "accepted",
9
- "processing",
10
- "queued",
11
- "pending",
12
- "unknown",
13
- ]);
14
- export function createMemoryWritebackTaskProjection(options) {
15
- const client = options.client;
16
- const liveTasks = new Map();
17
- return {
18
- client,
19
- observabilityHook: {
20
- recordEvent(event) {
21
- const projected = projectLiveWritebackTask(event);
22
- if (!projected || projected.client !== client)
23
- return;
24
- liveTasks.set(memoryWritebackTaskEventKey(projected), projected);
25
- while (liveTasks.size > LIVE_TASK_CAPACITY) {
26
- const oldest = liveTasks.keys().next().value;
27
- if (typeof oldest !== "string")
28
- break;
29
- liveTasks.delete(oldest);
30
- }
31
- },
32
- },
33
- async listPending() {
34
- const historical = await readMemoryWritebackTaskHistory(options.memoraxCodeHome, client);
35
- const merged = new Map();
36
- for (const record of [...historical, ...liveTasks.values()]) {
37
- merged.set(memoryWritebackTaskEventKey(record), record);
38
- }
39
- return pendingMemoryWritebackTasks([...merged.values()].sort(compareMemoryWritebackTaskRecords)).filter((task) => (task.client === client && Boolean(task.sessionId)));
40
- },
41
- clear() {
42
- liveTasks.clear();
43
- },
44
- };
45
- }
46
- export function projectMemoryWritebackTasks(records) {
47
- const statusByOriginalEvent = new Map();
48
- const statusByTask = new Map();
49
- for (const record of records) {
50
- if (record.kind !== "status")
51
- continue;
52
- if (record.originalEventId) {
53
- statusByOriginalEvent.set(memoryWritebackTaskEventKey({
54
- ...record,
55
- eventId: record.originalEventId,
56
- }), record);
57
- }
58
- const key = writebackTaskKey(record);
59
- if (key)
60
- statusByTask.set(key, record);
61
- }
62
- return records.flatMap((record) => {
63
- if (record.kind !== "task")
64
- return [];
65
- const key = writebackTaskKey(record);
66
- const explicitStatus = statusByOriginalEvent.get(memoryWritebackTaskEventKey(record));
67
- const status = explicitStatus && (!explicitStatus.taskId || explicitStatus.taskId === record.taskId)
68
- ? explicitStatus
69
- : key
70
- ? statusByTask.get(key)
71
- : undefined;
72
- return [{
73
- eventId: record.eventId,
74
- timestamp: record.timestamp,
75
- ...(record.client ? { client: record.client } : {}),
76
- ...(record.sessionId ? { sessionId: record.sessionId } : {}),
77
- ...(record.turnId ? { turnId: record.turnId } : {}),
78
- ...(record.memoryProject ? { memoryProject: record.memoryProject } : {}),
79
- accepted: record.ok,
80
- taskId: record.taskId,
81
- completion: status?.completion ?? completeMemoryWritebackTask({
82
- status: record.status,
83
- }),
84
- ...(status ? { statusEventId: status.eventId } : {}),
85
- }];
86
- });
87
- }
88
- export function memoryWritebackTaskEventKey(recordValue) {
89
- return JSON.stringify([
90
- recordValue.client ?? "",
91
- recordValue.sessionId ?? "",
92
- recordValue.eventId,
93
- ]);
94
- }
95
- export function pendingMemoryWritebackTasks(records) {
96
- return projectMemoryWritebackTasks(records)
97
- .filter((task) => (task.accepted
98
- && task.completion.ok
99
- && task.completion.outcome === "pending"));
100
- }
101
- export function completeMemoryWritebackTask(input) {
102
- const status = input.status.trim().toLowerCase();
103
- const savedMemories = uniqueStrings([
104
- ...stringArray(input.savedMemories),
105
- ...memoryTexts(input.memory),
106
- ]);
107
- const savedMemoryIds = uniqueStrings([
108
- ...stringArray(input.savedMemoryIds),
109
- ...memoryAddIds(input.memory),
110
- ]);
111
- const reportedMemoryCount = nonNegativeInteger(input.savedMemoryCount)
112
- ?? memorySavedCount(input.memory);
113
- const savedMemoryCount = reportedMemoryCount
114
- ?? (savedMemoryIds.length > 0 ? savedMemoryIds.length : savedMemories.length);
115
- const outcome = memoryWritebackTaskOutcome(input.outcome)
116
- ?? memoryWritebackTaskOutcomeForStatus(status, {
117
- memoryKnown: input.memoryKnown === true,
118
- savedMemoryCount,
119
- });
120
- return {
121
- status,
122
- outcome,
123
- ok: outcome !== "failed",
124
- ...(savedMemoryCount > 0 ? { savedMemoryCount } : {}),
125
- ...(savedMemoryIds.length > 0 ? { savedMemoryIds } : {}),
126
- ...(savedMemories.length > 0 ? { savedMemories } : {}),
127
- ...(input.error ? { error: input.error.slice(0, 2_000) } : {}),
128
- };
129
- }
130
- export function memoryWritebackTaskOutcome(value) {
131
- return value === "pending"
132
- || value === "saved"
133
- || value === "skipped"
134
- || value === "failed"
135
- || value === "completed"
136
- ? value
137
- : undefined;
138
- }
139
- export function memoryWritebackTaskOutcomeForStatus(status, result = {}) {
140
- const normalized = status.trim().toLowerCase();
141
- if (PENDING_WRITEBACK_STATUSES.has(normalized))
142
- return "pending";
143
- if (["failed", "error", "cancelled", "canceled"].includes(normalized))
144
- return "failed";
145
- if (normalized === "success" || normalized === "completed") {
146
- if ((result.savedMemoryCount ?? 0) > 0)
147
- return "saved";
148
- if (result.memoryKnown)
149
- return "skipped";
150
- return "completed";
151
- }
152
- return "completed";
153
- }
154
- export function memoryText(value) {
155
- const item = record(value);
156
- if (!item)
157
- return "";
158
- for (const key of ["memory", "summary", "content", "text"]) {
159
- const text = stringValue(item[key]);
160
- if (text)
161
- return text;
162
- }
163
- return "";
164
- }
165
- export function stringArray(value) {
166
- return Array.isArray(value)
167
- ? value.map(stringValue).filter(Boolean).slice(0, 1_000)
168
- : [];
169
- }
170
- export function nonNegativeInteger(value) {
171
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0
172
- ? value
173
- : undefined;
174
- }
175
- async function readMemoryWritebackTaskHistory(memoraxCodeHome, client) {
176
- return await readIncrementalJsonlProjection({
177
- namespace: `memory-writeback-task:${client}`,
178
- root: clientTracePaths(client, memoraxCodeHome).sessionsRoot,
179
- filename: "events.jsonl",
180
- identity: client,
181
- project(value, sessionDir) {
182
- const projected = projectTraceWritebackTask(value, sessionDir, client);
183
- return projected ? { value: projected } : undefined;
184
- },
185
- compare: compareMemoryWritebackTaskRecords,
186
- });
187
- }
188
- function projectLiveWritebackTask(event) {
189
- if (event.operation !== "writeback")
190
- return undefined;
191
- const state = writebackState(event.response);
192
- if (!state.taskId || !state.status)
193
- return undefined;
194
- const context = event.traceContext;
195
- return {
196
- kind: "task",
197
- eventId: event.eventId ?? `memory-observability-${randomUUID()}`,
198
- timestamp: new Date().toISOString(),
199
- ...(context?.client ? { client: context.client } : {}),
200
- ...(safeIdentifier(context?.sessionId) ? { sessionId: safeIdentifier(context?.sessionId) } : {}),
201
- ...(safeIdentifier(context?.turnId) ? { turnId: safeIdentifier(context?.turnId) } : {}),
202
- ...(context?.memoryProject ? { memoryProject: context.memoryProject } : {}),
203
- ok: event.ok,
204
- taskId: state.taskId,
205
- status: state.status,
206
- };
207
- }
208
- function projectTraceWritebackTask(value, sessionDir, expectedClient) {
209
- const raw = record(value);
210
- if (!raw)
211
- return undefined;
212
- const type = stringValue(raw.type);
213
- if (type !== "memory_writeback"
214
- && type !== "memory_cli_add"
215
- && type !== "memory_writeback_status") {
216
- return undefined;
217
- }
218
- const trace = record(raw.trace);
219
- const rawClient = stringValue(trace?.client);
220
- const client = isTraceClient(rawClient) ? rawClient : undefined;
221
- if (client !== expectedClient)
222
- return undefined;
223
- const sessionId = safeIdentifier(stringValue(trace?.session_id)
224
- || stringValue(trace?.sessionId)
225
- || sessionDir);
226
- const turnId = safeIdentifier(stringValue(trace?.turn_id) || stringValue(trace?.turnId));
227
- const request = record(raw.request);
228
- const memoryProject = memoryProjectFromUnknown(trace?.memory_project)
229
- ?? memoryProjectFromUnknown(trace?.memoryProject)
230
- ?? resolveMemoryProject(stringValue(trace?.cwd) || stringValue(request?.cwd));
231
- const timestamp = validTimestamp(raw.timestamp);
232
- const eventId = stringValue(raw.event_id)
233
- || `${sessionId || "unscoped"}:${type}:${timestamp}`;
234
- const response = record(raw.response);
235
- const state = writebackState(response);
236
- if (type === "memory_writeback_status") {
237
- const taskId = stringValue(request?.task_id)
238
- || stringValue(request?.taskId)
239
- || state.taskId;
240
- const status = state.status;
241
- if (!status)
242
- return undefined;
243
- const originalEventId = stringValue(request?.original_event_id ?? request?.originalEventId);
244
- if (!originalEventId && (!taskId || !sessionId))
245
- return undefined;
246
- return {
247
- kind: "status",
248
- eventId,
249
- timestamp,
250
- client,
251
- ...(sessionId ? { sessionId } : {}),
252
- ...(turnId ? { turnId } : {}),
253
- ...(memoryProject ? { memoryProject } : {}),
254
- ...(taskId ? { taskId } : {}),
255
- ...(originalEventId ? { originalEventId } : {}),
256
- completion: completeMemoryWritebackTask({
257
- status,
258
- outcome: response?.outcome,
259
- savedMemoryCount: response?.savedMemoryCount ?? response?.saved_memory_count,
260
- savedMemoryIds: response?.savedMemoryIds ?? response?.saved_memory_ids,
261
- savedMemories: response?.savedMemories ?? response?.saved_memories,
262
- error: stringValue(raw.error) || null,
263
- }),
264
- };
265
- }
266
- if (!state.taskId || !state.status)
267
- return undefined;
268
- return {
269
- kind: "task",
270
- eventId,
271
- timestamp,
272
- client,
273
- ...(sessionId ? { sessionId } : {}),
274
- ...(turnId ? { turnId } : {}),
275
- ...(memoryProject ? { memoryProject } : {}),
276
- ok: raw.ok !== false,
277
- taskId: state.taskId,
278
- status: state.status,
279
- };
280
- }
281
- function writebackState(value) {
282
- const response = record(value);
283
- const raw = record(response?.raw) ?? response;
284
- const data = record(raw?.data);
285
- return {
286
- taskId: stringValue(data?.task_id)
287
- || stringValue(response?.taskId)
288
- || stringValue(response?.task_id),
289
- status: (stringValue(data?.status)
290
- || stringValue(response?.status)
291
- || stringValue(response?.addStatus)).toLowerCase(),
292
- };
293
- }
294
- function writebackTaskKey(recordValue) {
295
- return recordValue.sessionId && recordValue.taskId
296
- ? JSON.stringify([recordValue.client ?? "", recordValue.sessionId, recordValue.taskId])
297
- : undefined;
298
- }
299
- function compareMemoryWritebackTaskRecords(left, right) {
300
- const leftTime = Date.parse(left.timestamp);
301
- const rightTime = Date.parse(right.timestamp);
302
- const leftOrder = Number.isFinite(leftTime) ? leftTime : 0;
303
- const rightOrder = Number.isFinite(rightTime) ? rightTime : 0;
304
- return leftOrder - rightOrder || left.eventId.localeCompare(right.eventId);
305
- }
306
- function validTimestamp(value) {
307
- const timestamp = stringValue(value);
308
- return timestamp && Number.isFinite(Date.parse(timestamp))
309
- ? timestamp
310
- : new Date().toISOString();
311
- }
312
- function safeIdentifier(value) {
313
- const candidate = stringValue(value);
314
- if (!candidate || candidate.length > 512)
315
- return "";
316
- if (/[\u0000-\u001f\u007f\\/]/.test(candidate))
317
- return "";
318
- return candidate;
319
- }
320
- function memoryTexts(value) {
321
- const output = [];
322
- const visit = (item, depth) => {
323
- if (depth > 4)
324
- return;
325
- if (typeof item === "string") {
326
- const text = item.trim();
327
- if (text)
328
- output.push(text);
329
- return;
330
- }
331
- if (Array.isArray(item)) {
332
- for (const entry of item)
333
- visit(entry, depth + 1);
334
- return;
335
- }
336
- const wrapped = record(item);
337
- if (!wrapped)
338
- return;
339
- const text = memoryText(item);
340
- if (text)
341
- output.push(text);
342
- for (const key of ["items", "memories", "facts", "samples"]) {
343
- visit(wrapped[key], depth + 1);
344
- }
345
- };
346
- visit(value, 0);
347
- return uniqueStrings(output);
348
- }
349
- function memorySavedCount(value) {
350
- const wrapped = record(value);
351
- if (!wrapped)
352
- return undefined;
353
- const total = nonNegativeInteger(wrapped.total);
354
- if (total !== undefined)
355
- return total;
356
- return nonNegativeInteger(record(wrapped.operations)?.ADD);
357
- }
358
- function memoryAddIds(value) {
359
- const wrapped = record(value);
360
- const events = Array.isArray(wrapped?.events) ? wrapped.events : [];
361
- return uniqueStrings(events
362
- .map(record)
363
- .filter((event) => stringValue(event?.event).toUpperCase() === "ADD")
364
- .map((event) => stringValue(event?.memory_id) || stringValue(event?.id))
365
- .filter(Boolean));
366
- }
367
- function uniqueStrings(values) {
368
- return [...new Set(values)];
369
- }
370
- function record(value) {
371
- return value && typeof value === "object" && !Array.isArray(value)
372
- ? value
373
- : undefined;
374
- }
375
- function stringValue(value) {
376
- return typeof value === "string" ? value.trim() : "";
377
- }
@@ -1,188 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { constants } from "node:fs";
3
- import { access } from "node:fs/promises";
4
- import { fileURLToPath, pathToFileURL } from "node:url";
5
- import { promisify } from "node:util";
6
- import { memoryProjectRoot } from "../memory/project.js";
7
- const execFileAsync = promisify(execFile);
8
- const STABLE_READINESS_CACHE_TTL_MS = 30_000;
9
- const PREPARING_READINESS_CACHE_TTL_MS = 5_000;
10
- const UNRESOLVED_READINESS_CACHE_TTL_MS = 10_000;
11
- const READINESS_CACHE_CAPACITY = 256;
12
- export const REPO_MEMORY_READINESS_MAX_CONCURRENT_VALIDATIONS = 4;
13
- const readinessCache = new Map();
14
- const readinessInFlight = new Map();
15
- const dependencyScopes = new WeakMap();
16
- const validationWaiters = [];
17
- let nextDependencyScope = 1;
18
- let activeBundleValidations = 0;
19
- const DEFAULT_READINESS_DEPENDENCIES = Object.freeze({});
20
- export async function repoMemoryReadinessForProject(projectId, memoraxCodeHome, dependencies = DEFAULT_READINESS_DEPENDENCIES) {
21
- const cacheKey = readinessCacheKey(projectId, memoraxCodeHome, dependencies);
22
- const cached = readCachedReadiness(cacheKey);
23
- if (cached)
24
- return cached;
25
- const pending = readinessInFlight.get(cacheKey);
26
- if (pending)
27
- return pending;
28
- const request = resolveRepoMemoryReadiness(projectId, memoraxCodeHome, dependencies)
29
- .then((value) => {
30
- cacheReadiness(cacheKey, value);
31
- return value;
32
- })
33
- .finally(() => {
34
- if (readinessInFlight.get(cacheKey) === request)
35
- readinessInFlight.delete(cacheKey);
36
- });
37
- readinessInFlight.set(cacheKey, request);
38
- return request;
39
- }
40
- function readinessCacheKey(projectId, memoraxCodeHome, dependencies) {
41
- if (dependencies === DEFAULT_READINESS_DEPENDENCIES) {
42
- return `default\u0000${memoraxCodeHome}\u0000${projectId}`;
43
- }
44
- let scope = dependencyScopes.get(dependencies);
45
- if (scope === undefined) {
46
- scope = nextDependencyScope;
47
- nextDependencyScope += 1;
48
- dependencyScopes.set(dependencies, scope);
49
- }
50
- return `dependencies:${scope}\u0000${memoraxCodeHome}\u0000${projectId}`;
51
- }
52
- function readCachedReadiness(cacheKey) {
53
- const cached = readinessCache.get(cacheKey);
54
- if (!cached)
55
- return undefined;
56
- if (cached.expiresAt <= Date.now()) {
57
- readinessCache.delete(cacheKey);
58
- return undefined;
59
- }
60
- readinessCache.delete(cacheKey);
61
- readinessCache.set(cacheKey, cached);
62
- return cached.value;
63
- }
64
- function cacheReadiness(cacheKey, value) {
65
- const now = Date.now();
66
- for (const [key, cached] of readinessCache) {
67
- if (cached.expiresAt <= now)
68
- readinessCache.delete(key);
69
- }
70
- while (readinessCache.size >= READINESS_CACHE_CAPACITY) {
71
- const oldest = readinessCache.keys().next().value;
72
- if (typeof oldest !== "string")
73
- break;
74
- readinessCache.delete(oldest);
75
- }
76
- readinessCache.delete(cacheKey);
77
- readinessCache.set(cacheKey, { expiresAt: now + readinessCacheTtl(value), value });
78
- }
79
- function readinessCacheTtl(value) {
80
- if (value.status === "preparing")
81
- return PREPARING_READINESS_CACHE_TTL_MS;
82
- if (value.reason === "project_unresolved")
83
- return UNRESOLVED_READINESS_CACHE_TTL_MS;
84
- return STABLE_READINESS_CACHE_TTL_MS;
85
- }
86
- async function resolveRepoMemoryReadiness(projectId, memoraxCodeHome, dependencies) {
87
- const repoRoot = (dependencies.resolveProjectRoot ?? memoryProjectRoot)(projectId);
88
- if (!repoRoot)
89
- return { status: "unknown", reason: "project_unresolved" };
90
- try {
91
- const active = await (dependencies.readActiveJob ?? readActiveRepoMemoryJob)({
92
- memoraxCodeHome,
93
- repoRealpath: repoRoot,
94
- });
95
- if (active.active)
96
- return { status: "preparing", reason: "active_job" };
97
- }
98
- catch {
99
- // Bundle validation remains useful when the optional job marker cannot be read.
100
- }
101
- const validateBundle = dependencies.validateBundle ?? validateRepoMemoryBundle;
102
- const bundle = await withBundleValidationSlot(() => validateBundle(repoRoot));
103
- if (bundle === "usable")
104
- return { status: "ready", reason: "usable" };
105
- if (bundle === "missing")
106
- return { status: "not_ready", reason: "bundle_missing" };
107
- if (bundle === "invalid")
108
- return { status: "not_ready", reason: "bundle_invalid" };
109
- return { status: "unknown", reason: "validator_unavailable" };
110
- }
111
- async function withBundleValidationSlot(task) {
112
- await acquireBundleValidationSlot();
113
- try {
114
- return await task();
115
- }
116
- finally {
117
- releaseBundleValidationSlot();
118
- }
119
- }
120
- async function acquireBundleValidationSlot() {
121
- if (activeBundleValidations < REPO_MEMORY_READINESS_MAX_CONCURRENT_VALIDATIONS) {
122
- activeBundleValidations += 1;
123
- return;
124
- }
125
- await new Promise((resolve) => validationWaiters.push(resolve));
126
- }
127
- function releaseBundleValidationSlot() {
128
- const next = validationWaiters.shift();
129
- if (next) {
130
- // The released slot transfers directly to the oldest waiter.
131
- next();
132
- return;
133
- }
134
- activeBundleValidations -= 1;
135
- }
136
- async function readActiveRepoMemoryJob(input) {
137
- const moduleUrl = new URL("../../../memorax-code-adapter-common/src/repo-memory/repo-memory-job-marker.mjs", import.meta.url);
138
- const markerModule = await import(moduleUrl.href);
139
- if (typeof markerModule.readActiveRepoMemoryJobMarker !== "function") {
140
- throw new Error("repo memory job marker reader is unavailable");
141
- }
142
- return markerModule.readActiveRepoMemoryJobMarker(input);
143
- }
144
- async function validateRepoMemoryBundle(repoRoot) {
145
- const profileUrl = new URL(".repo_memory/PROFILE.md", pathToDirectoryUrl(repoRoot));
146
- try {
147
- await access(profileUrl, constants.R_OK);
148
- }
149
- catch {
150
- return "missing";
151
- }
152
- const validatorUrl = new URL("../../../memorax-code-codex-adapter/skills/memorax-code/scripts/validate_memory.py", import.meta.url);
153
- try {
154
- await access(validatorUrl, constants.R_OK);
155
- }
156
- catch {
157
- return "unknown";
158
- }
159
- const python = process.env.MEMORAX_CODE_REPO_MEMORY_PYTHON_COMMAND || "python3";
160
- try {
161
- const { stdout } = await execFileAsync(python, [fileURLToPath(validatorUrl), repoRoot], {
162
- encoding: "utf8",
163
- timeout: 15_000,
164
- maxBuffer: 1024 * 1024,
165
- });
166
- return readinessFromValidatorOutput(stdout);
167
- }
168
- catch (error) {
169
- const stdout = typeof error?.stdout === "string"
170
- ? error.stdout
171
- : "";
172
- const outcome = readinessFromValidatorOutput(stdout);
173
- return outcome === "invalid" ? "invalid" : "unknown";
174
- }
175
- }
176
- function readinessFromValidatorOutput(value) {
177
- try {
178
- const report = JSON.parse(value);
179
- return report.ok === true ? "usable" : report.ok === false ? "invalid" : "unknown";
180
- }
181
- catch {
182
- return "unknown";
183
- }
184
- }
185
- function pathToDirectoryUrl(path) {
186
- const normalized = path.endsWith("/") ? path : `${path}/`;
187
- return pathToFileURL(normalized);
188
- }