memorix 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cli/index.js +407 -130
  3. package/dist/dashboard/static/app.js +37 -23
  4. package/dist/dashboard/static/index.html +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +633 -391
  7. package/dist/maintenance-runner.js +31 -25
  8. package/dist/media-audio-runner.js +31 -25
  9. package/dist/media-video-runner.js +31 -25
  10. package/dist/memcode-runtime/CHANGELOG.md +29 -0
  11. package/dist/sdk.js +625 -390
  12. package/dist/vector-backfill-runner.js +31 -25
  13. package/docs/1.2.0-PROVIDER-QUALITY.md +15 -6
  14. package/docs/1.3.3-MULTIMODAL-MEDIA-AND-MCP-COMPAT.md +7 -6
  15. package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +10 -8
  16. package/docs/API_REFERENCE.md +12 -8
  17. package/docs/ARCHITECTURE.md +3 -1
  18. package/docs/CONFIGURATION.md +2 -2
  19. package/docs/DASHBOARD.md +6 -0
  20. package/docs/DEVELOPMENT.md +2 -2
  21. package/docs/README.md +14 -8
  22. package/package.json +1 -1
  23. package/plugins/antigravity/memorix/plugin.json +2 -1
  24. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  25. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  26. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  27. package/plugins/copilot/memorix/plugin.json +1 -1
  28. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  29. package/plugins/hermes/memorix/plugin.yaml +1 -1
  30. package/plugins/omp/memorix/package.json +1 -1
  31. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  32. package/plugins/pi/memorix/package.json +1 -1
  33. package/server.json +3 -3
  34. package/src/cli/commands/dashboard.ts +1 -1
  35. package/src/cli/commands/serve-http.ts +38 -3
  36. package/src/codegraph/external-provider.ts +299 -19
  37. package/src/config/dotenv-loader.ts +9 -4
  38. package/src/config.ts +16 -16
  39. package/src/dashboard/maintenance.ts +4 -1
  40. package/src/dashboard/server.ts +85 -86
  41. package/src/dashboard/static/index.html +1 -1
  42. package/src/llm/provider.ts +17 -4
  43. package/src/server/mcp-compat.ts +82 -0
  44. package/src/server/mcp-diagnostics.ts +13 -4
  45. package/src/server.ts +9 -6
package/dist/sdk.js CHANGED
@@ -3267,8 +3267,10 @@ function loadEnvFile(filePath) {
3267
3267
  loadedEnvFiles.push(filePath);
3268
3268
  }
