@massa-ai/tools-api 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 (2) hide show
  1. package/dist/index.js +671 -415
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -979,7 +979,7 @@ function getConfigForEnv() {
979
979
  } else {
980
980
  console.error(`[getConfigForEnv] embedding.provider "${provider}" has no env-projection branch \u2014 no embedding env vars were set`);
981
981
  }
982
- env.LOG_LEVEL = config.logging.level;
982
+ env.MASSA_AI_LOG_LEVEL = config.logging.level;
983
983
  env.ENABLE_METRICS = String(config.logging.enableMetrics);
984
984
  return env;
985
985
  }
@@ -2025,7 +2025,7 @@ var init_config = __esm(() => {
2025
2025
  corsOrigins: envList("MASSA_AI_API_CORS_ORIGINS", fileConfig.security?.corsOrigins ?? [])
2026
2026
  },
2027
2027
  logging: {
2028
- level: process.env.LOG_LEVEL || fileConfig.logging?.level || "info",
2028
+ level: process.env.MASSA_AI_LOG_LEVEL || fileConfig.logging?.level || "info",
2029
2029
  enableMetrics: process.env.ENABLE_METRICS === "true" || process.env.ENABLE_METRICS === undefined && !!fileConfig.logging?.enableMetrics,
2030
2030
  file: process.env.MASSA_AI_LOG_FILE || fileConfig.logging?.file || path6.join(resolvedDataDir, "logs", "massa-ai.log"),
2031
2031
  enableFileSink: envBool("MASSA_AI_LOG_ENABLE_FILE_SINK", fileConfig.logging?.enableFileSink ?? true),
@@ -7558,6 +7558,32 @@ var init_log_buffer = __esm(() => {
7558
7558
  });
7559
7559
 
7560
7560
  // ../../packages/shared/dist/utils/logger.js
7561
+ function formatAgo(ms) {
7562
+ const totalSeconds = Math.floor(ms / 1000);
7563
+ if (totalSeconds < 60)
7564
+ return `${totalSeconds}s`;
7565
+ return `${Math.floor(totalSeconds / 60)}m`;
7566
+ }
7567
+ function capErrorText(value) {
7568
+ if (value.length <= MAX_ERROR_TEXT_CHARS)
7569
+ return value;
7570
+ const truncatedChars = value.length - MAX_ERROR_TEXT_CHARS;
7571
+ return `${value.slice(0, MAX_ERROR_TEXT_CHARS)}\u2026(truncated ${truncatedChars} chars)`;
7572
+ }
7573
+ function pickErrorFields(err, includeStack) {
7574
+ const out = { name: err.name, message: capErrorText(err.message) };
7575
+ if (includeStack)
7576
+ out.stack = err.stack;
7577
+ const code = err.code;
7578
+ if (code !== undefined)
7579
+ out.code = code;
7580
+ const cause = err.cause;
7581
+ if (cause !== undefined) {
7582
+ out.cause = capErrorText(cause instanceof Error ? cause.message : String(cause));
7583
+ }
7584
+ return out;
7585
+ }
7586
+
7561
7587
  class Logger {
7562
7588
  _level;
7563
7589
  _enableMetrics;
@@ -7566,6 +7592,7 @@ class Logger {
7566
7592
  _maxFileSizeBytes;
7567
7593
  _maxFiles;
7568
7594
  _initialized = false;
7595
+ repeats = new Map;
7569
7596
  constructor() {}
7570
7597
  ensureInitialized() {
7571
7598
  if (!this._initialized) {
@@ -7626,13 +7653,70 @@ class Logger {
7626
7653
  shouldLog(level) {
7627
7654
  return level >= this.level;
7628
7655
  }
7656
+ serializeMetaErrors(meta) {
7657
+ if (!meta)
7658
+ return meta;
7659
+ let out;
7660
+ for (const [key, value] of Object.entries(meta)) {
7661
+ if (value instanceof Error) {
7662
+ if (!out)
7663
+ out = { ...meta };
7664
+ out[key] = pickErrorFields(value, false);
7665
+ }
7666
+ }
7667
+ return out ?? meta;
7668
+ }
7669
+ applyRepeatAccounting(level, message, meta) {
7670
+ if (level !== LogLevel.WARN && level !== LogLevel.ERROR)
7671
+ return meta;
7672
+ const label = typeof meta?.label === "string" ? meta.label : "";
7673
+ const key = `${level}|${message}|${label}`;
7674
+ const now = Date.now();
7675
+ const existing = this.repeats.get(key);
7676
+ if (!existing || now - existing.firstSeenAt > REPEAT_WINDOW_MS) {
7677
+ if (this.repeats.size >= MAX_REPEAT_KEYS)
7678
+ this.repeats.clear();
7679
+ this.repeats.set(key, { firstSeenAt: now, count: 1 });
7680
+ return meta;
7681
+ }
7682
+ existing.count += 1;
7683
+ return {
7684
+ ...meta,
7685
+ occurrences: existing.count,
7686
+ firstSeenAgo: formatAgo(now - existing.firstSeenAt)
7687
+ };
7688
+ }
7689
+ _resetRepeatsForTesting() {
7690
+ this.repeats.clear();
7691
+ }
7692
+ safeStringifyMeta(meta) {
7693
+ const seen = new WeakSet;
7694
+ try {
7695
+ return JSON.stringify(meta, (_key, value) => {
7696
+ if (typeof value === "bigint")
7697
+ return value.toString();
7698
+ if (typeof value === "object" && value !== null) {
7699
+ if (seen.has(value))
7700
+ return "[Circular]";
7701
+ seen.add(value);
7702
+ }
7703
+ return value;
7704
+ });
7705
+ } catch (err) {
7706
+ return JSON.stringify({
7707
+ metaUnserializable: err instanceof Error ? err.message : String(err)
7708
+ });
7709
+ }
7710
+ }
7629
7711
  formatMessage(level, message, meta, timestamp = new Date().toISOString()) {
7630
- const metaStr = meta ? ` ${JSON.stringify(meta)}` : "";
7712
+ const metaStr = meta ? ` ${this.safeStringifyMeta(meta)}` : "";
7631
7713
  return `[${timestamp}] [${level}] ${message}${metaStr}`;
7632
7714
  }
7633
7715
  emit(level, message, meta) {
7716
+ const serializedMeta = this.serializeMetaErrors(meta);
7717
+ const finalMeta = this.applyRepeatAccounting(level, message, serializedMeta);
7634
7718
  const ts = new Date().toISOString();
7635
- const line = this.formatMessage(LOG_LEVEL_LABELS[level], message, meta, ts);
7719
+ const line = this.formatMessage(LOG_LEVEL_LABELS[level], message, finalMeta, ts);
7636
7720
  console.error(line);
7637
7721
  if (this.enableFileSink) {
7638
7722
  const filePath = this.logFilePath;
@@ -7644,7 +7728,7 @@ class Logger {
7644
7728
  ts,
7645
7729
  level: LOG_LEVEL_BUFFER_TAGS[level],
7646
7730
  message,
7647
- ...meta ? { meta } : {}
7731
+ ...finalMeta ? { meta: finalMeta } : {}
7648
7732
  });
7649
7733
  }
7650
7734
  debug(message, meta) {
@@ -7666,11 +7750,7 @@ class Logger {
7666
7750
  if (this.shouldLog(LogLevel.ERROR)) {
7667
7751
  const errorMeta = error ? {
7668
7752
  ...meta,
7669
- error: {
7670
- name: error.name,
7671
- message: error.message,
7672
- stack: error.stack
7673
- }
7753
+ error: error instanceof Error ? pickErrorFields(error, true) : { message: String(error) }
7674
7754
  } : meta;
7675
7755
  this.emit(LogLevel.ERROR, message, errorMeta);
7676
7756
  }
@@ -7701,7 +7781,7 @@ class Logger {
7701
7781
  return childLogger;
7702
7782
  }
7703
7783
  }
7704
- var LogLevel, LOG_LEVEL_LABELS, LOG_LEVEL_BUFFER_TAGS, logger;
7784
+ var LogLevel, LOG_LEVEL_LABELS, LOG_LEVEL_BUFFER_TAGS, REPEAT_WINDOW_MS, MAX_REPEAT_KEYS = 500, MAX_ERROR_TEXT_CHARS = 300, logger;
7705
7785
  var init_logger = __esm(() => {
7706
7786
  init_config();
7707
7787
  init_log_sink();
@@ -7724,6 +7804,7 @@ var init_logger = __esm(() => {
7724
7804
  [LogLevel.WARN]: "warn",
7725
7805
  [LogLevel.ERROR]: "error"
7726
7806
  };
7807
+ REPEAT_WINDOW_MS = 15 * 60 * 1000;
7727
7808
  logger = new Logger;
7728
7809
  });
7729
7810
 
@@ -7779,8 +7860,9 @@ var init_metrics = __esm(() => {
7779
7860
  }
7780
7861
  } catch (error) {
7781
7862
  const err = error instanceof Error ? error : new Error(String(error));
7782
- logger.warn(`Failed to fetch pricing for ${modelId}`, {
7783
- error: { name: err.name, message: err.message }
7863
+ logger.warn("MetricsCollector: failed to fetch pricing", {
7864
+ modelId,
7865
+ error: err
7784
7866
  });
7785
7867
  }
7786
7868
  const fallback = FALLBACK_PRICING[modelId];
@@ -7788,7 +7870,7 @@ var init_metrics = __esm(() => {
7788
7870
  logger.debug(`Using fallback pricing for ${modelId}`);
7789
7871
  return fallback;
7790
7872
  }
7791
- logger.warn(`Unknown model ${modelId}, using gpt-4 pricing as default`);
7873
+ logger.warn("MetricsCollector: unknown model, using gpt-4 pricing as default", { modelId });
7792
7874
  return FALLBACK_PRICING["gpt-4"];
7793
7875
  }
7794
7876
  static calculateCost(inputTokens, outputTokens, model) {
@@ -7967,7 +8049,9 @@ class SmartRateLimiter {
7967
8049
  const hasRequestCapacity = this.requestLimiter.tryConsume(1);
7968
8050
  const hasTokenCapacity = this.tokenLimiter.tryConsume(estimatedTokens);
7969
8051
  if (!hasRequestCapacity) {
7970
- logger.warn("Request rate limit exceeded");
8052
+ logger.warn("Request rate limit exceeded", {
8053
+ availableTokens: this.requestLimiter.getAvailableTokens()
8054
+ });
7971
8055
  return false;
7972
8056
  }
7973
8057
  if (!hasTokenCapacity) {
@@ -8510,6 +8594,7 @@ function readRoles(liveRoot, activeProfile) {
8510
8594
  }
8511
8595
  function runtimeDriftReport(opts = {}) {
8512
8596
  const targetHome = opts.targetHome ?? os6.homedir();
8597
+ const host = opts.host ?? "claude";
8513
8598
  const stateFilePath = opts.stateFilePath ?? path12.join(targetHome, ".config", "massa-ai", "install-state.json");
8514
8599
  let state = opts.state ?? null;
8515
8600
  if (state === null) {
@@ -8519,9 +8604,24 @@ function runtimeDriftReport(opts = {}) {
8519
8604
  state = null;
8520
8605
  }
8521
8606
  }
8522
- const platform = state?.platforms?.claude;
8607
+ const platform = state?.platforms?.[host];
8523
8608
  const stateVersion = typeof platform?.plugin?.version === "string" ? platform.plugin.version : null;
8524
8609
  const activeProfile = platform?.modelProfile?.profile ?? null;
8610
+ if (host !== "claude") {
8611
+ return {
8612
+ host,
8613
+ route: "unresolved",
8614
+ liveRoot: null,
8615
+ sourceVersion: null,
8616
+ stateVersion,
8617
+ pinnedVersion: null,
8618
+ activeProfile,
8619
+ roles: [],
8620
+ envOverride: detectEnvOverride(opts.env ?? process.env),
8621
+ versionDrift: false,
8622
+ profileMaterialized: false
8623
+ };
8624
+ }
8525
8625
  const install = resolveClaudeMarketplaceInstall({ targetHome, pluginKey: opts.pluginKey });
8526
8626
  const liveRoot = install?.root ?? null;
8527
8627
  const sourceVersion = liveRoot === null ? null : readPluginVersion(liveRoot);
@@ -8593,7 +8693,7 @@ function listProfiles(opts = {}) {
8593
8693
  installed: false,
8594
8694
  skipped: false,
8595
8695
  skipReason: null,
8596
- activeProfile: platform2.modelProfile?.profile ?? opts.hostDefaults?.[host] ?? "balanced",
8696
+ activeProfile: platform2.modelProfile?.profile ?? "balanced",
8597
8697
  bundleVersion: platform2.plugin?.version ?? null,
8598
8698
  availableProfiles: [],
8599
8699
  ...claudeDriftFields(host)
@@ -8620,7 +8720,7 @@ function listProfiles(opts = {}) {
8620
8720
  installed,
8621
8721
  skipped: false,
8622
8722
  skipReason: null,
8623
- activeProfile: platform?.modelProfile?.profile ?? opts.hostDefaults?.[host] ?? "balanced",
8723
+ activeProfile: platform?.modelProfile?.profile ?? "balanced",
8624
8724
  bundleVersion: platform?.plugin?.version ?? null,
8625
8725
  availableProfiles,
8626
8726
  ...claudeDriftFields(host)
@@ -9097,6 +9197,7 @@ var init_dist = __esm(() => {
9097
9197
  init_engine();
9098
9198
  init_variant_sync();
9099
9199
  init_repo_root();
9200
+ init_doctor();
9100
9201
  init_bootstrap();
9101
9202
  init_types();
9102
9203
  init_interfaces();
@@ -15310,7 +15411,7 @@ class ProjectIdentityAliasResolver {
15310
15411
  this.cache.set(projectId, { canonical, expiresAt: this.now() + this.ttlMs });
15311
15412
  return canonical;
15312
15413
  } catch (error) {
15313
- logger.warn("[project-identity] alias resolution failed; using original id", safeErrorSummary(error));
15414
+ logger.warn("[project-identity] alias resolution failed; using original id", { projectId, ...safeErrorSummary(error) });
15314
15415
  return projectId;
15315
15416
  }
15316
15417
  }
@@ -52855,7 +52956,7 @@ async function _checkJsonSchemaSupport() {
52855
52956
  } catch (e) {
52856
52957
  _jsonSchemaSupported = false;
52857
52958
  logger.warn("json_schema: version check error \u2014 falling back to json_object", {
52858
- error: e.message
52959
+ error: e
52859
52960
  });
52860
52961
  return false;
52861
52962
  }
@@ -52903,7 +53004,7 @@ function hostPort(url2) {
52903
53004
  return null;
52904
53005
  }
52905
53006
  }
52906
- function resolveInferenceSpec(baseUrl) {
53007
+ function resolveMatchedProviderSpec(baseUrl) {
52907
53008
  const target = hostPort(baseUrl);
52908
53009
  if (target) {
52909
53010
  const match2 = inferenceProviderList().find((spec) => hostPort(spec.defaultLlmBaseUrl) === target);
@@ -52921,7 +53022,13 @@ function resolveInferenceSpec(baseUrl) {
52921
53022
  if (embeddingProvider && LOCAL_INFERENCE_IDS.includes(embeddingProvider)) {
52922
53023
  return INFERENCE_PROVIDERS[embeddingProvider];
52923
53024
  }
52924
- return INFERENCE_PROVIDERS.ollama;
53025
+ return;
53026
+ }
53027
+ function resolveInferenceSpec(baseUrl) {
53028
+ return resolveMatchedProviderSpec(baseUrl) ?? INFERENCE_PROVIDERS.ollama;
53029
+ }
53030
+ function resolveProviderIdForLogging(baseUrl) {
53031
+ return resolveMatchedProviderSpec(baseUrl)?.id ?? "unknown";
52925
53032
  }
52926
53033
  function _wrapFetchDisableThink(baseFetch) {
52927
53034
  const wrapped = async (input, init) => {
@@ -53064,12 +53171,40 @@ function _isAbortOrTimeoutError(err) {
53064
53171
  }
53065
53172
  return false;
53066
53173
  }
53067
- async function llmComplete(prompt, opts = {}) {
53174
+ function summarizeZodIssues(error51, maxIssues = 5) {
53175
+ return error51.issues.slice(0, maxIssues).map((issue2) => `${issue2.path.join(".") || "(root)"}: ${issue2.message}`).join("; ");
53176
+ }
53177
+ function recordLlmFailure(label, role, model, baseUrl, timeoutMs, elapsedMs, err) {
53178
+ const consecutiveFailures = (llmFailureStreaks.get(label) ?? 0) + 1;
53179
+ llmFailureStreaks.set(label, consecutiveFailures);
53180
+ logger.warn("LLM call failed \u2014 using non-LLM fallback", {
53181
+ label,
53182
+ role,
53183
+ model,
53184
+ provider: resolveProviderIdForLogging(baseUrl),
53185
+ timeoutMs,
53186
+ elapsedMs,
53187
+ timedOut: _isAbortOrTimeoutError(err),
53188
+ error: err,
53189
+ consecutiveFailures
53190
+ });
53191
+ return consecutiveFailures;
53192
+ }
53193
+ function recordLlmSuccess(label, model) {
53194
+ const priorFailures = llmFailureStreaks.get(label) ?? 0;
53195
+ if (priorFailures > 0) {
53196
+ logger.info("LLM call recovered", { label, model, afterFailures: priorFailures });
53197
+ }
53198
+ llmFailureStreaks.set(label, 0);
53199
+ }
53200
+ async function llmComplete(prompt, opts) {
53068
53201
  if (!isLlmEnabled()) {
53069
53202
  return { ok: false, error: "llm disabled" };
53070
53203
  }
53071
53204
  const llm = getLlmConfig({ modelRole: opts.modelRole });
53205
+ const role = opts.modelRole ?? "instruct";
53072
53206
  const timeoutMs = opts.timeoutMs ?? llm.timeoutMs;
53207
+ const startedAt = Date.now();
53073
53208
  try {
53074
53209
  const result = await generateText({
53075
53210
  model: buildProvider(llm),
@@ -53080,14 +53215,17 @@ async function llmComplete(prompt, opts = {}) {
53080
53215
  abortSignal: timeoutSignal(timeoutMs)
53081
53216
  });
53082
53217
  const text2 = result.text ?? "";
53083
- if (text2.length > 0)
53218
+ if (text2.length > 0) {
53219
+ recordLlmSuccess(opts.label, llm.model);
53084
53220
  return { ok: true, value: text2 };
53221
+ }
53085
53222
  if (llm.disableThink) {
53086
53223
  const reasoning = _reasoningToText(result);
53087
53224
  if (reasoning.length > 0) {
53088
53225
  logger.warn("llmComplete: empty content \u2014 recovered from reasoning channel", {
53089
53226
  reasoningLen: reasoning.length
53090
53227
  });
53228
+ recordLlmSuccess(opts.label, llm.model);
53091
53229
  return { ok: true, value: reasoning };
53092
53230
  }
53093
53231
  logger.warn("llm reasoning-recovery empty", {
@@ -53095,21 +53233,22 @@ async function llmComplete(prompt, opts = {}) {
53095
53233
  finishReason: result?.finishReason ?? null
53096
53234
  });
53097
53235
  }
53098
- logger.warn("llmComplete: empty content and no reasoning \u2014 degrading", {});
53099
- return { ok: false, error: "empty content (thinking model)" };
53236
+ const emptyErr = new Error("empty content (thinking model)");
53237
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, emptyErr);
53238
+ return { ok: false, error: emptyErr.message };
53100
53239
  } catch (e) {
53101
- logger.warn("llmComplete failed \u2014 degrading to non-LLM path", {
53102
- error: e.message
53103
- });
53240
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, e);
53104
53241
  return { ok: false, error: e.message };
53105
53242
  }
53106
53243
  }
53107
- async function llmObject(prompt, schema, opts = {}) {
53244
+ async function llmObject(prompt, schema, opts) {
53108
53245
  if (!isLlmEnabled()) {
53109
53246
  return { ok: false, error: "llm disabled" };
53110
53247
  }
53111
53248
  const llm = getLlmConfig({ modelRole: opts.modelRole });
53249
+ const role = opts.modelRole ?? "instruct";
53112
53250
  const timeoutMs = opts.timeoutMs ?? llm.timeoutMs;
53251
+ const startedAt = Date.now();
53113
53252
  let result = null;
53114
53253
  try {
53115
53254
  const useJsonSchema = llm.disableThink && await _checkJsonSchemaSupport();
@@ -53124,7 +53263,8 @@ async function llmObject(prompt, schema, opts = {}) {
53124
53263
  maxOutputTokens: llm.maxOutputTokens,
53125
53264
  abortSignal: timeoutSignal(timeoutMs)
53126
53265
  });
53127
- logger.info("json_schema: constrained decoding used", {});
53266
+ logger.debug("json_schema: constrained decoding used", { label: opts.label, model: llm.model });
53267
+ recordLlmSuccess(opts.label, llm.model);
53128
53268
  return { ok: true, value: result.object };
53129
53269
  }
53130
53270
  result = await generateObject({
@@ -53138,7 +53278,8 @@ async function llmObject(prompt, schema, opts = {}) {
53138
53278
  });
53139
53279
  const validated = schema.safeParse(result.object);
53140
53280
  if (validated.success) {
53141
- logger.info("json_schema: fallback to json_object \u2014 validated", {});
53281
+ logger.debug("json_schema: fallback to json_object \u2014 validated", { label: opts.label, model: llm.model });
53282
+ recordLlmSuccess(opts.label, llm.model);
53142
53283
  return { ok: true, value: validated.data };
53143
53284
  }
53144
53285
  if (llm.disableThink) {
@@ -53151,15 +53292,17 @@ async function llmObject(prompt, schema, opts = {}) {
53151
53292
  logger.warn("llmObject: recovered object from reasoning channel (fallback path)", {
53152
53293
  reasoningLen: reasoning.length
53153
53294
  });
53295
+ recordLlmSuccess(opts.label, llm.model);
53154
53296
  return { ok: true, value: recovered.data };
53155
53297
  }
53156
53298
  }
53157
53299
  }
53158
53300
  }
53159
- logger.warn("llmObject: fallback validation failed", {
53160
- zodError: validated.error.issues.map((i) => i.message).join("; ")
53301
+ const validationErr = new Error("schema validation failed (fallback path)", {
53302
+ cause: summarizeZodIssues(validated.error)
53161
53303
  });
53162
- return { ok: false, error: "schema validation failed (fallback path)" };
53304
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, validationErr);
53305
+ return { ok: false, error: validationErr.message };
53163
53306
  } catch (e) {
53164
53307
  if (llm.disableThink && !_isAbortOrTimeoutError(e)) {
53165
53308
  const reasoning = _reasoningToText(result).length > 0 ? _reasoningToText(result) : _reasoningToText(e);
@@ -53171,6 +53314,7 @@ async function llmObject(prompt, schema, opts = {}) {
53171
53314
  logger.warn("llmObject: recovered object from reasoning channel", {
53172
53315
  reasoningLen: reasoning.length
53173
53316
  });
53317
+ recordLlmSuccess(opts.label, llm.model);
53174
53318
  return { ok: true, value: validated.data };
53175
53319
  }
53176
53320
  }
@@ -53180,19 +53324,18 @@ async function llmObject(prompt, schema, opts = {}) {
53180
53324
  finishReason: e?.finishReason ?? null
53181
53325
  });
53182
53326
  }
53183
- logger.warn("llmObject failed \u2014 degrading to non-LLM path", {
53184
- error: e.message
53185
- });
53327
+ recordLlmFailure(opts.label, role, llm.model, llm.baseUrl, timeoutMs, Date.now() - startedAt, e);
53186
53328
  return { ok: false, error: e.message };
53187
53329
  }
53188
53330
  }
53189
- var _jsonSchemaSupported = null, testEnabledOverride = null, testBaseUrlOverride = null, llm;
53331
+ var _jsonSchemaSupported = null, testEnabledOverride = null, testBaseUrlOverride = null, llmFailureStreaks, llm;
53190
53332
  var init_llm_client = __esm(() => {
53191
53333
  init_dist6();
53192
53334
  init_dist7();
53193
53335
  init_dist();
53194
53336
  init_config();
53195
53337
  init_inference_providers();
53338
+ llmFailureStreaks = new Map;
53196
53339
  llm = {
53197
53340
  complete: llmComplete,
53198
53341
  object: llmObject,
@@ -62205,7 +62348,7 @@ class MetricsCollector2 {
62205
62348
  try {
62206
62349
  writeFileSync(this.metricsPath, JSON.stringify(this.currentMetrics, null, 2));
62207
62350
  } catch (error51) {
62208
- logger.error("[Metrics] Failed to save:", error51);
62351
+ logger.error("Metrics: failed to save", error51, { path: this.metricsPath });
62209
62352
  }
62210
62353
  }
62211
62354
  reset() {
@@ -62380,7 +62523,8 @@ class EmbeddingRateLimiter {
62380
62523
  }
62381
62524
  }
62382
62525
  if (this.config.requestsPerDay && this.dailyRequestsWindow.length >= this.config.requestsPerDay) {
62383
- logger.warn(`[${this.providerId}] RPD limit reached, waiting 60s`, {
62526
+ logger.warn("EmbeddingRateLimiter: RPD limit reached, waiting 60s", {
62527
+ providerId: this.providerId,
62384
62528
  rpd: this.config.requestsPerDay,
62385
62529
  current: this.dailyRequestsWindow.length
62386
62530
  });
@@ -95683,16 +95827,16 @@ class LocalTransformersEmbeddingProvider {
95683
95827
  const out = await extractor("test", { pooling: "mean", normalize: true });
95684
95828
  const vec = Array.from(out.data);
95685
95829
  if (!Array.isArray(vec) || vec.length !== this.dimensions) {
95686
- logger.error(`[${this.id}] Invalid embedding dimensions`, undefined, { expected: this.dimensions, got: vec.length });
95830
+ logger.error("LocalTransformersProvider: invalid embedding dimensions", undefined, { providerId: this.id, expected: this.dimensions, got: vec.length });
95687
95831
  return false;
95688
95832
  }
95689
95833
  if (vec.some((v) => typeof v !== "number" || isNaN(v))) {
95690
- logger.error(`[${this.id}] Invalid embedding values (not numbers)`);
95834
+ logger.error("LocalTransformersProvider: invalid embedding values (not numbers)", undefined, { providerId: this.id });
95691
95835
  return false;
95692
95836
  }
95693
95837
  return true;
95694
95838
  } catch (error51) {
95695
- logger.error(`[${this.id}] Local provider unavailable`, error51);
95839
+ logger.error("LocalTransformersProvider: provider unavailable", error51, { providerId: this.id });
95696
95840
  return false;
95697
95841
  }
95698
95842
  }
@@ -95732,7 +95876,13 @@ async function withRetry(fn, config3, context2) {
95732
95876
  lastError2 = error51;
95733
95877
  if (attempt < config3.maxRetries) {
95734
95878
  const delay2 = getRetryDelay(attempt, config3);
95735
- logger.warn(`[EmbeddingProvider] ${context2} failed (attempt ${attempt + 1}/${config3.maxRetries + 1}), retrying in ${delay2}ms`, { error: lastError2.message });
95879
+ logger.warn("EmbeddingProvider: operation failed, retrying", {
95880
+ context: context2,
95881
+ attempt: attempt + 1,
95882
+ maxAttempts: config3.maxRetries + 1,
95883
+ delayMs: delay2,
95884
+ error: lastError2
95885
+ });
95736
95886
  await sleep(delay2);
95737
95887
  }
95738
95888
  }
@@ -96048,7 +96198,7 @@ var init_provider = __esm(() => {
96048
96198
  return output;
96049
96199
  }, this.retryConfig, `[${this.id}] embedBatchDirect (${texts.length} texts)`), this.timeout, `[${this.id}] embedBatchDirect`);
96050
96200
  } catch (error51) {
96051
- logger.warn(`[${this.id}] Ollama batch endpoint unavailable, falling back to sequential embeds: ${error51.message}`);
96201
+ logger.warn("EmbeddingProvider: Ollama batch endpoint unavailable, falling back to sequential embeds", { providerId: this.id, textCount: texts.length, error: error51 });
96052
96202
  const embeddings = [];
96053
96203
  let consecutiveFailures = 0;
96054
96204
  for (const text2 of texts) {
@@ -96087,11 +96237,11 @@ var init_provider = __esm(() => {
96087
96237
  });
96088
96238
  clearTimeout(timeoutId);
96089
96239
  if (!response.ok) {
96090
- logger.error(`[${this.id}] Ollama API returned ${response.status}`);
96240
+ logger.error("EmbeddingProvider: Ollama API returned non-OK status", undefined, { providerId: this.id, status: response.status });
96091
96241
  return false;
96092
96242
  }
96093
96243
  } catch {
96094
- logger.error(`[${this.id}] Ollama service unreachable`, undefined, { baseURL: this.baseURL, timeoutMs: 2000 });
96244
+ logger.error("EmbeddingProvider: Ollama service unreachable", undefined, { providerId: this.id, baseURL: this.baseURL, timeoutMs: 2000 });
96095
96245
  return false;
96096
96246
  }
96097
96247
  }
@@ -96101,16 +96251,16 @@ var init_provider = __esm(() => {
96101
96251
  if (Array.isArray(embedding)) {
96102
96252
  this.lastDimensionMismatch = new DimensionMismatchError(this.id, this.dimensions, embedding.length);
96103
96253
  }
96104
- logger.error(`[${this.id}] Invalid embedding dimensions`, undefined, { expected: this.dimensions, got: embedding.length });
96254
+ logger.error("EmbeddingProvider: invalid embedding dimensions", undefined, { providerId: this.id, expected: this.dimensions, got: embedding.length });
96105
96255
  return false;
96106
96256
  }
96107
96257
  if (!embedding.every((v) => typeof v === "number" && !isNaN(v))) {
96108
- logger.error(`[${this.id}] Invalid embedding values (not numbers)`);
96258
+ logger.error("EmbeddingProvider: invalid embedding values (not numbers)", undefined, { providerId: this.id });
96109
96259
  return false;
96110
96260
  }
96111
96261
  return true;
96112
96262
  } catch (error51) {
96113
- logger.error(`[${this.id}] Provider unavailable`, error51);
96263
+ logger.error("EmbeddingProvider: provider unavailable", error51, { providerId: this.id });
96114
96264
  return false;
96115
96265
  }
96116
96266
  }
@@ -106967,7 +107117,7 @@ function getPrismaClient2() {
106967
107117
  const pg = _adapters.loadPg();
106968
107118
  const { PrismaPg } = _adapters.loadPrismaPg();
106969
107119
  const pool = new pg.Pool({ connectionString: databaseUrl, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 5000 });
106970
- pool.on("error", (error51) => logger.error("Unexpected PG pool error", error51));
107120
+ pool.on("error", (error51) => logger.error("prisma-client: unexpected PG pool error", error51, { poolMax: 10 }));
106971
107121
  prismaPool = pool;
106972
107122
  prismaInstance = new import_prisma.PrismaClient({ adapter: new PrismaPg(pool) });
106973
107123
  logger.info("Prisma Client initialized with PostgreSQL");
@@ -107276,7 +107426,10 @@ var init_config2 = __esm(() => {
107276
107426
  "local"
107277
107427
  ]);
107278
107428
  if (!SELECTABLE_PROVIDERS.has(selectedProvider)) {
107279
- 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" });
107429
+ logger.warn("EmbeddingConfig: selected provider has no runtime entry, falling back to priority order", {
107430
+ selectedProvider,
107431
+ source: process.env.EMBEDDING_PROVIDER ? "EMBEDDING_PROVIDER env" : "config.json embedding.provider"
107432
+ });
107280
107433
  }
107281
107434
  embeddingProviders = {
107282
107435
  google: (() => {
@@ -107316,7 +107469,12 @@ var init_config2 = __esm(() => {
107316
107469
  const envDimensions = Number.isInteger(rawEnvDimensions) && rawEnvDimensions > 0 ? rawEnvDimensions : undefined;
107317
107470
  const resolvedDimensions = resolveEmbeddingDimensions(model, file3?.dimensions, envDimensions);
107318
107471
  if (resolvedDimensions.correctedFrom !== undefined) {
107319
- 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.");
107472
+ logger.warn("EmbeddingConfig: ollama config.json dimensions mismatch corrected", {
107473
+ provider: "ollama",
107474
+ model,
107475
+ configuredDimensions: resolvedDimensions.correctedFrom,
107476
+ correctedDimensions: resolvedDimensions.dimensions
107477
+ });
107320
107478
  }
107321
107479
  return {
107322
107480
  provider: "ollama",
@@ -107468,8 +107626,8 @@ class EmbeddingService {
107468
107626
  dimensions: this.provider.dimensions
107469
107627
  });
107470
107628
  } catch (error51) {
107471
- logger.error("Failed to initialize embedding service", error51);
107472
- logger.warn("Embedding service will use fallback mode");
107629
+ logger.error("Failed to initialize embedding service", error51, { stage: "initialize" });
107630
+ logger.warn("Embedding service will use fallback mode", { stage: "initialize" });
107473
107631
  }
107474
107632
  }
107475
107633
  async ensureInitialized() {
@@ -107551,7 +107709,7 @@ async function tryCreateProvider(config3, providerId, skipHealthCheck) {
107551
107709
  return { provider };
107552
107710
  }
107553
107711
  function refuseOnDimensionMismatch(providerId, mismatch) {
107554
- 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.");
107712
+ logger.error("EmbeddingProvider: configured provider failed with a dimension mismatch, refusing to fall through", mismatch, { providerId, configuredDimensions: mismatch.expected, modelDimensions: mismatch.got });
107555
107713
  throw mismatch;
107556
107714
  }
107557
107715
  async function createEmbeddingProvider(options = {}) {
@@ -107650,6 +107808,7 @@ Write the hypothetical implementation paragraph.`;
107650
107808
  }
107651
107809
  async function rewriteQuery(query, surface, opts = {}) {
107652
107810
  const res = await surface.object(rewritePrompt(query), QueryRewriteSchema, {
107811
+ label: "query-rewrite",
107653
107812
  system: REWRITE_SYSTEM,
107654
107813
  timeoutMs: opts.timeoutMs
107655
107814
  });
@@ -107662,6 +107821,7 @@ async function rewriteQuery(query, surface, opts = {}) {
107662
107821
  }
107663
107822
  async function hyde(query, surface, embedFn, opts = {}) {
107664
107823
  const text2 = await surface.complete(hydePrompt(query), {
107824
+ label: "hyde",
107665
107825
  system: HYDE_SYSTEM,
107666
107826
  timeoutMs: opts.timeoutMs
107667
107827
  });
@@ -107675,7 +107835,7 @@ async function hyde(query, surface, embedFn, opts = {}) {
107675
107835
  return vec;
107676
107836
  } catch (e) {
107677
107837
  logger.warn("hyde embed failed \u2014 skipping HyDE stream", {
107678
- error: e.message
107838
+ error: e
107679
107839
  });
107680
107840
  return null;
107681
107841
  }
@@ -109403,7 +109563,7 @@ class KeywordSearchPg {
109403
109563
  `);
109404
109564
  this.trigramAvailable = true;
109405
109565
  } catch (error51) {
109406
- logger.warn("pg_trgm unavailable \u2014 trigram RRF stream disabled on PG", { err: error51.message });
109566
+ logger.warn("pg_trgm unavailable \u2014 trigram RRF stream disabled on PG", { error: error51 });
109407
109567
  this.trigramAvailable = false;
109408
109568
  }
109409
109569
  logger.info("PostgreSQL keyword search initialized", {
@@ -109942,7 +110102,8 @@ var init_postgres_vector_store = __esm(() => {
109942
110102
  this.schemaDimensions = providerDimensions;
109943
110103
  const { rows } = await client.query(`SELECT tablename FROM pg_tables WHERE tablename = $1`, [this.tableName]);
109944
110104
  if (rows.length === 0) {
109945
- logger.warn(`Table ${this.tableName} not found. Creating fallback table.`, {
110105
+ logger.warn("PostgresVectorStore: table not found, creating fallback table", {
110106
+ tableName: this.tableName,
109946
110107
  note: 'Run "prisma migrate deploy" to create tables via migrations'
109947
110108
  });
109948
110109
  await this.createFallbackTable(client, providerDimensions);
@@ -109979,10 +110140,12 @@ var init_postgres_vector_store = __esm(() => {
109979
110140
  if (projects.length === 0)
109980
110141
  continue;
109981
110142
  const otherDim = tablename.match(/_([0-9]+)d$/)?.[1];
109982
- 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.`, {
110143
+ logger.warn("PostgresVectorStore: orphaned chunks detected, embedding model likely changed, reindex required", {
109983
110144
  currentTable: this.tableName,
109984
110145
  currentCount,
110146
+ currentDim,
109985
110147
  orphanedTable: tablename,
110148
+ orphanedDim: otherDim,
109986
110149
  affectedProjects: projects.map((p) => ({ projectId: p.project_id, chunks: p.n }))
109987
110150
  });
109988
110151
  }
@@ -110126,7 +110289,7 @@ var init_postgres_vector_store = __esm(() => {
110126
110289
  logger.warn("[postgres] Sub-batch embedding failed, falling back per-document", {
110127
110290
  subBatchIndex: Math.floor(i / EMBED_SUB_BATCH_SIZE),
110128
110291
  count: subBatch.length,
110129
- error: error51.message
110292
+ error: error51
110130
110293
  });
110131
110294
  }
110132
110295
  if (embeddings) {
@@ -110138,7 +110301,7 @@ var init_postgres_vector_store = __esm(() => {
110138
110301
  logger.warn("[postgres] Sub-batch insert failed, falling back per-document", {
110139
110302
  subBatchIndex: Math.floor(i / EMBED_SUB_BATCH_SIZE),
110140
110303
  count: subBatch.length,
110141
- error: error51.message
110304
+ error: error51
110142
110305
  });
110143
110306
  }
110144
110307
  }
@@ -110151,7 +110314,7 @@ var init_postgres_vector_store = __esm(() => {
110151
110314
  totalFailed++;
110152
110315
  logger.warn("[postgres] Skipping document due to embedding/insert error", {
110153
110316
  id: doc2.id,
110154
- error: singleError.message
110317
+ error: singleError
110155
110318
  });
110156
110319
  }
110157
110320
  }
@@ -110817,7 +110980,9 @@ class SearchAnalyticsPg {
110817
110980
  }
110818
110981
  trackSearch(event) {
110819
110982
  this.trackSearchAsync(event).catch((err) => {
110820
- logger.error("Failed to track search event", err);
110983
+ logger.error("Failed to track search event", err, {
110984
+ projectId: event.projectId
110985
+ });
110821
110986
  });
110822
110987
  }
110823
110988
  async trackSearchAsync(event) {
@@ -110842,7 +111007,9 @@ class SearchAnalyticsPg {
110842
111007
  event.score || null
110843
111008
  ]);
110844
111009
  } catch (error51) {
110845
- logger.error("Failed to track search event in PostgreSQL", error51);
111010
+ logger.error("Failed to track search event in PostgreSQL", error51, {
111011
+ projectId: event.projectId
111012
+ });
110846
111013
  }
110847
111014
  }
110848
111015
  async recordQuery(query, projectId, resultsCount = 0, duration3 = 0, cacheHit = false) {
@@ -113443,7 +113610,11 @@ class GraphStorePg {
113443
113610
  `;
113444
113611
  return rows[0] ? rowToEdge(rows[0]) : null;
113445
113612
  } catch (error51) {
113446
- logger.error("Failed to create edge", error51);
113613
+ logger.error("Failed to create edge", error51, {
113614
+ sourceId: edge.sourceId,
113615
+ targetId: edge.targetId,
113616
+ relationType: edge.relationType
113617
+ });
113447
113618
  return null;
113448
113619
  }
113449
113620
  }
@@ -114039,7 +114210,7 @@ class PgSynapseSessionStore {
114039
114210
  } catch (e) {
114040
114211
  this.hydrateFailedAt = Date.now();
114041
114212
  logger.warn("PgSynapseSessionStore hydrate failed (best-effort)", {
114042
- error: e.message
114213
+ error: e
114043
114214
  });
114044
114215
  } finally {
114045
114216
  this.hydrating = null;
@@ -114174,7 +114345,7 @@ class PgSynapseSessionStore {
114174
114345
  const next = prev.then(fn).catch((e) => {
114175
114346
  logger.warn("PgSynapseSessionStore write failed (best-effort)", {
114176
114347
  key,
114177
- error: e.message
114348
+ error: e
114178
114349
  });
114179
114350
  });
114180
114351
  this.inflight.set(key, next);
@@ -114280,7 +114451,7 @@ class SessionRegistry {
114280
114451
  try {
114281
114452
  this.store?.save(session);
114282
114453
  } catch (error51) {
114283
- logger.warn("[SessionRegistry] store save failed:", { error: error51.message });
114454
+ logger.warn("SessionRegistry: store save failed", { sessionId: session.sessionId, error: error51 });
114284
114455
  }
114285
114456
  return session;
114286
114457
  }
@@ -114288,7 +114459,7 @@ class SessionRegistry {
114288
114459
  try {
114289
114460
  await this.store?.ensureReady();
114290
114461
  } catch (error51) {
114291
- logger.warn("[SessionRegistry] store ensureReady failed:", { error: error51.message });
114462
+ logger.warn("SessionRegistry: store ensureReady failed", { error: error51 });
114292
114463
  }
114293
114464
  }
114294
114465
  async getAsync(sessionId, now2 = Date.now()) {
@@ -114309,7 +114480,7 @@ class SessionRegistry {
114309
114480
  session = loaded;
114310
114481
  }
114311
114482
  } catch (error51) {
114312
- logger.warn("[SessionRegistry] store load failed:", { error: error51.message });
114483
+ logger.warn("SessionRegistry: store load failed", { sessionId, error: error51 });
114313
114484
  }
114314
114485
  }
114315
114486
  if (!session)
@@ -114319,7 +114490,7 @@ class SessionRegistry {
114319
114490
  try {
114320
114491
  this.store?.delete(sessionId);
114321
114492
  } catch (error51) {
114322
- logger.warn("[SessionRegistry] store delete (expired) failed:", { error: error51.message });
114493
+ logger.warn("SessionRegistry: store delete (expired) failed", { sessionId, error: error51 });
114323
114494
  }
114324
114495
  return null;
114325
114496
  }
@@ -114341,7 +114512,7 @@ class SessionRegistry {
114341
114512
  try {
114342
114513
  this.store?.save(session);
114343
114514
  } catch (error51) {
114344
- logger.warn("[SessionRegistry] store save (updateTaskContext) failed:", { error: error51.message });
114515
+ logger.warn("SessionRegistry: store save (updateTaskContext) failed", { sessionId, error: error51 });
114345
114516
  }
114346
114517
  return session;
114347
114518
  }
@@ -114368,7 +114539,7 @@ class SessionRegistry {
114368
114539
  try {
114369
114540
  this.store?.recordAccess(sessionId, memoryId, nextCount);
114370
114541
  } catch (error51) {
114371
- logger.warn("[SessionRegistry] store recordAccess failed:", { error: error51.message });
114542
+ logger.warn("SessionRegistry: store recordAccess failed", { sessionId, memoryId, error: error51 });
114372
114543
  }
114373
114544
  }
114374
114545
  delete(sessionId) {
@@ -114376,7 +114547,7 @@ class SessionRegistry {
114376
114547
  try {
114377
114548
  this.store?.delete(sessionId);
114378
114549
  } catch (error51) {
114379
- logger.warn("[SessionRegistry] store delete failed:", { error: error51.message });
114550
+ logger.warn("SessionRegistry: store delete failed", { sessionId, error: error51 });
114380
114551
  }
114381
114552
  return removed;
114382
114553
  }
@@ -114404,7 +114575,7 @@ function getSessionRegistry() {
114404
114575
  const { getSessionStore: getSessionStore2 } = (init_session_store(), __toCommonJS(exports_session_store));
114405
114576
  store2 = getSessionStore2();
114406
114577
  } catch (error51) {
114407
- logger.warn("[SessionRegistry] store init failed, falling back to MemorySessionStore:", { error: error51.message });
114578
+ logger.warn("SessionRegistry: store init failed, falling back to MemorySessionStore", { error: error51 });
114408
114579
  const { MemorySessionStore: MemorySessionStore2 } = (init_session_store(), __toCommonJS(exports_session_store));
114409
114580
  store2 = new MemorySessionStore2;
114410
114581
  }
@@ -115221,19 +115392,22 @@ class LLMJudgeReranker {
115221
115392
  const tail = results.slice(k2);
115222
115393
  const prompt = buildPrompt(query, head);
115223
115394
  let verdict;
115395
+ let verdictError;
115224
115396
  try {
115225
- const res = await this.llm.object(prompt, RerankVerdictSchema, { modelRole: "code" });
115397
+ const res = await this.llm.object(prompt, RerankVerdictSchema, { label: "reranker", modelRole: "code" });
115226
115398
  verdict = res.ok ? res.value ?? null : null;
115399
+ verdictError = res.ok ? undefined : res.error;
115227
115400
  } catch (e) {
115228
115401
  logger.warn("LLMJudgeReranker threw \u2014 degrading to input order", {
115229
115402
  query,
115230
- error: e.message
115403
+ error: e
115231
115404
  });
115232
115405
  return results;
115233
115406
  }
115234
115407
  if (!verdict) {
115235
115408
  logger.warn("LLMJudgeReranker got {ok:false} \u2014 degrading to input order", {
115236
- query
115409
+ query,
115410
+ error: verdictError
115237
115411
  });
115238
115412
  return results;
115239
115413
  }
@@ -117079,7 +117253,7 @@ class TaskEnvelopeService {
117079
117253
  errors5.push("prime");
117080
117254
  logger.warn("synapse_task_begin: prime sub-step failed", {
117081
117255
  sessionId,
117082
- error: err instanceof Error ? err.message : String(err)
117256
+ error: err
117083
117257
  });
117084
117258
  }
117085
117259
  }
@@ -117102,7 +117276,7 @@ class TaskEnvelopeService {
117102
117276
  errors5.push("search");
117103
117277
  logger.warn("synapse_task_begin: search sub-step failed", {
117104
117278
  sessionId,
117105
- error: err instanceof Error ? err.message : String(err)
117279
+ error: err
117106
117280
  });
117107
117281
  }
117108
117282
  if (firstHitFile) {
@@ -117125,7 +117299,7 @@ class TaskEnvelopeService {
117125
117299
  errors5.push("prefetch");
117126
117300
  logger.warn("synapse_task_begin: prefetch sub-step failed", {
117127
117301
  sessionId,
117128
- error: err instanceof Error ? err.message : String(err)
117302
+ error: err
117129
117303
  });
117130
117304
  }
117131
117305
  }
@@ -117136,7 +117310,7 @@ class TaskEnvelopeService {
117136
117310
  errors5.push("access");
117137
117311
  logger.warn("synapse_task_begin: access sub-step failed", {
117138
117312
  sessionId,
117139
- error: err instanceof Error ? err.message : String(err)
117313
+ error: err
117140
117314
  });
117141
117315
  }
117142
117316
  }
@@ -117479,7 +117653,7 @@ async function applySynapseState(deps, baseResults, query, projectId, sessionId,
117479
117653
  logger.warn("Synapse session lookup failed \u2014 using stateless search", {
117480
117654
  sessionId,
117481
117655
  projectId,
117482
- error: error51.message
117656
+ error: error51
117483
117657
  });
117484
117658
  return baseResults;
117485
117659
  }
@@ -117500,7 +117674,7 @@ async function applySynapseState(deps, baseResults, query, projectId, sessionId,
117500
117674
  logger.warn("Synapse processing failed \u2014 using stateless search", {
117501
117675
  sessionId,
117502
117676
  projectId,
117503
- error: error51.message
117677
+ error: error51
117504
117678
  });
117505
117679
  return baseResults;
117506
117680
  }
@@ -118260,7 +118434,7 @@ class PgJobStore {
118260
118434
  } catch (e) {
118261
118435
  this.recovered = true;
118262
118436
  logger.warn("PgJobStore markStaleRunningFailed failed (best-effort)", {
118263
- error: e.message
118437
+ error: e
118264
118438
  });
118265
118439
  }
118266
118440
  }
@@ -118286,7 +118460,7 @@ class PgJobStore {
118286
118460
  logger.info("PgJobStore hydrated", { rows: this.mirror.size });
118287
118461
  } catch (e) {
118288
118462
  logger.warn("PgJobStore hydrate failed (best-effort)", {
118289
- error: e.message
118463
+ error: e
118290
118464
  });
118291
118465
  } finally {
118292
118466
  this.hydrating = null;
@@ -118309,7 +118483,7 @@ class PgJobStore {
118309
118483
  next.catch((e) => {
118310
118484
  logger.warn("PgJobStore.save failed (best-effort)", {
118311
118485
  jobId: job.jobId,
118312
- error: e.message
118486
+ error: e
118313
118487
  });
118314
118488
  });
118315
118489
  }
@@ -118441,7 +118615,7 @@ class PgJobStore {
118441
118615
  }
118442
118616
  } catch (e) {
118443
118617
  logger.warn("PgJobStore markStaleRunningFailed failed (best-effort)", {
118444
- error: e.message
118618
+ error: e
118445
118619
  });
118446
118620
  }
118447
118621
  })();
@@ -118631,7 +118805,13 @@ class IndexJobTracker {
118631
118805
  const stale = hbMs != null && hbMs < cutoff || hbMs == null && startedMs != null && startedMs < cutoff;
118632
118806
  if (!stale)
118633
118807
  continue;
118634
- 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 });
118808
+ logger.warn("indexJobTracker: reaping stale running job", {
118809
+ jobId: job.jobId,
118810
+ projectId: job.projectId,
118811
+ staleMs,
118812
+ heartbeatAt: job.heartbeatAt?.toISOString() ?? "n/a",
118813
+ startedAt: job.startedAt?.toISOString() ?? "n/a"
118814
+ });
118635
118815
  this.jobs.set(job.jobId, job);
118636
118816
  const reapedPrevStatus = job.status;
118637
118817
  this.setResult(job.jobId, undefined, "heartbeat stale (possible crash/OOM)");
@@ -118656,7 +118836,7 @@ class IndexJobTracker {
118656
118836
  try {
118657
118837
  this.store?.save(job);
118658
118838
  } catch (err) {
118659
- logger.warn(`indexJobTracker: job store write failed for ${jobId} on setResult`, { jobId, error: err?.message ?? String(err) });
118839
+ logger.warn("indexJobTracker: job store write failed on setResult", { jobId, error: err });
118660
118840
  }
118661
118841
  if (prevStatus === "pending") {
118662
118842
  this.publishStateChange(job, prevStatus);
@@ -118686,7 +118866,7 @@ class IndexJobTracker {
118686
118866
  const survivors = remaining.slice(0, this.MAX_JOBS);
118687
118867
  const overflow = remaining.slice(this.MAX_JOBS);
118688
118868
  for (const job of overflow) {
118689
- 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 });
118869
+ 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 });
118690
118870
  this.jobs.delete(job.jobId);
118691
118871
  }
118692
118872
  }
@@ -118840,8 +119020,9 @@ class DiscoverStage {
118840
119020
  };
118841
119021
  } catch (err) {
118842
119022
  logger.warn("DiscoverStage: failed to stat/read file", {
119023
+ projectId: ctx.projectId,
118843
119024
  relativePath,
118844
- error: err.message
119025
+ error: err
118845
119026
  });
118846
119027
  throw new Error(`required_file_unreadable:${relativePath}:${err.message}`);
118847
119028
  }
@@ -121366,8 +121547,9 @@ class ParseStage {
121366
121547
  timestamp: Date.now()
121367
121548
  });
121368
121549
  logger.warn("ParseStage: failed to parse file", {
121550
+ projectId: ctx.projectId,
121369
121551
  filePath: file3.relativePath,
121370
- error: err.message
121552
+ error: err
121371
121553
  });
121372
121554
  if (err instanceof StructuralEtlParseError)
121373
121555
  throw err;
@@ -122603,7 +122785,7 @@ class ResolveStage {
122603
122785
  throw new Error("structural_repository_seed_failed", { cause: err });
122604
122786
  logger.warn("buildSymbolIndex: repo seed failed, in-batch only", {
122605
122787
  projectId,
122606
- error: err?.message
122788
+ error: err
122607
122789
  });
122608
122790
  }
122609
122791
  const inBatch = new Map;
@@ -122766,7 +122948,7 @@ async function withDeadlockRetry(operation, options = {}) {
122766
122948
  attempt,
122767
122949
  maxAttempts,
122768
122950
  delayMs,
122769
- error: error51?.message?.slice(0, 120)
122951
+ error: error51
122770
122952
  });
122771
122953
  await new Promise((resolve5) => setTimeout(resolve5, delayMs));
122772
122954
  }
@@ -123896,7 +124078,7 @@ var init_pipeline = __esm(() => {
123896
124078
  logger.warn("EtlPipeline: search-admission marker write failed", {
123897
124079
  projectId,
123898
124080
  jobId,
123899
- error: markerError.message.slice(0, 160)
124081
+ error: markerError
123900
124082
  });
123901
124083
  }
123902
124084
  if (forceReindex) {
@@ -123908,7 +124090,7 @@ var init_pipeline = __esm(() => {
123908
124090
  logger.warn("EtlPipeline: embedding fingerprint stamp failed", {
123909
124091
  projectId,
123910
124092
  jobId,
123911
- error: stampError.message.slice(0, 160)
124093
+ error: stampError
123912
124094
  });
123913
124095
  }
123914
124096
  }
@@ -125140,9 +125322,9 @@ class SymbolGraphService {
125140
125322
  return null;
125141
125323
  const workspace = graphSnapshot.workspace;
125142
125324
  const arch = await this.computeArchitectureMapSafe(graphSnapshot.architecture).catch((err) => {
125143
- logger.warn("getProjectMap: architecture map failed; skipping", {
125325
+ logger.warn("SymbolGraphService: getProjectMap architecture map failed, skipping", {
125144
125326
  projectId,
125145
- error: err?.message?.slice(0, 160)
125327
+ error: err
125146
125328
  });
125147
125329
  return null;
125148
125330
  });
@@ -125684,7 +125866,7 @@ class RelationExtractor {
125684
125866
  } catch (error51) {
125685
125867
  logger.warn("RelationExtractor: extraction failed", {
125686
125868
  memoryId,
125687
- error: error51.message
125869
+ error: error51
125688
125870
  });
125689
125871
  }
125690
125872
  return edgesCreated;
@@ -126131,7 +126313,7 @@ class MemoryGraphService {
126131
126313
  } catch (error51) {
126132
126314
  logger.warn("Graph update failed after memory store", {
126133
126315
  memoryId,
126134
- error: error51.message
126316
+ error: error51
126135
126317
  });
126136
126318
  }
126137
126319
  }
@@ -126147,7 +126329,7 @@ class MemoryGraphService {
126147
126329
  } catch (error51) {
126148
126330
  logger.warn("Graph cleanup failed after memory delete", {
126149
126331
  memoryId,
126150
- error: error51.message
126332
+ error: error51
126151
126333
  });
126152
126334
  }
126153
126335
  }
@@ -126296,7 +126478,7 @@ async function consolidateWindow(candidates2, llm2, opts = {}) {
126296
126478
  if (!llm2.isEnabled())
126297
126479
  return null;
126298
126480
  const prompt = buildPrompt2(window2);
126299
- const result = await llm2.object(prompt, ConsolidatedBatchSchema);
126481
+ const result = await llm2.object(prompt, ConsolidatedBatchSchema, { label: "memory-consolidation" });
126300
126482
  if (!result.ok || !result.value)
126301
126483
  return null;
126302
126484
  const batch = {
@@ -126397,7 +126579,7 @@ class MemoryConsolidationJob {
126397
126579
  } catch (error51) {
126398
126580
  logger.warn("Memory consolidation skipped", {
126399
126581
  trigger,
126400
- error: error51.message
126582
+ error: error51
126401
126583
  });
126402
126584
  } finally {
126403
126585
  this.running = false;
@@ -126420,7 +126602,7 @@ class MemoryConsolidationJob {
126420
126602
  candidates2 = await Promise.resolve(repo.listConsolidationCandidates(staleSinceMs, 500));
126421
126603
  } catch (e) {
126422
126604
  logger.warn("consolidation: candidate list failed (decay)", {
126423
- error: e.message
126605
+ error: e
126424
126606
  });
126425
126607
  return 0;
126426
126608
  }
@@ -126442,7 +126624,7 @@ class MemoryConsolidationJob {
126442
126624
  } catch (e) {
126443
126625
  logger.warn("consolidation: decay write failed", {
126444
126626
  id: row.id,
126445
- error: e.message
126627
+ error: e
126446
126628
  });
126447
126629
  }
126448
126630
  }
@@ -126471,14 +126653,14 @@ class MemoryConsolidationJob {
126471
126653
  } catch (e) {
126472
126654
  logger.warn("consolidation: soft-delete failed", {
126473
126655
  id: row.id,
126474
- error: e.message
126656
+ error: e
126475
126657
  });
126476
126658
  }
126477
126659
  }
126478
126660
  }
126479
126661
  } catch (e) {
126480
126662
  logger.warn("consolidation: prune scan failed", {
126481
- error: e.message
126663
+ error: e
126482
126664
  });
126483
126665
  }
126484
126666
  return pruned;
@@ -126489,7 +126671,7 @@ class MemoryConsolidationJob {
126489
126671
  candidates2 = await Promise.resolve(repo.listConsolidationCandidates(staleSinceMs, 200));
126490
126672
  } catch (e) {
126491
126673
  logger.warn("consolidation: candidate list failed (merge)", {
126492
- error: e.message
126674
+ error: e
126493
126675
  });
126494
126676
  return { merged: 0, batchesCreated: 0 };
126495
126677
  }
@@ -126515,7 +126697,7 @@ class MemoryConsolidationJob {
126515
126697
  } catch (e) {
126516
126698
  logger.warn("consolidation: merge insert failed", {
126517
126699
  batchId: batch.id,
126518
- error: e.message
126700
+ error: e
126519
126701
  });
126520
126702
  return { merged: 0, batchesCreated: 0 };
126521
126703
  }
@@ -126528,7 +126710,7 @@ class MemoryConsolidationJob {
126528
126710
  logger.warn("consolidation: addSupercedesEdge failed", {
126529
126711
  newId,
126530
126712
  sourceId,
126531
- error: e.message
126713
+ error: e
126532
126714
  });
126533
126715
  }
126534
126716
  }
@@ -126568,7 +126750,7 @@ class MemoryConsolidationJob {
126568
126750
  return result;
126569
126751
  } catch (e) {
126570
126752
  logger.warn("consolidation: promote (PG) failed", {
126571
- error: e.message
126753
+ error: e
126572
126754
  });
126573
126755
  return 0;
126574
126756
  }
@@ -126607,19 +126789,22 @@ class SalienceJudge {
126607
126789
  }
126608
126790
  const prompt = buildPrompt3(trimmed, type);
126609
126791
  let verdict;
126792
+ let verdictError;
126610
126793
  try {
126611
- const res = await this.llm.object(prompt, SalienceSchema);
126794
+ const res = await this.llm.object(prompt, SalienceSchema, { label: "salience-judge" });
126612
126795
  verdict = res.ok ? res.value ?? null : null;
126796
+ verdictError = res.ok ? undefined : res.error;
126613
126797
  } catch (e) {
126614
126798
  logger.warn("SalienceJudge threw \u2014 degrading to neutral default", {
126615
126799
  type,
126616
- error: e.message
126800
+ error: e
126617
126801
  });
126618
126802
  return { salience: NEUTRAL_SALIENCE, source: "default" };
126619
126803
  }
126620
126804
  if (!verdict) {
126621
126805
  logger.warn("SalienceJudge got {ok:false} \u2014 degrading to neutral default", {
126622
- type
126806
+ type,
126807
+ error: verdictError
126623
126808
  });
126624
126809
  return { salience: NEUTRAL_SALIENCE, source: "default" };
126625
126810
  }
@@ -126834,7 +127019,8 @@ class MemoryController {
126834
127019
  }
126835
127020
  } catch (err) {
126836
127021
  logger.warn("Graph enrichment failed", {
126837
- error: err.message
127022
+ projectId,
127023
+ error: err
126838
127024
  });
126839
127025
  }
126840
127026
  }
@@ -127036,7 +127222,7 @@ class CodeCompressor {
127036
127222
  }
127037
127223
  const prompt = buildLlmCompressPrompt(content, language3, targetRatio, preservedElements);
127038
127224
  try {
127039
- const res = await this.llmCompleteFn(prompt, { timeoutMs, modelRole: "code" });
127225
+ const res = await this.llmCompleteFn(prompt, { label: "code-compressor", timeoutMs, modelRole: "code" });
127040
127226
  if (res.ok && typeof res.value === "string" && res.value.trim().length > 0 && res.value.length <= content.length) {
127041
127227
  compressed = res.value;
127042
127228
  compressionSource = "llm";
@@ -127076,7 +127262,10 @@ class CodeCompressor {
127076
127262
  });
127077
127263
  return compressedContent;
127078
127264
  } catch (error51) {
127079
- logger.error("Code compression failed", error51);
127265
+ logger.error("Code compression failed", error51, {
127266
+ strategy: useStrategy,
127267
+ originalLength: content.length
127268
+ });
127080
127269
  return CompressedContent.identity(content);
127081
127270
  }
127082
127271
  }
@@ -127386,9 +127575,9 @@ class TokenMetrics {
127386
127575
  }
127387
127576
  throw new Error("Model not found in models.dev");
127388
127577
  } catch (error51) {
127389
- logger.warn("Failed to fetch pricing from models.dev, using fallback", {
127578
+ logger.warn("TokenMetrics: failed to fetch pricing from models.dev, using fallback", {
127390
127579
  modelId,
127391
- error: error51 instanceof Error ? error51.message : String(error51)
127580
+ error: error51
127392
127581
  });
127393
127582
  const fallback = FALLBACK_PRICING2[modelId] || FALLBACK_PRICING2["gpt-4"];
127394
127583
  this.pricingCache.set(modelId, {
@@ -127726,7 +127915,7 @@ class ContextController {
127726
127915
  });
127727
127916
  }
127728
127917
  } catch (err) {
127729
- logger.warn("Graph prefilter failed", { query, error: err.message });
127918
+ logger.warn("ContextController: graph prefilter failed", { projectId, query, error: err });
127730
127919
  }
127731
127920
  }
127732
127921
  const [searchResult, memories] = await Promise.all([
@@ -127880,9 +128069,11 @@ class ContextController {
127880
128069
  });
127881
128070
  return result.memories;
127882
128071
  } catch (error51) {
127883
- logger.warn("Memory search failed, continuing without memories", {
127884
- error: error51.message,
127885
- query: query.slice(0, 30)
128072
+ logger.warn("ContextController: memory search failed, continuing without memories", {
128073
+ projectId: opts.projectId,
128074
+ sessionId: opts.sessionId,
128075
+ query: query.slice(0, 30),
128076
+ error: error51
127886
128077
  });
127887
128078
  return [];
127888
128079
  }
@@ -128063,7 +128254,7 @@ class PgCheckpointStore {
128063
128254
  } catch (e) {
128064
128255
  this.hydrateFailedAt = Date.now();
128065
128256
  logger.warn("PgCheckpointStore hydrate failed (best-effort)", {
128066
- error: e.message
128257
+ error: e
128067
128258
  });
128068
128259
  } finally {
128069
128260
  this.hydrating = null;
@@ -128257,8 +128448,9 @@ class PgCheckpointStore {
128257
128448
  }
128258
128449
  return existing;
128259
128450
  } catch (e) {
128260
- logger.warn("countExistingMemoryIds failed (best-effort: assuming all exist)", {
128261
- error: e.message
128451
+ logger.warn("PgCheckpointStore: countExistingMemoryIds failed (best-effort, assuming all exist)", {
128452
+ memoryIdCount: memoryIds.length,
128453
+ error: e
128262
128454
  });
128263
128455
  return memoryIds;
128264
128456
  }
@@ -128325,7 +128517,7 @@ class PgCheckpointStore {
128325
128517
  const next = prev.then(fn).catch((e) => {
128326
128518
  logger.warn("PgCheckpointStore write failed (best-effort)", {
128327
128519
  key,
128328
- error: e.message
128520
+ error: e
128329
128521
  });
128330
128522
  });
128331
128523
  this.inflight.set(key, next);
@@ -128464,7 +128656,7 @@ class PgObservationStore {
128464
128656
  } catch (e) {
128465
128657
  this.hydrateFailedAt = Date.now();
128466
128658
  logger.warn("PgObservationStore hydrate failed (best-effort)", {
128467
- error: e.message
128659
+ error: e
128468
128660
  });
128469
128661
  } finally {
128470
128662
  this.hydrating = null;
@@ -128515,7 +128707,7 @@ class PgObservationStore {
128515
128707
  const next = prev.then(fn).catch((e) => {
128516
128708
  logger.warn("PgObservationStore.insert failed (best-effort)", {
128517
128709
  id: key,
128518
- error: e.message
128710
+ error: e
128519
128711
  });
128520
128712
  });
128521
128713
  this.inflight.set(key, next);
@@ -129995,7 +130187,7 @@ function warnSandboxUnavailable() {
129995
130187
  return;
129996
130188
  _warnedAboutNoSandbox = true;
129997
130189
  const missingTool = process.platform === "darwin" ? "sandbox-exec" : "docker";
129998
- 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" });
130190
+ logger.warn("Sandbox: no sandbox tool found for auto mode, falling back to best-effort containment", { missingTool, platform: process.platform, effectiveMode: "none" });
129999
130191
  }
130000
130192
  function getSandboxMode() {
130001
130193
  const env6 = process.env.MASSA_AI_EXECUTOR_SANDBOX ?? "auto";
@@ -130910,7 +131102,10 @@ class ExecutorController {
130910
131102
  }
130911
131103
  };
130912
131104
  } catch (error51) {
130913
- logger.error("batch_execute failed", error51);
131105
+ logger.error("batch_execute failed", error51, {
131106
+ commandCount: commands.length,
131107
+ concurrency: effectiveConcurrency
131108
+ });
130914
131109
  return {
130915
131110
  success: false,
130916
131111
  error: `batch_execute failed: ${error51.message}`
@@ -132852,7 +133047,7 @@ class PgScheduledJobStore {
132852
133047
  logger.info("PgScheduledJobStore hydrated", { rows: this.mirror.size });
132853
133048
  } catch (e) {
132854
133049
  logger.warn("PgScheduledJobStore hydrate failed (best-effort)", {
132855
- error: e.message
133050
+ error: e
132856
133051
  });
132857
133052
  } finally {
132858
133053
  this.hydrating = null;
@@ -132866,9 +133061,10 @@ class PgScheduledJobStore {
132866
133061
  try {
132867
133062
  await action();
132868
133063
  } catch (e) {
132869
- logger.warn(`PgScheduledJobStore.${operation} failed (best-effort)`, {
133064
+ logger.warn("PgScheduledJobStore mutation failed (best-effort)", {
132870
133065
  id,
132871
- error: e.message
133066
+ operation,
133067
+ error: e
132872
133068
  });
132873
133069
  }
132874
133070
  };
@@ -133121,7 +133317,7 @@ class Scheduler {
133121
133317
  this.timer = setInterval(() => {
133122
133318
  this.tick().catch((e) => {
133123
133319
  logger.warn("Scheduler tick failed (swallowed)", {
133124
- error: e.message
133320
+ error: e
133125
133321
  });
133126
133322
  });
133127
133323
  }, this.tickIntervalMs);
@@ -133236,7 +133432,7 @@ class Scheduler {
133236
133432
  logger.warn("Scheduler: job handler threw (caught)", {
133237
133433
  id: job.id,
133238
133434
  jobKind: job.jobKind,
133239
- error: errMsg
133435
+ error: e
133240
133436
  });
133241
133437
  } finally {
133242
133438
  if (succeeded) {
@@ -133255,7 +133451,7 @@ class Scheduler {
133255
133451
  } catch (e) {
133256
133452
  logger.warn("Scheduler: persist after fire failed", {
133257
133453
  id: job.id,
133258
- error: e.message
133454
+ error: e
133259
133455
  });
133260
133456
  }
133261
133457
  this.running.delete(job.jobKind);
@@ -133275,6 +133471,8 @@ class Scheduler {
133275
133471
  enabled: j.enabled,
133276
133472
  nextRunAt: j.nextRunAt,
133277
133473
  lastRunAt: j.lastRunAt,
133474
+ lastSuccessAt: j.lastSuccessAt ?? null,
133475
+ consecutiveFailures: j.consecutiveFailures ?? 0,
133278
133476
  due: j.enabled && j.nextRunAt <= now2,
133279
133477
  currentlyRunning: this.running.has(j.jobKind)
133280
133478
  }))
@@ -133857,7 +134055,7 @@ async function enrichWithLlm(candidates2, observations, surface) {
133857
134055
  const prompt = buildEnrichmentPrompt(candidates2, observations);
133858
134056
  let enrichment = null;
133859
134057
  try {
133860
- const res = await surface.object(prompt, ProposalEnrichmentSchema);
134058
+ const res = await surface.object(prompt, ProposalEnrichmentSchema, { label: "auto-improve" });
133861
134059
  if (!res.ok || !res.value || !Array.isArray(res.value.items)) {
133862
134060
  return { candidates: candidates2, used: false };
133863
134061
  }
@@ -134053,7 +134251,7 @@ async function runOnce(job, projectId) {
134053
134251
  try {
134054
134252
  observations = job.observationStore.listRecent(projectId, job.maxWindow);
134055
134253
  } catch (e) {
134056
- logger.warn("auto-improve: listRecent failed", { projectId, error: e.message });
134254
+ logger.warn("auto-improve: listRecent failed", { projectId, error: e });
134057
134255
  return noop2;
134058
134256
  }
134059
134257
  if (observations.length < 2)
@@ -134068,7 +134266,7 @@ async function runOnce(job, projectId) {
134068
134266
  if (res.used)
134069
134267
  source = "llm";
134070
134268
  } catch (e) {
134071
- logger.warn("auto-improve: enrichWithLlm threw (silent)", { projectId, error: e.message });
134269
+ logger.warn("auto-improve: enrichWithLlm threw (silent)", { projectId, error: e });
134072
134270
  }
134073
134271
  const seen = new Set;
134074
134272
  const unique = candidates2.filter((c) => {
@@ -134116,7 +134314,7 @@ async function runOnce(job, projectId) {
134116
134314
  } catch (e) {
134117
134315
  if (e instanceof SearchServiceError)
134118
134316
  throw e;
134119
- logger.warn("proposal:auto-approved:threw", { id: r2.id, projectId, error: e.message });
134317
+ logger.warn("proposal:auto-approved:threw", { id: r2.id, projectId, error: e });
134120
134318
  }
134121
134319
  }
134122
134320
  result.proposalsApplied = applied;
@@ -134145,7 +134343,7 @@ async function approve(job, id, projectId, source = "rule-based") {
134145
134343
  appliedMemoryId = await applyProposal(job, row);
134146
134344
  } catch (e) {
134147
134345
  const reason = e instanceof ApplyRejection ? e.reason : "apply-failed";
134148
- logger.warn("proposal:apply-failed", { id, projectId: row.projectId, reason, error: e.message });
134346
+ logger.warn("proposal:apply-failed", { id, projectId: row.projectId, reason, error: e });
134149
134347
  return { ok: false, reason };
134150
134348
  }
134151
134349
  let updated;
@@ -134280,9 +134478,9 @@ class AutoImproveJob {
134280
134478
  return;
134281
134479
  this.newSinceRun = 0;
134282
134480
  this.lastRunAt = now2;
134283
- this.runOnce(projectId).catch((e) => logger.warn("auto-improve: runOnce failed (silent)", { projectId, error: e.message }));
134481
+ this.runOnce(projectId).catch((e) => logger.warn("auto-improve: runOnce failed (silent)", { projectId, error: e }));
134284
134482
  } catch (e) {
134285
- logger.warn("auto-improve: maybeRun swallowed", { projectId, error: e.message });
134483
+ logger.warn("auto-improve: maybeRun swallowed", { projectId, error: e });
134286
134484
  }
134287
134485
  }
134288
134486
  async runOnce(projectId) {
@@ -134382,13 +134580,13 @@ class ObservationConsolidationJob {
134382
134580
  this.runOnce(projectId).catch((e) => {
134383
134581
  logger.warn("observation consolidation: runOnce failed (silent)", {
134384
134582
  projectId,
134385
- error: e.message
134583
+ error: e
134386
134584
  });
134387
134585
  });
134388
134586
  } catch (e) {
134389
134587
  logger.warn("observation consolidation: maybeRun swallowed", {
134390
134588
  projectId,
134391
- error: e.message
134589
+ error: e
134392
134590
  });
134393
134591
  }
134394
134592
  }
@@ -134412,7 +134610,7 @@ class ObservationConsolidationJob {
134412
134610
  } catch (e) {
134413
134611
  logger.warn("observation consolidation: listRecent failed", {
134414
134612
  projectId,
134415
- error: e.message
134613
+ error: e
134416
134614
  });
134417
134615
  return noop2;
134418
134616
  }
@@ -134423,7 +134621,7 @@ class ObservationConsolidationJob {
134423
134621
  const prompt = buildObservationPrompt(window2);
134424
134622
  let batch;
134425
134623
  try {
134426
- const res = await this.llm.object(prompt, ConsolidatedBatchSchema);
134624
+ const res = await this.llm.object(prompt, ConsolidatedBatchSchema, { label: "observation-consolidation" });
134427
134625
  if (!res.ok || !res.value) {
134428
134626
  return noop2;
134429
134627
  }
@@ -134439,7 +134637,7 @@ class ObservationConsolidationJob {
134439
134637
  } catch (e) {
134440
134638
  logger.warn("observation consolidation: llm.object threw (silent)", {
134441
134639
  projectId,
134442
- error: e.message
134640
+ error: e
134443
134641
  });
134444
134642
  return noop2;
134445
134643
  }
@@ -134468,7 +134666,7 @@ class ObservationConsolidationJob {
134468
134666
  } catch (e) {
134469
134667
  logger.warn("observation consolidation: summary insert failed", {
134470
134668
  batchId: batch.id,
134471
- error: e.message
134669
+ error: e
134472
134670
  });
134473
134671
  return noop2;
134474
134672
  }
@@ -134745,8 +134943,9 @@ var init_models_dev_client = __esm(() => {
134745
134943
  path: cachePath
134746
134944
  });
134747
134945
  } catch (error51) {
134748
- logger.warn("Failed to save local pricing cache", {
134749
- error: error51.message
134946
+ logger.warn("ModelsDevClient: failed to save local pricing cache", {
134947
+ path: cachePath,
134948
+ error: error51
134750
134949
  });
134751
134950
  }
134752
134951
  }
@@ -134968,7 +135167,7 @@ var init_models_dev_client = __esm(() => {
134968
135167
  return value;
134969
135168
  }
134970
135169
  }
134971
- logger.warn(`Model pricing not found: ${modelId}`);
135170
+ logger.warn("ModelsDevClient: model pricing not found", { modelId });
134972
135171
  return null;
134973
135172
  }
134974
135173
  async searchModels(query) {
@@ -135072,8 +135271,9 @@ var init_models_dev_client = __esm(() => {
135072
135271
  logger.debug("Local pricing cache file deleted");
135073
135272
  }
135074
135273
  } catch (error51) {
135075
- logger.warn("Failed to delete local pricing cache", {
135076
- error: error51.message
135274
+ logger.warn("ModelsDevClient: failed to delete local pricing cache", {
135275
+ path: cachePath,
135276
+ error: error51
135077
135277
  });
135078
135278
  }
135079
135279
  }
@@ -135729,9 +135929,10 @@ class SearchSessionHook {
135729
135929
  });
135730
135930
  } catch (err) {
135731
135931
  logger.warn("SearchSessionHook: store failed (best-effort)", {
135732
- error: err.message,
135733
135932
  projectId,
135734
- query: query.slice(0, 60)
135933
+ sessionId,
135934
+ query: query.slice(0, 60),
135935
+ error: err
135735
135936
  });
135736
135937
  }
135737
135938
  }
@@ -135807,8 +136008,10 @@ class CoRetrievalHook {
135807
136008
  peers = await this.findPeers(memoryId, projectId, sessionId);
135808
136009
  } catch (err) {
135809
136010
  logger.warn("CoRetrievalHook: peer lookup failed", {
135810
- error: err.message,
135811
- memoryId
136011
+ projectId,
136012
+ sessionId,
136013
+ memoryId,
136014
+ error: err
135812
136015
  });
135813
136016
  return;
135814
136017
  }
@@ -152854,6 +153057,7 @@ async function fetchAndConvertOne(url2, deps, opts = {}) {
152854
153057
  } catch (err) {
152855
153058
  const msg = err instanceof Error ? err.message : String(err);
152856
153059
  logger.error("fetch_and_index indexChunk failed", err, {
153060
+ projectId,
152857
153061
  url: url2,
152858
153062
  chunkId: chunk.id
152859
153063
  });
@@ -153044,6 +153248,7 @@ class WebController {
153044
153248
  return s.value;
153045
153249
  const msg = s.reason instanceof Error ? s.reason.message : String(s.reason);
153046
153250
  logger.error("fetch_and_index job rejected", s.reason, {
153251
+ projectId,
153047
153252
  url: batch[i].url
153048
153253
  });
153049
153254
  return { kind: "error", url: batch[i].url, error: msg };
@@ -177750,7 +177955,7 @@ class ListCheckpointsTool {
177750
177955
  };
177751
177956
  return serializeToolResponse(responseData, { format, fields });
177752
177957
  } catch (error51) {
177753
- logger.error("Failed to list checkpoints", error51);
177958
+ logger.error("Failed to list checkpoints", error51, { taskId, projectId });
177754
177959
  return {
177755
177960
  success: false,
177756
177961
  error: `Failed to list checkpoints: ${error51.message}`
@@ -178053,7 +178258,8 @@ class CompactSnapshotTool {
178053
178258
  });
178054
178259
  } catch (e) {
178055
178260
  logger.warn("compact_snapshot: persist failed (non-fatal)", {
178056
- error: e.message
178261
+ sessionId,
178262
+ error: e
178057
178263
  });
178058
178264
  persistedId = undefined;
178059
178265
  }
@@ -178778,7 +178984,7 @@ class ProjectRootCache {
178778
178984
  return workspace.project_path;
178779
178985
  }
178780
178986
  } catch (error51) {
178781
- logger.warn("Failed to look up project root", { projectId, error: error51.message });
178987
+ logger.warn("ProjectRootCache: failed to look up project root", { projectId, error: error51 });
178782
178988
  }
178783
178989
  return null;
178784
178990
  }
@@ -179285,7 +179491,7 @@ class OperationLogRepositoryPg {
179285
179491
  op: input.op,
179286
179492
  projectId,
179287
179493
  result: input.result,
179288
- error: err.message
179494
+ error: err
179289
179495
  });
179290
179496
  }
179291
179497
  }
@@ -179500,9 +179706,11 @@ class HookService {
179500
179706
  });
179501
179707
  this.bridge.maybeRun(obs.projectId);
179502
179708
  } catch (e) {
179503
- logger.warn("observation persist failed", {
179709
+ logger.warn("HookService: observation persist failed", {
179504
179710
  id: obs.id,
179505
- error: e.message
179711
+ projectId: obs.projectId,
179712
+ sessionId: obs.sessionId,
179713
+ error: e
179506
179714
  });
179507
179715
  }
179508
179716
  });
@@ -179650,7 +179858,7 @@ class BootstrapService {
179650
179858
  } catch (e) {
179651
179859
  logger.warn("bootstrap: marker check threw (continuing)", {
179652
179860
  projectId,
179653
- error: e.message
179861
+ error: e
179654
179862
  });
179655
179863
  }
179656
179864
  } else if (!cfg.refreshEnabled) {
@@ -179698,7 +179906,7 @@ class BootstrapService {
179698
179906
  } catch (e) {
179699
179907
  logger.warn("bootstrap: storeSeeds failed (silent)", {
179700
179908
  projectId,
179701
- error: e.message
179909
+ error: e
179702
179910
  });
179703
179911
  return { ...noopResult("insert-failed"), signalCount, source };
179704
179912
  }
@@ -179851,7 +180059,7 @@ async function summarizeWithLlm(signals, surface, maxSeedMemories) {
179851
180059
  return { ok: false, reason: "llm disabled" };
179852
180060
  const prompt = buildSummarizePrompt(signals, maxSeedMemories);
179853
180061
  try {
179854
- const res = await surface.object(prompt, SeedMemoriesSchema, { modelRole: "code" });
180062
+ const res = await surface.object(prompt, SeedMemoriesSchema, { label: "bootstrap-seed", modelRole: "code" });
179855
180063
  if (!res.ok || !res.value) {
179856
180064
  return { ok: false, reason: res.error || "llm returned no value" };
179857
180065
  }
@@ -180454,7 +180662,7 @@ function formatMemoryContent(record2) {
180454
180662
  }
180455
180663
  async function polishSummary(surface, input) {
180456
180664
  const prompt = buildPolishPrompt(input);
180457
- const res = await surface.object(prompt, HandoffSummarySchema);
180665
+ const res = await surface.object(prompt, HandoffSummarySchema, { label: "handoff-summary" });
180458
180666
  if (!res.ok || !res.value || !res.value.summary)
180459
180667
  return null;
180460
180668
  return res.value.summary;
@@ -180664,7 +180872,10 @@ var memoryRoutes = new Elysia({ prefix: "/api/v1/memory" }).post("/store", async
180664
180872
  try {
180665
180873
  return await getStoreMemoryTool().handle(body);
180666
180874
  } catch (error51) {
180667
- logger.error("Failed to initialize StoreMemoryTool", error51);
180875
+ logger.error("Failed to initialize StoreMemoryTool", error51, {
180876
+ projectId: body.projectId,
180877
+ sessionId: body.sessionId
180878
+ });
180668
180879
  return {
180669
180880
  success: false,
180670
180881
  error: `Memory service unavailable: ${error51.message}`
@@ -180701,7 +180912,10 @@ var memoryRoutes = new Elysia({ prefix: "/api/v1/memory" }).post("/store", async
180701
180912
  try {
180702
180913
  return await getSearchMemoriesTool().handle(body);
180703
180914
  } catch (error51) {
180704
- logger.error("Failed to initialize SearchMemoriesTool", error51);
180915
+ logger.error("Failed to initialize SearchMemoriesTool", error51, {
180916
+ projectId: body.projectId,
180917
+ sessionId: body.sessionId
180918
+ });
180705
180919
  return {
180706
180920
  success: false,
180707
180921
  error: `Memory service unavailable: ${error51.message}`
@@ -180736,7 +180950,9 @@ var memoryRoutes = new Elysia({ prefix: "/api/v1/memory" }).post("/store", async
180736
180950
  try {
180737
180951
  return await getUpdateMemoryTool().handle(body);
180738
180952
  } catch (error51) {
180739
- logger.error("Failed to initialize UpdateMemoryTool", error51);
180953
+ logger.error("Failed to initialize UpdateMemoryTool", error51, {
180954
+ id: body.id
180955
+ });
180740
180956
  return {
180741
180957
  success: false,
180742
180958
  error: `Memory service unavailable: ${error51.message}`
@@ -180762,7 +180978,9 @@ var memoryRoutes = new Elysia({ prefix: "/api/v1/memory" }).post("/store", async
180762
180978
  try {
180763
180979
  return await getDeleteMemoryTool().handle(body);
180764
180980
  } catch (error51) {
180765
- logger.error("Failed to initialize DeleteMemoryTool", error51);
180981
+ logger.error("Failed to initialize DeleteMemoryTool", error51, {
180982
+ id: body.id
180983
+ });
180766
180984
  return {
180767
180985
  success: false,
180768
180986
  error: `Memory service unavailable: ${error51.message}`
@@ -180803,7 +181021,10 @@ var memoryRoutes = new Elysia({ prefix: "/api/v1/memory" }).post("/store", async
180803
181021
  data: { memories: rows.map(formatRow), total, limit, offset }
180804
181022
  };
180805
181023
  } catch (error51) {
180806
- logger.error("Failed to list memories", error51);
181024
+ logger.error("Failed to list memories", error51, {
181025
+ projectId: body.projectId,
181026
+ sessionId: body.sessionId
181027
+ });
180807
181028
  return {
180808
181029
  success: false,
180809
181030
  error: `Failed to list memories: ${error51.message}`
@@ -180873,7 +181094,10 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
180873
181094
  try {
180874
181095
  return await getListCheckpointsTool().handle(body);
180875
181096
  } catch (error51) {
180876
- logger.error("Failed to list checkpoints", error51);
181097
+ logger.error("Failed to list checkpoints", error51, {
181098
+ taskId: body.taskId,
181099
+ projectId: body.projectId
181100
+ });
180877
181101
  return {
180878
181102
  success: false,
180879
181103
  error: `Checkpoint service unavailable: ${error51.message}`
@@ -180897,7 +181121,10 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
180897
181121
  try {
180898
181122
  return await getCreateCheckpointTool().handle(body);
180899
181123
  } catch (error51) {
180900
- logger.error("Failed to create checkpoint", error51);
181124
+ logger.error("Failed to create checkpoint", error51, {
181125
+ taskId: body.taskId,
181126
+ projectId: body.projectId
181127
+ });
180901
181128
  return {
180902
181129
  success: false,
180903
181130
  error: `Checkpoint service unavailable: ${error51.message}`
@@ -180938,7 +181165,10 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
180938
181165
  try {
180939
181166
  return await getRestoreCheckpointTool().handle(body);
180940
181167
  } catch (error51) {
180941
- logger.error("Failed to restore checkpoint", error51);
181168
+ logger.error("Failed to restore checkpoint", error51, {
181169
+ checkpointId: body.checkpointId,
181170
+ taskId: body.taskId
181171
+ });
180942
181172
  return {
180943
181173
  success: false,
180944
181174
  error: `Checkpoint service unavailable: ${error51.message}`
@@ -180958,8 +181188,10 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
180958
181188
  description: "Restore a saved checkpoint and return its state plus integrity checks."
180959
181189
  }
180960
181190
  }).post("/delete", ({ body, set: set3 }) => {
181191
+ let checkpointId;
180961
181192
  try {
180962
181193
  const { id } = body;
181194
+ checkpointId = id;
180963
181195
  const existed = getCheckpointManager().deleteCheckpoint(id);
180964
181196
  if (!existed) {
180965
181197
  set3.status = 404;
@@ -180968,7 +181200,7 @@ var checkpointRoutes = new Elysia({ prefix: "/api/v1/checkpoints" }).post("/list
180968
181200
  set3.status = 200;
180969
181201
  return { success: true, data: { ok: true } };
180970
181202
  } catch (error51) {
180971
- logger.error("Failed to delete checkpoint", error51);
181203
+ logger.error("Failed to delete checkpoint", error51, { checkpointId });
180972
181204
  set3.status = 500;
180973
181205
  return {
180974
181206
  success: false,
@@ -182566,7 +182798,10 @@ var hookRoutes = new Elysia({ prefix: "/api/v1/hook" }).post("/", async ({ body,
182566
182798
  return { status: e.code, error: e.message };
182567
182799
  }
182568
182800
  const err = e;
182569
- logger.error("hook ingestion failed", err);
182801
+ logger.error("hook ingestion failed", err, {
182802
+ projectId: body.projectId,
182803
+ event: body.event
182804
+ });
182570
182805
  set3.status = 500;
182571
182806
  return { status: 500, error: `hook service unavailable: ${err.message}` };
182572
182807
  }
@@ -182605,7 +182840,9 @@ var hookRoutes = new Elysia({ prefix: "/api/v1/hook" }).post("/", async ({ body,
182605
182840
  return { status: e.code, error: e.message };
182606
182841
  }
182607
182842
  const err = e;
182608
- logger.error("hook batch ingestion failed", err);
182843
+ logger.error("hook batch ingestion failed", err, {
182844
+ count: (body.events ?? []).length
182845
+ });
182609
182846
  set3.status = 500;
182610
182847
  return { status: 500, error: `hook service unavailable: ${err.message}` };
182611
182848
  }
@@ -182684,7 +182921,7 @@ var bootstrapRoutes = new Elysia({ prefix: "/api/v1/bootstrap" }).post("/", asyn
182684
182921
  return { success: true, data: result };
182685
182922
  } catch (e) {
182686
182923
  const err = e;
182687
- logger.error("bootstrap failed", err);
182924
+ logger.error("bootstrap failed", err, { projectId, projectPath: projectPath2 });
182688
182925
  set3.status = 500;
182689
182926
  return { success: false, error: `bootstrap failed: ${err.message}` };
182690
182927
  }
@@ -182758,7 +182995,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182758
182995
  } catch (e) {
182759
182996
  rethrowCanonicalHandoffError(e);
182760
182997
  const err = e;
182761
- logger.error("handoff begin failed", err);
182998
+ logger.error("handoff begin failed", err, { projectId: b.projectId });
182762
182999
  set3.status = 500;
182763
183000
  return { success: false, error: `handoff begin failed: ${err.message}` };
182764
183001
  }
@@ -182794,7 +183031,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182794
183031
  } catch (e) {
182795
183032
  rethrowCanonicalHandoffError(e);
182796
183033
  const err = e;
182797
- logger.error("handoff accept failed", err);
183034
+ logger.error("handoff accept failed", err, { id: b.id, projectId: b.projectId });
182798
183035
  set3.status = 500;
182799
183036
  return { success: false, error: `handoff accept failed: ${err.message}` };
182800
183037
  }
@@ -182825,7 +183062,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182825
183062
  } catch (e) {
182826
183063
  rethrowCanonicalHandoffError(e);
182827
183064
  const err = e;
182828
- logger.error("handoff cancel failed", err);
183065
+ logger.error("handoff cancel failed", err, { id: b.id, projectId: b.projectId });
182829
183066
  set3.status = 500;
182830
183067
  return { success: false, error: `handoff cancel failed: ${err.message}` };
182831
183068
  }
@@ -182859,7 +183096,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182859
183096
  } catch (e) {
182860
183097
  rethrowCanonicalHandoffError(e);
182861
183098
  const err = e;
182862
- logger.error("handoff list failed", err);
183099
+ logger.error("handoff list failed", err, { projectId: b.projectId, targetAgent: b.targetAgent });
182863
183100
  set3.status = 500;
182864
183101
  return { success: false, error: `handoff list failed: ${err.message}` };
182865
183102
  }
@@ -182941,7 +183178,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182941
183178
  } catch (e) {
182942
183179
  rethrowCanonicalHandoffError(e);
182943
183180
  const err = e;
182944
- logger.error("handoff update failed", err);
183181
+ logger.error("handoff update failed", err, { id: params.id, projectId: query.projectId });
182945
183182
  set3.status = 500;
182946
183183
  return { success: false, error: `handoff update failed: ${err.message}` };
182947
183184
  }
@@ -182974,7 +183211,7 @@ var handoffRoutes = new Elysia({ prefix: "/api/v1/handoff" }).post("/begin", asy
182974
183211
  } catch (e) {
182975
183212
  rethrowCanonicalHandoffError(e);
182976
183213
  const err = e;
182977
- logger.error("handoff delete failed", err);
183214
+ logger.error("handoff delete failed", err, { id: params.id, projectId: query.projectId });
182978
183215
  set3.status = 500;
182979
183216
  return { success: false, error: `handoff delete failed: ${err.message}` };
182980
183217
  }
@@ -183045,7 +183282,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183045
183282
  if (e instanceof SearchServiceError)
183046
183283
  throw e;
183047
183284
  const err = e;
183048
- logger.error("proposal list failed", err);
183285
+ logger.error("proposal list failed", err, { projectId: b.projectId });
183049
183286
  set3.status = 500;
183050
183287
  return { success: false, error: `proposal list failed: ${err.message}` };
183051
183288
  }
@@ -183076,7 +183313,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183076
183313
  if (e instanceof SearchServiceError)
183077
183314
  throw e;
183078
183315
  const err = e;
183079
- logger.error("proposal approve failed", err);
183316
+ logger.error("proposal approve failed", err, { id: b.id, projectId: b.projectId });
183080
183317
  set3.status = 500;
183081
183318
  return { success: false, error: `proposal approve failed: ${err.message}` };
183082
183319
  }
@@ -183109,7 +183346,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183109
183346
  if (e instanceof SearchServiceError)
183110
183347
  throw e;
183111
183348
  const err = e;
183112
- logger.error("proposal reject failed", err);
183349
+ logger.error("proposal reject failed", err, { id: b.id, projectId: b.projectId });
183113
183350
  set3.status = 500;
183114
183351
  return { success: false, error: `proposal reject failed: ${err.message}` };
183115
183352
  }
@@ -183173,7 +183410,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183173
183410
  return { status: validationStatus, error: e.message };
183174
183411
  }
183175
183412
  const err = e;
183176
- logger.error("proposal create failed", err);
183413
+ logger.error("proposal create failed", err, { projectId, kind });
183177
183414
  set3.status = 500;
183178
183415
  return { success: false, error: `proposal create failed: ${err.message}` };
183179
183416
  }
@@ -183246,7 +183483,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183246
183483
  return { status: validationStatus, error: e.message };
183247
183484
  }
183248
183485
  const err = e;
183249
- logger.error("proposal update failed", err);
183486
+ logger.error("proposal update failed", err, { id: params.id, projectId: query.projectId });
183250
183487
  set3.status = 500;
183251
183488
  return { success: false, error: `proposal update failed: ${err.message}` };
183252
183489
  }
@@ -183295,7 +183532,7 @@ var proposalRoutes = new Elysia({ prefix: "/api/v1/proposal" }).post("/list", as
183295
183532
  if (e instanceof SearchServiceError)
183296
183533
  throw e;
183297
183534
  const err = e;
183298
- logger.error("proposal delete failed", err);
183535
+ logger.error("proposal delete failed", err, { id: params.id, projectId: query.projectId });
183299
183536
  set3.status = 500;
183300
183537
  return { success: false, error: `proposal delete failed: ${err.message}` };
183301
183538
  }
@@ -183707,8 +183944,8 @@ var dashboardRoutes = new Elysia({ prefix: "/api/v1" }).get("/scheduler/status",
183707
183944
  enabled: j.enabled,
183708
183945
  nextRunAt: j.nextRunAt,
183709
183946
  lastRunAt: j.lastRunAt,
183710
- lastSuccessAt: null,
183711
- consecutiveFailures: 0,
183947
+ lastSuccessAt: j.lastSuccessAt,
183948
+ consecutiveFailures: j.consecutiveFailures,
183712
183949
  due: j.due,
183713
183950
  currentlyRunning: j.currentlyRunning
183714
183951
  }))
@@ -183778,6 +184015,198 @@ function deploymentUnavailableMessage(what) {
183778
184015
  return `model-registry is unavailable in this deployment: ${what} was not found under ` + `${import.meta.dirname} (searched up ${MAX_LEVELS2} levels). This route requires a ` + `massa-ai source checkout.`;
183779
184016
  }
183780
184017
 
184018
+ // src/routes/profiles.ts
184019
+ var PROFILE_DETAIL = {
184020
+ tags: ["profiles"]
184021
+ };
184022
+ function isNamedError(e) {
184023
+ return e instanceof Error && typeof e.name === "string";
184024
+ }
184025
+ function statusFor(err) {
184026
+ switch (err.name) {
184027
+ case "UnknownProfileError":
184028
+ return 400;
184029
+ case "NoHostsDetectedError":
184030
+ return 404;
184031
+ default:
184032
+ break;
184033
+ }
184034
+ if (err instanceof LockError)
184035
+ return 409;
184036
+ if (err instanceof InstallStateError)
184037
+ return 500;
184038
+ return 500;
184039
+ }
184040
+ function errorBody(err) {
184041
+ return { success: false, error: { code: err.name, message: err.message } };
184042
+ }
184043
+ function validHost(value) {
184044
+ if (value === undefined)
184045
+ return;
184046
+ if (typeof value === "string" && isHost(value))
184047
+ return value;
184048
+ return;
184049
+ }
184050
+ var profileRoutes = new Elysia({ prefix: "/api/v1/profiles" }).get("/", ({ query, set: set3 }) => {
184051
+ const hostParam = query.host;
184052
+ if (hostParam !== undefined && !isHost(hostParam)) {
184053
+ set3.status = 400;
184054
+ return { success: false, error: { code: "InvalidHostError", message: `unknown host "${hostParam}"` } };
184055
+ }
184056
+ try {
184057
+ const inventory = listProfiles(hostParam ? { hosts: [hostParam] } : {});
184058
+ set3.status = 200;
184059
+ return { success: true, data: inventory };
184060
+ } catch (e) {
184061
+ const err = isNamedError(e) ? e : { name: "Error", message: String(e) };
184062
+ set3.status = statusFor(err);
184063
+ return errorBody(err);
184064
+ }
184065
+ }, {
184066
+ query: t.Object({ host: t.Optional(t.String()) }),
184067
+ detail: {
184068
+ ...PROFILE_DETAIL,
184069
+ summary: "List shipped profiles + per-host active profile",
184070
+ description: "Returns the shipped profile names, per-host active profile (from recorded install-state, falling back to 'balanced' when unrecorded), and per-host bundle version. Available profile names come from on-disk variant directories only; the registry is never consulted."
184071
+ }
184072
+ }).post("/switch", ({ body, set: set3 }) => {
184073
+ const { profile, host, dryRun } = body;
184074
+ if (host !== undefined && !isHost(host)) {
184075
+ set3.status = 400;
184076
+ return { success: false, error: { code: "InvalidHostError", message: `unknown host "${host}"` } };
184077
+ }
184078
+ try {
184079
+ syncGeneratedVariants({ sourceRoot: getDeploymentRoot() });
184080
+ const report = switchProfile({ profile, host: validHost(host), dryRun });
184081
+ set3.status = 200;
184082
+ return { success: true, data: report };
184083
+ } catch (e) {
184084
+ const err = isNamedError(e) ? e : { name: "Error", message: String(e) };
184085
+ set3.status = statusFor(err);
184086
+ return errorBody(err);
184087
+ }
184088
+ }, {
184089
+ body: t.Object({
184090
+ profile: t.String({ description: "Target profile name" }),
184091
+ host: t.Optional(t.String({ description: "Limit the switch to a single host" })),
184092
+ dryRun: t.Optional(t.Boolean({ description: "Print the per-host plan; change nothing" }))
184093
+ }),
184094
+ detail: {
184095
+ ...PROFILE_DETAIL,
184096
+ summary: "Switch installed agents to a profile",
184097
+ description: "Mutates the machine this server runs on: replaces the active installed agent files for every detected, supported host with the chosen profile's variant, and reports per host: switched / skipped (reason) / failed (reason). A session restart is required for the change to take effect. Local trust model \u2014 same as the executor routes."
184098
+ }
184099
+ });
184100
+
184101
+ // src/routes/config.ts
184102
+ init_dist();
184103
+ init_inference_providers();
184104
+ var CONFIG_DETAIL = {
184105
+ tags: ["config"]
184106
+ };
184107
+ function defaultEmbedBatchSize(provider) {
184108
+ const spec = typeof provider === "string" && LOCAL_INFERENCE_IDS.includes(provider) ? INFERENCE_PROVIDERS[provider] : INFERENCE_PROVIDERS.ollama;
184109
+ return spec.embedBatchSize;
184110
+ }
184111
+ var SENSITIVE_FIELDS = {
184112
+ database: ["url"],
184113
+ embedding: ["apiKey"],
184114
+ llm: ["apiKey"],
184115
+ security: ["apiKey"]
184116
+ };
184117
+ function getFieldByPath(config3, section, field3) {
184118
+ const sec = config3[section];
184119
+ if (!sec || typeof sec !== "object")
184120
+ return;
184121
+ const parts = field3.split(".");
184122
+ let val = sec;
184123
+ for (const p of parts) {
184124
+ if (val && typeof val === "object")
184125
+ val = val[p];
184126
+ else
184127
+ return;
184128
+ }
184129
+ return val;
184130
+ }
184131
+ var configRoutes = new Elysia({ prefix: "/api/v1/config" }).get("/", ({ set: set3 }) => {
184132
+ const config3 = loadConfig();
184133
+ const masked = maskSensitive(config3);
184134
+ const restart = restartNeededSections(config3);
184135
+ const shipped = maskSensitive(defaultMassaAiConfig);
184136
+ const defaults2 = {
184137
+ ...shipped,
184138
+ embedding: {
184139
+ ...shipped.embedding,
184140
+ contextWindow: INFERENCE_ROLE_DEFAULTS.embedding.contextWindow,
184141
+ batchSize: defaultEmbedBatchSize(config3.embedding?.provider)
184142
+ }
184143
+ };
184144
+ set3.status = 200;
184145
+ return {
184146
+ success: true,
184147
+ data: { config: masked, restartNeededSections: restart, defaults: defaults2 }
184148
+ };
184149
+ }, {
184150
+ detail: {
184151
+ ...CONFIG_DETAIL,
184152
+ summary: "Get current config with sensitive fields masked",
184153
+ description: "Returns the current config.json with security.apiKey, llm.apiKey, embedding.apiKey, and database.url masked to '***'. Includes restartNeededSections \u2014 the subset of [database, embedding, llm, security] present in the config \u2014 and defaults, the shipped default config (also masked) the Config tab falls back to for any field the persisted file omits. defaults.embedding.contextWindow and defaults.embedding.batchSize are derived rather than shipped: they come from the role table and the resolved provider's seam entry, because defaultMassaAiConfig deliberately leaves both unset (PDM-12)."
184154
+ }
184155
+ }).get("/reveal", ({ query, set: set3 }) => {
184156
+ const section = query.section;
184157
+ const field3 = query.field;
184158
+ if (!section || !field3) {
184159
+ set3.status = 400;
184160
+ return { success: false, error: "section and field query params are required" };
184161
+ }
184162
+ const allowed = SENSITIVE_FIELDS[section];
184163
+ if (!allowed || !allowed.includes(field3)) {
184164
+ set3.status = 400;
184165
+ return { success: false, error: `field "${section}.${field3}" is not a sensitive field` };
184166
+ }
184167
+ const config3 = loadConfig();
184168
+ const value = getFieldByPath(config3, section, field3);
184169
+ set3.status = 200;
184170
+ return { success: true, data: { section, field: field3, value: value ?? "" } };
184171
+ }, {
184172
+ query: t.Object({
184173
+ section: t.String(),
184174
+ field: t.String()
184175
+ }),
184176
+ detail: {
184177
+ ...CONFIG_DETAIL,
184178
+ summary: "Reveal a single sensitive config field (unmasked)",
184179
+ description: "Returns the unmasked value for one sensitive field (database.url, embedding.apiKey, llm.apiKey, security.apiKey). Requires API key. Only sensitive fields can be revealed."
184180
+ }
184181
+ }).put("/", ({ body, set: set3 }) => {
184182
+ const result = savePartialConfig(body);
184183
+ if (!result.success) {
184184
+ set3.status = 400;
184185
+ return {
184186
+ success: false,
184187
+ error: "validation failed",
184188
+ details: result.details
184189
+ };
184190
+ }
184191
+ const masked = maskSensitive(result.config);
184192
+ set3.status = 200;
184193
+ return {
184194
+ success: true,
184195
+ data: {
184196
+ config: masked,
184197
+ restartNeededSections: result.restartNeededSections,
184198
+ changedRestartSections: result.changedRestartSections
184199
+ }
184200
+ };
184201
+ }, {
184202
+ body: t.Object({}, { additionalProperties: true }),
184203
+ detail: {
184204
+ ...CONFIG_DETAIL,
184205
+ summary: "Update config sections (partial, validated, atomic)",
184206
+ description: "Accepts one or more top-level config sections. Validates each provided section, backs up to config.json.bak.<timestamp>, merges shallowly per top-level key, writes atomically. Returns the updated masked config + restartNeededSections. A sensitive field equal to '***' preserves the existing value."
184207
+ }
184208
+ });
184209
+
183781
184210
  // src/routes/model-registry.ts
183782
184211
  init_config();
183783
184212
  import fs28 from "fs";
@@ -183795,19 +184224,6 @@ function profilesLib() {
183795
184224
  }
183796
184225
  return _profilesLib;
183797
184226
  }
183798
- function getRegistryHostDefaults() {
183799
- try {
183800
- const root2 = getDeploymentRoot();
183801
- if (!root2)
183802
- return;
183803
- const lib = profilesLib();
183804
- const result = lib.loadEffectiveRegistry({ overlayPath: OVERLAY_PATH });
183805
- const hostDefaults = result?.registry?.hostDefaults;
183806
- return hostDefaults && typeof hostDefaults === "object" ? hostDefaults : undefined;
183807
- } catch {
183808
- return;
183809
- }
183810
- }
183811
184227
  var _generatorLib = null;
183812
184228
  function generatorLib() {
183813
184229
  if (!_generatorLib) {
@@ -183823,21 +184239,46 @@ function generatorLib() {
183823
184239
  async function loadAgentsInventory() {
183824
184240
  try {
183825
184241
  const gen = generatorLib();
183826
- const charters = await gen.loadAllCharters();
183827
- return { agents: charters.map((c) => ({ name: c.name, charterTier: c.modelTier })) };
184242
+ const names = await gen.scanCharterNames();
184243
+ return { agents: names.map((name26) => ({ name: name26 })) };
183828
184244
  } catch (e) {
183829
184245
  return { agents: [], agentsError: e.message };
183830
184246
  }
183831
184247
  }
184248
+ var ALLOWED_OVERLAY_KEYS = new Set(["models", "profiles"]);
184249
+ var LEGACY_OVERLAY_KEYS = new Set(["tiers", "hostDefaults", "workflowTiers", "agentTiers"]);
184250
+ function isPlainObj(v) {
184251
+ return typeof v === "object" && v !== null && !Array.isArray(v);
184252
+ }
184253
+ function overlayShapeViolations(overlay) {
184254
+ const violations = [];
184255
+ for (const key of Object.keys(overlay)) {
184256
+ if (ALLOWED_OVERLAY_KEYS.has(key))
184257
+ continue;
184258
+ violations.push(LEGACY_OVERLAY_KEYS.has(key) ? `overlay key "${key}" is a v1 registry key removed in v2 \u2014 only "models" and "profiles" are supported overlay sections` : `overlay has unknown top-level key "${key}" \u2014 only "models" and "profiles" are supported`);
184259
+ }
184260
+ if (isPlainObj(overlay.profiles)) {
184261
+ for (const [name26, val] of Object.entries(overlay.profiles)) {
184262
+ if (!isPlainObj(val)) {
184263
+ violations.push(`overlay.profiles.${name26} must be an object, got ${JSON.stringify(val)}`);
184264
+ }
184265
+ }
184266
+ }
184267
+ if (isPlainObj(overlay.models)) {
184268
+ for (const [id, val] of Object.entries(overlay.models)) {
184269
+ if (val !== null && !isPlainObj(val)) {
184270
+ violations.push(`overlay.models.${id} must be an object or null (tombstone), got ${JSON.stringify(val)}`);
184271
+ }
184272
+ }
184273
+ }
184274
+ return violations;
184275
+ }
183832
184276
  var REGISTRY_DETAIL = {
183833
184277
  tags: ["model-registry"]
183834
184278
  };
183835
184279
  var OVERLAY_PATH = path42.join(configDir("massa-ai"), "model-profiles.json");
183836
184280
  var ZERO_OVERLAY_OVERRIDE_BREAKDOWN = {
183837
- hostDefaults: 0,
183838
- workflowTiers: 0,
183839
- agentTiers: 0,
183840
- tiers: 0,
184281
+ models: 0,
183841
184282
  profiles: 0
183842
184283
  };
183843
184284
  var modelRegistryRoutes = new Elysia({ prefix: "/api/v1/model-registry" }).get("/", async ({ set: set3 }) => {
@@ -183858,6 +184299,7 @@ var modelRegistryRoutes = new Elysia({ prefix: "/api/v1/model-registry" }).get("
183858
184299
  overlayOverrideCount: result.overlayOverrideCount ?? 0,
183859
184300
  overlayOverrideBreakdown: result.overlayOverrideBreakdown ?? ZERO_OVERLAY_OVERRIDE_BREAKDOWN,
183860
184301
  ...result.overlayError ? { overlayError: result.overlayError } : {},
184302
+ ...result.v1BackupPath ? { v1BackupPath: result.v1BackupPath } : {},
183861
184303
  agents,
183862
184304
  ...agentsError ? { agentsError } : {}
183863
184305
  }
@@ -183866,7 +184308,7 @@ var modelRegistryRoutes = new Elysia({ prefix: "/api/v1/model-registry" }).get("
183866
184308
  detail: {
183867
184309
  ...REGISTRY_DETAIL,
183868
184310
  summary: "Get effective registry (builtin + overlay) with source attribution",
183869
- description: "Returns the merged registry (builtin + overlay), source attribution (builtin, overlay, tombstoned), overlayOverrideCount (APCR-01.10 \u2014 count of overlay entries surviving normalization, so an operator can see how much of the registry their overlay is overriding), overlayOverrideBreakdown (WUT-17 \u2014 the same count broken down per category: hostDefaults, workflowTiers, agentTiers, tiers, profiles), overlayError if the overlay is corrupted, and agents (design D-3, APUX-03 \u2014 {name, charterTier} for every charter under skills/agents/, best-effort with agentsError on failure) (200 status, never fails)."
184311
+ description: "Returns the merged v2 registry (builtin + overlay: models catalog + profiles, each profile carrying a per-host default cell and optional per-agent overrides), source attribution (builtin, overlay, tombstoned), overlayOverrideCount (count of overlay entries surviving normalization, so an operator can see how much of the registry their overlay is overriding), overlayOverrideBreakdown (the same count broken down per category: models, profiles), overlayError if the overlay is corrupted, and agents (spec AC6 \u2014 {name} for every charter under skills/agents/, from a directory scan, best-effort with agentsError on failure) (200 status, never fails)."
183870
184312
  }
183871
184313
  }).put("/", ({ body, set: set3 }) => {
183872
184314
  const root2 = getDeploymentRoot();
@@ -183876,6 +184318,15 @@ var modelRegistryRoutes = new Elysia({ prefix: "/api/v1/model-registry" }).get("
183876
184318
  }
183877
184319
  const lib = profilesLib();
183878
184320
  const overlay = body;
184321
+ const shapeViolations = overlayShapeViolations(overlay);
184322
+ if (shapeViolations.length > 0) {
184323
+ set3.status = 400;
184324
+ return {
184325
+ success: false,
184326
+ error: "validation failed",
184327
+ details: shapeViolations
184328
+ };
184329
+ }
183879
184330
  const builtin = lib.loadRegistry(lib.DEFAULT_REGISTRY_PATH);
183880
184331
  const merged = lib.mergeOverlay(builtin, overlay);
183881
184332
  try {
@@ -183916,7 +184367,7 @@ var modelRegistryRoutes = new Elysia({ prefix: "/api/v1/model-registry" }).get("
183916
184367
  detail: {
183917
184368
  ...REGISTRY_DETAIL,
183918
184369
  summary: "Write overlay (full-replace, validated, atomic)",
183919
- description: "Accepts the full overlay object. Validates the merged result (builtin + overlay) via validateRegistry(). On success, writes atomically to ~/.config/massa-ai/model-profiles.json and returns the updated effective registry, including overlayOverrideCount (APCR-01.10) and overlayOverrideBreakdown (WUT-17, per-category). On failure, returns 400 with all violations."
184370
+ description: "Accepts the full v2 overlay object ({models?, profiles?} only \u2014 a v1 top-level key (tiers/hostDefaults/workflowTiers/agentTiers) or any other unknown key is rejected outright with 400 before merging). Validates the merged result (builtin + overlay) via validateRegistry(). On success, writes atomically to ~/.config/massa-ai/model-profiles.json and returns the updated effective registry, including overlayOverrideCount and overlayOverrideBreakdown (per-category: models, profiles). On failure, returns 400 with all violations."
183920
184371
  }
183921
184372
  }).post("/regenerate", ({ set: set3 }) => {
183922
184373
  const root2 = getDeploymentRoot();
@@ -184006,201 +184457,6 @@ function writeOverlayAtomically(overlayPath, data) {
184006
184457
  }
184007
184458
  }
184008
184459
 
184009
- // src/routes/profiles.ts
184010
- var PROFILE_DETAIL = {
184011
- tags: ["profiles"]
184012
- };
184013
- function isNamedError(e) {
184014
- return e instanceof Error && typeof e.name === "string";
184015
- }
184016
- function statusFor(err) {
184017
- switch (err.name) {
184018
- case "UnknownProfileError":
184019
- return 400;
184020
- case "NoHostsDetectedError":
184021
- return 404;
184022
- default:
184023
- break;
184024
- }
184025
- if (err instanceof LockError)
184026
- return 409;
184027
- if (err instanceof InstallStateError)
184028
- return 500;
184029
- return 500;
184030
- }
184031
- function errorBody(err) {
184032
- return { success: false, error: { code: err.name, message: err.message } };
184033
- }
184034
- function validHost(value) {
184035
- if (value === undefined)
184036
- return;
184037
- if (typeof value === "string" && isHost(value))
184038
- return value;
184039
- return;
184040
- }
184041
- var profileRoutes = new Elysia({ prefix: "/api/v1/profiles" }).get("/", ({ query, set: set3 }) => {
184042
- const hostParam = query.host;
184043
- if (hostParam !== undefined && !isHost(hostParam)) {
184044
- set3.status = 400;
184045
- return { success: false, error: { code: "InvalidHostError", message: `unknown host "${hostParam}"` } };
184046
- }
184047
- try {
184048
- const inventory = listProfiles({
184049
- ...hostParam ? { hosts: [hostParam] } : {},
184050
- hostDefaults: getRegistryHostDefaults()
184051
- });
184052
- set3.status = 200;
184053
- return { success: true, data: inventory };
184054
- } catch (e) {
184055
- const err = isNamedError(e) ? e : { name: "Error", message: String(e) };
184056
- set3.status = statusFor(err);
184057
- return errorBody(err);
184058
- }
184059
- }, {
184060
- query: t.Object({ host: t.Optional(t.String()) }),
184061
- detail: {
184062
- ...PROFILE_DETAIL,
184063
- summary: "List shipped profiles + per-host active profile",
184064
- description: "Returns the shipped profile names, per-host active profile (from recorded state; the registry's declared per-host default shown when unrecorded, falling back to 'balanced' when the registry is unreachable), and per-host bundle version. Available profile names come from on-disk variant directories only; the registry is consulted only for that unrecorded-host default."
184065
- }
184066
- }).post("/switch", ({ body, set: set3 }) => {
184067
- const { profile, host, dryRun } = body;
184068
- if (host !== undefined && !isHost(host)) {
184069
- set3.status = 400;
184070
- return { success: false, error: { code: "InvalidHostError", message: `unknown host "${host}"` } };
184071
- }
184072
- try {
184073
- syncGeneratedVariants({ sourceRoot: getDeploymentRoot() });
184074
- const report = switchProfile({ profile, host: validHost(host), dryRun });
184075
- set3.status = 200;
184076
- return { success: true, data: report };
184077
- } catch (e) {
184078
- const err = isNamedError(e) ? e : { name: "Error", message: String(e) };
184079
- set3.status = statusFor(err);
184080
- return errorBody(err);
184081
- }
184082
- }, {
184083
- body: t.Object({
184084
- profile: t.String({ description: "Target profile name" }),
184085
- host: t.Optional(t.String({ description: "Limit the switch to a single host" })),
184086
- dryRun: t.Optional(t.Boolean({ description: "Print the per-host plan; change nothing" }))
184087
- }),
184088
- detail: {
184089
- ...PROFILE_DETAIL,
184090
- summary: "Switch installed agents to a profile",
184091
- description: "Mutates the machine this server runs on: replaces the active installed agent files for every detected, supported host with the chosen profile's variant, and reports per host: switched / skipped (reason) / failed (reason). A session restart is required for the change to take effect. Local trust model \u2014 same as the executor routes."
184092
- }
184093
- });
184094
-
184095
- // src/routes/config.ts
184096
- init_dist();
184097
- init_inference_providers();
184098
- var CONFIG_DETAIL = {
184099
- tags: ["config"]
184100
- };
184101
- function defaultEmbedBatchSize(provider) {
184102
- const spec = typeof provider === "string" && LOCAL_INFERENCE_IDS.includes(provider) ? INFERENCE_PROVIDERS[provider] : INFERENCE_PROVIDERS.ollama;
184103
- return spec.embedBatchSize;
184104
- }
184105
- var SENSITIVE_FIELDS = {
184106
- database: ["url"],
184107
- embedding: ["apiKey"],
184108
- llm: ["apiKey"],
184109
- security: ["apiKey"]
184110
- };
184111
- function getFieldByPath(config3, section, field3) {
184112
- const sec = config3[section];
184113
- if (!sec || typeof sec !== "object")
184114
- return;
184115
- const parts = field3.split(".");
184116
- let val = sec;
184117
- for (const p of parts) {
184118
- if (val && typeof val === "object")
184119
- val = val[p];
184120
- else
184121
- return;
184122
- }
184123
- return val;
184124
- }
184125
- var configRoutes = new Elysia({ prefix: "/api/v1/config" }).get("/", ({ set: set3 }) => {
184126
- const config3 = loadConfig();
184127
- const masked = maskSensitive(config3);
184128
- const restart = restartNeededSections(config3);
184129
- const shipped = maskSensitive(defaultMassaAiConfig);
184130
- const defaults2 = {
184131
- ...shipped,
184132
- embedding: {
184133
- ...shipped.embedding,
184134
- contextWindow: INFERENCE_ROLE_DEFAULTS.embedding.contextWindow,
184135
- batchSize: defaultEmbedBatchSize(config3.embedding?.provider)
184136
- }
184137
- };
184138
- set3.status = 200;
184139
- return {
184140
- success: true,
184141
- data: { config: masked, restartNeededSections: restart, defaults: defaults2 }
184142
- };
184143
- }, {
184144
- detail: {
184145
- ...CONFIG_DETAIL,
184146
- summary: "Get current config with sensitive fields masked",
184147
- description: "Returns the current config.json with security.apiKey, llm.apiKey, embedding.apiKey, and database.url masked to '***'. Includes restartNeededSections \u2014 the subset of [database, embedding, llm, security] present in the config \u2014 and defaults, the shipped default config (also masked) the Config tab falls back to for any field the persisted file omits. defaults.embedding.contextWindow and defaults.embedding.batchSize are derived rather than shipped: they come from the role table and the resolved provider's seam entry, because defaultMassaAiConfig deliberately leaves both unset (PDM-12)."
184148
- }
184149
- }).get("/reveal", ({ query, set: set3 }) => {
184150
- const section = query.section;
184151
- const field3 = query.field;
184152
- if (!section || !field3) {
184153
- set3.status = 400;
184154
- return { success: false, error: "section and field query params are required" };
184155
- }
184156
- const allowed = SENSITIVE_FIELDS[section];
184157
- if (!allowed || !allowed.includes(field3)) {
184158
- set3.status = 400;
184159
- return { success: false, error: `field "${section}.${field3}" is not a sensitive field` };
184160
- }
184161
- const config3 = loadConfig();
184162
- const value = getFieldByPath(config3, section, field3);
184163
- set3.status = 200;
184164
- return { success: true, data: { section, field: field3, value: value ?? "" } };
184165
- }, {
184166
- query: t.Object({
184167
- section: t.String(),
184168
- field: t.String()
184169
- }),
184170
- detail: {
184171
- ...CONFIG_DETAIL,
184172
- summary: "Reveal a single sensitive config field (unmasked)",
184173
- description: "Returns the unmasked value for one sensitive field (database.url, embedding.apiKey, llm.apiKey, security.apiKey). Requires API key. Only sensitive fields can be revealed."
184174
- }
184175
- }).put("/", ({ body, set: set3 }) => {
184176
- const result = savePartialConfig(body);
184177
- if (!result.success) {
184178
- set3.status = 400;
184179
- return {
184180
- success: false,
184181
- error: "validation failed",
184182
- details: result.details
184183
- };
184184
- }
184185
- const masked = maskSensitive(result.config);
184186
- set3.status = 200;
184187
- return {
184188
- success: true,
184189
- data: {
184190
- config: masked,
184191
- restartNeededSections: result.restartNeededSections,
184192
- changedRestartSections: result.changedRestartSections
184193
- }
184194
- };
184195
- }, {
184196
- body: t.Object({}, { additionalProperties: true }),
184197
- detail: {
184198
- ...CONFIG_DETAIL,
184199
- summary: "Update config sections (partial, validated, atomic)",
184200
- description: "Accepts one or more top-level config sections. Validates each provided section, backs up to config.json.bak.<timestamp>, merges shallowly per top-level key, writes atomically. Returns the updated masked config + restartNeededSections. A sensitive field equal to '***' preserves the existing value."
184201
- }
184202
- });
184203
-
184204
184460
  // src/routes/model-registry-stream.ts
184205
184461
  init_config();
184206
184462
  init_dist();
@@ -184293,7 +184549,7 @@ function installActiveProfiles(controller2, closedRef) {
184293
184549
  ...r2.error ? { error: r2.error } : {}
184294
184550
  }));
184295
184551
  }
184296
- const inventory = listProfiles({ hostDefaults: getRegistryHostDefaults() });
184552
+ const inventory = listProfiles();
184297
184553
  for (const hostEntry of inventory.hosts) {
184298
184554
  if (closedRef.closed)
184299
184555
  return;