memorix 1.5.0 → 1.6.0
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 +37 -0
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/dist/cli/index.js +452 -109
- package/dist/index.js +376 -87
- package/dist/maintenance-runner.js +174 -41
- package/dist/media-audio-runner.js +174 -41
- package/dist/media-video-runner.js +174 -41
- package/dist/memcode-runtime/CHANGELOG.md +37 -0
- package/dist/sdk.js +375 -86
- package/dist/types.d.ts +2 -0
- package/dist/vector-backfill-runner.js +174 -41
- package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
- package/docs/API_REFERENCE.md +1 -1
- package/docs/DEVELOPMENT.md +5 -3
- package/package.json +1 -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/codegraph.ts +48 -5
- package/src/cli/commands/context.ts +20 -4
- package/src/cli/commands/resume.ts +4 -0
- package/src/codegraph/auto-context.ts +4 -1
- package/src/codegraph/context-pack.ts +3 -1
- package/src/codegraph/external-provider.ts +93 -0
- package/src/embedding/api-provider.ts +105 -22
- package/src/embedding/provider.ts +2 -0
- package/src/hooks/installers/index.ts +1 -1
- package/src/hooks/official-skills.ts +3 -3
- package/src/hooks/rules/memorix-agent-rules.md +1 -1
- package/src/knowledge/context-receipt.ts +41 -0
- package/src/knowledge/workflows.ts +6 -3
- package/src/knowledge/workset.ts +56 -2
- package/src/llm/provider.ts +17 -8
- package/src/memory/formation/extract.ts +6 -3
- package/src/memory/formation/index.ts +2 -1
- package/src/memory/formation/resolve.ts +10 -6
- package/src/memory/formation/types.ts +3 -1
- package/src/memory/long-term.ts +7 -1
- package/src/server.ts +29 -13
- package/src/store/orama-store.ts +6 -4
- package/src/timeout.ts +67 -0
- package/src/types.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -3987,6 +3987,8 @@ function getPreferredBatchSize(config) {
|
|
|
3987
3987
|
}
|
|
3988
3988
|
function parseBatchLimit(error) {
|
|
3989
3989
|
if (!(error instanceof Error)) return null;
|
|
3990
|
+
const status = error instanceof EmbeddingAPIError ? error.status : Number(error.message.match(/Embedding API error \((\d{3})\)/i)?.[1] ?? 0);
|
|
3991
|
+
if (status > 0 && status !== 400) return null;
|
|
3990
3992
|
const explicit = error.message.match(/should not be larger than\s+(\d+)/i);
|
|
3991
3993
|
if (explicit) return parseInt(explicit[1], 10);
|
|
3992
3994
|
if (/batch size/i.test(error.message)) {
|
|
@@ -3999,37 +4001,99 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
3999
4001
|
const controller = new AbortController();
|
|
4000
4002
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
|
|
4001
4003
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4004
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
4002
4005
|
let response;
|
|
4003
4006
|
try {
|
|
4004
4007
|
response = await fetch(url, {
|
|
4005
4008
|
method: "POST",
|
|
4006
4009
|
headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
4007
4010
|
body: JSON.stringify(body),
|
|
4008
|
-
signal
|
|
4011
|
+
signal
|
|
4009
4012
|
});
|
|
4010
4013
|
} catch (err) {
|
|
4011
4014
|
clearTimeout(timeout);
|
|
4012
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
4015
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4013
4016
|
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4014
4017
|
}
|
|
4015
4018
|
throw err;
|
|
4016
4019
|
}
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
+
try {
|
|
4021
|
+
if (response.ok) {
|
|
4022
|
+
return await raceWithAbort(
|
|
4023
|
+
response.json(),
|
|
4024
|
+
signal
|
|
4025
|
+
);
|
|
4026
|
+
}
|
|
4027
|
+
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4028
|
+
const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4029
|
+
const retryAfter = response.headers.get("retry-after");
|
|
4030
|
+
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4031
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
|
|
4032
|
+
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4033
|
+
await waitForRetry(waitMs, options.signal);
|
|
4034
|
+
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
4035
|
+
}
|
|
4036
|
+
const errorText2 = await raceWithAbort(
|
|
4037
|
+
response.text().catch(() => "unknown error"),
|
|
4038
|
+
signal
|
|
4039
|
+
);
|
|
4040
|
+
throw new EmbeddingAPIError(response.status, errorText2);
|
|
4041
|
+
} catch (err) {
|
|
4042
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4043
|
+
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4044
|
+
}
|
|
4045
|
+
throw err;
|
|
4046
|
+
} finally {
|
|
4047
|
+
clearTimeout(timeout);
|
|
4020
4048
|
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4049
|
+
}
|
|
4050
|
+
function abortError() {
|
|
4051
|
+
const error = new Error("Embedding API request aborted");
|
|
4052
|
+
error.name = "AbortError";
|
|
4053
|
+
return error;
|
|
4054
|
+
}
|
|
4055
|
+
function raceWithAbort(promise, signal) {
|
|
4056
|
+
if (signal.aborted) return Promise.reject(abortError());
|
|
4057
|
+
return new Promise((resolve2, reject) => {
|
|
4058
|
+
const onAbort = () => {
|
|
4059
|
+
signal.removeEventListener("abort", onAbort);
|
|
4060
|
+
reject(abortError());
|
|
4061
|
+
};
|
|
4062
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4063
|
+
promise.then(
|
|
4064
|
+
(value) => {
|
|
4065
|
+
signal.removeEventListener("abort", onAbort);
|
|
4066
|
+
resolve2(value);
|
|
4067
|
+
},
|
|
4068
|
+
(error) => {
|
|
4069
|
+
signal.removeEventListener("abort", onAbort);
|
|
4070
|
+
reject(error);
|
|
4071
|
+
}
|
|
4072
|
+
);
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
async function waitForRetry(waitMs, signal) {
|
|
4076
|
+
if (!signal) {
|
|
4026
4077
|
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
4027
|
-
return
|
|
4078
|
+
return;
|
|
4028
4079
|
}
|
|
4029
|
-
const
|
|
4030
|
-
throw new Error(
|
|
4080
|
+
const abortSignal = signal;
|
|
4081
|
+
if (abortSignal.aborted) throw new Error("Embedding API retry aborted");
|
|
4082
|
+
await new Promise((resolve2, reject) => {
|
|
4083
|
+
const timer = setTimeout(done, waitMs);
|
|
4084
|
+
const onAbort = () => {
|
|
4085
|
+
clearTimeout(timer);
|
|
4086
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4087
|
+
reject(new Error("Embedding API retry aborted"));
|
|
4088
|
+
};
|
|
4089
|
+
function done() {
|
|
4090
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4091
|
+
resolve2();
|
|
4092
|
+
}
|
|
4093
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4094
|
+
});
|
|
4031
4095
|
}
|
|
4032
|
-
var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, APIEmbeddingProvider;
|
|
4096
|
+
var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
|
|
4033
4097
|
var init_api_provider = __esm({
|
|
4034
4098
|
"src/embedding/api-provider.ts"() {
|
|
4035
4099
|
"use strict";
|
|
@@ -4048,6 +4112,14 @@ var init_api_provider = __esm({
|
|
|
4048
4112
|
DASHSCOPE_MAX_BATCH_SIZE = 10;
|
|
4049
4113
|
MAX_RETRIES2 = 3;
|
|
4050
4114
|
BASE_DELAY_MS = 500;
|
|
4115
|
+
EmbeddingAPIError = class extends Error {
|
|
4116
|
+
status;
|
|
4117
|
+
constructor(status, detail) {
|
|
4118
|
+
super(`Embedding API error (${status}): ${detail}`);
|
|
4119
|
+
this.name = "EmbeddingAPIError";
|
|
4120
|
+
this.status = status;
|
|
4121
|
+
}
|
|
4122
|
+
};
|
|
4051
4123
|
APIEmbeddingProvider = class _APIEmbeddingProvider {
|
|
4052
4124
|
name;
|
|
4053
4125
|
dimensions;
|
|
@@ -4259,15 +4331,14 @@ var init_api_provider = __esm({
|
|
|
4259
4331
|
}
|
|
4260
4332
|
} catch (error) {
|
|
4261
4333
|
const providerLimit = parseBatchLimit(error);
|
|
4262
|
-
|
|
4263
|
-
if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
|
|
4334
|
+
if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
|
|
4264
4335
|
console.error(
|
|
4265
|
-
`[memorix] Embedding batch too large for provider, retrying in chunks of ${
|
|
4336
|
+
`[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
|
|
4266
4337
|
);
|
|
4267
|
-
for (let start = 0; start < chunkTexts.length; start +=
|
|
4338
|
+
for (let start = 0; start < chunkTexts.length; start += providerLimit) {
|
|
4268
4339
|
await processChunk(
|
|
4269
|
-
chunkTexts.slice(start, start +
|
|
4270
|
-
chunkIndices.slice(start, start +
|
|
4340
|
+
chunkTexts.slice(start, start + providerLimit),
|
|
4341
|
+
chunkIndices.slice(start, start + providerLimit)
|
|
4271
4342
|
);
|
|
4272
4343
|
}
|
|
4273
4344
|
return;
|
|
@@ -5131,22 +5202,23 @@ function getLLMConfig() {
|
|
|
5131
5202
|
function setLLMConfig(config) {
|
|
5132
5203
|
currentConfig = config;
|
|
5133
5204
|
}
|
|
5134
|
-
async function callLLM(systemPrompt, userMessage) {
|
|
5205
|
+
async function callLLM(systemPrompt, userMessage, signal) {
|
|
5135
5206
|
if (!currentConfig) {
|
|
5136
5207
|
throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
|
|
5137
5208
|
}
|
|
5138
5209
|
if (currentConfig.provider === "anthropic") {
|
|
5139
|
-
return callAnthropic(systemPrompt, userMessage);
|
|
5210
|
+
return callAnthropic(systemPrompt, userMessage, signal);
|
|
5140
5211
|
}
|
|
5141
|
-
return callOpenAICompatible(systemPrompt, userMessage);
|
|
5212
|
+
return callOpenAICompatible(systemPrompt, userMessage, signal);
|
|
5142
5213
|
}
|
|
5143
|
-
async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
5214
|
+
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5144
5215
|
const config = currentConfig;
|
|
5145
5216
|
let base = config.baseUrl.replace(/\/+$/, "");
|
|
5146
5217
|
if (!base.endsWith("/v1")) base += "/v1";
|
|
5147
5218
|
const url = `${base}/chat/completions`;
|
|
5219
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5148
5220
|
const response = await fetch(url, {
|
|
5149
|
-
signal:
|
|
5221
|
+
signal: fetchSignal,
|
|
5150
5222
|
method: "POST",
|
|
5151
5223
|
headers: {
|
|
5152
5224
|
"Content-Type": "application/json",
|
|
@@ -5163,10 +5235,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5163
5235
|
})
|
|
5164
5236
|
});
|
|
5165
5237
|
if (!response.ok) {
|
|
5166
|
-
const error = await readResponseText(response,
|
|
5238
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5167
5239
|
throw new Error(`LLM API error (${response.status}): ${error}`);
|
|
5168
5240
|
}
|
|
5169
|
-
const data = await readResponseJson(response);
|
|
5241
|
+
const data = await readResponseJson(response, signal);
|
|
5170
5242
|
return {
|
|
5171
5243
|
content: data.choices[0]?.message?.content ?? "",
|
|
5172
5244
|
usage: data.usage ? {
|
|
@@ -5175,11 +5247,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5175
5247
|
} : void 0
|
|
5176
5248
|
};
|
|
5177
5249
|
}
|
|
5178
|
-
async function callAnthropic(systemPrompt, userMessage) {
|
|
5250
|
+
async function callAnthropic(systemPrompt, userMessage, signal) {
|
|
5179
5251
|
const config = currentConfig;
|
|
5180
5252
|
const url = `${config.baseUrl}/messages`;
|
|
5253
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5181
5254
|
const response = await fetch(url, {
|
|
5182
|
-
signal:
|
|
5255
|
+
signal: fetchSignal,
|
|
5183
5256
|
method: "POST",
|
|
5184
5257
|
headers: {
|
|
5185
5258
|
"Content-Type": "application/json",
|
|
@@ -5197,10 +5270,10 @@ async function callAnthropic(systemPrompt, userMessage) {
|
|
|
5197
5270
|
})
|
|
5198
5271
|
});
|
|
5199
5272
|
if (!response.ok) {
|
|
5200
|
-
const error = await readResponseText(response,
|
|
5273
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5201
5274
|
throw new Error(`Anthropic API error (${response.status}): ${error}`);
|
|
5202
5275
|
}
|
|
5203
|
-
const data = await readResponseJson(response);
|
|
5276
|
+
const data = await readResponseJson(response, signal);
|
|
5204
5277
|
return {
|
|
5205
5278
|
content: data.content[0]?.text ?? "",
|
|
5206
5279
|
usage: data.usage ? {
|
|
@@ -5705,6 +5778,57 @@ function withTimeout(promise, ms, label) {
|
|
|
5705
5778
|
);
|
|
5706
5779
|
});
|
|
5707
5780
|
}
|
|
5781
|
+
function withTimeoutSignal(operation, ms, label, parentSignal) {
|
|
5782
|
+
const controller = new AbortController();
|
|
5783
|
+
const signal = parentSignal ? AbortSignal.any([parentSignal, controller.signal]) : controller.signal;
|
|
5784
|
+
return new Promise((resolve2, reject) => {
|
|
5785
|
+
let settled = false;
|
|
5786
|
+
let timedOut = false;
|
|
5787
|
+
let timer;
|
|
5788
|
+
const cleanup = () => {
|
|
5789
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5790
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
5791
|
+
};
|
|
5792
|
+
const onParentAbort = () => {
|
|
5793
|
+
if (settled || timedOut) return;
|
|
5794
|
+
settled = true;
|
|
5795
|
+
cleanup();
|
|
5796
|
+
reject(parentSignal?.reason ?? new Error(`${label} aborted`));
|
|
5797
|
+
};
|
|
5798
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
5799
|
+
timer = setTimeout(() => {
|
|
5800
|
+
if (settled) return;
|
|
5801
|
+
timedOut = true;
|
|
5802
|
+
controller.abort(new Error(`${label} timed out after ${ms}ms`));
|
|
5803
|
+
settled = true;
|
|
5804
|
+
cleanup();
|
|
5805
|
+
reject(new Error(`${label} timed out after ${ms}ms`));
|
|
5806
|
+
}, ms);
|
|
5807
|
+
let pending;
|
|
5808
|
+
try {
|
|
5809
|
+
pending = operation(signal);
|
|
5810
|
+
} catch (error) {
|
|
5811
|
+
settled = true;
|
|
5812
|
+
cleanup();
|
|
5813
|
+
reject(error);
|
|
5814
|
+
return;
|
|
5815
|
+
}
|
|
5816
|
+
pending.then(
|
|
5817
|
+
(value) => {
|
|
5818
|
+
if (settled) return;
|
|
5819
|
+
settled = true;
|
|
5820
|
+
cleanup();
|
|
5821
|
+
resolve2(value);
|
|
5822
|
+
},
|
|
5823
|
+
(error) => {
|
|
5824
|
+
if (settled) return;
|
|
5825
|
+
settled = true;
|
|
5826
|
+
cleanup();
|
|
5827
|
+
reject(timedOut ? new Error(`${label} timed out after ${ms}ms`) : error);
|
|
5828
|
+
}
|
|
5829
|
+
);
|
|
5830
|
+
});
|
|
5831
|
+
}
|
|
5708
5832
|
var init_timeout = __esm({
|
|
5709
5833
|
"src/timeout.ts"() {
|
|
5710
5834
|
"use strict";
|
|
@@ -6569,16 +6693,18 @@ async function searchObservations(options) {
|
|
|
6569
6693
|
);
|
|
6570
6694
|
} else {
|
|
6571
6695
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
6572
|
-
queryVector = await
|
|
6573
|
-
provider2.embedInput ? provider2.embedInput(
|
|
6696
|
+
queryVector = await withTimeoutSignal(
|
|
6697
|
+
(signal) => provider2.embedInput ? provider2.embedInput(
|
|
6574
6698
|
{ modality: "text", text: expandedEmbeddingQuery },
|
|
6575
|
-
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
|
|
6699
|
+
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
|
|
6576
6700
|
) : provider2.embed(expandedEmbeddingQuery, {
|
|
6577
6701
|
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
6578
|
-
retry: false
|
|
6702
|
+
retry: false,
|
|
6703
|
+
signal
|
|
6579
6704
|
}),
|
|
6580
6705
|
EMBEDDING_TIMEOUT_MS,
|
|
6581
|
-
"Embedding"
|
|
6706
|
+
"Embedding",
|
|
6707
|
+
options.signal
|
|
6582
6708
|
);
|
|
6583
6709
|
mark("embedding");
|
|
6584
6710
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
@@ -144998,7 +145124,13 @@ async function maintainLongTermMemories(input) {
|
|
|
144998
145124
|
}
|
|
144999
145125
|
for (const group of groups.values()) {
|
|
145000
145126
|
if (group.length < 2) continue;
|
|
145001
|
-
group.sort((a, b) =>
|
|
145127
|
+
group.sort((a, b) => {
|
|
145128
|
+
const byCreatedAt = Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
|
145129
|
+
if (byCreatedAt !== 0) return byCreatedAt;
|
|
145130
|
+
const byUpdatedAt = Date.parse(b.updatedAt) - Date.parse(a.updatedAt);
|
|
145131
|
+
if (byUpdatedAt !== 0) return byUpdatedAt;
|
|
145132
|
+
return b.id.localeCompare(a.id);
|
|
145133
|
+
});
|
|
145002
145134
|
const newest = group[0];
|
|
145003
145135
|
for (const older of group.slice(1)) {
|
|
145004
145136
|
try {
|
|
@@ -148726,6 +148858,7 @@ var init_task_lens = __esm({
|
|
|
148726
148858
|
var workflows_exports = {};
|
|
148727
148859
|
__export(workflows_exports, {
|
|
148728
148860
|
WORKFLOW_ADAPTER_TARGETS: () => WORKFLOW_ADAPTER_TARGETS,
|
|
148861
|
+
WORKFLOW_AGENT_TARGETS: () => WORKFLOW_AGENT_TARGETS,
|
|
148729
148862
|
applyWorkflowAdapter: () => applyWorkflowAdapter,
|
|
148730
148863
|
importWindsurfWorkflows: () => importWindsurfWorkflows,
|
|
148731
148864
|
parseWorkflowMarkdown: () => parseWorkflowMarkdown,
|
|
@@ -148791,7 +148924,7 @@ function optionalStatus(data) {
|
|
|
148791
148924
|
return value;
|
|
148792
148925
|
}
|
|
148793
148926
|
function normalizeAgents(values) {
|
|
148794
|
-
const unknown3 = values.filter((value) => !
|
|
148927
|
+
const unknown3 = values.filter((value) => !WORKFLOW_AGENT_TARGETS.includes(value));
|
|
148795
148928
|
if (unknown3.length > 0) {
|
|
148796
148929
|
throw new Error("workflow frontmatter has unsupported agent: " + unknown3[0]);
|
|
148797
148930
|
}
|
|
@@ -149067,7 +149200,7 @@ function taskScore(workflow, task) {
|
|
|
149067
149200
|
return { score, reasons: [...new Set(reasons)] };
|
|
149068
149201
|
}
|
|
149069
149202
|
function selectWorkflows(input) {
|
|
149070
|
-
const selected = input.workflows.filter((workflow) => workflow.status === "active").map((workflow) => {
|
|
149203
|
+
const selected = input.workflows.filter((workflow) => workflow.status === "active" && (!input.agent || workflow.compatibleAgents.includes(input.agent))).map((workflow) => {
|
|
149071
149204
|
const match2 = taskScore(workflow, input.task);
|
|
149072
149205
|
const cautions = input.store && input.projectId ? input.store.recentFailureCautions(input.projectId, workflow.id) : [];
|
|
149073
149206
|
return {
|
|
@@ -149347,7 +149480,7 @@ async function selectWorkspaceWorkflows(input) {
|
|
|
149347
149480
|
errors: synced.errors
|
|
149348
149481
|
};
|
|
149349
149482
|
}
|
|
149350
|
-
var
|
|
149483
|
+
var WORKFLOW_AGENT_TARGETS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
|
|
149351
149484
|
var init_workflows2 = __esm({
|
|
149352
149485
|
"src/knowledge/workflows.ts"() {
|
|
149353
149486
|
"use strict";
|
|
@@ -149359,7 +149492,7 @@ var init_workflows2 = __esm({
|
|
|
149359
149492
|
init_workflow_store();
|
|
149360
149493
|
init_outcome_store();
|
|
149361
149494
|
init_task_lens();
|
|
149362
|
-
|
|
149495
|
+
WORKFLOW_AGENT_TARGETS = [
|
|
149363
149496
|
"windsurf",
|
|
149364
149497
|
"cursor",
|
|
149365
149498
|
"claude-code",
|
|
@@ -155333,13 +155466,13 @@ function verifyType(declaredType, narrative, title) {
|
|
|
155333
155466
|
}
|
|
155334
155467
|
return { type: declaredType, corrected: false };
|
|
155335
155468
|
}
|
|
155336
|
-
async function extractFactsWithLLM(narrative, title, existingFacts) {
|
|
155469
|
+
async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
|
|
155337
155470
|
try {
|
|
155338
155471
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155339
155472
|
const input = `Title: ${title}
|
|
155340
155473
|
Content: ${narrative}${existingFacts.length > 0 ? `
|
|
155341
155474
|
Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
155342
|
-
const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
|
|
155475
|
+
const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
|
|
155343
155476
|
const text2 = response.content.trim();
|
|
155344
155477
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155345
155478
|
if (!jsonMatch) return [];
|
|
@@ -155348,15 +155481,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
|
155348
155481
|
if (!Array.isArray(facts)) return [];
|
|
155349
155482
|
const existingLower = new Set(existingFacts.map((f3) => f3.toLowerCase().trim()));
|
|
155350
155483
|
return facts.filter((f3) => typeof f3 === "string" && f3.length >= 5).filter((f3) => !existingLower.has(f3.toLowerCase().trim())).slice(0, 10);
|
|
155351
|
-
} catch {
|
|
155484
|
+
} catch (error) {
|
|
155485
|
+
if (signal?.aborted) throw error;
|
|
155352
155486
|
return [];
|
|
155353
155487
|
}
|
|
155354
155488
|
}
|
|
155355
|
-
async function runExtract(input, existingEntities, useLLM = false) {
|
|
155489
|
+
async function runExtract(input, existingEntities, useLLM = false, signal) {
|
|
155356
155490
|
const callerFacts = input.facts ?? [];
|
|
155357
155491
|
let extractedFacts;
|
|
155358
155492
|
if (useLLM) {
|
|
155359
|
-
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
|
|
155493
|
+
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
|
|
155360
155494
|
if (extractedFacts.length === 0) {
|
|
155361
155495
|
extractedFacts = extractFacts2(input.narrative, callerFacts);
|
|
155362
155496
|
}
|
|
@@ -155576,7 +155710,7 @@ function mergeFacts2(oldFacts, newFacts) {
|
|
|
155576
155710
|
}
|
|
155577
155711
|
return merged;
|
|
155578
155712
|
}
|
|
155579
|
-
async function resolveWithLLM(extracted, hits, getObservation2) {
|
|
155713
|
+
async function resolveWithLLM(extracted, hits, getObservation2, signal) {
|
|
155580
155714
|
try {
|
|
155581
155715
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155582
155716
|
const existingMemories = hits.slice(0, 5).map((h2, i2) => ({
|
|
@@ -155593,7 +155727,7 @@ Facts: ${extracted.facts.join("; ")}
|
|
|
155593
155727
|
|
|
155594
155728
|
EXISTING MEMORIES:
|
|
155595
155729
|
${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
|
|
155596
|
-
const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
|
|
155730
|
+
const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
|
|
155597
155731
|
const text2 = response.content.trim();
|
|
155598
155732
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155599
155733
|
if (!jsonMatch) return null;
|
|
@@ -155630,7 +155764,8 @@ ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Fact
|
|
|
155630
155764
|
};
|
|
155631
155765
|
}
|
|
155632
155766
|
return null;
|
|
155633
|
-
} catch {
|
|
155767
|
+
} catch (error) {
|
|
155768
|
+
if (signal?.aborted) throw error;
|
|
155634
155769
|
return null;
|
|
155635
155770
|
}
|
|
155636
155771
|
}
|
|
@@ -155648,19 +155783,20 @@ function scoreCandidate(extracted, candidate) {
|
|
|
155648
155783
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
155649
155784
|
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
155650
155785
|
}
|
|
155651
|
-
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
155786
|
+
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false, signal) {
|
|
155652
155787
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
155653
155788
|
let hits;
|
|
155654
155789
|
try {
|
|
155655
|
-
hits = await searchMemories(query, 5, projectId);
|
|
155656
|
-
} catch {
|
|
155790
|
+
hits = await searchMemories(query, 5, projectId, signal);
|
|
155791
|
+
} catch (error) {
|
|
155792
|
+
if (signal?.aborted) throw error;
|
|
155657
155793
|
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
155658
155794
|
}
|
|
155659
155795
|
if (hits.length === 0) {
|
|
155660
155796
|
return { action: "new", reason: "No similar existing memories found" };
|
|
155661
155797
|
}
|
|
155662
155798
|
if (useLLM) {
|
|
155663
|
-
const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
|
|
155799
|
+
const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
|
|
155664
155800
|
if (llmResult) return llmResult;
|
|
155665
155801
|
}
|
|
155666
155802
|
const scored = hits.map((hit) => ({
|
|
@@ -156082,7 +156218,7 @@ async function runFormation(input, config) {
|
|
|
156082
156218
|
const existingEntities = config.getEntityNames();
|
|
156083
156219
|
const extractStartTime = Date.now();
|
|
156084
156220
|
emitStageEvent("extract", "start");
|
|
156085
|
-
const extraction = await runExtract(input, existingEntities, config.useLLM);
|
|
156221
|
+
const extraction = await runExtract(input, existingEntities, config.useLLM, config.signal);
|
|
156086
156222
|
stageDurationsMs.extract = Date.now() - extractStartTime;
|
|
156087
156223
|
emitStageEvent("extract", "success", stageDurationsMs.extract);
|
|
156088
156224
|
stagesCompleted = 1;
|
|
@@ -156102,7 +156238,8 @@ async function runFormation(input, config) {
|
|
|
156102
156238
|
input.projectId,
|
|
156103
156239
|
config.searchMemories,
|
|
156104
156240
|
config.getObservation,
|
|
156105
|
-
config.useLLM
|
|
156241
|
+
config.useLLM,
|
|
156242
|
+
config.signal
|
|
156106
156243
|
);
|
|
156107
156244
|
stageDurationsMs.resolve = Date.now() - resolveStartTime;
|
|
156108
156245
|
emitStageEvent("resolve", "success", stageDurationsMs.resolve);
|
|
@@ -156991,6 +157128,15 @@ function workflowOutput(selection) {
|
|
|
156991
157128
|
cautions: selection.cautions.map((caution) => short(caution, 22))
|
|
156992
157129
|
};
|
|
156993
157130
|
}
|
|
157131
|
+
function workflowLoadout(agent, selections) {
|
|
157132
|
+
if (!agent) return void 0;
|
|
157133
|
+
return {
|
|
157134
|
+
agent,
|
|
157135
|
+
workflowIds: selections.map((selection) => selection.workflow.id),
|
|
157136
|
+
requiredContext: unique(selections.flatMap((selection) => selection.workflow.requiredContext)).map((item) => short(item, 18)).slice(0, 4),
|
|
157137
|
+
allowedTools: unique(selections.flatMap((selection) => selection.workflow.allowedTools)).map((item) => short(item, 12)).slice(0, 6)
|
|
157138
|
+
};
|
|
157139
|
+
}
|
|
156994
157140
|
function appendLine(lines, candidate, maxTokens, omitted, omittedKind, selected, receiptSelection) {
|
|
156995
157141
|
const next = lines.length ? lines.join("\n") + "\n" + candidate : candidate;
|
|
156996
157142
|
if (countTextTokens(next) <= maxTokens) {
|
|
@@ -157451,6 +157597,22 @@ function renderTaskWorksetPrompt(input) {
|
|
|
157451
157597
|
);
|
|
157452
157598
|
}
|
|
157453
157599
|
}
|
|
157600
|
+
if (input.agentLoadout) {
|
|
157601
|
+
appendLine(lines, "", maxTokens, omitted, "agent-loadout-heading");
|
|
157602
|
+
appendLine(lines, "Agent loadout (" + input.agentLoadout.agent + ")", maxTokens, omitted, "agent-loadout-heading");
|
|
157603
|
+
for (const required of input.agentLoadout.requiredContext.slice(0, 2)) {
|
|
157604
|
+
appendLine(lines, "- Need: " + required, maxTokens, omitted, "agent-loadout-context");
|
|
157605
|
+
}
|
|
157606
|
+
if (input.agentLoadout.allowedTools.length > 0) {
|
|
157607
|
+
appendLine(
|
|
157608
|
+
lines,
|
|
157609
|
+
"- Workflow tools: " + input.agentLoadout.allowedTools.join(", "),
|
|
157610
|
+
maxTokens,
|
|
157611
|
+
omitted,
|
|
157612
|
+
"agent-loadout-tools"
|
|
157613
|
+
);
|
|
157614
|
+
}
|
|
157615
|
+
}
|
|
157454
157616
|
if (input.verification.length > 0) {
|
|
157455
157617
|
appendLine(lines, "", maxTokens, omitted, "verification-heading");
|
|
157456
157618
|
appendLine(lines, "Verify", maxTokens, omitted, "verification-heading");
|
|
@@ -157542,6 +157704,7 @@ async function buildTaskWorkset(input) {
|
|
|
157542
157704
|
let workspace;
|
|
157543
157705
|
let pages = [];
|
|
157544
157706
|
let workflows = [];
|
|
157707
|
+
let workflowSelections = [];
|
|
157545
157708
|
try {
|
|
157546
157709
|
workspace = await preferredWorkspace(input.projectId, input.dataDir);
|
|
157547
157710
|
if (workspace) {
|
|
@@ -157558,14 +157721,15 @@ async function buildTaskWorkset(input) {
|
|
|
157558
157721
|
if (task) {
|
|
157559
157722
|
const workflowStore = new WorkflowStore();
|
|
157560
157723
|
await workflowStore.init(input.dataDir);
|
|
157561
|
-
|
|
157724
|
+
workflowSelections = selectWorkflows({
|
|
157562
157725
|
workflows: workflowStore.listWorkflows(workspace.id, "active"),
|
|
157563
157726
|
task,
|
|
157564
157727
|
projectId: input.projectId,
|
|
157565
157728
|
store: workflowStore,
|
|
157729
|
+
...input.agent ? { agent: input.agent } : {},
|
|
157566
157730
|
limit: 2
|
|
157567
157731
|
});
|
|
157568
|
-
workflows =
|
|
157732
|
+
workflows = workflowSelections.map(workflowOutput);
|
|
157569
157733
|
for (const workflow of workflows) {
|
|
157570
157734
|
for (const caution of workflow.cautions) {
|
|
157571
157735
|
cautions.push({ kind: "workflow-failed-verification", message: caution });
|
|
@@ -157587,6 +157751,10 @@ async function buildTaskWorkset(input) {
|
|
|
157587
157751
|
workflows
|
|
157588
157752
|
});
|
|
157589
157753
|
const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
|
|
157754
|
+
const agentLoadout = workflowLoadout(
|
|
157755
|
+
input.agent,
|
|
157756
|
+
workflowSelections.filter((selection2) => governed.workflows.some((workflow) => workflow.id === selection2.workflow.id))
|
|
157757
|
+
);
|
|
157590
157758
|
const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
|
|
157591
157759
|
claim,
|
|
157592
157760
|
evidenceByClaim.get(claim.id) ?? []
|
|
@@ -157631,6 +157799,7 @@ async function buildTaskWorkset(input) {
|
|
|
157631
157799
|
pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
|
|
157632
157800
|
durableMemory: governed.durableMemory,
|
|
157633
157801
|
workflows: governed.workflows,
|
|
157802
|
+
...agentLoadout ? { agentLoadout } : {},
|
|
157634
157803
|
cautions: normalizedCautions,
|
|
157635
157804
|
verification,
|
|
157636
157805
|
evidenceIds,
|
|
@@ -157849,10 +158018,12 @@ var init_current_facts = __esm({
|
|
|
157849
158018
|
var external_provider_exports = {};
|
|
157850
158019
|
__export(external_provider_exports, {
|
|
157851
158020
|
DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
|
|
158021
|
+
EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS: () => EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
|
|
157852
158022
|
MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES: () => MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES,
|
|
157853
158023
|
MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
|
|
157854
158024
|
getExternalCodeGraphContext: () => getExternalCodeGraphContext,
|
|
157855
|
-
inspectExternalCodeGraph: () => inspectExternalCodeGraph
|
|
158025
|
+
inspectExternalCodeGraph: () => inspectExternalCodeGraph,
|
|
158026
|
+
runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
|
|
157856
158027
|
});
|
|
157857
158028
|
import { spawn as spawn5 } from "child_process";
|
|
157858
158029
|
import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
|
|
@@ -158051,6 +158222,66 @@ async function inspectExternalCodeGraph(input) {
|
|
|
158051
158222
|
const health = healthFromStatus(status);
|
|
158052
158223
|
return { health, quality: providerQuality({ mode, health }) };
|
|
158053
158224
|
}
|
|
158225
|
+
async function runExternalCodeGraphLifecycle(input) {
|
|
158226
|
+
const mode = input.mode ?? "auto";
|
|
158227
|
+
if (mode === "off") {
|
|
158228
|
+
const health = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
|
|
158229
|
+
return {
|
|
158230
|
+
action: input.action,
|
|
158231
|
+
performed: false,
|
|
158232
|
+
message: "External CodeGraph is disabled by configuration.",
|
|
158233
|
+
health,
|
|
158234
|
+
quality: providerQuality({ mode, health })
|
|
158235
|
+
};
|
|
158236
|
+
}
|
|
158237
|
+
const indexPath = join20(input.projectRoot, ".codegraph");
|
|
158238
|
+
if (input.action === "sync" && !existsSync15(indexPath)) {
|
|
158239
|
+
const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
|
|
158240
|
+
return {
|
|
158241
|
+
action: input.action,
|
|
158242
|
+
performed: false,
|
|
158243
|
+
message: 'Initialize CodeGraph first with "memorix codegraph init".',
|
|
158244
|
+
health,
|
|
158245
|
+
quality: providerQuality({ mode, health })
|
|
158246
|
+
};
|
|
158247
|
+
}
|
|
158248
|
+
if (input.action === "init" && existsSync15(indexPath)) {
|
|
158249
|
+
const inspected2 = await inspectExternalCodeGraph(input);
|
|
158250
|
+
return {
|
|
158251
|
+
action: input.action,
|
|
158252
|
+
performed: false,
|
|
158253
|
+
message: "A local CodeGraph directory already exists; no initialization was performed.",
|
|
158254
|
+
...inspected2
|
|
158255
|
+
};
|
|
158256
|
+
}
|
|
158257
|
+
const result = await runSafely(input.runner ?? defaultRunner, {
|
|
158258
|
+
command: input.command,
|
|
158259
|
+
args: input.action === "init" ? ["init", input.projectRoot] : ["sync", input.projectRoot, "--quiet"],
|
|
158260
|
+
cwd: input.projectRoot,
|
|
158261
|
+
// A context read must stay fast; an explicit user-requested index sync is
|
|
158262
|
+
// a different operation and gets its own bounded maintenance window.
|
|
158263
|
+
timeoutMs: EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
|
|
158264
|
+
maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
|
|
158265
|
+
});
|
|
158266
|
+
if (!result.ok) {
|
|
158267
|
+
const health = unavailableHealth(result);
|
|
158268
|
+
return {
|
|
158269
|
+
action: input.action,
|
|
158270
|
+
performed: false,
|
|
158271
|
+
message: "CodeGraph " + input.action + " did not complete: " + (health.reason ?? "unknown local error"),
|
|
158272
|
+
health,
|
|
158273
|
+
quality: providerQuality({ mode, health })
|
|
158274
|
+
};
|
|
158275
|
+
}
|
|
158276
|
+
const inspected = await inspectExternalCodeGraph(input);
|
|
158277
|
+
const remainsStale = inspected.health.state === "stale";
|
|
158278
|
+
return {
|
|
158279
|
+
action: input.action,
|
|
158280
|
+
performed: true,
|
|
158281
|
+
message: input.action === "init" ? 'Local CodeGraph initialization completed. Run "memorix codegraph sync" when source changes.' : remainsStale ? "Local CodeGraph synchronization completed, but the graph remains stale against the current worktree; this task will use Lite evidence." : "Local CodeGraph synchronization completed and is ready for task-scoped semantic context.",
|
|
158282
|
+
...inspected
|
|
158283
|
+
};
|
|
158284
|
+
}
|
|
158054
158285
|
function safeRelativePath(projectRoot, value, exclude) {
|
|
158055
158286
|
const path37 = safeText(value, 1024);
|
|
158056
158287
|
if (!path37 || isAbsolute(path37)) return void 0;
|
|
@@ -158176,7 +158407,7 @@ async function getExternalCodeGraphContext(input) {
|
|
|
158176
158407
|
quality: providerQuality({ mode, health: inspected.health, ...contributes ? { selected: "external" } : {} })
|
|
158177
158408
|
};
|
|
158178
158409
|
}
|
|
158179
|
-
var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
|
|
158410
|
+
var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
|
|
158180
158411
|
var init_external_provider = __esm({
|
|
158181
158412
|
"src/codegraph/external-provider.ts"() {
|
|
158182
158413
|
"use strict";
|
|
@@ -158186,6 +158417,7 @@ var init_external_provider = __esm({
|
|
|
158186
158417
|
init_ids();
|
|
158187
158418
|
DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 1200;
|
|
158188
158419
|
MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 5e3;
|
|
158420
|
+
EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS = 3e4;
|
|
158189
158421
|
MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES = 256 * 1024;
|
|
158190
158422
|
MAX_EXTERNAL_NODE_COUNT = 16;
|
|
158191
158423
|
MAX_EXTERNAL_EDGE_COUNT = 24;
|
|
@@ -159011,6 +159243,7 @@ async function buildAutoProjectContext(input) {
|
|
|
159011
159243
|
projectId: input.project.id,
|
|
159012
159244
|
dataDir: input.dataDir,
|
|
159013
159245
|
...task ? { task } : {},
|
|
159246
|
+
...input.agent ? { agent: input.agent } : {},
|
|
159014
159247
|
lens: lens.id,
|
|
159015
159248
|
startHere,
|
|
159016
159249
|
...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
|
|
@@ -159347,6 +159580,34 @@ var init_auto_context = __esm({
|
|
|
159347
159580
|
}
|
|
159348
159581
|
});
|
|
159349
159582
|
|
|
159583
|
+
// src/knowledge/context-receipt.ts
|
|
159584
|
+
var context_receipt_exports = {};
|
|
159585
|
+
__export(context_receipt_exports, {
|
|
159586
|
+
buildBoundedContextReceipt: () => buildBoundedContextReceipt
|
|
159587
|
+
});
|
|
159588
|
+
function buildBoundedContextReceipt(input) {
|
|
159589
|
+
const provider2 = input.providerQuality ?? input.workset.provenance.codeProvider;
|
|
159590
|
+
return {
|
|
159591
|
+
schemaVersion: "1",
|
|
159592
|
+
task: input.workset.task,
|
|
159593
|
+
brief: input.workset.prompt,
|
|
159594
|
+
receipt: input.workset.receipt,
|
|
159595
|
+
code: {
|
|
159596
|
+
selected: provider2?.selected ?? "lite",
|
|
159597
|
+
quality: provider2?.selectedQuality ?? "heuristic",
|
|
159598
|
+
externalState: provider2?.external.state ?? "not-detected",
|
|
159599
|
+
...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
|
|
159600
|
+
},
|
|
159601
|
+
...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
|
|
159602
|
+
};
|
|
159603
|
+
}
|
|
159604
|
+
var init_context_receipt = __esm({
|
|
159605
|
+
"src/knowledge/context-receipt.ts"() {
|
|
159606
|
+
"use strict";
|
|
159607
|
+
init_esm_shims();
|
|
159608
|
+
}
|
|
159609
|
+
});
|
|
159610
|
+
|
|
159350
159611
|
// src/codegraph/context-pack.ts
|
|
159351
159612
|
var context_pack_exports = {};
|
|
159352
159613
|
__export(context_pack_exports, {
|
|
@@ -159505,6 +159766,7 @@ async function attachTaskWorkset(input) {
|
|
|
159505
159766
|
projectId: input.projectId,
|
|
159506
159767
|
dataDir: input.dataDir,
|
|
159507
159768
|
task: input.pack.task,
|
|
159769
|
+
...input.agent ? { agent: input.agent } : {},
|
|
159508
159770
|
lens: input.lens,
|
|
159509
159771
|
currentFacts: input.currentFacts ?? [],
|
|
159510
159772
|
...input.codeState ? { codeState: input.codeState } : {},
|
|
@@ -163897,8 +164159,8 @@ var init_official_skills = __esm({
|
|
|
163897
164159
|
"",
|
|
163898
164160
|
"| Situation | Prefer | CLI fallback |",
|
|
163899
164161
|
"|---|---|---|",
|
|
163900
|
-
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --json` |',
|
|
163901
|
-
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --json` |',
|
|
164162
|
+
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --brief-json` |',
|
|
164163
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
|
|
163902
164164
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
163903
164165
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
163904
164166
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -163911,7 +164173,7 @@ var init_official_skills = __esm({
|
|
|
163911
164173
|
"",
|
|
163912
164174
|
"- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
|
|
163913
164175
|
"- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
|
|
163914
|
-
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --json` instead. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
164176
|
+
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
163915
164177
|
"- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
163916
164178
|
"- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
163917
164179
|
"- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
|
|
@@ -165170,7 +165432,7 @@ alwaysApply: true
|
|
|
165170
165432
|
"",
|
|
165171
165433
|
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
165172
165434
|
"",
|
|
165173
|
-
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --json`. For a new task, use `memorix context "<task>" --json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
165435
|
+
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --brief-json`. For a new task, use `memorix context "<task>" --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
165174
165436
|
"",
|
|
165175
165437
|
"After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
165176
165438
|
"If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
@@ -165834,7 +166096,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
165834
166096
|
};
|
|
165835
166097
|
const server = existingServer ?? new McpServer({
|
|
165836
166098
|
name: "memorix",
|
|
165837
|
-
version: true ? "1.
|
|
166099
|
+
version: true ? "1.6.0" : "1.0.1"
|
|
165838
166100
|
});
|
|
165839
166101
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
165840
166102
|
server.registerTool = ((name, ...args) => {
|
|
@@ -166023,8 +166285,8 @@ The path should point to a directory containing a .git folder.`
|
|
|
166023
166285
|
mode: "active",
|
|
166024
166286
|
useLLM: isLLMEnabled(),
|
|
166025
166287
|
minValueScore: 0.3,
|
|
166026
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166027
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166288
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166289
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
166028
166290
|
if (result.entries.length === 0) return [];
|
|
166029
166291
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166030
166292
|
return details.documents.map((d, i2) => ({
|
|
@@ -166054,16 +166316,19 @@ The path should point to a directory containing a .git folder.`
|
|
|
166054
166316
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
166055
166317
|
onStageEvent: onFormationStageEvent
|
|
166056
166318
|
};
|
|
166057
|
-
formationResult = await
|
|
166058
|
-
|
|
166059
|
-
|
|
166060
|
-
|
|
166061
|
-
|
|
166062
|
-
|
|
166063
|
-
|
|
166064
|
-
|
|
166065
|
-
|
|
166066
|
-
|
|
166319
|
+
formationResult = await withTimeoutSignal(
|
|
166320
|
+
async (signal) => {
|
|
166321
|
+
formationConfig.signal = signal;
|
|
166322
|
+
return runFormation({
|
|
166323
|
+
entityName,
|
|
166324
|
+
type,
|
|
166325
|
+
title,
|
|
166326
|
+
narrative,
|
|
166327
|
+
facts: safeFacts,
|
|
166328
|
+
projectId: project.id,
|
|
166329
|
+
source: "explicit"
|
|
166330
|
+
}, formationConfig);
|
|
166331
|
+
},
|
|
166067
166332
|
FORMATION_TIMEOUT_MS,
|
|
166068
166333
|
"Formation pipeline"
|
|
166069
166334
|
);
|
|
@@ -166413,8 +166678,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166413
166678
|
mode: formationMode,
|
|
166414
166679
|
useLLM: isLLMEnabled(),
|
|
166415
166680
|
minValueScore: 0.3,
|
|
166416
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166417
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166681
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166682
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
166418
166683
|
if (result.entries.length === 0) return [];
|
|
166419
166684
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166420
166685
|
return details.documents.map((d, i2) => ({
|
|
@@ -166435,8 +166700,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166435
166700
|
},
|
|
166436
166701
|
getEntityNames: () => graphManager.getEntityNames()
|
|
166437
166702
|
};
|
|
166438
|
-
const formed = await
|
|
166439
|
-
|
|
166703
|
+
const formed = await withTimeoutSignal(
|
|
166704
|
+
async (signal) => {
|
|
166705
|
+
formationConfig.signal = signal;
|
|
166706
|
+
return runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig);
|
|
166707
|
+
},
|
|
166440
166708
|
FORMATION_TIMEOUT_MS,
|
|
166441
166709
|
"Shadow formation"
|
|
166442
166710
|
);
|
|
@@ -166662,13 +166930,28 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166662
166930
|
refresh: z626.enum(["auto", "always", "never"]).optional().default("auto").describe(
|
|
166663
166931
|
"Code Memory refresh policy. auto refreshes only when missing or stale."
|
|
166664
166932
|
),
|
|
166665
|
-
format: z626.enum(["prompt", "summary", "json"]).optional().default("prompt").describe(
|
|
166666
|
-
'Output format. "prompt" is agent-ready; "summary" is human-readable; "json" is
|
|
166933
|
+
format: z626.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
|
|
166934
|
+
'Output format. "prompt" is agent-ready; "summary" is human-readable; "receipt" is bounded JSON; "json" is detailed diagnostics.'
|
|
166667
166935
|
),
|
|
166936
|
+
agent: z626.enum([
|
|
166937
|
+
"windsurf",
|
|
166938
|
+
"cursor",
|
|
166939
|
+
"claude-code",
|
|
166940
|
+
"codex",
|
|
166941
|
+
"copilot",
|
|
166942
|
+
"antigravity",
|
|
166943
|
+
"gemini-cli",
|
|
166944
|
+
"openclaw",
|
|
166945
|
+
"hermes",
|
|
166946
|
+
"omp",
|
|
166947
|
+
"kiro",
|
|
166948
|
+
"opencode",
|
|
166949
|
+
"trae"
|
|
166950
|
+
]).optional().describe("Optional target agent for compatible workflow selection."),
|
|
166668
166951
|
limit: z626.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
|
|
166669
166952
|
}
|
|
166670
166953
|
},
|
|
166671
|
-
async ({ task, refresh, format }) => {
|
|
166954
|
+
async ({ task, refresh, format, agent }) => {
|
|
166672
166955
|
const unresolved = requireResolvedProject("build project context for the current project");
|
|
166673
166956
|
if (unresolved) return unresolved;
|
|
166674
166957
|
const [
|
|
@@ -166680,12 +166963,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166680
166963
|
},
|
|
166681
166964
|
{ getObservationStore: getObservationStore2 },
|
|
166682
166965
|
{ MaintenanceJobStore: MaintenanceJobStore2 },
|
|
166683
|
-
{ enqueueCodegraphRefresh: enqueueCodegraphRefresh2 }
|
|
166966
|
+
{ enqueueCodegraphRefresh: enqueueCodegraphRefresh2 },
|
|
166967
|
+
{ buildBoundedContextReceipt: buildBoundedContextReceipt2 }
|
|
166684
166968
|
] = await Promise.all([
|
|
166685
166969
|
Promise.resolve().then(() => (init_auto_context(), auto_context_exports)),
|
|
166686
166970
|
Promise.resolve().then(() => (init_obs_store(), obs_store_exports)),
|
|
166687
166971
|
Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)),
|
|
166688
|
-
Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports))
|
|
166972
|
+
Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports)),
|
|
166973
|
+
Promise.resolve().then(() => (init_context_receipt(), context_receipt_exports))
|
|
166689
166974
|
]);
|
|
166690
166975
|
const observations2 = filterReadableObservations(
|
|
166691
166976
|
await getObservationStore2().loadByProject(project.id, { status: "active" }),
|
|
@@ -166696,6 +166981,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166696
166981
|
dataDir: projectDir2,
|
|
166697
166982
|
observations: observations2,
|
|
166698
166983
|
task,
|
|
166984
|
+
agent,
|
|
166699
166985
|
refresh: refresh ?? "auto",
|
|
166700
166986
|
reader: getObservationReader(),
|
|
166701
166987
|
enqueueRefresh: () => {
|
|
@@ -166708,7 +166994,10 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166708
166994
|
});
|
|
166709
166995
|
}
|
|
166710
166996
|
});
|
|
166711
|
-
const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "
|
|
166997
|
+
const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "receipt" ? JSON.stringify(buildBoundedContextReceipt2({
|
|
166998
|
+
workset: context.workset,
|
|
166999
|
+
providerQuality: context.providerQuality
|
|
167000
|
+
}), null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
|
|
166712
167001
|
autopilotRetrievalBoundary = {
|
|
166713
167002
|
projectId: project.id,
|
|
166714
167003
|
issuedAt: Date.now(),
|
|
@@ -170213,7 +170502,7 @@ var init_serve_shared = __esm({
|
|
|
170213
170502
|
|
|
170214
170503
|
// src/cli/version.ts
|
|
170215
170504
|
function getCliVersion() {
|
|
170216
|
-
return true ? "1.
|
|
170505
|
+
return true ? "1.6.0" : pkg.version;
|
|
170217
170506
|
}
|
|
170218
170507
|
var init_version3 = __esm({
|
|
170219
170508
|
"src/cli/version.ts"() {
|