3269
3269
  function loadDotenv(projectRoot, options = {}) {
3270
- if (dotenvLoaded && dotenvProjectRoot === (projectRoot ?? null)) return;
3271
- if (dotenvLoaded && dotenvProjectRoot !== (projectRoot ?? null)) {
3270
+ const userHomeDir = options.userHomeDir ?? homedir4();
3271
+ const normalizedProjectRoot = projectRoot ?? null;
3272
+ if (dotenvLoaded && dotenvProjectRoot === normalizedProjectRoot && dotenvHomeDir === userHomeDir) return;
3273
+ if (dotenvLoaded && (dotenvProjectRoot !== normalizedProjectRoot || dotenvHomeDir !== userHomeDir)) {
3272
3274
  resetDotenv();
3273
3275
  }
3274
3276
  loadedEnvFiles.length = 0;
@@ -3277,9 +3279,10 @@ function loadDotenv(projectRoot, options = {}) {
3277
3279
  if (projectRoot) {
3278
3280
  loadEnvFile(getProjectDotenvPath(projectRoot));
3279
3281
  }
3280
- loadEnvFile(getGlobalDotenvPath(options.userHomeDir ?? homedir4()));
3282
+ loadEnvFile(getGlobalDotenvPath(userHomeDir));
3281
3283
  dotenvLoaded = true;
3282
- dotenvProjectRoot = projectRoot ?? null;
3284
+ dotenvProjectRoot = normalizedProjectRoot;
3285
+ dotenvHomeDir = userHomeDir;
3283
3286
  }
3284
3287
  function resetDotenv() {
3285
3288
  for (const key of injectedKeys) {
@@ -3288,6 +3291,7 @@ function resetDotenv() {
3288
3291
  injectedKeys.clear();
3289
3292
  dotenvLoaded = false;
3290
3293
  dotenvProjectRoot = null;
3294
+ dotenvHomeDir = null;
3291
3295
  loadedEnvFiles.length = 0;
3292
3296
  loadedEnvKeys.clear();
3293
3297
  }
@@ -3300,7 +3304,7 @@ function getLoadedEnvKeys() {
3300
3304
  function getLoadedEnvValue(key) {
3301
3305
  return loadedEnvValues.get(key);
3302
3306
  }
3303
- var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
3307
+ var dotenvLoaded, dotenvProjectRoot, dotenvHomeDir, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
3304
3308
  var init_dotenv_loader = __esm({
3305
3309
  "src/config/dotenv-loader.ts"() {
3306
3310
  "use strict";
@@ -3308,6 +3312,7 @@ var init_dotenv_loader = __esm({
3308
3312
  init_config_paths();
3309
3313
  dotenvLoaded = false;
3310
3314
  dotenvProjectRoot = null;
3315
+ dotenvHomeDir = null;
3311
3316
  loadedEnvFiles = [];
3312
3317
  loadedEnvKeys = /* @__PURE__ */ new Set();
3313
3318
  loadedEnvValues = /* @__PURE__ */ new Map();
@@ -3659,33 +3664,33 @@ __export(config_exports, {
3659
3664
  resetConfigCache: () => resetConfigCache,
3660
3665
  resetDotenv: () => resetDotenv
3661
3666
  });
3662
- function getLLMApiKey() {
3663
- return getResolvedMemoryLane().llm.apiKey;
3667
+ function getLLMApiKey(options = {}) {
3668
+ return getResolvedMemoryLane(options).llm.apiKey;
3664
3669
  }
3665
- function getLLMProvider() {
3666
- const provider2 = getResolvedMemoryLane().llm.provider;
3670
+ function getLLMProvider(options = {}) {
3671
+ const provider2 = getResolvedMemoryLane(options).llm.provider;
3667
3672
  if (provider2) return provider2;
3668
3673
  if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return "anthropic";
3669
3674
  if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return "openrouter";
3670
3675
  return "openai";
3671
3676
  }
3672
- function getLLMModel(providerDefault) {
3673
- return getResolvedMemoryLane().llm.model || providerDefault;
3677
+ function getLLMModel(providerDefault, options = {}) {
3678
+ return getResolvedMemoryLane(options).llm.model || providerDefault;
3674
3679
  }
3675
- function getLLMBaseUrl(providerDefault) {
3676
- return getResolvedMemoryLane().llm.baseUrl || providerDefault;
3680
+ function getLLMBaseUrl(providerDefault, options = {}) {
3681
+ return getResolvedMemoryLane(options).llm.baseUrl || providerDefault;
3677
3682
  }
3678
- function getAgentLLMApiKey() {
3679
- return getResolvedAgentLane().apiKey;
3683
+ function getAgentLLMApiKey(options = {}) {
3684
+ return getResolvedAgentLane(options).apiKey;
3680
3685
  }
3681
- function getAgentLLMProvider() {
3682
- return getResolvedAgentLane().provider || getLLMProvider();
3686
+ function getAgentLLMProvider(options = {}) {
3687
+ return getResolvedAgentLane(options).provider || getLLMProvider(options);
3683
3688
  }
3684
- function getAgentLLMModel(providerDefault) {
3685
- return getResolvedAgentLane().model || getLLMModel(providerDefault);
3689
+ function getAgentLLMModel(providerDefault, options = {}) {
3690
+ return getResolvedAgentLane(options).model || getLLMModel(providerDefault, options);
3686
3691
  }
3687
- function getAgentLLMBaseUrl(providerDefault) {
3688
- return getResolvedAgentLane().baseUrl || getLLMBaseUrl(providerDefault);
3692
+ function getAgentLLMBaseUrl(providerDefault, options = {}) {
3693
+ return getResolvedAgentLane(options).baseUrl || getLLMBaseUrl(providerDefault, options);
3689
3694
  }
3690
3695
  function getEmbeddingMode() {
3691
3696
  const provider2 = getResolvedEmbeddingLane().provider?.toLowerCase()?.trim();
@@ -5944,18 +5949,19 @@ async function* callLLMWithToolsStream(messages, tools) {
5944
5949
  }
5945
5950
  function initLLM(options = {}) {
5946
5951
  const scope = options.scope ?? "memory";
5947
- const apiKey = scope === "agent" ? getAgentLLMApiKey() : getLLMApiKey();
5952
+ const configOptions = { projectRoot: options.projectRoot, homeDir: options.homeDir };
5953
+ const apiKey = scope === "agent" ? getAgentLLMApiKey(configOptions) : getLLMApiKey(configOptions);
5948
5954
  if (!apiKey) {
5949
5955
  currentConfig = null;
5950
5956
  return null;
5951
5957
  }
5952
- const provider2 = scope === "agent" ? getAgentLLMProvider() : getLLMProvider();
5958
+ const provider2 = scope === "agent" ? getAgentLLMProvider(configOptions) : getLLMProvider(configOptions);
5953
5959
  const defaults2 = PROVIDER_DEFAULTS[provider2] ?? PROVIDER_DEFAULTS.openai;
5954
5960
  currentConfig = {
5955
5961
  provider: provider2,
5956
5962
  apiKey,
5957
- model: scope === "agent" ? getAgentLLMModel(defaults2.model) : getLLMModel(defaults2.model),
5958
- baseUrl: scope === "agent" ? getAgentLLMBaseUrl(defaults2.baseUrl) : getLLMBaseUrl(defaults2.baseUrl)
5963
+ model: scope === "agent" ? getAgentLLMModel(defaults2.model, configOptions) : getLLMModel(defaults2.model, configOptions),
5964
+ baseUrl: scope === "agent" ? getAgentLLMBaseUrl(defaults2.baseUrl, configOptions) : getLLMBaseUrl(defaults2.baseUrl, configOptions)
5959
5965
  };
5960
5966
  return currentConfig;
5961
5967
  }
@@ -65975,11 +65981,11 @@ var require_bignumber = __commonJS({
65975
65981
  return n > 0 || n === i2 ? i2 : i2 - 1;
65976
65982
  }
65977
65983
  function coeffToString(a) {
65978
- var s2, z627, i2 = 1, j = a.length, r2 = a[0] + "";
65984
+ var s2, z628, i2 = 1, j = a.length, r2 = a[0] + "";
65979
65985
  for (; i2 < j; ) {
65980
65986
  s2 = a[i2++] + "";
65981
- z627 = LOG_BASE - s2.length;
65982
- for (; z627--; s2 = "0" + s2) ;
65987
+ z628 = LOG_BASE - s2.length;
65988
+ for (; z628--; s2 = "0" + s2) ;
65983
65989
  r2 += s2;
65984
65990
  }
65985
65991
  for (j = r2.length; r2.charCodeAt(--j) === 48; ) ;
@@ -66012,15 +66018,15 @@ var require_bignumber = __commonJS({
66012
66018
  function toExponential(str2, e2) {
66013
66019
  return (str2.length > 1 ? str2.charAt(0) + "." + str2.slice(1) : str2) + (e2 < 0 ? "e" : "e+") + e2;
66014
66020
  }
66015
- function toFixedPoint(str2, e2, z627) {
66021
+ function toFixedPoint(str2, e2, z628) {
66016
66022
  var len, zs;
66017
66023
  if (e2 < 0) {
66018
- for (zs = z627 + "."; ++e2; zs += z627) ;
66024
+ for (zs = z628 + "."; ++e2; zs += z628) ;
66019
66025
  str2 = zs + str2;
66020
66026
  } else {
66021
66027
  len = str2.length;
66022
66028
  if (++e2 > len) {
66023
- for (zs = z627, e2 -= len; --e2; zs += z627) ;
66029
+ for (zs = z628, e2 -= len; --e2; zs += z628) ;
66024
66030
  str2 += zs;
66025
66031
  } else if (e2 < len) {
66026
66032
  str2 = str2.slice(0, e2) + "." + str2.slice(e2);
@@ -155820,6 +155826,27 @@ function unavailableHealth(result) {
155820
155826
  if (result.outputLimited) return { state: "invalid", reason: "A local CodeGraph response exceeded the safety limit." };
155821
155827
  return { state: "unavailable", reason: "A local CodeGraph command did not complete." };
155822
155828
  }
155829
+ function notAttemptedDiagnostic(command) {
155830
+ return { command, attempted: false, outcome: "not-attempted" };
155831
+ }
155832
+ function commandDiagnostic(command, result, outcome, reason) {
155833
+ return {
155834
+ command,
155835
+ attempted: true,
155836
+ outcome,
155837
+ ...typeof result.exitCode === "number" ? { exitCode: result.exitCode } : {},
155838
+ ...reason ? { reason: sanitizeCredentials(reason).slice(0, 240) } : {}
155839
+ };
155840
+ }
155841
+ function failedCommandDiagnostic(command, result) {
155842
+ const outcome = result.timedOut ? "timed-out" : result.outputLimited ? "output-limited" : "failed";
155843
+ return commandDiagnostic(
155844
+ command,
155845
+ result,
155846
+ outcome,
155847
+ result.error || result.stderr || "CodeGraph command did not complete."
155848
+ );
155849
+ }
155823
155850
  async function runSafely(runner, input) {
155824
155851
  try {
155825
155852
  return await runner.run(input);
@@ -155969,6 +155996,7 @@ function parseOutline(value, projectRoot, exclude) {
155969
155996
  if (nodes.some((node) => !node)) return void 0;
155970
155997
  const byId = /* @__PURE__ */ new Map();
155971
155998
  for (const node of nodes) {
155999
+ if (byId.has(node.id)) return void 0;
155972
156000
  byId.set(node.id, externalSymbol(node));
155973
156001
  }
155974
156002
  const entryPoints = value.entryPoints.map((item) => parseNode(item, projectRoot, exclude)).filter((node) => Boolean(node)).map(externalSymbol).filter((node, index, items) => items.findIndex((item) => item.id === node.id) === index).slice(0, 5);
@@ -155982,7 +156010,7 @@ function parseOutline(value, projectRoot, exclude) {
155982
156010
  if (!source || !target || !kind || rawEdge.line !== void 0 && (!line || line < 1)) return void 0;
155983
156011
  const from = byId.get(source);
155984
156012
  const to = byId.get(target);
155985
- if (!from || !to) continue;
156013
+ if (!from || !to) return void 0;
155986
156014
  relations.push({ from, to, kind, ...line ? { line } : {} });
155987
156015
  }
155988
156016
  const relatedFiles = value.relatedFiles.map((item) => safeRelativePath(projectRoot, item, exclude));
@@ -156000,45 +156028,234 @@ function parseOutline(value, projectRoot, exclude) {
156000
156028
  stats: { nodes: nodeCount, edges: edgeCount, files: fileCount }
156001
156029
  };
156002
156030
  }
156031
+ function parseTextLocation(value) {
156032
+ const match2 = value.trim().match(/^(.*?)(?::([1-9]\d*))?$/);
156033
+ if (!match2?.[1]) return void 0;
156034
+ return {
156035
+ filePath: match2[1].trim(),
156036
+ ...match2[2] ? { line: Number(match2[2]) } : {}
156037
+ };
156038
+ }
156039
+ function parseExploreText(value, projectRoot, exclude) {
156040
+ if (!value.trim() || Buffer.byteLength(value, "utf8") > MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES) return void 0;
156041
+ const entryPoints = [];
156042
+ const nodes = [];
156043
+ const relatedFiles = /* @__PURE__ */ new Set();
156044
+ const byName = /* @__PURE__ */ new Map();
156045
+ let section = null;
156046
+ let relationKind = "references";
156047
+ const addNode = (node, entry) => {
156048
+ const key = `${node.filePath}\0${node.name}`;
156049
+ const existing = byName.get(key);
156050
+ if (existing) return;
156051
+ byName.set(key, node);
156052
+ relatedFiles.add(node.filePath);
156053
+ (entry ? entryPoints : nodes).push(node);
156054
+ };
156055
+ for (const rawLine of value.split(/\r?\n/)) {
156056
+ const line = rawLine.trim();
156057
+ const fileHeader = line.match(/^\*\*`([^`]+)`\*\*\s+(?:—|-)\s+(.+)$/);
156058
+ if (fileHeader) {
156059
+ const filePath = safeRelativePath(projectRoot, fileHeader[1], exclude);
156060
+ if (!filePath) return void 0;
156061
+ const symbolText = fileHeader[2].split(/\s+·\s+/, 1)[0] ?? "";
156062
+ const symbols = [...symbolText.matchAll(/([^,]+?)\(([^()]+)\)/g)];
156063
+ if (symbols.length === 0) return void 0;
156064
+ const isFirstFile = entryPoints.length === 0 && nodes.length === 0;
156065
+ for (const symbol of symbols.slice(0, MAX_EXTERNAL_NODE_COUNT)) {
156066
+ const name = symbol[1]?.trim();
156067
+ const kind = symbol[2]?.trim();
156068
+ if (!name || !kind) return void 0;
156069
+ addNode({
156070
+ id: `explore:${filePath}:${name}`,
156071
+ kind,
156072
+ name,
156073
+ filePath
156074
+ }, isFirstFile);
156075
+ }
156076
+ section = null;
156077
+ continue;
156078
+ }
156079
+ if (/^#{2,3}\s+Entry Points?\b/i.test(line)) {
156080
+ section = "entry";
156081
+ continue;
156082
+ }
156083
+ if (/^#{2,3}\s+Related Symbols?\b/i.test(line)) {
156084
+ section = "related";
156085
+ continue;
156086
+ }
156087
+ if (/^\*\*Relationships\*\*$/i.test(line)) {
156088
+ section = "relationships";
156089
+ continue;
156090
+ }
156091
+ if (/^\*\*(?:Source Code|Code)\*\*$/i.test(line) || /^#{2,3}\s+/i.test(line)) {
156092
+ section = null;
156093
+ continue;
156094
+ }
156095
+ if (section === "entry") {
156096
+ const match2 = line.match(/^-\s+\*\*(.+?)\*\*\s+\(([^)]+)\)\s+-\s+(.+)$/);
156097
+ if (!match2) continue;
156098
+ const location = parseTextLocation(match2[3]);
156099
+ if (!location) return void 0;
156100
+ const filePath = safeRelativePath(projectRoot, location.filePath, exclude);
156101
+ if (!filePath) return void 0;
156102
+ addNode({
156103
+ id: `explore:${filePath}:${match2[1]}`,
156104
+ kind: match2[2],
156105
+ name: match2[1],
156106
+ filePath,
156107
+ ...location.line ? { startLine: location.line, endLine: location.line } : {}
156108
+ }, true);
156109
+ continue;
156110
+ }
156111
+ if (section === "related") {
156112
+ const match2 = line.match(/^-\s+([^:]+):\s+(.+)$/);
156113
+ if (!match2) continue;
156114
+ const filePath = safeRelativePath(projectRoot, match2[1], exclude);
156115
+ if (!filePath) return void 0;
156116
+ relatedFiles.add(filePath);
156117
+ for (const rawSymbol of match2[2].split(",")) {
156118
+ const symbol = rawSymbol.trim().match(/^(.+?)(?::([1-9]\d*))?$/);
156119
+ if (!symbol?.[1]) return void 0;
156120
+ addNode({
156121
+ id: `explore:${filePath}:${symbol[1].trim()}`,
156122
+ kind: "unknown",
156123
+ name: symbol[1].trim(),
156124
+ filePath,
156125
+ ...symbol[2] ? { startLine: Number(symbol[2]), endLine: Number(symbol[2]) } : {}
156126
+ }, false);
156127
+ }
156128
+ continue;
156129
+ }
156130
+ if (section === "relationships") {
156131
+ const kind = line.match(/^\*\*([^*]+):\*\*$/);
156132
+ if (kind?.[1]) {
156133
+ relationKind = kind[1].trim();
156134
+ continue;
156135
+ }
156136
+ }
156137
+ }
156138
+ const bySymbolName = /* @__PURE__ */ new Map();
156139
+ for (const node of [...entryPoints, ...nodes]) {
156140
+ if (!bySymbolName.has(node.name)) bySymbolName.set(node.name, node);
156141
+ }
156142
+ const relations = [];
156143
+ if (section === "relationships") {
156144
+ for (const rawLine of value.split(/\r?\n/)) {
156145
+ const line = rawLine.trim();
156146
+ const match2 = line.match(/^-\s+(.+?)\s+(?:\u2192|->)\s+(.+)$/);
156147
+ if (!match2) continue;
156148
+ const from = bySymbolName.get(match2[1].trim());
156149
+ const to = bySymbolName.get(match2[2].trim());
156150
+ if (!from || !to) continue;
156151
+ relations.push({
156152
+ from: externalSymbol(from),
156153
+ to: externalSymbol(to),
156154
+ kind: relationKind
156155
+ });
156156
+ }
156157
+ } else {
156158
+ const relationshipStart = value.split(/\r?\n/).findIndex((line) => /^\s*\*\*Relationships\*\*\s*$/i.test(line));
156159
+ if (relationshipStart >= 0) {
156160
+ const relationshipLines = value.split(/\r?\n/).slice(relationshipStart + 1);
156161
+ for (const rawLine of relationshipLines) {
156162
+ const line = rawLine.trim();
156163
+ if (/^\*\*(?:Source Code|Code)\*\*$/i.test(line) || /^#{2,3}\s+/i.test(line)) break;
156164
+ const kind = line.match(/^\*\*([^*]+):\*\*$/);
156165
+ if (kind?.[1]) {
156166
+ relationKind = kind[1].trim();
156167
+ continue;
156168
+ }
156169
+ const match2 = line.match(/^-\s+(.+?)\s+(?:\u2192|->)\s+(.+)$/);
156170
+ if (!match2) continue;
156171
+ const from = bySymbolName.get(match2[1].trim());
156172
+ const to = bySymbolName.get(match2[2].trim());
156173
+ if (from && to) relations.push({ from: externalSymbol(from), to: externalSymbol(to), kind: relationKind });
156174
+ }
156175
+ }
156176
+ }
156177
+ const allNodes = [...entryPoints, ...nodes];
156178
+ if (allNodes.length === 0) return void 0;
156179
+ return {
156180
+ provider: "external",
156181
+ entryPoints: entryPoints.map(externalSymbol).slice(0, 5),
156182
+ relations: relations.slice(0, 6),
156183
+ relatedFiles: [...relatedFiles].slice(0, 5),
156184
+ stats: {
156185
+ nodes: allNodes.length,
156186
+ edges: relations.length,
156187
+ files: relatedFiles.size
156188
+ }
156189
+ };
156190
+ }
156191
+ function parseExplorePayload(value, projectRoot, exclude) {
156192
+ if (typeof value === "string") return parseExploreText(value, projectRoot, exclude);
156193
+ if (isRecord3(value) && isRecord3(value.result)) value = value.result;
156194
+ if (isRecord3(value) && Array.isArray(value.content)) {
156195
+ const text2 = value.content.filter((item) => isRecord3(item) && item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n");
156196
+ return parseExploreText(text2, projectRoot, exclude);
156197
+ }
156198
+ return parseOutline(value, projectRoot, exclude);
156199
+ }
156003
156200
  function fallbackCaution(health) {
156004
156201
  if (health.state === "disabled" || health.state === "not-detected" || health.state === "not-initialized" || health.state === "ready") return void 0;
156005
156202
  return "External semantic CodeGraph is " + health.state + "; using Lite structural evidence for this brief.";
156006
156203
  }
156204
+ function queryFallbackCaution(diagnostics) {
156205
+ return `External semantic CodeGraph context was unavailable (context: ${diagnostics.context.outcome}; explore: ${diagnostics.explore.outcome}); using Lite structural evidence.`;
156206
+ }
156007
156207
  async function getExternalCodeGraphContext(input) {
156008
156208
  const inspected = await inspectExternalCodeGraph(input);
156009
156209
  if (inspected.health.state !== "ready") {
156010
156210
  return { ...inspected, caution: fallbackCaution(inspected.health) };
156011
156211
  }
156012
156212
  const mode = input.mode ?? "auto";
156013
- const result = await runSafely(input.runner ?? defaultRunner, {
156213
+ const runner = input.runner ?? defaultRunner;
156214
+ const contextResult = await runSafely(runner, {
156014
156215
  command: input.command,
156015
156216
  args: ["context", "--path", input.projectRoot, "--format", "json", "--max-nodes", "8", "--no-code", input.task],
156016
156217
  cwd: input.projectRoot,
156017
156218
  timeoutMs: boundedTimeout(input.timeoutMs),
156018
156219
  maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
156019
156220
  });
156020
- if (!result.ok) {
156021
- const health = unavailableHealth(result);
156221
+ const diagnostics = {
156222
+ context: contextResult.ok ? commandDiagnostic("context", contextResult, "success") : failedCommandDiagnostic("context", contextResult),
156223
+ explore: notAttemptedDiagnostic("explore")
156224
+ };
156225
+ const contextOutline = contextResult.ok ? parseOutline(parseJson2(contextResult.stdout), input.projectRoot, input.exclude) : void 0;
156226
+ if (contextOutline && (contextOutline.entryPoints.length > 0 || contextOutline.relations.length > 0 || contextOutline.relatedFiles.length > 0)) {
156022
156227
  return {
156023
- health,
156024
- quality: providerQuality({ mode, health }),
156025
- caution: fallbackCaution(health)
156228
+ ...inspected,
156229
+ outline: contextOutline,
156230
+ diagnostics,
156231
+ quality: providerQuality({ mode, health: inspected.health, selected: "external" })
156026
156232
  };
156027
156233
  }
156028
- const outline = parseOutline(parseJson2(result.stdout), input.projectRoot, input.exclude);
156029
- if (!outline) {
156030
- const health = { state: "invalid", reason: "The local CodeGraph context payload failed validation." };
156234
+ if (contextResult.ok) diagnostics.context = commandDiagnostic("context", contextResult, "invalid-output", "The context payload failed validation or contained no safe outline.");
156235
+ const exploreResult = await runSafely(runner, {
156236
+ command: input.command,
156237
+ args: ["explore", "--path", input.projectRoot, "--max-files", "4", input.task],
156238
+ cwd: input.projectRoot,
156239
+ timeoutMs: boundedTimeout(input.timeoutMs),
156240
+ maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
156241
+ });
156242
+ diagnostics.explore = exploreResult.ok ? commandDiagnostic("explore", exploreResult, "success") : failedCommandDiagnostic("explore", exploreResult);
156243
+ const exploreOutline = exploreResult.ok ? parseExplorePayload(parseJson2(exploreResult.stdout) ?? exploreResult.stdout, input.projectRoot, input.exclude) : void 0;
156244
+ if (exploreOutline && (exploreOutline.entryPoints.length > 0 || exploreOutline.relations.length > 0 || exploreOutline.relatedFiles.length > 0)) {
156031
156245
  return {
156032
- health,
156033
- quality: providerQuality({ mode, health }),
156034
- caution: fallbackCaution(health)
156246
+ ...inspected,
156247
+ outline: exploreOutline,
156248
+ diagnostics,
156249
+ quality: providerQuality({ mode, health: inspected.health, selected: "external" })
156035
156250
  };
156036
156251
  }
156037
- const contributes = outline.entryPoints.length > 0 || outline.relations.length > 0 || outline.relatedFiles.length > 0;
156252
+ if (exploreResult.ok) diagnostics.explore = commandDiagnostic("explore", exploreResult, "invalid-output", "The explore payload failed validation or contained no safe outline.");
156253
+ const health = exploreResult.ok ? { state: "invalid", reason: "The local CodeGraph context and explore payloads failed validation." } : unavailableHealth(exploreResult);
156038
156254
  return {
156039
- ...inspected,
156040
- ...contributes ? { outline } : {},
156041
- quality: providerQuality({ mode, health: inspected.health, ...contributes ? { selected: "external" } : {} })
156255
+ health,
156256
+ quality: providerQuality({ mode, health }),
156257
+ diagnostics,
156258
+ caution: queryFallbackCaution(diagnostics)
156042
156259
  };
156043
156260
  }
156044
156261
  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;
@@ -156049,7 +156266,7 @@ var init_external_provider = __esm({
156049
156266
  init_secret_filter();
156050
156267
  init_exclude3();
156051
156268
  init_ids();
156052
- DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 1200;
156269
+ DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 3e3;
156053
156270
  MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 5e3;
156054
156271
  EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS = 3e4;
156055
156272
  MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES = 256 * 1024;
@@ -159332,6 +159549,7 @@ async function executeCleanup(context, payload, token) {
159332
159549
  return { action: "cleanup", projectId: context.projectId, ...result };
159333
159550
  }
159334
159551
  async function previewDeduplicate(context) {
159552
+ initLLM({ scope: "memory", projectRoot: context.projectRoot });
159335
159553
  if (!isLLMEnabled()) {
159336
159554
  return {
159337
159555
  action: "deduplicate",
@@ -160824,6 +161042,37 @@ function normalizeDashboardTask(task) {
160824
161042
  preferredRole: task.preferred_role ?? task.preferredRole ?? null
160825
161043
  };
160826
161044
  }
161045
+ function emptyTeamSnapshot(mode, scope, status) {
161046
+ return {
161047
+ status,
161048
+ mode,
161049
+ readOnly: true,
161050
+ scope,
161051
+ agents: [],
161052
+ activeCount: 0,
161053
+ recentCount: 0,
161054
+ historicalCount: 0,
161055
+ totalAgents: 0,
161056
+ recentWindowDays: 7,
161057
+ locks: [],
161058
+ tasks: [],
161059
+ availableTasks: 0,
161060
+ sessions: 0,
161061
+ roles: [],
161062
+ roleOccupancy: [],
161063
+ handoffs: [],
161064
+ openTasks: 0,
161065
+ openHandoffs: 0,
161066
+ totalUnread: 0,
161067
+ activeSessions: 0,
161068
+ error: status === "error" ? "Coordination state unavailable" : "Coordination state is incomplete",
161069
+ errorCode: status === "error" ? "COORDINATION_STATE_UNAVAILABLE" : "COORDINATION_STATE_DEGRADED"
161070
+ };
161071
+ }
161072
+ function logTeamSnapshotFailure(scope, status) {
161073
+ const safeScope = scope === "global" ? "global" : "project";
161074
+ console.error("[dashboard] coordination snapshot unavailable", { status, scope: safeScope });
161075
+ }
160827
161076
  async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
160828
161077
  try {
160829
161078
  const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
@@ -160850,8 +161099,9 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
160850
161099
  const roleOccupancy = effectiveProjectId ? teamStore.getRoleOccupancy(effectiveProjectId) : [];
160851
161100
  const handoffs = effectiveProjectId ? teamStore.listHandoffs(effectiveProjectId) : [];
160852
161101
  return {
161102
+ status: "ok",
160853
161103
  mode,
160854
- readOnly: mode === "standalone",
161104
+ readOnly: true,
160855
161105
  scope,
160856
161106
  agents: withTier,
160857
161107
  activeCount,
@@ -160872,28 +161122,8 @@ async function buildTeamSnapshot(dataDir, projectId, scope, mode) {
160872
161122
  activeSessions: activeCount
160873
161123
  };
160874
161124
  } catch {
160875
- return {
160876
- mode,
160877
- readOnly: mode === "standalone",
160878
- scope,
160879
- agents: [],
160880
- activeCount: 0,
160881
- recentCount: 0,
160882
- historicalCount: 0,
160883
- totalAgents: 0,
160884
- recentWindowDays: 7,
160885
- locks: [],
160886
- tasks: [],
160887
- availableTasks: 0,
160888
- sessions: 0,
160889
- roles: [],
160890
- roleOccupancy: [],
160891
- handoffs: [],
160892
- openTasks: 0,
160893
- openHandoffs: 0,
160894
- totalUnread: 0,
160895
- activeSessions: 0
160896
- };
161125
+ logTeamSnapshotFailure(scope, "error");
161126
+ return emptyTeamSnapshot(mode, scope, "error");
160897
161127
  }
160898
161128
  }
160899
161129
  function readBody(req) {
@@ -160912,13 +161142,12 @@ function readBody(req) {
160912
161142
  req.on("error", reject);
160913
161143
  });
160914
161144
  }
160915
- async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true, teamInstances, projectRoot = null, projectResolved = true) {
161145
+ async function startDashboard(dataDir, port, staticDir, projectId, projectName, autoOpen = true, projectRoot = null, projectResolved = true) {
160916
161146
  await initObservationStore(dataDir);
160917
161147
  await initSessionStore(dataDir);
160918
161148
  const resolvedStaticDir = staticDir;
160919
161149
  const baseDir = getBaseDataDir();
160920
- const isControlPlane = !!teamInstances;
160921
- const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: isControlPlane ? "control-plane" : "standalone", port };
161150
+ const state = { projectId, projectName, dataDir, projectRoot, projectResolved, mode: "standalone", port };
160922
161151
  const server = createServer(async (req, res) => {
160923
161152
  const url = req.url || "/";
160924
161153
  if (url.startsWith("/api/set-current-project") && req.method === "POST") {
@@ -160940,54 +161169,20 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
160940
161169
  }
160941
161170
  return;
160942
161171
  }
160943
- if (url.startsWith("/api/team")) {
160944
- if (!teamInstances) {
160945
- const parsedUrl = new URL(url, `http://127.0.0.1:${port}`);
160946
- const scope = parsedUrl.searchParams.get("scope") || "project";
160947
- sendJson(res, await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode));
160948
- return;
160949
- }
160950
- try {
160951
- teamInstances.fileLocks.cleanExpired();
160952
- const agents = teamInstances.registry.listAgents();
160953
- const locks = teamInstances.fileLocks.listLocks();
160954
- const tasks = teamInstances.taskManager.list();
160955
- const available = teamInstances.taskManager.getAvailable();
160956
- let roles = [];
160957
- let roleOccupancy = [];
160958
- let handoffs = [];
160959
- try {
160960
- const { getTeamStore: getTeamStore2, isTeamStoreInitialized: isTeamStoreInitialized2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
160961
- if (isTeamStoreInitialized2()) {
160962
- const teamStore = getTeamStore2();
160963
- const projectId2 = state.projectId;
160964
- roles = teamStore.listRoles(projectId2);
160965
- roleOccupancy = teamStore.getRoleOccupancy(projectId2);
160966
- handoffs = teamStore.listHandoffs(projectId2);
160967
- }
160968
- } catch {
160969
- }
161172
+ const parsedUrl = new URL(url, `http://127.0.0.1:${port}`);
161173
+ if (parsedUrl.pathname === "/api/team") {
161174
+ if (req.method !== "GET") {
160970
161175
  sendJson(res, {
160971
- agents: agents.map((a) => ({
160972
- ...a,
160973
- unread: teamInstances.messageBus.getUnreadCount(a.id)
160974
- })),
160975
- activeCount: teamInstances.registry.getActiveCount(),
160976
- locks,
160977
- tasks,
160978
- availableTasks: available.length,
160979
- roles,
160980
- roleOccupancy,
160981
- handoffs,
160982
- // Resume data for "Continue this project" area
160983
- openTasks: tasks.filter((t2) => t2.status === "pending" || t2.status === "in_progress").length,
160984
- openHandoffs: handoffs.filter((h2) => h2.handoff_status === "open" || h2.handoffStatus === "open").length,
160985
- totalUnread: agents.reduce((sum, a) => sum + teamInstances.messageBus.getUnreadCount(a.id), 0),
160986
- activeSessions: agents.filter((a) => a.status === "active").length
160987
- });
160988
- } catch {
160989
- sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0, roles: [], roleOccupancy: [], handoffs: [] });
161176
+ status: "error",
161177
+ readOnly: true,
161178
+ error: "Coordination status is read-only",
161179
+ errorCode: "COORDINATION_STATUS_READ_ONLY"
161180
+ }, 405);
161181
+ return;
160990
161182
  }
161183
+ const scope = parsedUrl.searchParams.get("scope") || "project";
161184
+ const snapshot = await buildTeamSnapshot(state.dataDir, state.projectId, scope, state.mode);
161185
+ sendJson(res, snapshot, snapshot.status === "error" ? 503 : 200);
160991
161186
  return;
160992
161187
  }
160993
161188
  if (url.startsWith("/api/")) {
@@ -161008,13 +161203,12 @@ async function startDashboard(dataDir, port, staticDir, projectId, projectName,
161008
161203
  server.listen(port, "127.0.0.1", () => {
161009
161204
  const url = `http://127.0.0.1:${port}`;
161010
161205
  const resolvedLabel = projectResolved ? "resolved" : "unresolved";
161011
- const modeLabel = isControlPlane ? "Control Plane" : "Standalone";
161206
+ const modeLabel = "Standalone";
161012
161207
  console.error(` Memorix Dashboard [${modeLabel}]`);
161013
161208
  console.error(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
161014
161209
  console.error(` Mode: ${modeLabel}`);
161015
161210
  console.error(` Project: ${projectName} (${projectId}) [${resolvedLabel}]`);
161016
161211
  console.error(` Local: ${url}`);
161017
- if (isControlPlane) console.error(` MCP: ${url}/mcp`);
161018
161212
  console.error(` Data dir: ${dataDir}`);
161019
161213
  console.error(`
161020
161214
  Press Ctrl+C to stop
@@ -161112,7 +161306,7 @@ var init_event_bus = __esm({
161112
161306
  });
161113
161307
 
161114
161308
  // src/orchestrate/task-graph.ts
161115
- import { z as z625 } from "zod";
161309
+ import { z as z626 } from "zod";
161116
161310
  function parseTaskGraph(raw) {
161117
161311
  const json2 = extractJson(raw);
161118
161312
  if (!json2) {
@@ -161304,25 +161498,25 @@ var init_task_graph = __esm({
161304
161498
  "src/orchestrate/task-graph.ts"() {
161305
161499
  "use strict";
161306
161500
  init_esm_shims();
161307
- TaskNodeSchema = z625.object({
161308
- tempId: z625.string().min(1).describe('Temporary ID like "t1", "t2"'),
161309
- role: z625.enum(["pm", "engineer", "qa", "reviewer"]),
161310
- description: z625.string().min(30).describe("Self-contained task description with all context"),
161311
- deps: z625.array(z625.string()).describe("tempIds of prerequisite tasks"),
161312
- files: z625.array(z625.string()).optional().describe("Files this task will create or modify"),
161501
+ TaskNodeSchema = z626.object({
161502
+ tempId: z626.string().min(1).describe('Temporary ID like "t1", "t2"'),
161503
+ role: z626.enum(["pm", "engineer", "qa", "reviewer"]),
161504
+ description: z626.string().min(30).describe("Self-contained task description with all context"),
161505
+ deps: z626.array(z626.string()).describe("tempIds of prerequisite tasks"),
161506
+ files: z626.array(z626.string()).optional().describe("Files this task will create or modify"),
161313
161507
  /** Phase 7: Natural-language acceptance criteria (Goal-First Testing) */
161314
- goals: z625.array(z625.string()).optional().describe("Acceptance criteria for task verification")
161508
+ goals: z626.array(z626.string()).optional().describe("Acceptance criteria for task verification")
161315
161509
  });
161316
- TaskGraphSchema = z625.object({
161317
- summary: z625.string().min(10).describe("One-paragraph plan summary"),
161318
- tasks: z625.array(TaskNodeSchema).min(2).max(30)
161510
+ TaskGraphSchema = z626.object({
161511
+ summary: z626.string().min(10).describe("One-paragraph plan summary"),
161512
+ tasks: z626.array(TaskNodeSchema).min(2).max(30)
161319
161513
  }).superRefine((data, ctx) => {
161320
161514
  const ids = new Set(data.tasks.map((t2) => t2.tempId));
161321
161515
  for (const task of data.tasks) {
161322
161516
  for (const dep of task.deps) {
161323
161517
  if (!ids.has(dep)) {
161324
161518
  ctx.addIssue({
161325
- code: z625.ZodIssueCode.custom,
161519
+ code: z626.ZodIssueCode.custom,
161326
161520
  message: `Task "${task.tempId}" references unknown dependency "${dep}"`,
161327
161521
  path: ["tasks"]
161328
161522
  });
@@ -161330,7 +161524,7 @@ var init_task_graph = __esm({
161330
161524
  }
161331
161525
  if (task.deps.includes(task.tempId)) {
161332
161526
  ctx.addIssue({
161333
- code: z625.ZodIssueCode.custom,
161527
+ code: z626.ZodIssueCode.custom,
161334
161528
  message: `Task "${task.tempId}" depends on itself`,
161335
161529
  path: ["tasks"]
161336
161530
  });
@@ -161338,21 +161532,21 @@ var init_task_graph = __esm({
161338
161532
  }
161339
161533
  if (data.tasks.length > 0 && data.tasks[data.tasks.length - 1].role !== "reviewer") {
161340
161534
  ctx.addIssue({
161341
- code: z625.ZodIssueCode.custom,
161535
+ code: z626.ZodIssueCode.custom,
161342
161536
  message: 'Last task must have role "reviewer"',
161343
161537
  path: ["tasks"]
161344
161538
  });
161345
161539
  }
161346
161540
  if (hasCycle(data.tasks)) {
161347
161541
  ctx.addIssue({
161348
- code: z625.ZodIssueCode.custom,
161542
+ code: z626.ZodIssueCode.custom,
161349
161543
  message: "Task graph contains a cycle",
161350
161544
  path: ["tasks"]
161351
161545
  });
161352
161546
  }
161353
161547
  if (ids.size !== data.tasks.length) {
161354
161548
  ctx.addIssue({
161355
- code: z625.ZodIssueCode.custom,
161549
+ code: z626.ZodIssueCode.custom,
161356
161550
  message: "Duplicate tempId values detected",
161357
161551
  path: ["tasks"]
161358
161552
  });
@@ -163820,7 +164014,7 @@ init_mini_skill_store();
163820
164014
  init_session_store();
163821
164015
  import { createHash as createHash16 } from "crypto";
163822
164016
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
163823
- import { z as z626 } from "zod";
164017
+ import { z as z627 } from "zod";
163824
164018
 
163825
164019
  // src/memory/attribution-guard.ts
163826
164020
  init_esm_shims();
@@ -167608,6 +167802,45 @@ function createProjectBindingController(projectRoot) {
167608
167802
  return new ProjectBindingController(projectRoot);
167609
167803
  }
167610
167804
 
167805
+ // src/server/mcp-compat.ts
167806
+ init_esm_shims();
167807
+ import { RequestSchema } from "@modelcontextprotocol/sdk/types.js";
167808
+ import { z as z625 } from "zod/v4";
167809
+ var MCP_MODERN_PROTOCOL_VERSION = "2026-07-28";
167810
+ var MCP_LEGACY_PROTOCOL_VERSION = "2025-11-25";
167811
+ var MCP_OLDEST_LEGACY_PROTOCOL_VERSION = "2024-11-05";
167812
+ var MCP_SERVER_DISCOVER_METHOD = "server/discover";
167813
+ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
167814
+ var ServerDiscoverRequestSchema = RequestSchema.extend({
167815
+ method: z625.literal(MCP_SERVER_DISCOVER_METHOD),
167816
+ params: z625.looseObject({}).optional()
167817
+ });
167818
+ var registeredServers = /* @__PURE__ */ new WeakSet();
167819
+ function buildMcpDiscoverResult(server, serverInfo) {
167820
+ const getCapabilities = server.server.getCapabilities.bind(server.server);
167821
+ return {
167822
+ resultType: "complete",
167823
+ supportedVersions: [
167824
+ MCP_MODERN_PROTOCOL_VERSION,
167825
+ MCP_LEGACY_PROTOCOL_VERSION,
167826
+ MCP_OLDEST_LEGACY_PROTOCOL_VERSION
167827
+ ],
167828
+ capabilities: getCapabilities(),
167829
+ _meta: {
167830
+ [MCP_SERVER_INFO_META_KEY]: { ...serverInfo }
167831
+ },
167832
+ // v1 has no response-cache negotiation. A zero private TTL is the
167833
+ // conservative result and prevents clients from inventing a shared cache.
167834
+ ttlMs: 0,
167835
+ cacheScope: "private"
167836
+ };
167837
+ }
167838
+ function registerMcpDiscovery(server, serverInfo) {
167839
+ if (registeredServers.has(server)) return;
167840
+ server.server.setRequestHandler(ServerDiscoverRequestSchema, async () => buildMcpDiscoverResult(server, serverInfo));
167841
+ registeredServers.add(server);
167842
+ }
167843
+
167611
167844
  // src/server.ts
167612
167845
  var FORMATION_TIMEOUT_MS = parseFormationTimeoutMs(process.env.MEMORIX_FORMATION_TIMEOUT_MS);
167613
167846
  var COMPACT_ON_WRITE_TIMEOUT_MS = 12e3;
@@ -168005,10 +168238,12 @@ The path should point to a directory containing a .git folder.`
168005
168238
  isError: true
168006
168239
  };
168007
168240
  };
168008
- const server = existingServer ?? new McpServer({
168241
+ const serverInfo = {
168009
168242
  name: "memorix",
168010
- version: true ? "1.8.0" : "1.0.1"
168011
- });
168243
+ version: true ? "1.8.2" : "1.0.1"
168244
+ };
168245
+ const server = existingServer ?? new McpServer(serverInfo);
168246
+ registerMcpDiscovery(server, serverInfo);
168012
168247
  const originalRegisterTool = server.registerTool.bind(server);
168013
168248
  server.registerTool = ((name, ...args) => {
168014
168249
  if (!isToolInProfile(name, toolProfile)) {
@@ -168091,42 +168326,42 @@ The path should point to a directory containing a .git folder.`
168091
168326
  title: "Store Memory",
168092
168327
  description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. Set longTerm only when the caller explicitly wants an additional source-backed long-term candidate; it is never injected until an operator records a review through the CLI. For a read-only task, do not store unless the user explicitly asks to save a record.",
168093
168328
  inputSchema: {
168094
- entityName: z626.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
168095
- type: z626.enum(OBSERVATION_TYPES).describe("Observation type for classification"),
168096
- title: z626.string().describe("Short descriptive title (~5-10 words)"),
168097
- narrative: z626.string().describe("Full description of the observation"),
168098
- facts: z626.array(z626.string()).optional().describe('Structured facts (e.g., "Default timeout: 60s")'),
168099
- filesModified: z626.array(z626.string()).optional().describe("Files involved"),
168100
- concepts: z626.array(z626.string()).optional().describe("Related concepts/keywords"),
168101
- topicKey: z626.string().optional().describe(
168329
+ entityName: z627.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
168330
+ type: z627.enum(OBSERVATION_TYPES).describe("Observation type for classification"),
168331
+ title: z627.string().describe("Short descriptive title (~5-10 words)"),
168332
+ narrative: z627.string().describe("Full description of the observation"),
168333
+ facts: z627.array(z627.string()).optional().describe('Structured facts (e.g., "Default timeout: 60s")'),
168334
+ filesModified: z627.array(z627.string()).optional().describe("Files involved"),
168335
+ concepts: z627.array(z627.string()).optional().describe("Related concepts/keywords"),
168336
+ topicKey: z627.string().optional().describe(
168102
168337
  'Optional topic identifier for upserts (e.g., "architecture/auth-model"). If an observation with the same topicKey already exists in this project, it will be UPDATED instead of creating a new one. Use memorix_suggest_topic_key to generate a stable key. Good for evolving decisions, architecture docs, etc.'
168103
168338
  ),
168104
- progress: z626.object({
168105
- feature: z626.string().describe("Feature or task name"),
168106
- status: z626.enum(["in-progress", "completed", "blocked"]).describe("Current status"),
168107
- completion: z626.number().optional().describe("Completion percentage 0-100")
168339
+ progress: z627.object({
168340
+ feature: z627.string().describe("Feature or task name"),
168341
+ status: z627.enum(["in-progress", "completed", "blocked"]).describe("Current status"),
168342
+ completion: z627.number().optional().describe("Completion percentage 0-100")
168108
168343
  }).optional().describe("Progress tracking for task/feature observations"),
168109
- relatedCommits: z626.array(z626.string()).optional().describe("Git commit hashes this memory relates to (links ground truth \u2194 reasoning)"),
168110
- relatedEntities: z626.array(z626.string()).optional().describe("Other entity names this memory cross-references"),
168111
- visibility: z626.enum(["personal", "project", "team"]).optional().describe(
168344
+ relatedCommits: z627.array(z627.string()).optional().describe("Git commit hashes this memory relates to (links ground truth \u2194 reasoning)"),
168345
+ relatedEntities: z627.array(z627.string()).optional().describe("Other entity names this memory cross-references"),
168346
+ visibility: z627.enum(["personal", "project", "team"]).optional().describe(
168112
168347
  "Retrieval scope. Project is the normal shared default; personal/team require memorix_session_start with joinTeam=true."
168113
168348
  ),
168114
- longTerm: z626.object({
168115
- kind: z626.enum(["episodic", "semantic", "procedural"]).describe("Cognitive kind for an additional long-term candidate."),
168116
- scope: z626.enum(["project", "user", "team"]).optional().default("project").describe("Long-term scope. User capture is private source evidence and needs a bound agent identity."),
168117
- tags: z626.array(z626.string()).optional().describe("Small set of retrieval tags for the candidate."),
168118
- applicability: z626.string().optional().describe("When this durable fact or procedure applies.")
168349
+ longTerm: z627.object({
168350
+ kind: z627.enum(["episodic", "semantic", "procedural"]).describe("Cognitive kind for an additional long-term candidate."),
168351
+ scope: z627.enum(["project", "user", "team"]).optional().default("project").describe("Long-term scope. User capture is private source evidence and needs a bound agent identity."),
168352
+ tags: z627.array(z627.string()).optional().describe("Small set of retrieval tags for the candidate."),
168353
+ applicability: z627.string().optional().describe("When this durable fact or procedure applies.")
168119
168354
  }).optional().describe("Optional explicit request to create a source-backed long-term candidate alongside this observation. Candidates are not automatically injected."),
168120
- overrideReadOnly: z626.boolean().optional().describe(
168355
+ overrideReadOnly: z627.boolean().optional().describe(
168121
168356
  "Use only when the user explicitly asks to save memory during a read-only or no-modification task."
168122
168357
  ),
168123
- attachments: z626.array(z626.object({
168124
- modality: z626.enum(["image", "audio", "video", "document"]),
168125
- url: z626.string().describe(
168358
+ attachments: z627.array(z627.object({
168359
+ modality: z627.enum(["image", "audio", "video", "document"]),
168360
+ url: z627.string().describe(
168126
168361
  "Public HTTPS provenance reference without query parameters or fragments. Memorix does not fetch this URL: attachment metadata is persisted and BM25-searchable, while observation vectors remain text-only."
168127
168362
  ),
168128
- mimeType: z626.string().optional(),
168129
- name: z626.string().optional()
168363
+ mimeType: z627.string().optional(),
168364
+ name: z627.string().optional()
168130
168365
  })).optional().describe("Safe public provenance references. They are stored as metadata for lexical retrieval; raw inline media is never stored.")
168131
168366
  }
168132
168367
  },
@@ -168664,8 +168899,8 @@ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? `
168664
168899
  title: "Suggest Topic Key",
168665
168900
  description: 'Suggest a stable topic_key for memory upserts. Use this before memorix_store when you want evolving topics (like architecture decisions, config docs) to update a single observation over time instead of creating duplicates. Returns a key like "architecture/auth-model" or "bug/timeout-in-api-gateway".',
168666
168901
  inputSchema: {
168667
- type: z626.string().describe("Observation type (e.g., decision, architecture, bugfix, discovery)"),
168668
- title: z626.string().describe("Observation title \u2014 used to generate the stable key")
168902
+ type: z627.string().describe("Observation type (e.g., decision, architecture, bugfix, discovery)"),
168903
+ title: z627.string().describe("Observation title \u2014 used to generate the stable key")
168669
168904
  }
168670
168905
  },
168671
168906
  async ({ type: obsType, title }) => {
@@ -168690,28 +168925,28 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
168690
168925
  title: "Search Memory",
168691
168926
  description: "Search project memory. Returns a compact index (~50-100 tokens/result). Do not use as a follow-up to a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Use memorix_detail to fetch full content for specific IDs. Use memorix_timeline to see chronological context. Searches across all observations stored from any IDE session \u2014 enabling cross-session and cross-agent context retrieval.",
168692
168927
  inputSchema: {
168693
- query: z626.string().describe("Search query (natural language or keywords)"),
168694
- limit: z626.number().optional().describe("Max results (default: 20)"),
168695
- type: z626.enum(OBSERVATION_TYPES).optional().describe("Filter by observation type"),
168696
- maxTokens: z626.number().optional().describe("Token budget \u2014 trim results to fit (0 = unlimited)"),
168697
- scope: z626.enum(["project", "global"]).optional().default("project").describe(
168928
+ query: z627.string().describe("Search query (natural language or keywords)"),
168929
+ limit: z627.number().optional().describe("Max results (default: 20)"),
168930
+ type: z627.enum(OBSERVATION_TYPES).optional().describe("Filter by observation type"),
168931
+ maxTokens: z627.number().optional().describe("Token budget \u2014 trim results to fit (0 = unlimited)"),
168932
+ scope: z627.enum(["project", "global"]).optional().default("project").describe(
168698
168933
  'Search scope: "project" (default) only searches current project, "global" searches all projects'
168699
168934
  ),
168700
- since: z626.string().optional().describe('Only return observations created after this date (ISO 8601 or natural like "2025-01-15")'),
168701
- until: z626.string().optional().describe('Only return observations created before this date (ISO 8601 or natural like "2025-02-01")'),
168702
- status: z626.enum(["active", "resolved", "archived", "all"]).optional().default("active").describe(
168935
+ since: z627.string().optional().describe('Only return observations created after this date (ISO 8601 or natural like "2025-01-15")'),
168936
+ until: z627.string().optional().describe('Only return observations created before this date (ISO 8601 or natural like "2025-02-01")'),
168937
+ status: z627.enum(["active", "resolved", "archived", "all"]).optional().default("active").describe(
168703
168938
  'Filter by memory status. "active" (default) shows current memories, "all" includes resolved/archived.'
168704
168939
  ),
168705
- source: z626.enum(["agent", "git", "manual"]).optional().describe(
168940
+ source: z627.enum(["agent", "git", "manual"]).optional().describe(
168706
168941
  'Filter by memory source. "git" returns only commit-derived ground truth memories. Omit for all sources.'
168707
168942
  ),
168708
- quality: z626.enum(["fast", "balanced", "thorough"]).optional().default("balanced").describe(
168943
+ quality: z627.enum(["fast", "balanced", "thorough"]).optional().default("balanced").describe(
168709
168944
  "Retrieval profile: fast stays local, balanced uses configured embeddings, thorough explicitly permits optional LLM refinement."
168710
168945
  ),
168711
- purpose: z626.string().optional().describe(
168946
+ purpose: z627.string().optional().describe(
168712
168947
  "Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
168713
168948
  ),
168714
- force: z626.boolean().optional().describe(
168949
+ force: z627.boolean().optional().describe(
168715
168950
  "Use only when the user explicitly asks to read a record already represented in the latest Autopilot brief."
168716
168951
  )
168717
168952
  }
@@ -168800,9 +169035,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
168800
169035
  title: "Memory Graph Context",
168801
169036
  description: "Build a compact, prompt-ready memory graph context packet for the current project. Use this for broad memory overview questions, project memory graph questions, or task-specific memory grounding. Returns high-signal memories, entities, relations, and risks as background context, not instructions.",
168802
169037
  inputSchema: {
168803
- query: z626.string().describe("Current task or topic to build memory graph context for"),
168804
- limit: z626.number().optional().describe("Max high-signal memories to include (default: 5)"),
168805
- format: z626.enum(["prompt", "summary"]).optional().default("prompt").describe(
169038
+ query: z627.string().describe("Current task or topic to build memory graph context for"),
169039
+ limit: z627.number().optional().describe("Max high-signal memories to include (default: 5)"),
169040
+ format: z627.enum(["prompt", "summary"]).optional().default("prompt").describe(
168806
169041
  'Output format. "prompt" is agent-ready; "summary" is a compact human overview.'
168807
169042
  )
168808
169043
  }
@@ -168837,14 +169072,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
168837
169072
  title: "Memory Autopilot Project Context",
168838
169073
  description: "Build a compact Memory Autopilot brief for the current coding task. Schedules Code Memory refresh when needed, includes Start here files, reliable code-bound memories, stale/suspect cautions, and verification hints. Use this at the start of a new coding turn or after switching tasks.",
168839
169074
  inputSchema: {
168840
- task: z626.string().optional().describe("Current coding task or question"),
168841
- refresh: z626.enum(["auto", "always", "never"]).optional().default("auto").describe(
169075
+ task: z627.string().optional().describe("Current coding task or question"),
169076
+ refresh: z627.enum(["auto", "always", "never"]).optional().default("auto").describe(
168842
169077
  "Code Memory refresh policy. auto refreshes only when missing or stale."
168843
169078
  ),
168844
- format: z626.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
169079
+ format: z627.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
168845
169080
  'Output format. "prompt" is agent-ready; "summary" is human-readable; "receipt" is bounded JSON; "json" is detailed diagnostics.'
168846
169081
  ),
168847
- agent: z626.enum([
169082
+ agent: z627.enum([
168848
169083
  "windsurf",
168849
169084
  "cursor",
168850
169085
  "claude-code",
@@ -168859,7 +169094,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
168859
169094
  "opencode",
168860
169095
  "trae"
168861
169096
  ]).optional().describe("Optional target agent for compatible workflow selection."),
168862
- limit: z626.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
169097
+ limit: z627.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
168863
169098
  }
168864
169099
  },
168865
169100
  async ({ task, refresh, format, agent }) => {
@@ -168960,12 +169195,12 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
168960
169195
  title: "Context Pack",
168961
169196
  description: "Build a prompt-ready working context pack for a coding task. Combines relevant memories, CodeGraph Memory facts, freshness warnings, suggested reads, and verification hints. After a complete memorix_project_context brief, provide purpose only when deliberately expanding beyond it.",
168962
169197
  inputSchema: {
168963
- task: z626.string().describe("Current coding task or question"),
168964
- limit: z626.preprocess(
169198
+ task: z627.string().describe("Current coding task or question"),
169199
+ limit: z627.preprocess(
168965
169200
  (value) => typeof value === "string" && value.trim() !== "" ? Number(value) : value,
168966
- z626.number().int().positive().max(100)
169201
+ z627.number().int().positive().max(100)
168967
169202
  ).optional().describe("Max active memories to inspect before code-ref filtering (default: 20)"),
168968
- purpose: z626.string().optional().describe(
169203
+ purpose: z627.string().optional().describe(
168969
169204
  "Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
168970
169205
  )
168971
169206
  }
@@ -169060,7 +169295,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
169060
169295
  title: "Knowledge Workspace",
169061
169296
  description: "Manage the reviewable project Knowledge Workspace. Use it only for deliberate knowledge operations: initialize a local or versioned workspace, review source-backed claims, compile proposals, lint, apply a reviewed proposal, or manage canonical workflows. It is intentionally absent from the default micro/lite profiles.",
169062
169297
  inputSchema: {
169063
- action: z626.enum([
169298
+ action: z627.enum([
169064
169299
  "workspace_init",
169065
169300
  "status",
169066
169301
  "claim_list",
@@ -169075,21 +169310,21 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
169075
169310
  "workflow_apply",
169076
169311
  "workflow_run"
169077
169312
  ]).describe("Knowledge operation to perform"),
169078
- mode: z626.enum(["local", "versioned"]).optional().default("local").describe("Workspace mode; versioned writes require an explicit project path during workspace_init"),
169079
- path: z626.string().optional().describe("Explicit versioned workspace path, used only by workspace_init"),
169080
- proposalId: z626.string().optional().describe("Pending proposal id for proposal_apply"),
169081
- allowManualOverwrite: z626.boolean().optional().default(false).describe("Explicitly allow proposal_apply to replace a manually edited page"),
169082
- claimId: z626.string().optional().describe("Source-backed claim id for claim_review"),
169083
- claimReviewState: z626.enum(["approved", "rejected"]).optional().describe("Deliberate review verdict for claim_review"),
169084
- reviewDetail: z626.string().max(2e3).optional().describe("Evidence check performed before approving or rejecting a claim"),
169085
- workflowId: z626.string().optional().describe("Canonical workflow id for workflow preview, apply, or run"),
169086
- agent: z626.string().optional().describe("Target agent for a workflow adapter"),
169087
- task: z626.string().optional().describe("Task text for workflow selection or a workflow run"),
169088
- outcome: z626.enum(["passed", "failed", "cancelled", "in-progress"]).optional().describe("Workflow run outcome"),
169089
- verificationVerdict: z626.enum(["passed", "failed", "not-run"]).optional().describe("Workflow run verification verdict"),
169090
- failureReason: z626.string().optional().describe("Sanitized workflow failure reason"),
169091
- startingSnapshotId: z626.string().optional().describe("Code snapshot id present when a workflow run began"),
169092
- evidenceIds: z626.array(z626.string()).max(24).optional().describe("Selected evidence ids for a workflow run")
169313
+ mode: z627.enum(["local", "versioned"]).optional().default("local").describe("Workspace mode; versioned writes require an explicit project path during workspace_init"),
169314
+ path: z627.string().optional().describe("Explicit versioned workspace path, used only by workspace_init"),
169315
+ proposalId: z627.string().optional().describe("Pending proposal id for proposal_apply"),
169316
+ allowManualOverwrite: z627.boolean().optional().default(false).describe("Explicitly allow proposal_apply to replace a manually edited page"),
169317
+ claimId: z627.string().optional().describe("Source-backed claim id for claim_review"),
169318
+ claimReviewState: z627.enum(["approved", "rejected"]).optional().describe("Deliberate review verdict for claim_review"),
169319
+ reviewDetail: z627.string().max(2e3).optional().describe("Evidence check performed before approving or rejecting a claim"),
169320
+ workflowId: z627.string().optional().describe("Canonical workflow id for workflow preview, apply, or run"),
169321
+ agent: z627.string().optional().describe("Target agent for a workflow adapter"),
169322
+ task: z627.string().optional().describe("Task text for workflow selection or a workflow run"),
169323
+ outcome: z627.enum(["passed", "failed", "cancelled", "in-progress"]).optional().describe("Workflow run outcome"),
169324
+ verificationVerdict: z627.enum(["passed", "failed", "not-run"]).optional().describe("Workflow run verification verdict"),
169325
+ failureReason: z627.string().optional().describe("Sanitized workflow failure reason"),
169326
+ startingSnapshotId: z627.string().optional().describe("Code snapshot id present when a workflow run began"),
169327
+ evidenceIds: z627.array(z627.string()).max(24).optional().describe("Selected evidence ids for a workflow run")
169093
169328
  }
169094
169329
  },
169095
169330
  async ({
@@ -169365,8 +169600,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
169365
169600
  title: "Resolve Memories",
169366
169601
  description: `Mark observations as resolved (completed/no longer active). Resolved memories are hidden from default search but can still be found with status="all". Use this to mark completed tasks, fixed bugs, or outdated information so they don't pollute future context.`,
169367
169602
  inputSchema: {
169368
- ids: z626.array(z626.number()).describe("Observation IDs to mark as resolved"),
169369
- status: z626.enum(["resolved", "archived"]).optional().default("resolved").describe(
169603
+ ids: z627.array(z627.number()).describe("Observation IDs to mark as resolved"),
169604
+ status: z627.enum(["resolved", "archived"]).optional().default("resolved").describe(
169370
169605
  'Target status: "resolved" (default, completed/done) or "archived" (permanently hidden)'
169371
169606
  )
169372
169607
  }
@@ -169404,17 +169639,17 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
169404
169639
  title: "Store Reasoning Trace",
169405
169640
  description: "Store a reasoning trace \u2014 WHY you chose this approach, what alternatives you considered, and what outcome you expect. This creates a searchable record of your decision-making process. Use this when making non-trivial technical decisions, choosing between approaches, or solving complex problems. Unlike regular memories that record WHAT happened, reasoning memories record HOW you thought about it.",
169406
169641
  inputSchema: {
169407
- entityName: z626.string().describe('The entity this reasoning applies to (e.g., "auth-module", "database-schema")'),
169408
- decision: z626.string().describe("What was decided or chosen"),
169409
- alternatives: z626.array(z626.string()).optional().describe("Other options that were considered"),
169410
- rationale: z626.string().describe("Why this approach was chosen over alternatives"),
169411
- constraints: z626.array(z626.string()).optional().describe("Constraints that influenced the decision (time, perf, compat, etc.)"),
169412
- expectedOutcome: z626.string().optional().describe("What outcome is expected from this decision"),
169413
- risks: z626.array(z626.string()).optional().describe("Known risks or potential downsides"),
169414
- concepts: z626.array(z626.string()).optional().describe("Related technical concepts"),
169415
- filesModified: z626.array(z626.string()).optional().describe("Files related to this reasoning"),
169416
- relatedCommits: z626.array(z626.string()).optional().describe("Git commit hashes this reasoning explains (links ground truth \u2194 reasoning)"),
169417
- relatedEntities: z626.array(z626.string()).optional().describe("Other entity names this reasoning relates to (cross-references)")
169642
+ entityName: z627.string().describe('The entity this reasoning applies to (e.g., "auth-module", "database-schema")'),
169643
+ decision: z627.string().describe("What was decided or chosen"),
169644
+ alternatives: z627.array(z627.string()).optional().describe("Other options that were considered"),
169645
+ rationale: z627.string().describe("Why this approach was chosen over alternatives"),
169646
+ constraints: z627.array(z627.string()).optional().describe("Constraints that influenced the decision (time, perf, compat, etc.)"),
169647
+ expectedOutcome: z627.string().optional().describe("What outcome is expected from this decision"),
169648
+ risks: z627.array(z627.string()).optional().describe("Known risks or potential downsides"),
169649
+ concepts: z627.array(z627.string()).optional().describe("Related technical concepts"),
169650
+ filesModified: z627.array(z627.string()).optional().describe("Files related to this reasoning"),
169651
+ relatedCommits: z627.array(z627.string()).optional().describe("Git commit hashes this reasoning explains (links ground truth \u2194 reasoning)"),
169652
+ relatedEntities: z627.array(z627.string()).optional().describe("Other entity names this reasoning relates to (cross-references)")
169418
169653
  }
169419
169654
  },
169420
169655
  async ({ entityName, decision, alternatives, rationale, constraints, expectedOutcome, risks, concepts, filesModified, relatedCommits, relatedEntities }) => {
@@ -169489,7 +169724,7 @@ Entity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningA
169489
169724
  title: "Audit Project Attribution",
169490
169725
  description: "Scan the current project for observations that may have been written to the wrong project bucket. Identifies observations whose entityName appears exclusively in a different project. Read-only \u2014 no data is changed. Use memorix_resolve to archive confirmed mis-attributed observations.",
169491
169726
  inputSchema: {
169492
- threshold: z626.number().int().min(1).optional().describe(
169727
+ threshold: z627.number().int().min(1).optional().describe(
169493
169728
  "Minimum occurrences of an entityName in another project to flag it as suspicious (default: 2)"
169494
169729
  )
169495
169730
  }
@@ -169553,9 +169788,9 @@ Entity: ${entityName} | ${facts.length} facts | ${obs.tokens} tokens${reasoningA
169553
169788
  title: "Search Reasoning Patterns",
169554
169789
  description: "Search past reasoning traces to understand WHY decisions were made. Returns reasoning memories that explain the thought process behind technical choices. Use this when revisiting code, questioning a design decision, or looking for precedent on how similar problems were solved before.",
169555
169790
  inputSchema: {
169556
- query: z626.string().describe('Search query \u2014 describe what reasoning you want to find (e.g., "why did we choose PostgreSQL", "auth approach rationale")'),
169557
- limit: z626.number().optional().describe("Max results (default: 10)"),
169558
- scope: z626.enum(["project", "global"]).optional().default("project").describe("Search scope")
169791
+ query: z627.string().describe('Search query \u2014 describe what reasoning you want to find (e.g., "why did we choose PostgreSQL", "auth approach rationale")'),
169792
+ limit: z627.number().optional().describe("Max results (default: 10)"),
169793
+ scope: z627.enum(["project", "global"]).optional().default("project").describe("Search scope")
169559
169794
  }
169560
169795
  },
169561
169796
  async ({ query, limit: limit2, scope }) => {
@@ -169589,8 +169824,8 @@ ${result.formatted}` }]
169589
169824
  title: "Deduplicate Memories",
169590
169825
  description: "Scan active memories for duplicates, contradictions, and outdated information using LLM analysis. Automatically resolves redundant memories. Requires LLM to be configured (set MEMORIX_LLM_API_KEY or OPENAI_API_KEY environment variable). Without LLM, falls back to basic similarity-based consolidation.",
169591
169826
  inputSchema: {
169592
- query: z626.string().optional().describe("Optional query to scope dedup to a topic (default: scan all)"),
169593
- dryRun: z626.boolean().optional().default(false).describe("Preview only \u2014 show what would be resolved without making changes")
169827
+ query: z627.string().optional().describe("Optional query to scope dedup to a topic (default: scan all)"),
169828
+ dryRun: z627.boolean().optional().default(false).describe("Preview only \u2014 show what would be resolved without making changes")
169594
169829
  }
169595
169830
  },
169596
169831
  async ({ query, dryRun }) => {
@@ -169659,9 +169894,9 @@ ${actionLines.join("\n")}`
169659
169894
  title: "Memory Timeline",
169660
169895
  description: "Deep retrieval: expand chronological context around a specific observation \u2014 distinguishes explicit memory evolution, hook activity traces, and git-backed facts. Natural follow-up after session L1 routing hints (hook traces) or L3 evidence pointers (git memory).",
169661
169896
  inputSchema: {
169662
- anchorId: z626.number().describe("Observation ID to center the timeline on"),
169663
- depthBefore: z626.number().optional().describe("Number of observations before (default: 3)"),
169664
- depthAfter: z626.number().optional().describe("Number of observations after (default: 3)")
169897
+ anchorId: z627.number().describe("Observation ID to center the timeline on"),
169898
+ depthBefore: z627.number().optional().describe("Number of observations before (default: 3)"),
169899
+ depthAfter: z627.number().optional().describe("Number of observations after (default: 3)")
169665
169900
  }
169666
169901
  },
169667
169902
  async ({ anchorId, depthBefore, depthAfter }) => {
@@ -169691,18 +169926,18 @@ ${actionLines.join("\n")}`
169691
169926
  title: "Memory Details",
169692
169927
  description: 'Fetch full observation, mini-skill, or curated durable-memory details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Do not re-fetch content already covered by a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") and durable refs from a project brief (e.g. "durable:<uuid>") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
169693
169928
  inputSchema: {
169694
- ids: z626.array(z626.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
169695
- refs: z626.array(
169696
- z626.object({
169697
- id: z626.number().describe("Observation ID"),
169698
- projectId: z626.string().optional().describe("Project ID for global-search disambiguation")
169929
+ ids: z627.array(z627.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
169930
+ refs: z627.array(
169931
+ z627.object({
169932
+ id: z627.number().describe("Observation ID"),
169933
+ projectId: z627.string().optional().describe("Project ID for global-search disambiguation")
169699
169934
  })
169700
169935
  ).optional().describe("Explicit observation refs. Prefer this for global search results."),
169701
- typedRefs: z626.array(z626.string()).optional().describe('Typed memory refs from search results or a project brief, e.g. "obs:42", "skill:3", "durable:<uuid>", "obs:42@org/proj"'),
169702
- purpose: z626.string().optional().describe(
169936
+ typedRefs: z627.array(z627.string()).optional().describe('Typed memory refs from search results or a project brief, e.g. "obs:42", "skill:3", "durable:<uuid>", "obs:42@org/proj"'),
169937
+ purpose: z627.string().optional().describe(
169703
169938
  "Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
169704
169939
  ),
169705
- force: z626.boolean().optional().describe(
169940
+ force: z627.boolean().optional().describe(
169706
169941
  "Use only when the user explicitly asks to read a record already represented in the latest Autopilot brief."
169707
169942
  )
169708
169943
  }
@@ -169781,7 +170016,7 @@ ${actionLines.join("\n")}`
169781
170016
  title: "Memory Retention Status & Archive",
169782
170017
  description: 'Show memory retention status or archive expired memories. action="report" (default): show active/stale/archive-candidate counts. action="archive": move expired observations to archive file (reversible). action="stale": list stale observations with full retention explanation. Uses exponential decay scoring based on importance, age, and access patterns.',
169783
170018
  inputSchema: {
169784
- action: z626.enum(["report", "archive", "stale"]).optional().describe('Action: "report" (show status, default) or "archive" (move expired to archive) or "stale" (list stale observations with explanation)')
170019
+ action: z627.enum(["report", "archive", "stale"]).optional().describe('Action: "report" (show status, default) or "archive" (move expired to archive) or "stale" (list stale observations with explanation)')
169785
170020
  }
169786
170021
  },
169787
170022
  async (args) => {
@@ -170046,10 +170281,10 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170046
170281
  title: "Create Entities",
170047
170282
  description: "Create multiple new entities in the knowledge graph",
170048
170283
  inputSchema: {
170049
- entities: z626.array(z626.object({
170050
- name: z626.string().describe("The name of the entity"),
170051
- entityType: z626.string().describe("The type of the entity"),
170052
- observations: z626.array(z626.string()).describe("Initial observations")
170284
+ entities: z627.array(z627.object({
170285
+ name: z627.string().describe("The name of the entity"),
170286
+ entityType: z627.string().describe("The type of the entity"),
170287
+ observations: z627.array(z627.string()).describe("Initial observations")
170053
170288
  }))
170054
170289
  }
170055
170290
  },
@@ -170069,10 +170304,10 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170069
170304
  title: "Create Relations",
170070
170305
  description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice. Recommended relation types (from mcp-memory-service): causes, fixes, supports, opposes, contradicts, depends_on, implements, extends, replaces, documents",
170071
170306
  inputSchema: {
170072
- relations: z626.array(z626.object({
170073
- from: z626.string().describe("Source entity name"),
170074
- to: z626.string().describe("Target entity name"),
170075
- relationType: z626.string().describe("Type of relation (e.g., causes, fixes, supports, depends_on, implements)")
170307
+ relations: z627.array(z627.object({
170308
+ from: z627.string().describe("Source entity name"),
170309
+ to: z627.string().describe("Target entity name"),
170310
+ relationType: z627.string().describe("Type of relation (e.g., causes, fixes, supports, depends_on, implements)")
170076
170311
  }))
170077
170312
  }
170078
170313
  },
@@ -170092,9 +170327,9 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170092
170327
  title: "Add Observations",
170093
170328
  description: "Add new observations to existing entities in the knowledge graph",
170094
170329
  inputSchema: {
170095
- observations: z626.array(z626.object({
170096
- entityName: z626.string().describe("Entity name to add observations to"),
170097
- contents: z626.array(z626.string()).describe("Observation contents to add")
170330
+ observations: z627.array(z627.object({
170331
+ entityName: z627.string().describe("Entity name to add observations to"),
170332
+ contents: z627.array(z627.string()).describe("Observation contents to add")
170098
170333
  }))
170099
170334
  }
170100
170335
  },
@@ -170114,7 +170349,7 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170114
170349
  title: "Delete Entities",
170115
170350
  description: "Delete multiple entities and their associated relations from the knowledge graph",
170116
170351
  inputSchema: {
170117
- entityNames: z626.array(z626.string()).describe("Entity names to delete")
170352
+ entityNames: z627.array(z627.string()).describe("Entity names to delete")
170118
170353
  }
170119
170354
  },
170120
170355
  async ({ entityNames }) => {
@@ -170133,9 +170368,9 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170133
170368
  title: "Delete Observations",
170134
170369
  description: "Delete specific observations from entities in the knowledge graph",
170135
170370
  inputSchema: {
170136
- deletions: z626.array(z626.object({
170137
- entityName: z626.string().describe("Entity containing the observations"),
170138
- observations: z626.array(z626.string()).describe("Observations to delete")
170371
+ deletions: z627.array(z627.object({
170372
+ entityName: z627.string().describe("Entity containing the observations"),
170373
+ observations: z627.array(z627.string()).describe("Observations to delete")
170139
170374
  }))
170140
170375
  }
170141
170376
  },
@@ -170155,10 +170390,10 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170155
170390
  title: "Delete Relations",
170156
170391
  description: "Delete multiple relations from the knowledge graph",
170157
170392
  inputSchema: {
170158
- relations: z626.array(z626.object({
170159
- from: z626.string(),
170160
- to: z626.string(),
170161
- relationType: z626.string()
170393
+ relations: z627.array(z627.object({
170394
+ from: z627.string(),
170395
+ to: z627.string(),
170396
+ relationType: z627.string()
170162
170397
  }))
170163
170398
  }
170164
170399
  },
@@ -170207,7 +170442,7 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170207
170442
  title: "Search Nodes",
170208
170443
  description: "Search for nodes in the knowledge graph based on a query",
170209
170444
  inputSchema: {
170210
- query: z626.string().describe("Search query to match against entity names, types, and observations")
170445
+ query: z627.string().describe("Search query to match against entity names, types, and observations")
170211
170446
  }
170212
170447
  },
170213
170448
  async ({ query }) => {
@@ -170226,7 +170461,7 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170226
170461
  title: "Open Nodes",
170227
170462
  description: "Open specific nodes in the knowledge graph by their names",
170228
170463
  inputSchema: {
170229
- names: z626.array(z626.string()).describe("Entity names to retrieve")
170464
+ names: z627.array(z627.string()).describe("Entity names to retrieve")
170230
170465
  }
170231
170466
  },
170232
170467
  async ({ names }) => {
@@ -170248,8 +170483,8 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170248
170483
  title: "Rules Sync",
170249
170484
  description: "Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity, Gemini CLI, Copilot, Kiro, OpenCode, Trae), deduplicate, detect conflicts, and optionally generate rules for a target agent format. Without target: returns sync status report. With target: generates converted rule files.",
170250
170485
  inputSchema: {
170251
- action: z626.enum(["status", "generate"]).describe('Action: "status" for report, "generate" to produce target files'),
170252
- target: z626.enum(RULE_SOURCES).optional().describe("Target agent format for generation (required when action=generate)")
170486
+ action: z627.enum(["status", "generate"]).describe('Action: "status" for report, "generate" to produce target files'),
170487
+ target: z627.enum(RULE_SOURCES).optional().describe("Target agent format for generation (required when action=generate)")
170253
170488
  }
170254
170489
  },
170255
170490
  async ({ action, target }) => {
@@ -170304,9 +170539,9 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170304
170539
  title: "Workspace Sync",
170305
170540
  description: 'Migrate your entire workspace environment between AI coding agents (Cursor, Windsurf, Claude Code, Codex, Copilot, Gemini CLI, OpenClaw, Hermes Agent, Oh-my-Pi, Kiro, Antigravity, OpenCode, Trae). Syncs MCP server configs, workflows, rules, and skills across IDEs. Action "scan": detect all workspace configs. Action "migrate": generate configs for target agent (preview only). Action "apply": migrate AND write configs to disk with backup/rollback.',
170306
170541
  inputSchema: {
170307
- action: z626.enum(["scan", "migrate", "apply"]).describe('Action: "scan" to detect configs, "migrate" to preview, "apply" to write to disk'),
170308
- target: z626.enum(AGENT_TARGETS).optional().describe("Target agent for migration (required for migrate)"),
170309
- items: z626.array(z626.string()).optional().describe('Selective sync: list specific MCP server or skill names to sync (e.g. ["figma-remote-mcp-server", "create-subagent"]). Omit to sync all.')
170542
+ action: z627.enum(["scan", "migrate", "apply"]).describe('Action: "scan" to detect configs, "migrate" to preview, "apply" to write to disk'),
170543
+ target: z627.enum(AGENT_TARGETS).optional().describe("Target agent for migration (required for migrate)"),
170544
+ items: z627.array(z627.string()).optional().describe('Selective sync: list specific MCP server or skill names to sync (e.g. ["figma-remote-mcp-server", "create-subagent"]). Omit to sync all.')
170310
170545
  }
170311
170546
  },
170312
170547
  async ({ action, target, items }) => {
@@ -170402,10 +170637,10 @@ ${Math.max(0, managedIds.size - result.resolved.length)} visible writable observ
170402
170637
  title: "Project Skills",
170403
170638
  description: `Memory-driven project skills. Action "list": show all available skills from all agents. Action "generate": auto-generate project-specific skills from observation patterns (gotchas, decisions, how-it-works). Action "inject": return a specific skill's full content for direct use. Generated skills follow the SKILL.md standard and can be synced across Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, and Trae. OpenClaw, Hermes Agent, and Oh-my-Pi receive skills through their official bundle/plugin/package setup lanes rather than generic workspace skill copy.`,
170404
170639
  inputSchema: {
170405
- action: z626.enum(["list", "generate", "inject"]).describe('Action: "list" to discover skills, "generate" to create from memory, "inject" to get skill content'),
170406
- name: z626.string().optional().describe('Skill name (required for "inject")'),
170407
- target: z626.enum(AGENT_TARGETS).optional().describe('Target agent to write generated skills to (optional for "generate")'),
170408
- write: z626.boolean().optional().describe("Whether to write generated skills to disk (default: false, preview only)")
170640
+ action: z627.enum(["list", "generate", "inject"]).describe('Action: "list" to discover skills, "generate" to create from memory, "inject" to get skill content'),
170641
+ name: z627.string().optional().describe('Skill name (required for "inject")'),
170642
+ target: z627.enum(AGENT_TARGETS).optional().describe('Target agent to write generated skills to (optional for "generate")'),
170643
+ write: z627.boolean().optional().describe("Whether to write generated skills to disk (default: false, preview only)")
170409
170644
  }
170410
170645
  },
170411
170646
  async ({ action, name, target, write }) => {
@@ -170515,12 +170750,12 @@ ${skill2.content}` }]
170515
170750
  title: "Promote to Mini-Skill",
170516
170751
  description: 'Promote observations to permanent mini-skills that never decay and are auto-injected at session start. Action "promote": convert observation(s) to a mini-skill. Action "list": show all active mini-skills. Action "delete": remove a mini-skill by ID.\n\nMini-skills are project-specific specialized knowledge derived from your actual memories \u2014 gotchas, decisions, fixes that generic online skills cannot provide.',
170517
170752
  inputSchema: {
170518
- action: z626.enum(["promote", "list", "delete"]).describe("Action to perform"),
170519
- observationIds: z626.array(z626.number()).optional().describe('Observation IDs to promote (required for "promote")'),
170520
- skillId: z626.number().optional().describe('Mini-skill ID to delete (required for "delete")'),
170521
- trigger: z626.string().optional().describe("Override: when this skill should be applied"),
170522
- instruction: z626.string().optional().describe("Override: what the agent should do"),
170523
- tags: z626.array(z626.string()).optional().describe("Extra classification tags")
170753
+ action: z627.enum(["promote", "list", "delete"]).describe("Action to perform"),
170754
+ observationIds: z627.array(z627.number()).optional().describe('Observation IDs to promote (required for "promote")'),
170755
+ skillId: z627.number().optional().describe('Mini-skill ID to delete (required for "delete")'),
170756
+ trigger: z627.string().optional().describe("Override: when this skill should be applied"),
170757
+ instruction: z627.string().optional().describe("Override: what the agent should do"),
170758
+ tags: z627.array(z627.string()).optional().describe("Extra classification tags")
170524
170759
  }
170525
170760
  },
170526
170761
  async ({ action, observationIds, skillId, trigger, instruction, tags }) => {
@@ -170599,8 +170834,8 @@ ${skill2.content}` }]
170599
170834
  title: "Consolidate Memories",
170600
170835
  description: 'Find and merge similar observations to reduce memory bloat. Uses text similarity to cluster related observations by entity+type, then merges them into single consolidated records. Use action="preview" to see candidates without changing data, action="execute" to merge.\n\nExample: 10 similar gotchas about Windows paths \u2192 1 consolidated gotcha with all facts preserved.',
170601
170836
  inputSchema: {
170602
- action: z626.enum(["preview", "execute"]).describe("preview = dry run showing candidates, execute = actually merge"),
170603
- threshold: z626.number().optional().describe("Similarity threshold 0.0-1.0 (default: 0.45). Lower = more aggressive merging")
170837
+ action: z627.enum(["preview", "execute"]).describe("preview = dry run showing candidates, execute = actually merge"),
170838
+ threshold: z627.number().optional().describe("Similarity threshold 0.0-1.0 (default: 0.45). Lower = more aggressive merging")
170604
170839
  }
170605
170840
  },
170606
170841
  async ({ action, threshold }) => {
@@ -170646,13 +170881,13 @@ ${skill2.content}` }]
170646
170881
  title: "Start Session",
170647
170882
  description: "Start a new coding session. Returns a compact continuation card with the latest handoff and a few memory references. Call this at the beginning of a session to track activity; retrieve a referenced memory only when it is relevant. Any previous active session for this project will be auto-closed. By default this is lightweight: it binds the project, opens a session, and avoids dumping full history into the new context. Coordination identity is opt-in via `joinTeam: true` or a separate `team_manage` join call.\n\nIMPORTANT for HTTP/control-plane mode: pass `projectRoot` with the absolute path to your workspace root (e.g., the directory open in your IDE). Memorix uses this to detect the git project and bind this session to the correct project context. Without it, project-scoped tools will be disabled.",
170648
170883
  inputSchema: {
170649
- sessionId: z626.string().optional().describe("Custom session ID (auto-generated if omitted)"),
170650
- agent: z626.string().optional().describe('Agent/IDE name (e.g., "cursor", "windsurf", "claude-code")'),
170651
- agentType: z626.string().optional().describe('Agent type used for optional coordination identity mapping (e.g., "windsurf", "cursor").'),
170652
- instanceId: z626.string().optional().describe("Stable instance ID for optional coordination identity across restarts. If omitted with joinTeam=true, Memorix derives a deterministic fallback from the project and agent identity."),
170653
- joinTeam: z626.boolean().optional().describe("If true, also join orchestration coordination state for this session. Defaults to false."),
170654
- role: z626.string().optional().describe("Explicit role override used only when joinTeam=true."),
170655
- projectRoot: z626.string().optional().describe(
170884
+ sessionId: z627.string().optional().describe("Custom session ID (auto-generated if omitted)"),
170885
+ agent: z627.string().optional().describe('Agent/IDE name (e.g., "cursor", "windsurf", "claude-code")'),
170886
+ agentType: z627.string().optional().describe('Agent type used for optional coordination identity mapping (e.g., "windsurf", "cursor").'),
170887
+ instanceId: z627.string().optional().describe("Stable instance ID for optional coordination identity across restarts. If omitted with joinTeam=true, Memorix derives a deterministic fallback from the project and agent identity."),
170888
+ joinTeam: z627.boolean().optional().describe("If true, also join orchestration coordination state for this session. Defaults to false."),
170889
+ role: z627.string().optional().describe("Explicit role override used only when joinTeam=true."),
170890
+ projectRoot: z627.string().optional().describe(
170656
170891
  "Absolute path to the workspace/project root directory (e.g., the folder open in your IDE). Memorix will detect the git project from this path and bind this session to it. Required for HTTP transport when multiple projects are open simultaneously or when rebinding an existing control-plane session."
170657
170892
  )
170658
170893
  }
@@ -170859,8 +171094,8 @@ ${s2.instruction}`.toLowerCase();
170859
171094
  title: "End Session",
170860
171095
  description: "End a coding session with a structured summary. This summary will be injected into the next session so the next agent can resume work seamlessly.\n\nRecommended summary format:\n## Goal\n[What we were working on]\n\n## Discoveries\n- [Technical findings, gotchas, learnings]\n\n## Accomplished\n- [OK] [Completed tasks]\n- [PENDING] [Pending for next session]\n\n## Relevant Files\n- path/to/file \u2014 [what changed]",
170861
171096
  inputSchema: {
170862
- sessionId: z626.string().describe("Session ID to close (from memorix_session_start)"),
170863
- summary: z626.string().optional().describe("Structured session summary (Goal/Discoveries/Accomplished/Files format)")
171097
+ sessionId: z627.string().describe("Session ID to close (from memorix_session_start)"),
171098
+ summary: z627.string().optional().describe("Structured session summary (Goal/Discoveries/Accomplished/Files format)")
170864
171099
  }
170865
171100
  },
170866
171101
  async ({ sessionId, summary }) => {
@@ -170888,7 +171123,7 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
170888
171123
  title: "Session Context",
170889
171124
  description: "Get context from previous coding sessions. Use this after compaction to recover lost context, or to manually review session history. Returns previous session summaries and key observations.",
170890
171125
  inputSchema: {
170891
- limit: z626.number().optional().describe("Number of recent sessions to include (default: 3)")
171126
+ limit: z627.number().optional().describe("Number of recent sessions to include (default: 3)")
170892
171127
  }
170893
171128
  },
170894
171129
  async ({ limit: limit2 }) => {
@@ -170921,14 +171156,14 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
170921
171156
  title: "Compact Continuity Checkpoints",
170922
171157
  description: "Inspect, preview, or archive bounded checkpoints recorded around a host-native context compaction. Use only to debug or explicitly review compaction continuity. These are lifecycle records, not durable memories or transcript backups. CLI equivalent: memorix checkpoint list|show|context|archive.",
170923
171158
  inputSchema: {
170924
- action: z626.enum(["list", "show", "context", "archive"]).default("list"),
170925
- id: z626.string().optional().describe("Checkpoint ID for show, context, or archive"),
170926
- sessionId: z626.string().optional().describe("Optional host session ID filter"),
170927
- agent: z626.string().optional().describe("Optional host agent filter"),
170928
- task: z626.string().optional().describe("Current task for a bounded context preview"),
170929
- maxTokens: z626.number().optional().describe("Maximum tokens for action=context (default: 420)"),
170930
- limit: z626.number().optional().describe("Maximum records for action=list (default: 20)"),
170931
- includeArchived: z626.boolean().optional().default(false).describe("Include archived records in action=list")
171159
+ action: z627.enum(["list", "show", "context", "archive"]).default("list"),
171160
+ id: z627.string().optional().describe("Checkpoint ID for show, context, or archive"),
171161
+ sessionId: z627.string().optional().describe("Optional host session ID filter"),
171162
+ agent: z627.string().optional().describe("Optional host agent filter"),
171163
+ task: z627.string().optional().describe("Current task for a bounded context preview"),
171164
+ maxTokens: z627.number().optional().describe("Maximum tokens for action=context (default: 420)"),
171165
+ limit: z627.number().optional().describe("Maximum records for action=list (default: 20)"),
171166
+ includeArchived: z627.boolean().optional().default(false).describe("Include archived records in action=list")
170932
171167
  }
170933
171168
  },
170934
171169
  async ({ action, id, sessionId, agent, task, maxTokens, limit: limit2, includeArchived }) => {
@@ -171001,9 +171236,9 @@ ${summary ? "Summary saved for next session context injection." : "No summary pr
171001
171236
  title: "Transfer Memories",
171002
171237
  description: 'Export or import project memories. Action "export": export observations visible to the current agent and project sessions (JSON or Markdown). Action "import": import from a JSON export (re-assigns IDs, skips duplicate topicKeys).',
171003
171238
  inputSchema: {
171004
- action: z626.enum(["export", "import"]).describe("Operation: export or import"),
171005
- format: z626.enum(["json", "markdown"]).optional().describe("Export format (for export, default: json)"),
171006
- data: z626.string().optional().describe("JSON string from a previous export (for import)")
171239
+ action: z627.enum(["export", "import"]).describe("Operation: export or import"),
171240
+ format: z627.enum(["json", "markdown"]).optional().describe("Export format (for export, default: json)"),
171241
+ data: z627.string().optional().describe("JSON string from a previous export (for import)")
171007
171242
  }
171008
171243
  },
171009
171244
  async ({ action, format, data: jsonStr }) => {
@@ -171052,7 +171287,7 @@ ${json2}
171052
171287
  title: "Launch Dashboard",
171053
171288
  description: "Launch the Memorix Web Dashboard in the browser. In HTTP control-plane mode, this reuses the current control-plane dashboard. In stdio/standalone mode, it starts the standalone dashboard server.",
171054
171289
  inputSchema: {
171055
- port: z626.number().optional().describe("Optional port override for standalone mode. In HTTP control-plane mode, the active dashboard port is reused.")
171290
+ port: z627.number().optional().describe("Optional port override for standalone mode. In HTTP control-plane mode, the active dashboard port is reused.")
171056
171291
  }
171057
171292
  },
171058
171293
  async ({ port: dashboardPort }) => {
@@ -171160,7 +171395,7 @@ ${json2}
171160
171395
  }
171161
171396
  }
171162
171397
  console.error(`[memorix] Dashboard staticDir: ${staticDir}`);
171163
- startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false, void 0, project.rootPath, projectResolved).then(() => {
171398
+ startDashboard2(projectDir2, portNum, staticDir, project.id, project.name, false, project.rootPath, projectResolved).then(() => {
171164
171399
  dashboardRunning = true;
171165
171400
  }).catch((err) => {
171166
171401
  console.error("[memorix] Dashboard error:", err);
@@ -171216,13 +171451,13 @@ ${json2}
171216
171451
  title: "Evidence Cards",
171217
171452
  description: "Inspect the bounded, project-scoped provenance cards behind Memorix context. Use list for a compact index, get/events for one source, sync to repair the projection, and stale when known source files changed. Cards expose sourceRef, locator, capturedHash, and freshness.",
171218
171453
  inputSchema: {
171219
- action: z626.enum(["list", "get", "sync", "stale", "events"]).describe("Evidence operation"),
171220
- candidateKind: z626.enum(["observation", "code", "git", "test", "document", "workflow", "graph"]).optional().default("observation"),
171221
- candidateId: z626.string().optional().describe("Candidate id, usually an observation id"),
171222
- query: z626.string().optional().describe("Optional title/source query for list"),
171223
- paths: z626.array(z626.string()).max(200).optional().describe("Changed source paths for stale"),
171224
- reason: z626.string().max(500).optional().describe("Why evidence became stale"),
171225
- limit: z626.number().int().positive().max(100).optional().default(20)
171454
+ action: z627.enum(["list", "get", "sync", "stale", "events"]).describe("Evidence operation"),
171455
+ candidateKind: z627.enum(["observation", "code", "git", "test", "document", "workflow", "graph"]).optional().default("observation"),
171456
+ candidateId: z627.string().optional().describe("Candidate id, usually an observation id"),
171457
+ query: z627.string().optional().describe("Optional title/source query for list"),
171458
+ paths: z627.array(z627.string()).max(200).optional().describe("Changed source paths for stale"),
171459
+ reason: z627.string().max(500).optional().describe("Why evidence became stale"),
171460
+ limit: z627.number().int().positive().max(100).optional().default(20)
171226
171461
  }
171227
171462
  },
171228
171463
  async ({ action, candidateKind, candidateId, query, paths, reason, limit: limit2 }) => {
@@ -171262,15 +171497,15 @@ ${json2}
171262
171497
  title: "Memory Feedback",
171263
171498
  description: "Record or inspect auditable memory outcomes. Positive verification/use strengthens recall; correction, conflict, source change, or weaken lowers it. Use revoke with targetEventId to undo one prior signal without deleting audit history.",
171264
171499
  inputSchema: {
171265
- action: z626.enum(["record", "show", "audit"]).describe("Feedback operation"),
171266
- candidateKind: z626.enum(["observation", "claim", "durable-memory", "workflow"]).optional().default("observation"),
171267
- candidateId: z626.string().describe("Memory or knowledge candidate id"),
171268
- signal: z626.enum(["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"]).optional(),
171269
- sourceRef: z626.string().max(500).optional().describe("Source of this feedback, such as test:run-42 or user:chat"),
171270
- actor: z626.string().max(200).optional(),
171271
- note: z626.string().max(2e3).optional(),
171272
- targetEventId: z626.string().optional().describe("Existing event id when action=record and signal=revoke"),
171273
- limit: z626.number().int().positive().max(200).optional().default(100)
171500
+ action: z627.enum(["record", "show", "audit"]).describe("Feedback operation"),
171501
+ candidateKind: z627.enum(["observation", "claim", "durable-memory", "workflow"]).optional().default("observation"),
171502
+ candidateId: z627.string().describe("Memory or knowledge candidate id"),
171503
+ signal: z627.enum(["user-correction", "verification-success", "verification-failure", "code-change", "used", "not-used", "code-conflict", "strengthen", "weaken", "revoke"]).optional(),
171504
+ sourceRef: z627.string().max(500).optional().describe("Source of this feedback, such as test:run-42 or user:chat"),
171505
+ actor: z627.string().max(200).optional(),
171506
+ note: z627.string().max(2e3).optional(),
171507
+ targetEventId: z627.string().optional().describe("Existing event id when action=record and signal=revoke"),
171508
+ limit: z627.number().int().positive().max(200).optional().default(100)
171274
171509
  }
171275
171510
  },
171276
171511
  async ({ action, candidateKind, candidateId, signal, sourceRef, actor, note, targetEventId, limit: limit2 }) => {
@@ -171336,19 +171571,19 @@ ${json2}
171336
171571
  title: "Coordination Management",
171337
171572
  description: 'Register, unregister, or list agents in the project coordination state. Action "join": register this agent (returns agent ID and instance ID for reactivation). Action "leave": mark agent inactive, release locks. Action "status": list all agents with roles and capabilities, plus role occupancy. Action "listRoles": show defined roles for this project. Action "addRole": define a new role for this project. Action "removeRole": remove a role definition.',
171338
171573
  inputSchema: {
171339
- action: z626.enum(["join", "leave", "status", "listRoles", "addRole", "removeRole"]).describe("Operation to perform"),
171340
- name: z626.string().optional().describe('Agent display name for join (e.g., "cursor-frontend")'),
171341
- agentType: z626.string().optional().describe('Agent type for join (e.g., "windsurf", "cursor", "claude-code")'),
171342
- instanceId: z626.string().optional().describe("Stable instance ID for join (preserves identity across restarts)"),
171343
- role: z626.string().optional().describe("Agent role for join (defaults by agentType if omitted)"),
171344
- capabilities: z626.array(z626.string()).optional().describe("Agent capabilities for join"),
171345
- agentId: z626.string().optional().describe("Agent ID for leave"),
171574
+ action: z627.enum(["join", "leave", "status", "listRoles", "addRole", "removeRole"]).describe("Operation to perform"),
171575
+ name: z627.string().optional().describe('Agent display name for join (e.g., "cursor-frontend")'),
171576
+ agentType: z627.string().optional().describe('Agent type for join (e.g., "windsurf", "cursor", "claude-code")'),
171577
+ instanceId: z627.string().optional().describe("Stable instance ID for join (preserves identity across restarts)"),
171578
+ role: z627.string().optional().describe("Agent role for join (defaults by agentType if omitted)"),
171579
+ capabilities: z627.array(z627.string()).optional().describe("Agent capabilities for join"),
171580
+ agentId: z627.string().optional().describe("Agent ID for leave"),
171346
171581
  // Role management params
171347
- roleId: z626.string().optional().describe("Role ID (for addRole/removeRole)"),
171348
- label: z626.string().optional().describe("Role label (for addRole)"),
171349
- roleDescription: z626.string().optional().describe("Role description (for addRole)"),
171350
- preferredAgentTypes: z626.array(z626.string()).optional().describe("Preferred agent types for this role (for addRole)"),
171351
- maxConcurrent: z626.number().optional().describe("Max concurrent agents for this role (for addRole, default 1)")
171582
+ roleId: z627.string().optional().describe("Role ID (for addRole/removeRole)"),
171583
+ label: z627.string().optional().describe("Role label (for addRole)"),
171584
+ roleDescription: z627.string().optional().describe("Role description (for addRole)"),
171585
+ preferredAgentTypes: z627.array(z627.string()).optional().describe("Preferred agent types for this role (for addRole)"),
171586
+ maxConcurrent: z627.number().optional().describe("Max concurrent agents for this role (for addRole, default 1)")
171352
171587
  }
171353
171588
  },
171354
171589
  async ({ action, name, agentType, instanceId, role, capabilities, agentId, roleId, label, roleDescription, preferredAgentTypes, maxConcurrent }) => {
@@ -171461,9 +171696,9 @@ ${agentLines.join("\n")}`
171461
171696
  title: "File Lock Management",
171462
171697
  description: 'Advisory file locks to prevent conflicting edits. Auto-releases after 10 min TTL. Action "lock": acquire lock. Action "unlock": release lock. Action "status": check lock status.',
171463
171698
  inputSchema: {
171464
- action: z626.enum(["lock", "unlock", "status"]).describe("Operation to perform"),
171465
- file: z626.string().optional().describe("File path (required for lock/unlock, optional for status \u2014 omit to list all)"),
171466
- agentId: z626.string().optional().describe("Agent ID (required for lock/unlock)")
171699
+ action: z627.enum(["lock", "unlock", "status"]).describe("Operation to perform"),
171700
+ file: z627.string().optional().describe("File path (required for lock/unlock, optional for status \u2014 omit to list all)"),
171701
+ agentId: z627.string().optional().describe("Agent ID (required for lock/unlock)")
171467
171702
  }
171468
171703
  },
171469
171704
  async ({ action, file, agentId }) => {
@@ -171502,20 +171737,20 @@ ${lines.join("\n")}` }] };
171502
171737
  server.registerTool(
171503
171738
  "team_task",
171504
171739
  {
171505
- title: "Task Board",
171740
+ title: "Task Status",
171506
171741
  description: 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. Action "create": create a task. Action "claim": assign to yourself (atomic, race-safe). Action "complete": mark done with result. Action "list": show tasks.',
171507
171742
  inputSchema: {
171508
- action: z626.enum(["create", "claim", "complete", "list"]).describe("Operation to perform"),
171509
- description: z626.string().optional().describe("Task description (for create)"),
171510
- deps: z626.array(z626.string()).optional().describe("Dependency task IDs (for create)"),
171511
- taskId: z626.string().optional().describe("Task ID (for claim/complete)"),
171512
- agentId: z626.string().optional().describe("Agent ID (for claim/complete)"),
171513
- result: z626.string().optional().describe("Result summary (for complete)"),
171514
- status: z626.enum(["pending", "in_progress", "completed", "failed"]).optional().describe("Filter by status (for list)"),
171515
- available: z626.boolean().optional().describe("Show only claimable tasks (for list)"),
171516
- metadata: z626.string().optional().describe("JSON metadata for the task (for create). Used by planner/review tasks for autonomous mode."),
171517
- requiredRole: z626.string().optional().describe("Required role for this task (for create). Agents without this role cannot claim."),
171518
- preferredRole: z626.string().optional().describe("Preferred role for this task (for create). Agents with this role are prioritized.")
171743
+ action: z627.enum(["create", "claim", "complete", "list"]).describe("Operation to perform"),
171744
+ description: z627.string().optional().describe("Task description (for create)"),
171745
+ deps: z627.array(z627.string()).optional().describe("Dependency task IDs (for create)"),
171746
+ taskId: z627.string().optional().describe("Task ID (for claim/complete)"),
171747
+ agentId: z627.string().optional().describe("Agent ID (for claim/complete)"),
171748
+ result: z627.string().optional().describe("Result summary (for complete)"),
171749
+ status: z627.enum(["pending", "in_progress", "completed", "failed"]).optional().describe("Filter by status (for list)"),
171750
+ available: z627.boolean().optional().describe("Show only claimable tasks (for list)"),
171751
+ metadata: z627.string().optional().describe("JSON metadata for the task (for create). Used by planner/review tasks for autonomous mode."),
171752
+ requiredRole: z627.string().optional().describe("Required role for this task (for create). Agents without this role cannot claim."),
171753
+ preferredRole: z627.string().optional().describe("Preferred role for this task (for create). Agents with this role are prioritized.")
171519
171754
  }
171520
171755
  },
171521
171756
  async ({ action, description: desc, deps, taskId, agentId, result, status, available, metadata, requiredRole, preferredRole }) => {
@@ -171588,15 +171823,15 @@ ${lines.join("\n")}` }] };
171588
171823
  title: "Team Messaging",
171589
171824
  description: `Send, broadcast, or read messages between agents. Durable: messages survive restarts and reach inactive recipients. Action "send": direct message to one agent. Action "broadcast": message all agents. Action "inbox": read this agent's inbox.`,
171590
171825
  inputSchema: {
171591
- action: z626.enum(["send", "broadcast", "inbox"]).describe("Operation to perform"),
171592
- from: z626.string().optional().describe("Your sender agent ID. Omit it to use this session identity."),
171593
- to: z626.string().optional().describe("Receiver agent ID (for send)"),
171594
- type: z626.enum(["request", "response", "info", "announcement", "contract", "error", "handoff"]).optional().describe("Message type (for send/broadcast)"),
171595
- content: z626.string().optional().describe("Message content (for send/broadcast)"),
171596
- agentId: z626.string().optional().describe("Agent ID (for inbox)"),
171597
- markRead: z626.boolean().optional().default(false).describe("Mark messages as read (for inbox)"),
171598
- toRole: z626.string().optional().describe("Target role for role-based messaging/handoff (for send)"),
171599
- handoffStatus: z626.enum(["open", "claimed", "completed", "archived"]).optional().describe("Handoff status (for send with type=handoff)")
171826
+ action: z627.enum(["send", "broadcast", "inbox"]).describe("Operation to perform"),
171827
+ from: z627.string().optional().describe("Your sender agent ID. Omit it to use this session identity."),
171828
+ to: z627.string().optional().describe("Receiver agent ID (for send)"),
171829
+ type: z627.enum(["request", "response", "info", "announcement", "contract", "error", "handoff"]).optional().describe("Message type (for send/broadcast)"),
171830
+ content: z627.string().optional().describe("Message content (for send/broadcast)"),
171831
+ agentId: z627.string().optional().describe("Agent ID (for inbox)"),
171832
+ markRead: z627.boolean().optional().default(false).describe("Mark messages as read (for inbox)"),
171833
+ toRole: z627.string().optional().describe("Target role for role-based messaging/handoff (for send)"),
171834
+ handoffStatus: z627.enum(["open", "claimed", "completed", "archived"]).optional().describe("Handoff status (for send with type=handoff)")
171600
171835
  }
171601
171836
  },
171602
171837
  async ({ action, from, to, type: msgType, content, agentId, markRead, toRole, handoffStatus }) => {
@@ -171666,8 +171901,8 @@ ${lines.join("\n")}` }] };
171666
171901
  title: "Team Poll \u2014 Situational Awareness",
171667
171902
  description: "Get a full snapshot of your project coordination state in one call. Returns: your agent info, watermark (new observations since last session), inbox (unread messages), tasks (your in-progress, available to claim, completed, failed), and team roster (active agents). Use this to decide what to work on next.",
171668
171903
  inputSchema: {
171669
- agentId: z626.string().optional().describe("Your agent ID (from team_manage join or session_start with joinTeam=true). If omitted, returns project-level overview only."),
171670
- markInboxRead: z626.boolean().optional().describe("If true, mark all inbox messages as read after returning them.")
171904
+ agentId: z627.string().optional().describe("Your agent ID (from team_manage join or session_start with joinTeam=true). If omitted, returns project-level overview only."),
171905
+ markInboxRead: z627.boolean().optional().describe("If true, mark all inbox messages as read after returning them.")
171671
171906
  }
171672
171907
  },
171673
171908
  async ({ agentId, markInboxRead }) => {
@@ -171761,13 +171996,13 @@ ${lines.join("\n")}` }] };
171761
171996
  title: "Team Handoff \u2014 Agent Context Transfer",
171762
171997
  description: "Create a structured handoff artifact when passing work to another agent. A targeted handoff is visible only to its sender and recipient; a broadcast handoff is team-visible. The handoff is stored as a durable observation (immune to archival) and a notification message is sent to the recipient. Use this when completing a task and another agent should continue, or when you want to leave context for whoever works on this next.",
171763
171998
  inputSchema: {
171764
- fromAgentId: z626.string().describe("Your agent ID (from team_manage join or session_start with joinTeam=true)"),
171765
- summary: z626.string().describe("Human-readable summary of what you did and what needs to happen next"),
171766
- context: z626.string().describe("Detailed context for the next agent: what was done, current state, known issues, next steps"),
171767
- toAgentId: z626.string().optional().describe("Specific recipient agent ID. Omit to broadcast to all."),
171768
- taskId: z626.string().optional().describe("Link to a specific team_task ID"),
171769
- filesModified: z626.array(z626.string()).optional().describe("Files you modified during this work"),
171770
- concepts: z626.array(z626.string()).optional().describe("Key concepts for search discoverability")
171999
+ fromAgentId: z627.string().describe("Your agent ID (from team_manage join or session_start with joinTeam=true)"),
172000
+ summary: z627.string().describe("Human-readable summary of what you did and what needs to happen next"),
172001
+ context: z627.string().describe("Detailed context for the next agent: what was done, current state, known issues, next steps"),
172002
+ toAgentId: z627.string().optional().describe("Specific recipient agent ID. Omit to broadcast to all."),
172003
+ taskId: z627.string().optional().describe("Link to a specific team_task ID"),
172004
+ filesModified: z627.array(z627.string()).optional().describe("Files you modified during this work"),
172005
+ concepts: z627.array(z627.string()).optional().describe("Key concepts for search discoverability")
171771
172006
  }
171772
172007
  },
171773
172008
  async ({ fromAgentId, summary, context, toAgentId, taskId, filesModified, concepts }) => {
@@ -171847,7 +172082,7 @@ ${lines.join("\n")}` }] };
171847
172082
  title: "Manage Controlled Media",
171848
172083
  description: "Use the controlled local media library for an explicit import, attachment, inspection, or MiniMax generation request. Assets stay outside the Git worktree and enter normal memory only when attach is explicitly true. Use the CLI for destructive removal, quota cleanup, and direct generation. MCP generation is disabled by default and requires MEMORIX_MCP_MEDIA_GENERATION=1 after the operator reviews provider billing.",
171849
172084
  inputSchema: {
171850
- action: z626.enum([
172085
+ action: z627.enum([
171851
172086
  "import",
171852
172087
  "attach",
171853
172088
  "list",
@@ -171858,32 +172093,32 @@ ${lines.join("\n")}` }] };
171858
172093
  ...mediaTranscriptionEnabled ? ["derive-audio"] : [],
171859
172094
  ...mediaGenerationEnabled ? ["generate-image", "generate-video"] : []
171860
172095
  ]),
171861
- path: z626.string().optional().describe("Explicit local image/audio/video/PDF path for import."),
171862
- assetId: z626.string().optional().describe("Controlled MediaAsset ID for attach/show."),
171863
- jobId: z626.string().optional().describe("Durable media job ID for status."),
171864
- kind: z626.enum(["image", "audio", "video", "document"]).optional().describe("Optional asset list filter."),
171865
- limit: z626.number().int().min(1).max(100).optional().describe("Maximum assets to list."),
171866
- title: z626.string().optional().describe("Observation title when attaching generated/imported output."),
171867
- narrative: z626.string().optional().describe("Short retrieval text when attaching an asset."),
171868
- maxPages: z626.number().int().min(1).max(100).optional().describe("Bounded PDF extraction page limit."),
171869
- maxChars: z626.number().int().min(1).max(6e4).optional().describe("Bounded PDF extraction character limit."),
171870
- attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly."),
172096
+ path: z627.string().optional().describe("Explicit local image/audio/video/PDF path for import."),
172097
+ assetId: z627.string().optional().describe("Controlled MediaAsset ID for attach/show."),
172098
+ jobId: z627.string().optional().describe("Durable media job ID for status."),
172099
+ kind: z627.enum(["image", "audio", "video", "document"]).optional().describe("Optional asset list filter."),
172100
+ limit: z627.number().int().min(1).max(100).optional().describe("Maximum assets to list."),
172101
+ title: z627.string().optional().describe("Observation title when attaching generated/imported output."),
172102
+ narrative: z627.string().optional().describe("Short retrieval text when attaching an asset."),
172103
+ maxPages: z627.number().int().min(1).max(100).optional().describe("Bounded PDF extraction page limit."),
172104
+ maxChars: z627.number().int().min(1).max(6e4).optional().describe("Bounded PDF extraction character limit."),
172105
+ attach: z627.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly."),
171871
172106
  ...mediaGenerationOrTranscription ? {
171872
- model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
171873
- prompt: z626.string().optional().describe("Explicit prompt for generation or transcription.")
172107
+ model: z627.string().max(160).optional().describe("Provider model for the selected media action."),
172108
+ prompt: z627.string().optional().describe("Explicit prompt for generation or transcription.")
171874
172109
  } : {},
171875
172110
  ...mediaTranscriptionEnabled ? {
171876
- provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
171877
- language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription.")
172111
+ provider: z627.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
172112
+ language: z627.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription.")
171878
172113
  } : {},
171879
172114
  ...mediaGenerationEnabled ? {
171880
- image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
171881
- region: z626.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
171882
- n: z626.number().int().min(1).max(4).optional().describe("Image output count."),
171883
- ratio: z626.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
171884
- width: z626.number().int().min(1).max(8192).optional().describe("Requested image width."),
171885
- height: z626.number().int().min(1).max(8192).optional().describe("Requested image height."),
171886
- duration: z626.union([z626.literal(5), z626.literal(10)]).optional().describe("MiniMax video duration in seconds.")
172115
+ image: z627.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
172116
+ region: z627.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
172117
+ n: z627.number().int().min(1).max(4).optional().describe("Image output count."),
172118
+ ratio: z627.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
172119
+ width: z627.number().int().min(1).max(8192).optional().describe("Requested image width."),
172120
+ height: z627.number().int().min(1).max(8192).optional().describe("Requested image height."),
172121
+ duration: z627.union([z627.literal(5), z627.literal(10)]).optional().describe("MiniMax video duration in seconds.")
171887
172122
  } : {}
171888
172123
  }
171889
172124
  },
@@ -172081,10 +172316,10 @@ ${lines.join("\n")}` }] };
172081
172316
  title: "Ingest Image",
172082
172317
  description: "Legacy compatibility path: import caller-provided image bytes into the controlled local asset library, then store a text retrieval projection. For durable media operations, prefer memorix_media or the media CLI.",
172083
172318
  inputSchema: {
172084
- base64: z626.string().describe("Base64-encoded image data"),
172085
- mimeType: z626.string().optional().describe("Deprecated compatibility hint. Memorix detects the actual MIME type from the image bytes."),
172086
- filename: z626.string().optional().describe("Original filename"),
172087
- prompt: z626.string().optional().describe("Custom analysis prompt")
172319
+ base64: z627.string().describe("Base64-encoded image data"),
172320
+ mimeType: z627.string().optional().describe("Deprecated compatibility hint. Memorix detects the actual MIME type from the image bytes."),
172321
+ filename: z627.string().optional().describe("Original filename"),
172322
+ prompt: z627.string().optional().describe("Custom analysis prompt")
172088
172323
  }
172089
172324
  },
172090
172325
  async (args) => {