@massa-ai/mcp-client 1.60.1 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/config-cli.js +434 -162
  2. package/dist/index.js +384 -173
  3. package/package.json +3 -3
@@ -997,7 +997,7 @@ function getConfigForEnv() {
997
997
  } else {
998
998
  console.error(`[getConfigForEnv] embedding.provider "${provider}" has no env-projection branch \u2014 no embedding env vars were set`);
999
999
  }
1000
- env.LOG_LEVEL = config.logging.level;
1000
+ env.MASSA_AI_LOG_LEVEL = config.logging.level;
1001
1001
  env.ENABLE_METRICS = String(config.logging.enableMetrics);
1002
1002
  return env;
1003
1003
  }
@@ -1571,7 +1571,7 @@ var init_config = __esm(() => {
1571
1571
  corsOrigins: envList("MASSA_AI_API_CORS_ORIGINS", fileConfig.security?.corsOrigins ?? [])
1572
1572
  },
1573
1573
  logging: {
1574
- level: process.env.LOG_LEVEL || fileConfig.logging?.level || "info",
1574
+ level: process.env.MASSA_AI_LOG_LEVEL || fileConfig.logging?.level || "info",
1575
1575
  enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics,
1576
1576
  file: process.env.MASSA_AI_LOG_FILE || fileConfig.logging?.file || path4.join(resolvedDataDir, "logs", "massa-ai.log"),
1577
1577
  enableFileSink: envBool("MASSA_AI_LOG_ENABLE_FILE_SINK", fileConfig.logging?.enableFileSink ?? true),
@@ -1904,6 +1904,32 @@ var init_log_buffer = __esm(() => {
1904
1904
  });
1905
1905
 
1906
1906
  // ../../packages/shared/dist/utils/logger.js
1907
+ function formatAgo(ms) {
1908
+ const totalSeconds = Math.floor(ms / 1000);
1909
+ if (totalSeconds < 60)
1910
+ return `${totalSeconds}s`;
1911
+ return `${Math.floor(totalSeconds / 60)}m`;
1912
+ }
1913
+ function capErrorText(value) {
1914
+ if (value.length <= MAX_ERROR_TEXT_CHARS)
1915
+ return value;
1916
+ const truncatedChars = value.length - MAX_ERROR_TEXT_CHARS;
1917
+ return `${value.slice(0, MAX_ERROR_TEXT_CHARS)}\u2026(truncated ${truncatedChars} chars)`;
1918
+ }
1919
+ function pickErrorFields(err, includeStack) {
1920
+ const out = { name: err.name, message: capErrorText(err.message) };
1921
+ if (includeStack)
1922
+ out.stack = err.stack;
1923
+ const code = err.code;
1924
+ if (code !== undefined)
1925
+ out.code = code;
1926
+ const cause = err.cause;
1927
+ if (cause !== undefined) {
1928
+ out.cause = capErrorText(cause instanceof Error ? cause.message : String(cause));
1929
+ }
1930
+ return out;
1931
+ }
1932
+
1907
1933
  class Logger {
1908
1934
  _level;
1909
1935
  _enableMetrics;
@@ -1912,6 +1938,7 @@ class Logger {
1912
1938
  _maxFileSizeBytes;
1913
1939
  _maxFiles;
1914
1940
  _initialized = false;
1941
+ repeats = new Map;
1915
1942
  constructor() {}
1916
1943
  ensureInitialized() {
1917
1944
  if (!this._initialized) {
@@ -1972,13 +1999,70 @@ class Logger {
1972
1999
  shouldLog(level) {
1973
2000
  return level >= this.level;
1974
2001
  }
2002
+ serializeMetaErrors(meta) {
2003
+ if (!meta)
2004
+ return meta;
2005
+ let out;
2006
+ for (const [key, value] of Object.entries(meta)) {
2007
+ if (value instanceof Error) {
2008
+ if (!out)
2009
+ out = { ...meta };
2010
+ out[key] = pickErrorFields(value, false);
2011
+ }
2012
+ }
2013
+ return out ?? meta;
2014
+ }
2015
+ applyRepeatAccounting(level, message, meta) {
2016
+ if (level !== LogLevel.WARN && level !== LogLevel.ERROR)
2017
+ return meta;
2018
+ const label = typeof meta?.label === "string" ? meta.label : "";
2019
+ const key = `${level}|${message}|${label}`;
2020
+ const now = Date.now();
2021
+ const existing = this.repeats.get(key);
2022
+ if (!existing || now - existing.firstSeenAt > REPEAT_WINDOW_MS) {
2023
+ if (this.repeats.size >= MAX_REPEAT_KEYS)
2024
+ this.repeats.clear();
2025
+ this.repeats.set(key, { firstSeenAt: now, count: 1 });
2026
+ return meta;
2027
+ }
2028
+ existing.count += 1;
2029
+ return {
2030
+ ...meta,
2031
+ occurrences: existing.count,
2032
+ firstSeenAgo: formatAgo(now - existing.firstSeenAt)
2033
+ };
2034
+ }
2035
+ _resetRepeatsForTesting() {
2036
+ this.repeats.clear();
2037
+ }
2038
+ safeStringifyMeta(meta) {
2039
+ const seen = new WeakSet;
2040
+ try {
2041
+ return JSON.stringify(meta, (_key, value) => {
2042
+ if (typeof value === "bigint")
2043
+ return value.toString();
2044
+ if (typeof value === "object" && value !== null) {
2045
+ if (seen.has(value))
2046
+ return "[Circular]";
2047
+ seen.add(value);
2048
+ }
2049
+ return value;
2050
+ });
2051
+ } catch (err) {
2052
+ return JSON.stringify({
2053
+ metaUnserializable: err instanceof Error ? err.message : String(err)
2054
+ });
2055
+ }
2056
+ }
1975
2057
  formatMessage(level, message, meta, timestamp = new Date().toISOString()) {
1976
- const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
2058
+ const metaStr = meta ? ` ${this.safeStringifyMeta(meta)}` : "";
1977
2059
  return `[${timestamp}] [${level}] ${message}${metaStr}`;
1978
2060
  }
1979
2061
  emit(level, message, meta) {
2062
+ const serializedMeta = this.serializeMetaErrors(meta);
2063
+ const finalMeta = this.applyRepeatAccounting(level, message, serializedMeta);
1980
2064
  const ts = new Date().toISOString();
1981
- const line = this.formatMessage(LOG_LEVEL_LABELS[level], message, meta, ts);
2065
+ const line = this.formatMessage(LOG_LEVEL_LABELS[level], message, finalMeta, ts);
1982
2066
  console.error(line);
1983
2067
  if (this.enableFileSink) {
1984
2068
  const filePath = this.logFilePath;
@@ -1990,7 +2074,7 @@ class Logger {
1990
2074
  ts,
1991
2075
  level: LOG_LEVEL_BUFFER_TAGS[level],
1992
2076
  message,
1993
- ...meta ? { meta } : {}
2077
+ ...finalMeta ? { meta: finalMeta } : {}
1994
2078
  });
1995
2079
  }
1996
2080
  debug(message, meta) {
@@ -2012,11 +2096,7 @@ class Logger {
2012
2096
  if (this.shouldLog(LogLevel.ERROR)) {
2013
2097
  const errorMeta = error ? {
2014
2098
  ...meta,
2015
- error: {
2016
- name: error.name,
2017
- message: error.message,
2018
- stack: error.stack
2019
- }
2099
+ error: error instanceof Error ? pickErrorFields(error, true) : { message: String(error) }
2020
2100
  } : meta;
2021
2101
  this.emit(LogLevel.ERROR, message, errorMeta);
2022
2102
  }
@@ -2047,7 +2127,7 @@ class Logger {
2047
2127
  return childLogger;
2048
2128
  }
2049
2129
  }
2050
- var LogLevel, LOG_LEVEL_LABELS, LOG_LEVEL_BUFFER_TAGS, logger;
2130
+ var LogLevel, LOG_LEVEL_LABELS, LOG_LEVEL_BUFFER_TAGS, REPEAT_WINDOW_MS, MAX_REPEAT_KEYS = 500, MAX_ERROR_TEXT_CHARS = 300, logger;
2051
2131
  var init_logger = __esm(() => {
2052
2132
  init_config();
2053
2133
  init_log_sink();
@@ -2070,6 +2150,7 @@ var init_logger = __esm(() => {
2070
2150
  [LogLevel.WARN]: "warn",
2071
2151
  [LogLevel.ERROR]: "error"
2072
2152
  };
2153
+ REPEAT_WINDOW_MS = 15 * 60 * 1000;
2073
2154
  logger = new Logger;
2074
2155
  });
2075
2156
 
@@ -2125,8 +2206,9 @@ var init_metrics = __esm(() => {
2125
2206
  }
2126
2207
  } catch (error) {
2127
2208
  const err = error instanceof Error ? error : new Error(String(error));
2128
- logger.warn(`Failed to fetch pricing for ${modelId}`, {
2129
- error: { name: err.name, message: err.message }
2209
+ logger.warn("MetricsCollector: failed to fetch pricing", {
2210
+ modelId,
2211
+ error: err
2130
2212
  });
2131
2213
  }
2132
2214
  const fallback = FALLBACK_PRICING[modelId];
@@ -2134,7 +2216,7 @@ var init_metrics = __esm(() => {
2134
2216
  logger.debug(`Using fallback pricing for ${modelId}`);
2135
2217
  return fallback;
2136
2218
  }
2137
- logger.warn(`Unknown model ${modelId}, using gpt-4 pricing as default`);
2219
+ logger.warn("MetricsCollector: unknown model, using gpt-4 pricing as default", { modelId });
2138
2220
  return FALLBACK_PRICING["gpt-4"];
2139
2221
  }
2140
2222
  static calculateCost(inputTokens, outputTokens, model) {
@@ -2313,7 +2395,9 @@ class SmartRateLimiter {
2313
2395
  const hasRequestCapacity = this.requestLimiter.tryConsume(1);
2314
2396
  const hasTokenCapacity = this.tokenLimiter.tryConsume(estimatedTokens);
2315
2397
  if (!hasRequestCapacity) {
2316
- logger.warn("Request rate limit exceeded");
2398
+ logger.warn("Request rate limit exceeded", {
2399
+ availableTokens: this.requestLimiter.getAvailableTokens()
2400
+ });
2317
2401
  return false;
2318
2402
  }
2319
2403
  if (!hasTokenCapacity) {
@@ -2856,6 +2940,7 @@ function readRoles(liveRoot, activeProfile) {
2856
2940
  }
2857
2941
  function runtimeDriftReport(opts = {}) {
2858
2942
  const targetHome = opts.targetHome ?? os6.homedir();
2943
+ const host = opts.host ?? "claude";
2859
2944
  const stateFilePath = opts.stateFilePath ?? path10.join(targetHome, ".config", "massa-ai", "install-state.json");
2860
2945
  let state = opts.state ?? null;
2861
2946
  if (state === null) {
@@ -2865,9 +2950,24 @@ function runtimeDriftReport(opts = {}) {
2865
2950
  state = null;
2866
2951
  }
2867
2952
  }
2868
- const platform = state?.platforms?.claude;
2953
+ const platform = state?.platforms?.[host];
2869
2954
  const stateVersion = typeof platform?.plugin?.version === "string" ? platform.plugin.version : null;
2870
2955
  const activeProfile = platform?.modelProfile?.profile ?? null;
2956
+ if (host !== "claude") {
2957
+ return {
2958
+ host,
2959
+ route: "unresolved",
2960
+ liveRoot: null,
2961
+ sourceVersion: null,
2962
+ stateVersion,
2963
+ pinnedVersion: null,
2964
+ activeProfile,
2965
+ roles: [],
2966
+ envOverride: detectEnvOverride(opts.env ?? process.env),
2967
+ versionDrift: false,
2968
+ profileMaterialized: false
2969
+ };
2970
+ }
2871
2971
  const install = resolveClaudeMarketplaceInstall({ targetHome, pluginKey: opts.pluginKey });
2872
2972
  const liveRoot = install?.root ?? null;
2873
2973
  const sourceVersion = liveRoot === null ? null : readPluginVersion(liveRoot);
@@ -2939,7 +3039,7 @@ function listProfiles(opts = {}) {
2939
3039
  installed: false,
2940
3040
  skipped: false,
2941
3041
  skipReason: null,
2942
- activeProfile: platform2.modelProfile?.profile ?? opts.hostDefaults?.[host] ?? "balanced",
3042
+ activeProfile: platform2.modelProfile?.profile ?? "balanced",
2943
3043
  bundleVersion: platform2.plugin?.version ?? null,
2944
3044
  availableProfiles: [],
2945
3045
  ...claudeDriftFields(host)
@@ -2966,7 +3066,7 @@ function listProfiles(opts = {}) {
2966
3066
  installed,
2967
3067
  skipped: false,
2968
3068
  skipReason: null,
2969
- activeProfile: platform?.modelProfile?.profile ?? opts.hostDefaults?.[host] ?? "balanced",
3069
+ activeProfile: platform?.modelProfile?.profile ?? "balanced",
2970
3070
  bundleVersion: platform?.plugin?.version ?? null,
2971
3071
  availableProfiles,
2972
3072
  ...claudeDriftFields(host)
@@ -3946,6 +4046,7 @@ var init_dist = __esm(() => {
3946
4046
  init_engine();
3947
4047
  init_variant_sync();
3948
4048
  init_repo_root();
4049
+ init_doctor();
3949
4050
  init_bootstrap();
3950
4051
  init_types();
3951
4052
  init_interfaces();
@@ -15098,7 +15199,7 @@ class ProjectIdentityAliasResolver {
15098
15199
  this.cache.set(projectId, { canonical, expiresAt: this.now() + this.ttlMs });
15099
15200
  return canonical;
15100
15201
  } catch (error) {
15101
- logger.warn("[project-identity] alias resolution failed; using original id", safeErrorSummary(error));
15202
+ logger.warn("[project-identity] alias resolution failed; using original id", { projectId, ...safeErrorSummary(error) });
15102
15203
  return projectId;
15103
15204
  }
15104
15205
  }
@@ -52643,7 +52744,7 @@ async function _checkJsonSchemaSupport() {
52643
52744
  } catch (e) {
52644
52745
  _jsonSchemaSupported = false;
52645
52746
  logger.warn("json_schema: version check error \u2014 falling back to json_object", {
52646
- error: e.message
52747
+ error: e
52647
52748
  });
52648
52749
  return false;
52649
52750
  }
@@ -52691,7 +52792,7 @@ function hostPort(url2) {
52691
52792
  return null;
52692
52793
  }
52693
52794
  }
52694
- function resolveInferenceSpec(baseUrl) {
52795
+ function resolveMatchedProviderSpec(baseUrl) {
52695
52796
  const target = hostPort(baseUrl);
52696
52797
  if (target) {
52697
52798
  const match2 = inferenceProviderList().find((spec) => hostPort(spec.defaultLlmBaseUrl) === target);
@@ -52709,7 +52810,13 @@ function resolveInferenceSpec(baseUrl) {
52709
52810
  if (embeddingProvider && LOCAL_INFERENCE_IDS.includes(embeddingProvider)) {
52710
52811
  return INFERENCE_PROVIDERS[embeddingProvider];
52711
52812
  }
52712
- return INFERENCE_PROVIDERS.ollama;
52813
+ return;
52814
+ }
52815
+ function resolveInferenceSpec(baseUrl) {
52816
+ return resolveMatchedProviderSpec(baseUrl) ?? INFERENCE_PROVIDERS.ollama;
52817
+ }
52818
+ function resolveProviderIdForLogging(baseUrl) {
52819
+ return resolveMatchedProviderSpec(baseUrl)?.id ?? "unknown";
52713
52820
  }
52714
52821
  function _wrapFetchDisableThink(baseFetch) {
52715
52822
  const wrapped = async (input, init) => {
@@ -52852,12 +52959,40 @@ function _isAbortOrTimeoutError(err) {
52852
52959
  }
52853
52960
  return false;
52854
52961
  }
52855
- async function llmComplete(prompt, opts = {}) {
52962
+ function summarizeZodIssues(error51, maxIssues = 5) {
52963
+ return error51.issues.slice(0, maxIssues).map((issue2) => `${issue2.path.join(".") || "(root)"}: ${issue2.message}`).join("; ");
52964
+ }
52965
+ function recordLlmFailure(label, role, model, baseUrl, timeoutMs, elapsedMs, err) {
52966
+ const consecutiveFailures = (llmFailureStreaks.get(label) ?? 0) + 1;
52967
+ llmFailureStreaks.set(label, consecutiveFailures);
52968
+ logger.warn("LLM call failed \u2014 using non-LLM fallback", {
52969
+ label,
52970
+ role,
52971
+ model,
52972
+ provider: resolveProviderIdForLogging(baseUrl),
52973
+ timeoutMs,
52974
+ elapsedMs,
52975
+ timedOut: _isAbortOrTimeoutError(err),
52976
+ error: err,
52977
+ consecutiveFailures
52978
+ });
52979
+ return consecutiveFailures;
52980
+ }
52981
+ function recordLlmSuccess(label, model) {
52982
+ const priorFailures = llmFailureStreaks.get(label) ?? 0;
52983
+ if (priorFailures > 0) {
52984
+ logger.info("LLM call recovered", { label, model, afterFailures: priorFailures });
52985
+ }
52986
+ llmFailureStreaks.set(label, 0);
52987
+ }
52988
+ async function llmComplete(prompt, opts) {
52856
52989
  if (!isLlmEnabled()) {
52857
52990
  return { ok: false, error: "llm disabled" };
52858
52991
  }
52859
52992
  const llm = getLlmConfig({ modelRole: opts.modelRole });
52993
+ const role = opts.modelRole ?? "instruct";
52860
52994
  const timeoutMs = opts.timeoutMs ?? llm.timeoutMs;
52995
+ const startedAt = Date.now();
52861
52996
  try {
52862
52997
  const result = await generateText({
52863
52998
  model: buildProvider(llm),
@@ -52868,14 +53003,17 @@ async function llmComplete(prompt, opts = {}) {
52868
53003
  abortSignal: timeoutSignal(timeoutMs)
52869
53004
  });
52870
53005
  const text2 = result.text ?? "";
52871
- if (text2.length > 0)
53006
+ if (text2.length > 0) {
53007
+ recordLlmSuccess(opts.label, llm.model);
52872
53008
  return { ok: true, value: text2 };
53009
+ }
52873
53010
  if (llm.disableThink) {
52874
53011
  const reasoning = _reasoningToText(result);
52875
53012
  if (reasoning.length > 0) {
52876
53013
  logger.warn("llmComplete: empty content \u2014 recovered from reasoning channel", {
52877
53014
  reasoningLen: reasoning.length
52878
53015
  });
53016
+ recordLlmSuccess(opts.label, llm.model);
52879
53017
  return { ok: true, value: reasoning };
52880
53018
  }
52881
53019
  logger.warn("llm reasoning-recovery empty", {
@@ -52883,21 +53021,22 @@ async function llmComplete(prompt, opts = {}) {
52883
53021
  finishReason: result?.finishReason ?? null
52884
53022
  });
52885
53023
  }
52886
- logger.warn("llmComplete: empty content and no reasoning \u2014 degrading", {});
52887
- return { ok: false, error: "empty content (thinking model)" };
53024
+ const emptyErr = new Error("empty content (thinking model)");
53025
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, emptyErr);
53026
+ return { ok: false, error: emptyErr.message };
52888
53027
  } catch (e) {
52889
- logger.warn("llmComplete failed \u2014 degrading to non-LLM path", {
52890
- error: e.message
52891
- });
53028
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, e);
52892
53029
  return { ok: false, error: e.message };
52893
53030
  }
52894
53031
  }
52895
- async function llmObject(prompt, schema, opts = {}) {
53032
+ async function llmObject(prompt, schema, opts) {
52896
53033
  if (!isLlmEnabled()) {
52897
53034
  return { ok: false, error: "llm disabled" };
52898
53035
  }
52899
53036
  const llm = getLlmConfig({ modelRole: opts.modelRole });
53037
+ const role = opts.modelRole ?? "instruct";
52900
53038
  const timeoutMs = opts.timeoutMs ?? llm.timeoutMs;
53039
+ const startedAt = Date.now();
52901
53040
  let result = null;
52902
53041
  try {
52903
53042
  const useJsonSchema = llm.disableThink && await _checkJsonSchemaSupport();
@@ -52912,7 +53051,8 @@ async function llmObject(prompt, schema, opts = {}) {
52912
53051
  maxOutputTokens: llm.maxOutputTokens,
52913
53052
  abortSignal: timeoutSignal(timeoutMs)
52914
53053
  });
52915
- logger.info("json_schema: constrained decoding used", {});
53054
+ logger.debug("json_schema: constrained decoding used", { label: opts.label, model: llm.model });
53055
+ recordLlmSuccess(opts.label, llm.model);
52916
53056
  return { ok: true, value: result.object };
52917
53057
  }
52918
53058
  result = await generateObject({
@@ -52926,7 +53066,8 @@ async function llmObject(prompt, schema, opts = {}) {
52926
53066
  });
52927
53067
  const validated = schema.safeParse(result.object);
52928
53068
  if (validated.success) {
52929
- logger.info("json_schema: fallback to json_object \u2014 validated", {});
53069
+ logger.debug("json_schema: fallback to json_object \u2014 validated", { label: opts.label, model: llm.model });
53070
+ recordLlmSuccess(opts.label, llm.model);
52930
53071
  return { ok: true, value: validated.data };
52931
53072
  }
52932
53073
  if (llm.disableThink) {
@@ -52939,15 +53080,17 @@ async function llmObject(prompt, schema, opts = {}) {
52939
53080
  logger.warn("llmObject: recovered object from reasoning channel (fallback path)", {
52940
53081
  reasoningLen: reasoning.length
52941
53082
  });
53083
+ recordLlmSuccess(opts.label, llm.model);
52942
53084
  return { ok: true, value: recovered.data };
52943
53085
  }
52944
53086
  }
52945
53087
  }
52946
53088
  }
52947
- logger.warn("llmObject: fallback validation failed", {
52948
- zodError: validated.error.issues.map((i) => i.message).join("; ")
53089
+ const validationErr = new Error("schema validation failed (fallback path)", {
53090
+ cause: summarizeZodIssues(validated.error)
52949
53091
  });
52950
- return { ok: false, error: "schema validation failed (fallback path)" };
53092
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, validationErr);
53093
+ return { ok: false, error: validationErr.message };
52951
53094
  } catch (e) {
52952
53095
  if (llm.disableThink && !_isAbortOrTimeoutError(e)) {
52953
53096
  const reasoning = _reasoningToText(result).length > 0 ? _reasoningToText(result) : _reasoningToText(e);
@@ -52959,6 +53102,7 @@ async function llmObject(prompt, schema, opts = {}) {
52959
53102
  logger.warn("llmObject: recovered object from reasoning channel", {
52960
53103
  reasoningLen: reasoning.length
52961
53104
  });
53105
+ recordLlmSuccess(opts.label, llm.model);
52962
53106
  return { ok: true, value: validated.data };
52963
53107
  }
52964
53108
  }
@@ -52968,19 +53112,18 @@ async function llmObject(prompt, schema, opts = {}) {
52968
53112
  finishReason: e?.finishReason ?? null
52969
53113
  });
52970
53114
  }
52971
- logger.warn("llmObject failed \u2014 degrading to non-LLM path", {
52972
- error: e.message
52973
- });
53115
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, e);
52974
53116
  return { ok: false, error: e.message };
52975
53117
  }
52976
53118
  }
52977
- var _jsonSchemaSupported = null, testEnabledOverride = null, testBaseUrlOverride = null, llm;
53119
+ var _jsonSchemaSupported = null, testEnabledOverride = null, testBaseUrlOverride = null, llmFailureStreaks, llm;
52978
53120
  var init_llm_client = __esm(() => {
52979
53121
  init_dist6();
52980
53122
  init_dist7();
52981
53123
  init_dist();
52982
53124
  init_config();
52983
53125
  init_inference_providers();
53126
+ llmFailureStreaks = new Map;
52984
53127
  llm = {
52985
53128
  complete: llmComplete,
52986
53129
  object: llmObject,
@@ -61993,7 +62136,7 @@ class MetricsCollector2 {
61993
62136
  try {
61994
62137
  writeFileSync(this.metricsPath, JSON.stringify(this.currentMetrics, null, 2));
61995
62138
  } catch (error51) {
61996
- logger.error("[Metrics] Failed to save:", error51);
62139
+ logger.error("Metrics: failed to save", error51, { path: this.metricsPath });
61997
62140
  }
61998
62141
  }
61999
62142
  reset() {
@@ -62168,7 +62311,8 @@ class EmbeddingRateLimiter {
62168
62311
  }
62169
62312
  }
62170
62313
  if (this.config.requestsPerDay && this.dailyRequestsWindow.length >= this.config.requestsPerDay) {
62171
- logger.warn(`[${this.providerId}] RPD limit reached, waiting 60s`, {
62314
+ logger.warn("EmbeddingRateLimiter: RPD limit reached, waiting 60s", {
62315
+ providerId: this.providerId,
62172
62316
  rpd: this.config.requestsPerDay,
62173
62317
  current: this.dailyRequestsWindow.length
62174
62318
  });
@@ -95471,16 +95615,16 @@ class LocalTransformersEmbeddingProvider {
95471
95615
  const out = await extractor("test", { pooling: "mean", normalize: true });
95472
95616
  const vec = Array.from(out.data);
95473
95617
  if (!Array.isArray(vec) || vec.length !== this.dimensions) {
95474
- logger.error(`[${this.id}] Invalid embedding dimensions`, undefined, { expected: this.dimensions, got: vec.length });
95618
+ logger.error("LocalTransformersProvider: invalid embedding dimensions", undefined, { providerId: this.id, expected: this.dimensions, got: vec.length });
95475
95619
  return false;
95476
95620
  }
95477
95621
  if (vec.some((v) => typeof v !== "number" || isNaN(v))) {
95478
- logger.error(`[${this.id}] Invalid embedding values (not numbers)`);
95622
+ logger.error("LocalTransformersProvider: invalid embedding values (not numbers)", undefined, { providerId: this.id });
95479
95623
  return false;
95480
95624
  }
95481
95625
  return true;
95482
95626
  } catch (error51) {
95483
- logger.error(`[${this.id}] Local provider unavailable`, error51);
95627
+ logger.error("LocalTransformersProvider: provider unavailable", error51, { providerId: this.id });
95484
95628
  return false;
95485
95629
  }
95486
95630
  }
@@ -95520,7 +95664,13 @@ async function withRetry(fn, config3, context2) {
95520
95664
  lastError2 = error51;
95521
95665
  if (attempt < config3.maxRetries) {
95522
95666
  const delay2 = getRetryDelay(attempt, config3);
95523
- logger.warn(`[EmbeddingProvider] ${context2} failed (attempt ${attempt + 1}/${config3.maxRetries + 1}), retrying in ${delay2}ms`, { error: lastError2.message });
95667
+ logger.warn("EmbeddingProvider: operation failed, retrying", {
95668
+ context: context2,
95669
+ attempt: attempt + 1,
95670
+ maxAttempts: config3.maxRetries + 1,
95671
+ delayMs: delay2,
95672
+ error: lastError2
95673
+ });
95524
95674
  await sleep(delay2);
95525
95675
  }
95526
95676
  }
@@ -95836,7 +95986,7 @@ var init_provider = __esm(() => {
95836
95986
  return output;
95837
95987
  }, this.retryConfig, `[${this.id}] embedBatchDirect (${texts.length} texts)`), this.timeout, `[${this.id}] embedBatchDirect`);
95838
95988
  } catch (error51) {
95839
- logger.warn(`[${this.id}] Ollama batch endpoint unavailable, falling back to sequential embeds: ${error51.message}`);
95989
+ logger.warn("EmbeddingProvider: Ollama batch endpoint unavailable, falling back to sequential embeds", { providerId: this.id, textCount: texts.length, error: error51 });
95840
95990
  const embeddings = [];
95841
95991
  let consecutiveFailures = 0;
95842
95992
  for (const text2 of texts) {
@@ -95875,11 +96025,11 @@ var init_provider = __esm(() => {
95875
96025
  });
95876
96026
  clearTimeout(timeoutId);
95877
96027
  if (!response.ok) {
95878
- logger.error(`[${this.id}] Ollama API returned ${response.status}`);
96028
+ logger.error("EmbeddingProvider: Ollama API returned non-OK status", undefined, { providerId: this.id, status: response.status });
95879
96029
  return false;
95880
96030
  }
95881
96031
  } catch {
95882
- logger.error(`[${this.id}] Ollama service unreachable`, undefined, { baseURL: this.baseURL, timeoutMs: 2000 });
96032
+ logger.error("EmbeddingProvider: Ollama service unreachable", undefined, { providerId: this.id, baseURL: this.baseURL, timeoutMs: 2000 });
95883
96033
  return false;
95884
96034
  }
95885
96035
  }
@@ -95889,16 +96039,16 @@ var init_provider = __esm(() => {
95889
96039
  if (Array.isArray(embedding)) {
95890
96040
  this.lastDimensionMismatch = new DimensionMismatchError(this.id, this.dimensions, embedding.length);
95891
96041
  }
95892
- logger.error(`[${this.id}] Invalid embedding dimensions`, undefined, { expected: this.dimensions, got: embedding.length });
96042
+ logger.error("EmbeddingProvider: invalid embedding dimensions", undefined, { providerId: this.id, expected: this.dimensions, got: embedding.length });
95893
96043
  return false;
95894
96044
  }
95895
96045
  if (!embedding.every((v) => typeof v === "number" && !isNaN(v))) {
95896
- logger.error(`[${this.id}] Invalid embedding values (not numbers)`);
96046
+ logger.error("EmbeddingProvider: invalid embedding values (not numbers)", undefined, { providerId: this.id });
95897
96047
  return false;
95898
96048
  }
95899
96049
  return true;
95900
96050
  } catch (error51) {
95901
- logger.error(`[${this.id}] Provider unavailable`, error51);
96051
+ logger.error("EmbeddingProvider: provider unavailable", error51, { providerId: this.id });
95902
96052
  return false;
95903
96053
  }
95904
96054
  }
@@ -108114,7 +108264,7 @@ function getPrismaClient2() {
108114
108264
  const pg2 = _adapters.loadPg();
108115
108265
  const { PrismaPg: PrismaPg2 } = _adapters.loadPrismaPg();
108116
108266
  const pool = new pg2.Pool({ connectionString: databaseUrl, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000 });
108117
- pool.on("error", (error51) => logger.error("Unexpected PG pool error", error51));
108267
+ pool.on("error", (error51) => logger.error("prisma-client: unexpected PG pool error", error51, { poolMax: 10 }));
108118
108268
  prismaPool = pool;
108119
108269
  prismaInstance = new import_prisma.PrismaClient({ adapter: new PrismaPg2(pool) });
108120
108270
  logger.info("Prisma Client initialized with PostgreSQL");
@@ -108423,7 +108573,10 @@ var init_config2 = __esm(() => {
108423
108573
  "local"
108424
108574
  ]);
108425
108575
  if (!SELECTABLE_PROVIDERS.has(selectedProvider)) {
108426
- logger.warn(`[EmbeddingConfig] selected provider "${selectedProvider}" has no runtime entry \u2014 falling back to priority order`, { source: process.env.EMBEDDING_PROVIDER ? "EMBEDDING_PROVIDER env" : "config.json embedding.provider" });
108576
+ logger.warn("EmbeddingConfig: selected provider has no runtime entry, falling back to priority order", {
108577
+ selectedProvider,
108578
+ source: process.env.EMBEDDING_PROVIDER ? "EMBEDDING_PROVIDER env" : "config.json embedding.provider"
108579
+ });
108427
108580
  }
108428
108581
  embeddingProviders = {
108429
108582
  google: (() => {
@@ -108463,7 +108616,12 @@ var init_config2 = __esm(() => {
108463
108616
  const envDimensions = Number.isInteger(rawEnvDimensions) && rawEnvDimensions > 0 ? rawEnvDimensions : undefined;
108464
108617
  const resolvedDimensions = resolveEmbeddingDimensions(model, file2?.dimensions, envDimensions);
108465
108618
  if (resolvedDimensions.correctedFrom !== undefined) {
108466
- logger.warn(`[ollama] config.json records embedding.dimensions ${resolvedDimensions.correctedFrom} for model ` + `"${model}", which emits ${resolvedDimensions.dimensions}. Using ${resolvedDimensions.dimensions}. ` + "Update embedding.dimensions in config.json (or set OLLAMA_EMBEDDING_DIMENSIONS) to silence this.");
108619
+ logger.warn("EmbeddingConfig: ollama config.json dimensions mismatch corrected", {
108620
+ provider: "ollama",
108621
+ model,
108622
+ configuredDimensions: resolvedDimensions.correctedFrom,
108623
+ correctedDimensions: resolvedDimensions.dimensions
108624
+ });
108467
108625
  }
108468
108626
  return {
108469
108627
  provider: "ollama",
@@ -108615,8 +108773,8 @@ class EmbeddingService {
108615
108773
  dimensions: this.provider.dimensions
108616
108774
  });
108617
108775
  } catch (error51) {
108618
- logger.error("Failed to initialize embedding service", error51);
108619
- logger.warn("Embedding service will use fallback mode");
108776
+ logger.error("Failed to initialize embedding service", error51, { stage: "initialize" });
108777
+ logger.warn("Embedding service will use fallback mode", { stage: "initialize" });
108620
108778
  }
108621
108779
  }
108622
108780
  async ensureInitialized() {
@@ -108698,7 +108856,7 @@ async function tryCreateProvider(config3, providerId, skipHealthCheck) {
108698
108856
  return { provider };
108699
108857
  }
108700
108858
  function refuseOnDimensionMismatch(providerId, mismatch) {
108701
- logger.error(`[${providerId}] Configured embedding provider failed with a dimension mismatch \u2014 refusing to ` + `fall through to another provider (that would silently degrade retrieval quality). ` + `configured dimensions ${mismatch.expected} \u2260 model output ${mismatch.got} \u2014 fix ` + "`embedding.dimensions` in config.json or OLLAMA_EMBEDDING_DIMENSIONS to match the model actually pulled.");
108859
+ logger.error("EmbeddingProvider: configured provider failed with a dimension mismatch, refusing to fall through", mismatch, { providerId, configuredDimensions: mismatch.expected, modelDimensions: mismatch.got });
108702
108860
  throw mismatch;
108703
108861
  }
108704
108862
  async function createEmbeddingProvider(options = {}) {
@@ -108797,6 +108955,7 @@ Write the hypothetical implementation paragraph.`;
108797
108955
  }
108798
108956
  async function rewriteQuery(query, surface, opts = {}) {
108799
108957
  const res = await surface.object(rewritePrompt(query), QueryRewriteSchema, {
108958
+ label: "query-rewrite",
108800
108959
  system: REWRITE_SYSTEM,
108801
108960
  timeoutMs: opts.timeoutMs
108802
108961
  });
@@ -108809,6 +108968,7 @@ async function rewriteQuery(query, surface, opts = {}) {
108809
108968
  }
108810
108969
  async function hyde(query, surface, embedFn, opts = {}) {
108811
108970
  const text2 = await surface.complete(hydePrompt(query), {
108971
+ label: "hyde",
108812
108972
  system: HYDE_SYSTEM,
108813
108973
  timeoutMs: opts.timeoutMs
108814
108974
  });
@@ -108822,7 +108982,7 @@ async function hyde(query, surface, embedFn, opts = {}) {
108822
108982
  return vec;
108823
108983
  } catch (e) {
108824
108984
  logger.warn("hyde embed failed \u2014 skipping HyDE stream", {
108825
- error: e.message
108985
+ error: e
108826
108986
  });
108827
108987
  return null;
108828
108988
  }
@@ -110550,7 +110710,7 @@ class KeywordSearchPg {
110550
110710
  `);
110551
110711
  this.trigramAvailable = true;
110552
110712
  } catch (error51) {
110553
- logger.warn("pg_trgm unavailable \u2014 trigram RRF stream disabled on PG", { err: error51.message });
110713
+ logger.warn("pg_trgm unavailable \u2014 trigram RRF stream disabled on PG", { error: error51 });
110554
110714
  this.trigramAvailable = false;
110555
110715
  }
110556
110716
  logger.info("PostgreSQL keyword search initialized", {
@@ -111089,7 +111249,8 @@ var init_postgres_vector_store = __esm(() => {
111089
111249
  this.schemaDimensions = providerDimensions;
111090
111250
  const { rows } = await client.query(`SELECT tablename FROM pg_tables WHERE tablename = $1`, [this.tableName]);
111091
111251
  if (rows.length === 0) {
111092
- logger.warn(`Table ${this.tableName} not found. Creating fallback table.`, {
111252
+ logger.warn("PostgresVectorStore: table not found, creating fallback table", {
111253
+ tableName: this.tableName,
111093
111254
  note: 'Run "prisma migrate deploy" to create tables via migrations'
111094
111255
  });
111095
111256
  await this.createFallbackTable(client, providerDimensions);
@@ -111126,10 +111287,12 @@ var init_postgres_vector_store = __esm(() => {
111126
111287
  if (projects.length === 0)
111127
111288
  continue;
111128
111289
  const otherDim = tablename.match(/_([0-9]+)d$/)?.[1];
111129
- logger.warn(`[vector] Orphaned chunks detected: ${tablename} has data for projects not in ${this.tableName}. Embedding model likely changed from ${otherDim}d \u2192 ${currentDim}d. Reindex required.`, {
111290
+ logger.warn("PostgresVectorStore: orphaned chunks detected, embedding model likely changed, reindex required", {
111130
111291
  currentTable: this.tableName,
111131
111292
  currentCount,
111293
+ currentDim,
111132
111294
  orphanedTable: tablename,
111295
+ orphanedDim: otherDim,
111133
111296
  affectedProjects: projects.map((p) => ({ projectId: p.project_id, chunks: p.n }))
111134
111297
  });
111135
111298
  }
@@ -111273,7 +111436,7 @@ var init_postgres_vector_store = __esm(() => {
111273
111436
  logger.warn("[postgres] Sub-batch embedding failed, falling back per-document", {
111274
111437
  subBatchIndex: Math.floor(i / EMBED_SUB_BATCH_SIZE),
111275
111438
  count: subBatch.length,
111276
- error: error51.message
111439
+ error: error51
111277
111440
  });
111278
111441
  }
111279
111442
  if (embeddings) {
@@ -111285,7 +111448,7 @@ var init_postgres_vector_store = __esm(() => {
111285
111448
  logger.warn("[postgres] Sub-batch insert failed, falling back per-document", {
111286
111449
  subBatchIndex: Math.floor(i / EMBED_SUB_BATCH_SIZE),
111287
111450
  count: subBatch.length,
111288
- error: error51.message
111451
+ error: error51
111289
111452
  });
111290
111453
  }
111291
111454
  }
@@ -111298,7 +111461,7 @@ var init_postgres_vector_store = __esm(() => {
111298
111461
  totalFailed++;
111299
111462
  logger.warn("[postgres] Skipping document due to embedding/insert error", {
111300
111463
  id: doc2.id,
111301
- error: singleError.message
111464
+ error: singleError
111302
111465
  });
111303
111466
  }
111304
111467
  }
@@ -111970,7 +112133,9 @@ class SearchAnalyticsPg {
111970
112133
  }
111971
112134
  trackSearch(event) {
111972
112135
  this.trackSearchAsync(event).catch((err) => {
111973
- logger.error("Failed to track search event", err);
112136
+ logger.error("Failed to track search event", err, {
112137
+ projectId: event.projectId
112138
+ });
111974
112139
  });
111975
112140
  }
111976
112141
  async trackSearchAsync(event) {
@@ -111995,7 +112160,9 @@ class SearchAnalyticsPg {
111995
112160
  event.score || null
111996
112161
  ]);
111997
112162
  } catch (error51) {
111998
- logger.error("Failed to track search event in PostgreSQL", error51);
112163
+ logger.error("Failed to track search event in PostgreSQL", error51, {
112164
+ projectId: event.projectId
112165
+ });
111999
112166
  }
112000
112167
  }
112001
112168
  async recordQuery(query, projectId, resultsCount = 0, duration3 = 0, cacheHit = false) {
@@ -114596,7 +114763,11 @@ class GraphStorePg {
114596
114763
  `;
114597
114764
  return rows[0] ? rowToEdge(rows[0]) : null;
114598
114765
  } catch (error51) {
114599
- logger.error("Failed to create edge", error51);
114766
+ logger.error("Failed to create edge", error51, {
114767
+ sourceId: edge.sourceId,
114768
+ targetId: edge.targetId,
114769
+ relationType: edge.relationType
114770
+ });
114600
114771
  return null;
114601
114772
  }
114602
114773
  }
@@ -115192,7 +115363,7 @@ class PgSynapseSessionStore {
115192
115363
  } catch (e) {
115193
115364
  this.hydrateFailedAt = Date.now();
115194
115365
  logger.warn("PgSynapseSessionStore hydrate failed (best-effort)", {
115195
- error: e.message
115366
+ error: e
115196
115367
  });
115197
115368
  } finally {
115198
115369
  this.hydrating = null;
@@ -115327,7 +115498,7 @@ class PgSynapseSessionStore {
115327
115498
  const next = prev.then(fn).catch((e) => {
115328
115499
  logger.warn("PgSynapseSessionStore write failed (best-effort)", {
115329
115500
  key,
115330
- error: e.message
115501
+ error: e
115331
115502
  });
115332
115503
  });
115333
115504
  this.inflight.set(key, next);
@@ -115433,7 +115604,7 @@ class SessionRegistry {
115433
115604
  try {
115434
115605
  this.store?.save(session);
115435
115606
  } catch (error51) {
115436
- logger.warn("[SessionRegistry] store save failed:", { error: error51.message });
115607
+ logger.warn("SessionRegistry: store save failed", { sessionId: session.sessionId, error: error51 });
115437
115608
  }
115438
115609
  return session;
115439
115610
  }
@@ -115441,7 +115612,7 @@ class SessionRegistry {
115441
115612
  try {
115442
115613
  await this.store?.ensureReady();
115443
115614
  } catch (error51) {
115444
- logger.warn("[SessionRegistry] store ensureReady failed:", { error: error51.message });
115615
+ logger.warn("SessionRegistry: store ensureReady failed", { error: error51 });
115445
115616
  }
115446
115617
  }
115447
115618
  async getAsync(sessionId, now2 = Date.now()) {
@@ -115462,7 +115633,7 @@ class SessionRegistry {
115462
115633
  session = loaded;
115463
115634
  }
115464
115635
  } catch (error51) {
115465
- logger.warn("[SessionRegistry] store load failed:", { error: error51.message });
115636
+ logger.warn("SessionRegistry: store load failed", { sessionId, error: error51 });
115466
115637
  }
115467
115638
  }
115468
115639
  if (!session)
@@ -115472,7 +115643,7 @@ class SessionRegistry {
115472
115643
  try {
115473
115644
  this.store?.delete(sessionId);
115474
115645
  } catch (error51) {
115475
- logger.warn("[SessionRegistry] store delete (expired) failed:", { error: error51.message });
115646
+ logger.warn("SessionRegistry: store delete (expired) failed", { sessionId, error: error51 });
115476
115647
  }
115477
115648
  return null;
115478
115649
  }
@@ -115494,7 +115665,7 @@ class SessionRegistry {
115494
115665
  try {
115495
115666
  this.store?.save(session);
115496
115667
  } catch (error51) {
115497
- logger.warn("[SessionRegistry] store save (updateTaskContext) failed:", { error: error51.message });
115668
+ logger.warn("SessionRegistry: store save (updateTaskContext) failed", { sessionId, error: error51 });
115498
115669
  }
115499
115670
  return session;
115500
115671
  }
@@ -115521,7 +115692,7 @@ class SessionRegistry {
115521
115692
  try {
115522
115693
  this.store?.recordAccess(sessionId, memoryId, nextCount);
115523
115694
  } catch (error51) {
115524
- logger.warn("[SessionRegistry] store recordAccess failed:", { error: error51.message });
115695
+ logger.warn("SessionRegistry: store recordAccess failed", { sessionId, memoryId, error: error51 });
115525
115696
  }
115526
115697
  }
115527
115698
  delete(sessionId) {
@@ -115529,7 +115700,7 @@ class SessionRegistry {
115529
115700
  try {
115530
115701
  this.store?.delete(sessionId);
115531
115702
  } catch (error51) {
115532
- logger.warn("[SessionRegistry] store delete failed:", { error: error51.message });
115703
+ logger.warn("SessionRegistry: store delete failed", { sessionId, error: error51 });
115533
115704
  }
115534
115705
  return removed;
115535
115706
  }
@@ -115557,7 +115728,7 @@ function getSessionRegistry() {
115557
115728
  const { getSessionStore: getSessionStore2 } = (init_session_store(), __toCommonJS(exports_session_store));
115558
115729
  store2 = getSessionStore2();
115559
115730
  } catch (error51) {
115560
- logger.warn("[SessionRegistry] store init failed, falling back to MemorySessionStore:", { error: error51.message });
115731
+ logger.warn("SessionRegistry: store init failed, falling back to MemorySessionStore", { error: error51 });
115561
115732
  const { MemorySessionStore: MemorySessionStore2 } = (init_session_store(), __toCommonJS(exports_session_store));
115562
115733
  store2 = new MemorySessionStore2;
115563
115734
  }
@@ -116374,19 +116545,22 @@ class LLMJudgeReranker {
116374
116545
  const tail = results.slice(k);
116375
116546
  const prompt = buildPrompt(query, head);
116376
116547
  let verdict;
116548
+ let verdictError;
116377
116549
  try {
116378
- const res = await this.llm.object(prompt, RerankVerdictSchema, { modelRole: "code" });
116550
+ const res = await this.llm.object(prompt, RerankVerdictSchema, { label: "reranker", modelRole: "code" });
116379
116551
  verdict = res.ok ? res.value ?? null : null;
116552
+ verdictError = res.ok ? undefined : res.error;
116380
116553
  } catch (e) {
116381
116554
  logger.warn("LLMJudgeReranker threw \u2014 degrading to input order", {
116382
116555
  query,
116383
- error: e.message
116556
+ error: e
116384
116557
  });
116385
116558
  return results;
116386
116559
  }
116387
116560
  if (!verdict) {
116388
116561
  logger.warn("LLMJudgeReranker got {ok:false} \u2014 degrading to input order", {
116389
- query
116562
+ query,
116563
+ error: verdictError
116390
116564
  });
116391
116565
  return results;
116392
116566
  }
@@ -118232,7 +118406,7 @@ class TaskEnvelopeService {
118232
118406
  errors4.push("prime");
118233
118407
  logger.warn("synapse_task_begin: prime sub-step failed", {
118234
118408
  sessionId,
118235
- error: err instanceof Error ? err.message : String(err)
118409
+ error: err
118236
118410
  });
118237
118411
  }
118238
118412
  }
@@ -118255,7 +118429,7 @@ class TaskEnvelopeService {
118255
118429
  errors4.push("search");
118256
118430
  logger.warn("synapse_task_begin: search sub-step failed", {
118257
118431
  sessionId,
118258
- error: err instanceof Error ? err.message : String(err)
118432
+ error: err
118259
118433
  });
118260
118434
  }
118261
118435
  if (firstHitFile) {
@@ -118278,7 +118452,7 @@ class TaskEnvelopeService {
118278
118452
  errors4.push("prefetch");
118279
118453
  logger.warn("synapse_task_begin: prefetch sub-step failed", {
118280
118454
  sessionId,
118281
- error: err instanceof Error ? err.message : String(err)
118455
+ error: err
118282
118456
  });
118283
118457
  }
118284
118458
  }
@@ -118289,7 +118463,7 @@ class TaskEnvelopeService {
118289
118463
  errors4.push("access");
118290
118464
  logger.warn("synapse_task_begin: access sub-step failed", {
118291
118465
  sessionId,
118292
- error: err instanceof Error ? err.message : String(err)
118466
+ error: err
118293
118467
  });
118294
118468
  }
118295
118469
  }
@@ -118632,7 +118806,7 @@ async function applySynapseState(deps, baseResults, query, projectId, sessionId,
118632
118806
  logger.warn("Synapse session lookup failed \u2014 using stateless search", {
118633
118807
  sessionId,
118634
118808
  projectId,
118635
- error: error51.message
118809
+ error: error51
118636
118810
  });
118637
118811
  return baseResults;
118638
118812
  }
@@ -118653,7 +118827,7 @@ async function applySynapseState(deps, baseResults, query, projectId, sessionId,
118653
118827
  logger.warn("Synapse processing failed \u2014 using stateless search", {
118654
118828
  sessionId,
118655
118829
  projectId,
118656
- error: error51.message
118830
+ error: error51
118657
118831
  });
118658
118832
  return baseResults;
118659
118833
  }
@@ -119548,7 +119722,7 @@ class RelationExtractor {
119548
119722
  } catch (error51) {
119549
119723
  logger.warn("RelationExtractor: extraction failed", {
119550
119724
  memoryId,
119551
- error: error51.message
119725
+ error: error51
119552
119726
  });
119553
119727
  }
119554
119728
  return edgesCreated;
@@ -119995,7 +120169,7 @@ class MemoryGraphService {
119995
120169
  } catch (error51) {
119996
120170
  logger.warn("Graph update failed after memory store", {
119997
120171
  memoryId,
119998
- error: error51.message
120172
+ error: error51
119999
120173
  });
120000
120174
  }
120001
120175
  }
@@ -120011,7 +120185,7 @@ class MemoryGraphService {
120011
120185
  } catch (error51) {
120012
120186
  logger.warn("Graph cleanup failed after memory delete", {
120013
120187
  memoryId,
120014
- error: error51.message
120188
+ error: error51
120015
120189
  });
120016
120190
  }
120017
120191
  }
@@ -120160,7 +120334,7 @@ async function consolidateWindow(candidates, llm2, opts = {}) {
120160
120334
  if (!llm2.isEnabled())
120161
120335
  return null;
120162
120336
  const prompt = buildPrompt2(window2);
120163
- const result = await llm2.object(prompt, ConsolidatedBatchSchema);
120337
+ const result = await llm2.object(prompt, ConsolidatedBatchSchema, { label: "memory-consolidation" });
120164
120338
  if (!result.ok || !result.value)
120165
120339
  return null;
120166
120340
  const batch = {
@@ -120261,7 +120435,7 @@ class MemoryConsolidationJob {
120261
120435
  } catch (error51) {
120262
120436
  logger.warn("Memory consolidation skipped", {
120263
120437
  trigger,
120264
- error: error51.message
120438
+ error: error51
120265
120439
  });
120266
120440
  } finally {
120267
120441
  this.running = false;
@@ -120284,7 +120458,7 @@ class MemoryConsolidationJob {
120284
120458
  candidates = await Promise.resolve(repo.listConsolidationCandidates(staleSinceMs, 500));
120285
120459
  } catch (e) {
120286
120460
  logger.warn("consolidation: candidate list failed (decay)", {
120287
- error: e.message
120461
+ error: e
120288
120462
  });
120289
120463
  return 0;
120290
120464
  }
@@ -120306,7 +120480,7 @@ class MemoryConsolidationJob {
120306
120480
  } catch (e) {
120307
120481
  logger.warn("consolidation: decay write failed", {
120308
120482
  id: row.id,
120309
- error: e.message
120483
+ error: e
120310
120484
  });
120311
120485
  }
120312
120486
  }
@@ -120335,14 +120509,14 @@ class MemoryConsolidationJob {
120335
120509
  } catch (e) {
120336
120510
  logger.warn("consolidation: soft-delete failed", {
120337
120511
  id: row.id,
120338
- error: e.message
120512
+ error: e
120339
120513
  });
120340
120514
  }
120341
120515
  }
120342
120516
  }
120343
120517
  } catch (e) {
120344
120518
  logger.warn("consolidation: prune scan failed", {
120345
- error: e.message
120519
+ error: e
120346
120520
  });
120347
120521
  }
120348
120522
  return pruned;
@@ -120353,7 +120527,7 @@ class MemoryConsolidationJob {
120353
120527
  candidates = await Promise.resolve(repo.listConsolidationCandidates(staleSinceMs, 200));
120354
120528
  } catch (e) {
120355
120529
  logger.warn("consolidation: candidate list failed (merge)", {
120356
- error: e.message
120530
+ error: e
120357
120531
  });
120358
120532
  return { merged: 0, batchesCreated: 0 };
120359
120533
  }
@@ -120379,7 +120553,7 @@ class MemoryConsolidationJob {
120379
120553
  } catch (e) {
120380
120554
  logger.warn("consolidation: merge insert failed", {
120381
120555
  batchId: batch.id,
120382
- error: e.message
120556
+ error: e
120383
120557
  });
120384
120558
  return { merged: 0, batchesCreated: 0 };
120385
120559
  }
@@ -120392,7 +120566,7 @@ class MemoryConsolidationJob {
120392
120566
  logger.warn("consolidation: addSupercedesEdge failed", {
120393
120567
  newId,
120394
120568
  sourceId,
120395
- error: e.message
120569
+ error: e
120396
120570
  });
120397
120571
  }
120398
120572
  }
@@ -120432,7 +120606,7 @@ class MemoryConsolidationJob {
120432
120606
  return result;
120433
120607
  } catch (e) {
120434
120608
  logger.warn("consolidation: promote (PG) failed", {
120435
- error: e.message
120609
+ error: e
120436
120610
  });
120437
120611
  return 0;
120438
120612
  }
@@ -120471,19 +120645,22 @@ class SalienceJudge {
120471
120645
  }
120472
120646
  const prompt = buildPrompt3(trimmed, type);
120473
120647
  let verdict;
120648
+ let verdictError;
120474
120649
  try {
120475
- const res = await this.llm.object(prompt, SalienceSchema);
120650
+ const res = await this.llm.object(prompt, SalienceSchema, { label: "salience-judge" });
120476
120651
  verdict = res.ok ? res.value ?? null : null;
120652
+ verdictError = res.ok ? undefined : res.error;
120477
120653
  } catch (e) {
120478
120654
  logger.warn("SalienceJudge threw \u2014 degrading to neutral default", {
120479
120655
  type,
120480
- error: e.message
120656
+ error: e
120481
120657
  });
120482
120658
  return { salience: NEUTRAL_SALIENCE, source: "default" };
120483
120659
  }
120484
120660
  if (!verdict) {
120485
120661
  logger.warn("SalienceJudge got {ok:false} \u2014 degrading to neutral default", {
120486
- type
120662
+ type,
120663
+ error: verdictError
120487
120664
  });
120488
120665
  return { salience: NEUTRAL_SALIENCE, source: "default" };
120489
120666
  }
@@ -120698,7 +120875,8 @@ class MemoryController {
120698
120875
  }
120699
120876
  } catch (err) {
120700
120877
  logger.warn("Graph enrichment failed", {
120701
- error: err.message
120878
+ projectId,
120879
+ error: err
120702
120880
  });
120703
120881
  }
120704
120882
  }
@@ -120900,7 +121078,7 @@ class CodeCompressor {
120900
121078
  }
120901
121079
  const prompt = buildLlmCompressPrompt(content, language3, targetRatio, preservedElements);
120902
121080
  try {
120903
- const res = await this.llmCompleteFn(prompt, { timeoutMs, modelRole: "code" });
121081
+ const res = await this.llmCompleteFn(prompt, { label: "code-compressor", timeoutMs, modelRole: "code" });
120904
121082
  if (res.ok && typeof res.value === "string" && res.value.trim().length > 0 && res.value.length <= content.length) {
120905
121083
  compressed = res.value;
120906
121084
  compressionSource = "llm";
@@ -120940,7 +121118,10 @@ class CodeCompressor {
120940
121118
  });
120941
121119
  return compressedContent;
120942
121120
  } catch (error51) {
120943
- logger.error("Code compression failed", error51);
121121
+ logger.error("Code compression failed", error51, {
121122
+ strategy: useStrategy,
121123
+ originalLength: content.length
121124
+ });
120944
121125
  return CompressedContent.identity(content);
120945
121126
  }
120946
121127
  }
@@ -121250,9 +121431,9 @@ class TokenMetrics {
121250
121431
  }
121251
121432
  throw new Error("Model not found in models.dev");
121252
121433
  } catch (error51) {
121253
- logger.warn("Failed to fetch pricing from models.dev, using fallback", {
121434
+ logger.warn("TokenMetrics: failed to fetch pricing from models.dev, using fallback", {
121254
121435
  modelId,
121255
- error: error51 instanceof Error ? error51.message : String(error51)
121436
+ error: error51
121256
121437
  });
121257
121438
  const fallback = FALLBACK_PRICING2[modelId] || FALLBACK_PRICING2["gpt-4"];
121258
121439
  this.pricingCache.set(modelId, {
@@ -122790,9 +122971,9 @@ class SymbolGraphService {
122790
122971
  return null;
122791
122972
  const workspace = graphSnapshot.workspace;
122792
122973
  const arch = await this.computeArchitectureMapSafe(graphSnapshot.architecture).catch((err) => {
122793
- logger.warn("getProjectMap: architecture map failed; skipping", {
122974
+ logger.warn("SymbolGraphService: getProjectMap architecture map failed, skipping", {
122794
122975
  projectId,
122795
- error: err?.message?.slice(0, 160)
122976
+ error: err
122796
122977
  });
122797
122978
  return null;
122798
122979
  });
@@ -123067,7 +123248,7 @@ class ContextController {
123067
123248
  });
123068
123249
  }
123069
123250
  } catch (err) {
123070
- logger.warn("Graph prefilter failed", { query, error: err.message });
123251
+ logger.warn("ContextController: graph prefilter failed", { projectId, query, error: err });
123071
123252
  }
123072
123253
  }
123073
123254
  const [searchResult, memories] = await Promise.all([
@@ -123221,9 +123402,11 @@ class ContextController {
123221
123402
  });
123222
123403
  return result.memories;
123223
123404
  } catch (error51) {
123224
- logger.warn("Memory search failed, continuing without memories", {
123225
- error: error51.message,
123226
- query: query.slice(0, 30)
123405
+ logger.warn("ContextController: memory search failed, continuing without memories", {
123406
+ projectId: opts.projectId,
123407
+ sessionId: opts.sessionId,
123408
+ query: query.slice(0, 30),
123409
+ error: error51
123227
123410
  });
123228
123411
  return [];
123229
123412
  }
@@ -123545,7 +123728,7 @@ function warnSandboxUnavailable() {
123545
123728
  return;
123546
123729
  _warnedAboutNoSandbox = true;
123547
123730
  const missingTool = process.platform === "darwin" ? "sandbox-exec" : "docker";
123548
- logger.warn(`sandbox: MASSA_AI_EXECUTOR_SANDBOX=auto found no '${missingTool}' on this platform, ` + `so code is executing with best-effort containment and no OS-level isolation. ` + `Install '${missingTool}', or set MASSA_AI_EXECUTOR_SANDBOX=on to fail loudly instead of falling back.`, { missingTool, platform: process.platform, effectiveMode: "none" });
123731
+ logger.warn("Sandbox: no sandbox tool found for auto mode, falling back to best-effort containment", { missingTool, platform: process.platform, effectiveMode: "none" });
123549
123732
  }
123550
123733
  function getSandboxMode() {
123551
123734
  const env4 = process.env.MASSA_AI_EXECUTOR_SANDBOX ?? "auto";
@@ -124460,7 +124643,10 @@ class ExecutorController {
124460
124643
  }
124461
124644
  };
124462
124645
  } catch (error51) {
124463
- logger.error("batch_execute failed", error51);
124646
+ logger.error("batch_execute failed", error51, {
124647
+ commandCount: commands.length,
124648
+ concurrency: effectiveConcurrency
124649
+ });
124464
124650
  return {
124465
124651
  success: false,
124466
124652
  error: `batch_execute failed: ${error51.message}`
@@ -127016,7 +127202,7 @@ class PgJobStore {
127016
127202
  } catch (e) {
127017
127203
  this.recovered = true;
127018
127204
  logger.warn("PgJobStore markStaleRunningFailed failed (best-effort)", {
127019
- error: e.message
127205
+ error: e
127020
127206
  });
127021
127207
  }
127022
127208
  }
@@ -127042,7 +127228,7 @@ class PgJobStore {
127042
127228
  logger.info("PgJobStore hydrated", { rows: this.mirror.size });
127043
127229
  } catch (e) {
127044
127230
  logger.warn("PgJobStore hydrate failed (best-effort)", {
127045
- error: e.message
127231
+ error: e
127046
127232
  });
127047
127233
  } finally {
127048
127234
  this.hydrating = null;
@@ -127065,7 +127251,7 @@ class PgJobStore {
127065
127251
  next.catch((e) => {
127066
127252
  logger.warn("PgJobStore.save failed (best-effort)", {
127067
127253
  jobId: job.jobId,
127068
- error: e.message
127254
+ error: e
127069
127255
  });
127070
127256
  });
127071
127257
  }
@@ -127197,7 +127383,7 @@ class PgJobStore {
127197
127383
  }
127198
127384
  } catch (e) {
127199
127385
  logger.warn("PgJobStore markStaleRunningFailed failed (best-effort)", {
127200
- error: e.message
127386
+ error: e
127201
127387
  });
127202
127388
  }
127203
127389
  })();
@@ -127387,7 +127573,13 @@ class IndexJobTracker {
127387
127573
  const stale = hbMs != null && hbMs < cutoff || hbMs == null && startedMs != null && startedMs < cutoff;
127388
127574
  if (!stale)
127389
127575
  continue;
127390
- logger.warn(`indexJobTracker: reaping stale running job ${job.jobId} (heartbeatAt=${job.heartbeatAt?.toISOString() ?? "n/a"}, startedAt=${job.startedAt?.toISOString() ?? "n/a"}, staleMs=${staleMs})`, { jobId: job.jobId, projectId: job.projectId, staleMs });
127576
+ logger.warn("indexJobTracker: reaping stale running job", {
127577
+ jobId: job.jobId,
127578
+ projectId: job.projectId,
127579
+ staleMs,
127580
+ heartbeatAt: job.heartbeatAt?.toISOString() ?? "n/a",
127581
+ startedAt: job.startedAt?.toISOString() ?? "n/a"
127582
+ });
127391
127583
  this.jobs.set(job.jobId, job);
127392
127584
  const reapedPrevStatus = job.status;
127393
127585
  this.setResult(job.jobId, undefined, "heartbeat stale (possible crash/OOM)");
@@ -127412,7 +127604,7 @@ class IndexJobTracker {
127412
127604
  try {
127413
127605
  this.store?.save(job);
127414
127606
  } catch (err) {
127415
- logger.warn(`indexJobTracker: job store write failed for ${jobId} on setResult`, { jobId, error: err?.message ?? String(err) });
127607
+ logger.warn("indexJobTracker: job store write failed on setResult", { jobId, error: err });
127416
127608
  }
127417
127609
  if (prevStatus === "pending") {
127418
127610
  this.publishStateChange(job, prevStatus);
@@ -127442,7 +127634,7 @@ class IndexJobTracker {
127442
127634
  const survivors = remaining.slice(0, this.MAX_JOBS);
127443
127635
  const overflow = remaining.slice(this.MAX_JOBS);
127444
127636
  for (const job of overflow) {
127445
- logger.warn(`indexJobTracker: evicting non-terminal job ${job.jobId} (status=${job.status}) to honor MAX_JOBS cap \u2014 caller may lose visibility`, { jobId: job.jobId, projectId: job.projectId, status: job.status });
127637
+ logger.warn("indexJobTracker: evicting non-terminal job to honor MAX_JOBS cap \u2014 caller may lose visibility", { jobId: job.jobId, projectId: job.projectId, status: job.status });
127446
127638
  this.jobs.delete(job.jobId);
127447
127639
  }
127448
127640
  }
@@ -127679,7 +127871,7 @@ class PgScheduledJobStore {
127679
127871
  logger.info("PgScheduledJobStore hydrated", { rows: this.mirror.size });
127680
127872
  } catch (e) {
127681
127873
  logger.warn("PgScheduledJobStore hydrate failed (best-effort)", {
127682
- error: e.message
127874
+ error: e
127683
127875
  });
127684
127876
  } finally {
127685
127877
  this.hydrating = null;
@@ -127693,9 +127885,10 @@ class PgScheduledJobStore {
127693
127885
  try {
127694
127886
  await action();
127695
127887
  } catch (e) {
127696
- logger.warn(`PgScheduledJobStore.${operation} failed (best-effort)`, {
127888
+ logger.warn("PgScheduledJobStore mutation failed (best-effort)", {
127697
127889
  id,
127698
- error: e.message
127890
+ operation,
127891
+ error: e
127699
127892
  });
127700
127893
  }
127701
127894
  };
@@ -127948,7 +128141,7 @@ class Scheduler {
127948
128141
  this.timer = setInterval(() => {
127949
128142
  this.tick().catch((e) => {
127950
128143
  logger.warn("Scheduler tick failed (swallowed)", {
127951
- error: e.message
128144
+ error: e
127952
128145
  });
127953
128146
  });
127954
128147
  }, this.tickIntervalMs);
@@ -128063,7 +128256,7 @@ class Scheduler {
128063
128256
  logger.warn("Scheduler: job handler threw (caught)", {
128064
128257
  id: job.id,
128065
128258
  jobKind: job.jobKind,
128066
- error: errMsg
128259
+ error: e
128067
128260
  });
128068
128261
  } finally {
128069
128262
  if (succeeded) {
@@ -128082,7 +128275,7 @@ class Scheduler {
128082
128275
  } catch (e) {
128083
128276
  logger.warn("Scheduler: persist after fire failed", {
128084
128277
  id: job.id,
128085
- error: e.message
128278
+ error: e
128086
128279
  });
128087
128280
  }
128088
128281
  this.running.delete(job.jobKind);
@@ -128102,6 +128295,8 @@ class Scheduler {
128102
128295
  enabled: j.enabled,
128103
128296
  nextRunAt: j.nextRunAt,
128104
128297
  lastRunAt: j.lastRunAt,
128298
+ lastSuccessAt: j.lastSuccessAt ?? null,
128299
+ consecutiveFailures: j.consecutiveFailures ?? 0,
128105
128300
  due: j.enabled && j.nextRunAt <= now2,
128106
128301
  currentlyRunning: this.running.has(j.jobKind)
128107
128302
  }))
@@ -128603,7 +128798,7 @@ class PgObservationStore {
128603
128798
  } catch (e) {
128604
128799
  this.hydrateFailedAt = Date.now();
128605
128800
  logger.warn("PgObservationStore hydrate failed (best-effort)", {
128606
- error: e.message
128801
+ error: e
128607
128802
  });
128608
128803
  } finally {
128609
128804
  this.hydrating = null;
@@ -128654,7 +128849,7 @@ class PgObservationStore {
128654
128849
  const next = prev.then(fn).catch((e) => {
128655
128850
  logger.warn("PgObservationStore.insert failed (best-effort)", {
128656
128851
  id: key,
128657
- error: e.message
128852
+ error: e
128658
128853
  });
128659
128854
  });
128660
128855
  this.inflight.set(key, next);
@@ -128968,7 +129163,7 @@ async function enrichWithLlm(candidates, observations, surface) {
128968
129163
  const prompt = buildEnrichmentPrompt(candidates, observations);
128969
129164
  let enrichment = null;
128970
129165
  try {
128971
- const res = await surface.object(prompt, ProposalEnrichmentSchema);
129166
+ const res = await surface.object(prompt, ProposalEnrichmentSchema, { label: "auto-improve" });
128972
129167
  if (!res.ok || !res.value || !Array.isArray(res.value.items)) {
128973
129168
  return { candidates, used: false };
128974
129169
  }
@@ -129164,7 +129359,7 @@ async function runOnce(job, projectId) {
129164
129359
  try {
129165
129360
  observations = job.observationStore.listRecent(projectId, job.maxWindow);
129166
129361
  } catch (e) {
129167
- logger.warn("auto-improve: listRecent failed", { projectId, error: e.message });
129362
+ logger.warn("auto-improve: listRecent failed", { projectId, error: e });
129168
129363
  return noop2;
129169
129364
  }
129170
129365
  if (observations.length < 2)
@@ -129179,7 +129374,7 @@ async function runOnce(job, projectId) {
129179
129374
  if (res.used)
129180
129375
  source = "llm";
129181
129376
  } catch (e) {
129182
- logger.warn("auto-improve: enrichWithLlm threw (silent)", { projectId, error: e.message });
129377
+ logger.warn("auto-improve: enrichWithLlm threw (silent)", { projectId, error: e });
129183
129378
  }
129184
129379
  const seen = new Set;
129185
129380
  const unique = candidates.filter((c) => {
@@ -129227,7 +129422,7 @@ async function runOnce(job, projectId) {
129227
129422
  } catch (e) {
129228
129423
  if (e instanceof SearchServiceError)
129229
129424
  throw e;
129230
- logger.warn("proposal:auto-approved:threw", { id: r.id, projectId, error: e.message });
129425
+ logger.warn("proposal:auto-approved:threw", { id: r.id, projectId, error: e });
129231
129426
  }
129232
129427
  }
129233
129428
  result.proposalsApplied = applied;
@@ -129256,7 +129451,7 @@ async function approve(job, id, projectId, source = "rule-based") {
129256
129451
  appliedMemoryId = await applyProposal(job, row);
129257
129452
  } catch (e) {
129258
129453
  const reason = e instanceof ApplyRejection ? e.reason : "apply-failed";
129259
- logger.warn("proposal:apply-failed", { id, projectId: row.projectId, reason, error: e.message });
129454
+ logger.warn("proposal:apply-failed", { id, projectId: row.projectId, reason, error: e });
129260
129455
  return { ok: false, reason };
129261
129456
  }
129262
129457
  let updated;
@@ -129391,9 +129586,9 @@ class AutoImproveJob {
129391
129586
  return;
129392
129587
  this.newSinceRun = 0;
129393
129588
  this.lastRunAt = now2;
129394
- this.runOnce(projectId).catch((e) => logger.warn("auto-improve: runOnce failed (silent)", { projectId, error: e.message }));
129589
+ this.runOnce(projectId).catch((e) => logger.warn("auto-improve: runOnce failed (silent)", { projectId, error: e }));
129395
129590
  } catch (e) {
129396
- logger.warn("auto-improve: maybeRun swallowed", { projectId, error: e.message });
129591
+ logger.warn("auto-improve: maybeRun swallowed", { projectId, error: e });
129397
129592
  }
129398
129593
  }
129399
129594
  async runOnce(projectId) {
@@ -129493,13 +129688,13 @@ class ObservationConsolidationJob {
129493
129688
  this.runOnce(projectId).catch((e) => {
129494
129689
  logger.warn("observation consolidation: runOnce failed (silent)", {
129495
129690
  projectId,
129496
- error: e.message
129691
+ error: e
129497
129692
  });
129498
129693
  });
129499
129694
  } catch (e) {
129500
129695
  logger.warn("observation consolidation: maybeRun swallowed", {
129501
129696
  projectId,
129502
- error: e.message
129697
+ error: e
129503
129698
  });
129504
129699
  }
129505
129700
  }
@@ -129523,7 +129718,7 @@ class ObservationConsolidationJob {
129523
129718
  } catch (e) {
129524
129719
  logger.warn("observation consolidation: listRecent failed", {
129525
129720
  projectId,
129526
- error: e.message
129721
+ error: e
129527
129722
  });
129528
129723
  return noop2;
129529
129724
  }
@@ -129534,7 +129729,7 @@ class ObservationConsolidationJob {
129534
129729
  const prompt = buildObservationPrompt(window2);
129535
129730
  let batch;
129536
129731
  try {
129537
- const res = await this.llm.object(prompt, ConsolidatedBatchSchema);
129732
+ const res = await this.llm.object(prompt, ConsolidatedBatchSchema, { label: "observation-consolidation" });
129538
129733
  if (!res.ok || !res.value) {
129539
129734
  return noop2;
129540
129735
  }
@@ -129550,7 +129745,7 @@ class ObservationConsolidationJob {
129550
129745
  } catch (e) {
129551
129746
  logger.warn("observation consolidation: llm.object threw (silent)", {
129552
129747
  projectId,
129553
- error: e.message
129748
+ error: e
129554
129749
  });
129555
129750
  return noop2;
129556
129751
  }
@@ -129579,7 +129774,7 @@ class ObservationConsolidationJob {
129579
129774
  } catch (e) {
129580
129775
  logger.warn("observation consolidation: summary insert failed", {
129581
129776
  batchId: batch.id,
129582
- error: e.message
129777
+ error: e
129583
129778
  });
129584
129779
  return noop2;
129585
129780
  }
@@ -129690,7 +129885,7 @@ class PgCheckpointStore {
129690
129885
  } catch (e) {
129691
129886
  this.hydrateFailedAt = Date.now();
129692
129887
  logger.warn("PgCheckpointStore hydrate failed (best-effort)", {
129693
- error: e.message
129888
+ error: e
129694
129889
  });
129695
129890
  } finally {
129696
129891
  this.hydrating = null;
@@ -129884,8 +130079,9 @@ class PgCheckpointStore {
129884
130079
  }
129885
130080
  return existing;
129886
130081
  } catch (e) {
129887
- logger.warn("countExistingMemoryIds failed (best-effort: assuming all exist)", {
129888
- error: e.message
130082
+ logger.warn("PgCheckpointStore: countExistingMemoryIds failed (best-effort, assuming all exist)", {
130083
+ memoryIdCount: memoryIds.length,
130084
+ error: e
129889
130085
  });
129890
130086
  return memoryIds;
129891
130087
  }
@@ -129952,7 +130148,7 @@ class PgCheckpointStore {
129952
130148
  const next = prev.then(fn).catch((e) => {
129953
130149
  logger.warn("PgCheckpointStore write failed (best-effort)", {
129954
130150
  key,
129955
- error: e.message
130151
+ error: e
129956
130152
  });
129957
130153
  });
129958
130154
  this.inflight.set(key, next);
@@ -130241,8 +130437,9 @@ var init_models_dev_client = __esm(() => {
130241
130437
  path: cachePath
130242
130438
  });
130243
130439
  } catch (error51) {
130244
- logger.warn("Failed to save local pricing cache", {
130245
- error: error51.message
130440
+ logger.warn("ModelsDevClient: failed to save local pricing cache", {
130441
+ path: cachePath,
130442
+ error: error51
130246
130443
  });
130247
130444
  }
130248
130445
  }
@@ -130464,7 +130661,7 @@ var init_models_dev_client = __esm(() => {
130464
130661
  return value;
130465
130662
  }
130466
130663
  }
130467
- logger.warn(`Model pricing not found: ${modelId}`);
130664
+ logger.warn("ModelsDevClient: model pricing not found", { modelId });
130468
130665
  return null;
130469
130666
  }
130470
130667
  async searchModels(query) {
@@ -130568,8 +130765,9 @@ var init_models_dev_client = __esm(() => {
130568
130765
  logger.debug("Local pricing cache file deleted");
130569
130766
  }
130570
130767
  } catch (error51) {
130571
- logger.warn("Failed to delete local pricing cache", {
130572
- error: error51.message
130768
+ logger.warn("ModelsDevClient: failed to delete local pricing cache", {
130769
+ path: cachePath,
130770
+ error: error51
130573
130771
  });
130574
130772
  }
130575
130773
  }
@@ -131274,8 +131472,9 @@ class DiscoverStage {
131274
131472
  };
131275
131473
  } catch (err) {
131276
131474
  logger.warn("DiscoverStage: failed to stat/read file", {
131475
+ projectId: ctx.projectId,
131277
131476
  relativePath,
131278
- error: err.message
131477
+ error: err
131279
131478
  });
131280
131479
  throw new Error(`required_file_unreadable:${relativePath}:${err.message}`);
131281
131480
  }
@@ -133800,8 +133999,9 @@ class ParseStage {
133800
133999
  timestamp: Date.now()
133801
134000
  });
133802
134001
  logger.warn("ParseStage: failed to parse file", {
134002
+ projectId: ctx.projectId,
133803
134003
  filePath: file2.relativePath,
133804
- error: err.message
134004
+ error: err
133805
134005
  });
133806
134006
  if (err instanceof StructuralEtlParseError)
133807
134007
  throw err;
@@ -135037,7 +135237,7 @@ class ResolveStage {
135037
135237
  throw new Error("structural_repository_seed_failed", { cause: err });
135038
135238
  logger.warn("buildSymbolIndex: repo seed failed, in-batch only", {
135039
135239
  projectId,
135040
- error: err?.message
135240
+ error: err
135041
135241
  });
135042
135242
  }
135043
135243
  const inBatch = new Map;
@@ -135200,7 +135400,7 @@ async function withDeadlockRetry(operation, options = {}) {
135200
135400
  attempt,
135201
135401
  maxAttempts,
135202
135402
  delayMs,
135203
- error: error51?.message?.slice(0, 120)
135403
+ error: error51
135204
135404
  });
135205
135405
  await new Promise((resolve7) => setTimeout(resolve7, delayMs));
135206
135406
  }
@@ -136330,7 +136530,7 @@ var init_pipeline = __esm(() => {
136330
136530
  logger.warn("EtlPipeline: search-admission marker write failed", {
136331
136531
  projectId,
136332
136532
  jobId,
136333
- error: markerError.message.slice(0, 160)
136533
+ error: markerError
136334
136534
  });
136335
136535
  }
136336
136536
  if (forceReindex) {
@@ -136342,7 +136542,7 @@ var init_pipeline = __esm(() => {
136342
136542
  logger.warn("EtlPipeline: embedding fingerprint stamp failed", {
136343
136543
  projectId,
136344
136544
  jobId,
136345
- error: stampError.message.slice(0, 160)
136545
+ error: stampError
136346
136546
  });
136347
136547
  }
136348
136548
  }
@@ -136505,9 +136705,10 @@ class SearchSessionHook {
136505
136705
  });
136506
136706
  } catch (err) {
136507
136707
  logger.warn("SearchSessionHook: store failed (best-effort)", {
136508
- error: err.message,
136509
136708
  projectId,
136510
- query: query.slice(0, 60)
136709
+ sessionId,
136710
+ query: query.slice(0, 60),
136711
+ error: err
136511
136712
  });
136512
136713
  }
136513
136714
  }
@@ -136583,8 +136784,10 @@ class CoRetrievalHook {
136583
136784
  peers = await this.findPeers(memoryId, projectId, sessionId);
136584
136785
  } catch (err) {
136585
136786
  logger.warn("CoRetrievalHook: peer lookup failed", {
136586
- error: err.message,
136587
- memoryId
136787
+ projectId,
136788
+ sessionId,
136789
+ memoryId,
136790
+ error: err
136588
136791
  });
136589
136792
  return;
136590
136793
  }
@@ -154094,6 +154297,7 @@ async function fetchAndConvertOne(url2, deps, opts = {}) {
154094
154297
  } catch (err) {
154095
154298
  const msg = err instanceof Error ? err.message : String(err);
154096
154299
  logger.error("fetch_and_index indexChunk failed", err, {
154300
+ projectId,
154097
154301
  url: url2,
154098
154302
  chunkId: chunk.id
154099
154303
  });
@@ -154284,6 +154488,7 @@ class WebController {
154284
154488
  return s.value;
154285
154489
  const msg = s.reason instanceof Error ? s.reason.message : String(s.reason);
154286
154490
  logger.error("fetch_and_index job rejected", s.reason, {
154491
+ projectId,
154287
154492
  url: batch[i].url
154288
154493
  });
154289
154494
  return { kind: "error", url: batch[i].url, error: msg };
@@ -154459,6 +154664,14 @@ Commands:
154459
154664
  profile set <name> [--host <h>] [--dry-run]
154460
154665
  Switch installed agents to a profile (restart required after)
154461
154666
 
154667
+ doctor [--fix] [--host <h>] [--target <dir>]
154668
+ Report agent model/profile drift: live-tree vs recorded
154669
+ versions, per-role models, variant staleness, env
154670
+ overrides. --fix re-runs the profile switch for the
154671
+ recorded active profile (restart required after).
154672
+ --target redirects the home the state/registries are
154673
+ read from (test seam, same convention as bootstrap)
154674
+
154462
154675
  bootstrap list List every startup-contract rule: state, default, description
154463
154676
  bootstrap show Same as 'bootstrap list'
154464
154677
  bootstrap enable <rule-id> [--target <dir> --yes] [--dry-run]
@@ -154476,6 +154689,8 @@ Examples:
154476
154689
  massa-ai-config set embedding.dimensions 1024
154477
154690
  massa-ai-config recover my-project --path /home/user/renamed-dir
154478
154691
  massa-ai-config profile set work --dry-run
154692
+ massa-ai-config doctor
154693
+ massa-ai-config doctor --fix
154479
154694
  massa-ai-config bootstrap list
154480
154695
  massa-ai-config bootstrap disable caveman
154481
154696
  `);
@@ -154519,6 +154734,30 @@ function formatSwitchReport(report) {
154519
154734
  A host session restart is required for the change to take effect.`);
154520
154735
  }
154521
154736
  }
154737
+ function formatDriftReport(report) {
154738
+ console.log(`doctor (${report.host}, route: ${report.route})`);
154739
+ console.log(` live root: ${report.liveRoot ?? "n/a"}`);
154740
+ console.log(` source version: ${report.sourceVersion ?? "n/a"} (live tree)`);
154741
+ console.log(` state version: ${report.stateVersion ?? "n/a"} (install-state)`);
154742
+ console.log(` pinned version: ${report.pinnedVersion ?? "n/a"} (installed_plugins)`);
154743
+ console.log(` active profile: ${report.activeProfile ?? "n/a"}`);
154744
+ for (const role of report.roles) {
154745
+ const stale = role.staleVariant ? " \u2014 STALE vs the recorded profile's variant" : "";
154746
+ console.log(` ${role.name}: model=${role.model ?? "unknown"} effort=${role.effort ?? "unknown"}${stale}`);
154747
+ }
154748
+ if (report.versionDrift) {
154749
+ console.log(` drift: live tree ${report.sourceVersion} != recorded ${report.stateVersion} \u2014 update the plugin (or re-run the installer)`);
154750
+ }
154751
+ if (report.profileMaterialized) {
154752
+ console.log(" drift: active agent files differ from the recorded profile's variants \u2014 run `massa-ai-config doctor --fix` (re-runs the profile switch)");
154753
+ }
154754
+ if (report.envOverride) {
154755
+ console.log(` override: ${report.envOverride.name}=${report.envOverride.value} wins over every per-agent model at runtime \u2014 remove it from the host env to let profiles govern`);
154756
+ }
154757
+ if (report.route !== "unresolved" && !report.versionDrift && !report.profileMaterialized && !report.envOverride) {
154758
+ console.log(" healthy: every recording agrees.");
154759
+ }
154760
+ }
154522
154761
  async function runCli(argv) {
154523
154762
  const args = argv;
154524
154763
  const command = args[0];
@@ -154754,6 +154993,39 @@ Using defaults:`);
154754
154993
  console.error("Usage: massa-ai-config profile <list|show|set> ...");
154755
154994
  return 1;
154756
154995
  }
154996
+ case "doctor": {
154997
+ const fix = options["fix"] === true;
154998
+ const hostOpt = typeof options.host === "string" ? options.host : undefined;
154999
+ if (hostOpt !== undefined && !isHost(hostOpt)) {
155000
+ console.error(`Error: unknown host "${hostOpt}"`);
155001
+ return 1;
155002
+ }
155003
+ const host = hostOpt ?? "claude";
155004
+ const targetHome = typeof options.target === "string" ? options.target : os9.homedir();
155005
+ try {
155006
+ let report = runtimeDriftReport({ targetHome, host });
155007
+ if (fix) {
155008
+ const profile = report.activeProfile;
155009
+ if (!profile) {
155010
+ console.error("Error: no recorded active profile in install-state.json \u2014 run " + "`massa-ai-config profile set <name>` first; there is nothing to fix from.");
155011
+ return 1;
155012
+ }
155013
+ const sourceRoot = findRepoRootWithMarker(import.meta.dirname, GENERATOR_MARKER, GENERATOR_MARKER_MAX_LEVELS);
155014
+ formatVariantSync(syncGeneratedVariants({ sourceRoot, targetHome }));
155015
+ const switchReport = switchProfile({ profile, host, targetHome });
155016
+ formatSwitchReport(switchReport);
155017
+ if (!reportSucceeded(switchReport)) {
155018
+ return 1;
155019
+ }
155020
+ report = runtimeDriftReport({ targetHome, host });
155021
+ }
155022
+ formatDriftReport(report);
155023
+ return 0;
155024
+ } catch (e) {
155025
+ console.error(`Error: ${e.message}`);
155026
+ return 1;
155027
+ }
155028
+ }
154757
155029
  case "bootstrap": {
154758
155030
  const subcommand = args[1];
154759
155031
  if (subcommand === "list" || subcommand === "show") {