@wrongstack/webui-server 0.289.0 → 0.291.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.
@@ -1908,6 +1908,7 @@ async function handleGitDiff(ws, projectRoot, path23) {
1908
1908
  import * as fs6 from "node:fs/promises";
1909
1909
  import * as http from "node:http";
1910
1910
  import * as path7 from "node:path";
1911
+ import * as v8 from "node:v8";
1911
1912
 
1912
1913
  // src/server/http-server/api-handlers.ts
1913
1914
  async function handleApiSessions(res, globalRoot) {
@@ -3206,6 +3207,23 @@ function createHttpServer(opts) {
3206
3207
  }
3207
3208
  return;
3208
3209
  }
3210
+ if (url.pathname === "/debug/system" && req.method === "GET") {
3211
+ res.writeHead(200, {
3212
+ "Content-Type": "application/json",
3213
+ "Cache-Control": "no-store"
3214
+ });
3215
+ res.end(
3216
+ JSON.stringify({
3217
+ pid: process.pid,
3218
+ memoryUsage: process.memoryUsage(),
3219
+ heapLimit: v8.getHeapStatistics().heap_size_limit,
3220
+ uptime: process.uptime(),
3221
+ cpuUsage: process.cpuUsage(),
3222
+ timestamp: Date.now()
3223
+ })
3224
+ );
3225
+ return;
3226
+ }
3209
3227
  let filePath;
3210
3228
  if (url.pathname === "/" || url.pathname === "") {
3211
3229
  filePath = path7.join(distDir, "index.html");
@@ -5164,6 +5182,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
5164
5182
  "hqRawContent",
5165
5183
  "fallbackAuto",
5166
5184
  "favoriteModelsOnly",
5185
+ "modelAvailabilitySchedule",
5167
5186
  "breakerEnabled",
5168
5187
  "debugStream",
5169
5188
  // Chimera + auto-review master toggles
@@ -5308,7 +5327,10 @@ function validatePreferenceValue(key, value) {
5308
5327
  return `prefs.update payload.${key}.modelRuntime must be an object when provided`;
5309
5328
  }
5310
5329
  if (isRecord(modelRuntime)) {
5311
- const runtimeError = validateModelRuntimeValue(modelRuntime, `prefs.update payload.${key}.modelRuntime`);
5330
+ const runtimeError = validateModelRuntimeValue(
5331
+ modelRuntime,
5332
+ `prefs.update payload.${key}.modelRuntime`
5333
+ );
5312
5334
  if (runtimeError) return runtimeError;
5313
5335
  }
5314
5336
  if (model === void 0 && fallbackProfile === void 0 && modelRuntime === void 0) {
@@ -6544,7 +6566,7 @@ function registerShutdownHandlers(res) {
6544
6566
  import { watch as fsWatch } from "node:fs";
6545
6567
  import * as fs11 from "node:fs/promises";
6546
6568
  import * as path13 from "node:path";
6547
- import { getBoard, getKanbanDir } from "@wrongstack/kanban";
6569
+ import { getBoard, getKanbanDir, recordTaskFileActivity } from "@wrongstack/kanban";
6548
6570
 
6549
6571
  // src/server/codemap-telemetry.ts
6550
6572
  import * as path12 from "node:path";
@@ -6940,6 +6962,18 @@ function setupEvents(deps2) {
6940
6962
  on("file.activity", (e) => {
6941
6963
  broadcast2(clients, { type: "codemap.file_event", payload: e });
6942
6964
  });
6965
+ on("file.event", (e) => {
6966
+ if (e.scope !== "task" || !e.boardId || !e.taskId) return;
6967
+ void recordTaskFileActivity(context.projectRoot, e.boardId, e.taskId, e).then((recorded) => {
6968
+ if (recorded) {
6969
+ broadcast2(clients, {
6970
+ type: "kanban.task.activity.changed",
6971
+ payload: { boardId: e.boardId, taskId: e.taskId }
6972
+ });
6973
+ }
6974
+ }).catch(() => {
6975
+ });
6976
+ });
6943
6977
  on("tool.loop_detected", (e) => {
6944
6978
  broadcast2(clients, {
6945
6979
  type: "tool.loop_detected",
@@ -7064,12 +7098,14 @@ function setupEvents(deps2) {
7064
7098
  input: e.input,
7065
7099
  suggestedPattern: e.suggestedPattern,
7066
7100
  decisionSource: e.decisionSource,
7067
- riskTier: e.riskTier
7101
+ riskTier: e.riskTier,
7102
+ boundaryReason: e.boundaryReason
7068
7103
  });
7069
7104
  pendingConfirms.set(id, {
7070
7105
  resolve: e.resolve,
7071
7106
  decisionSource: e.decisionSource,
7072
7107
  riskTier: e.riskTier,
7108
+ boundaryReason: e.boundaryReason,
7073
7109
  payload
7074
7110
  });
7075
7111
  broadcast2(clients, { type: "tool.confirm_needed", payload });
@@ -7162,7 +7198,8 @@ function setupEvents(deps2) {
7162
7198
  oldState: e.oldState,
7163
7199
  newState: e.newState,
7164
7200
  reason: e.reason,
7165
- timestamp: e.timestamp
7201
+ timestamp: e.timestamp,
7202
+ stateExpiresAt: e.stateExpiresAt
7166
7203
  })
7167
7204
  });
7168
7205
  });
@@ -8269,6 +8306,7 @@ function seedContextMeta(config, context) {
8269
8306
  meta["fallbackProfiles"] = config.fallbackProfiles ?? {};
8270
8307
  meta["favoriteModels"] = config.favoriteModels ?? [];
8271
8308
  meta["favoriteModelsOnly"] = config.favoriteModelsOnly === true;
8309
+ meta["modelAvailabilitySchedule"] = config.modelAvailabilitySchedule ?? [];
8272
8310
  meta["modelMatrix"] = config.modelMatrix ?? {};
8273
8311
  meta["fallbackAuto"] = config.fallbackAuto !== false;
8274
8312
  if (typeof config.uiLocale === "string" && config.uiLocale) meta["uiLocale"] = config.uiLocale;
@@ -8351,9 +8389,7 @@ function seedContextMeta(config, context) {
8351
8389
  } catch {
8352
8390
  resolvedChain = [];
8353
8391
  }
8354
- meta["autoReviewFallbackModels"] = resolvedChain.map(
8355
- (e) => `${e.providerId}/${e.model}`
8356
- );
8392
+ meta["autoReviewFallbackModels"] = resolvedChain.map((e) => `${e.providerId}/${e.model}`);
8357
8393
  }
8358
8394
  }
8359
8395
 
@@ -9810,7 +9846,7 @@ function setupWebUICodebaseIndexing(deps2) {
9810
9846
  }
9811
9847
  if (idx) {
9812
9848
  cancelPendingReindexes();
9813
- shutdownCodebaseIndexHost();
9849
+ void shutdownCodebaseIndexHost();
9814
9850
  }
9815
9851
  }
9816
9852
  };
@@ -9977,6 +10013,9 @@ var DEFAULT_COLS = 80;
9977
10013
  var DEFAULT_ROWS = 24;
9978
10014
  var requireFromHere = createRequire4(import.meta.url);
9979
10015
  var cachedNodePty;
10016
+ function resolveTerminalShell(platform = process.platform, env = process.env) {
10017
+ return platform === "win32" ? env.COMSPEC || "cmd.exe" : env.SHELL || "/bin/sh";
10018
+ }
9980
10019
  var TerminalWebSocketHandler = class {
9981
10020
  constructor(getCwd, logger, loadNodePty = defaultLoadNodePty, killProcessTree = defaultKillProcessTree) {
9982
10021
  this.getCwd = getCwd;
@@ -10032,7 +10071,7 @@ var TerminalWebSocketHandler = class {
10032
10071
  });
10033
10072
  return;
10034
10073
  }
10035
- const shell = process.platform === "win32" ? process.env.COMSPEC || "cmd.exe" : process.env.SHELL || "/bin/bash";
10074
+ const shell = resolveTerminalShell();
10036
10075
  const nodePty = this.loadNodePty();
10037
10076
  if (!nodePty) {
10038
10077
  const msg = "Integrated terminal unavailable: optional dependency node-pty is not installed. Install node-pty to enable WebUI terminal sessions.";
@@ -10352,7 +10391,11 @@ async function createAgentServices(input) {
10352
10391
  toolExecutor
10353
10392
  });
10354
10393
  if (config.features.memory && config.features.memoryConsolidation !== false) {
10355
- agent.extensions.register(new SessionMemoryConsolidator({ memoryStore }));
10394
+ const consSuperMemory = typeof memoryStore["rememberSuper"] === "function" ? memoryStore : void 0;
10395
+ agent.extensions.register(new SessionMemoryConsolidator({
10396
+ memoryStore,
10397
+ ...consSuperMemory ? { superMemory: consSuperMemory } : {}
10398
+ }));
10356
10399
  }
10357
10400
  console.log("[WebUI] Agent initialized");
10358
10401
  const brainCfg = resolveBrainConfigDefaults(config.brain, {
@@ -10558,6 +10601,7 @@ function isSuperMemoryRetriever(memoryStore) {
10558
10601
  // src/server/pending-confirms.ts
10559
10602
  function resolveYoloEligiblePendingConfirms(pendingConfirms) {
10560
10603
  for (const [id, confirm] of pendingConfirms) {
10604
+ if (confirm.boundaryReason) continue;
10561
10605
  pendingConfirms.delete(id);
10562
10606
  confirm.resolve("yes");
10563
10607
  }
@@ -11037,7 +11081,7 @@ import {
11037
11081
  createBoard,
11038
11082
  duplicateBoard,
11039
11083
  exportBoardToTaskGraph,
11040
- generateBoardFromDescription,
11084
+ createBoardFromText,
11041
11085
  getBoard as getBoard2,
11042
11086
  getKanbanOrchestrationSnapshot,
11043
11087
  getKanbanQueueHealth,
@@ -11068,6 +11112,32 @@ import {
11068
11112
  updateTask
11069
11113
  } from "@wrongstack/kanban";
11070
11114
  import { applySessionKanbanTaskToSource } from "@wrongstack/tools/session-kanban";
11115
+ function paginateKanbanBoards(boards, input) {
11116
+ const pageSize = Math.min(100, Math.max(1, Math.floor(input.pageSize)));
11117
+ const activeSessionIds = new Set(input.activeSessionIds ?? []);
11118
+ const isActive = (board) => board.presence?.some((entry) => entry.active) === true || board.tags?.some(
11119
+ (tag) => tag.startsWith("session:") && activeSessionIds.has(tag.slice(8))
11120
+ ) === true;
11121
+ const sorted = [...boards].sort((left, right) => {
11122
+ const activityOrder = Number(isActive(right)) - Number(isActive(left));
11123
+ return activityOrder || right.updatedAt.localeCompare(left.updatedAt);
11124
+ });
11125
+ const activeTotal = sorted.filter(isActive).length;
11126
+ const total = sorted.length;
11127
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
11128
+ const requestedPage = Number.isFinite(input.page) ? Math.floor(input.page) : 1;
11129
+ const page = Math.min(totalPages, Math.max(1, requestedPage));
11130
+ const start = (page - 1) * pageSize;
11131
+ return {
11132
+ items: sorted.slice(start, start + pageSize),
11133
+ total,
11134
+ page,
11135
+ pageSize,
11136
+ totalPages,
11137
+ activeTotal,
11138
+ orphanedTotal: total - activeTotal
11139
+ };
11140
+ }
11071
11141
  async function syncSessionSource(ctx, task, remove = false) {
11072
11142
  if (!ctx.context) return;
11073
11143
  const update = await applySessionKanbanTaskToSource(ctx.context, task, { remove });
@@ -11117,9 +11187,26 @@ async function handleKanbanRoute(ws, msg, ctx) {
11117
11187
  const type = msg.type;
11118
11188
  try {
11119
11189
  switch (type) {
11120
- case "kanban.list":
11121
- ok(ws, type, await listBoards(ctx.projectRoot));
11190
+ case "kanban.list": {
11191
+ const boards = await listBoards(ctx.projectRoot);
11192
+ const requestedPage = Number(payload?.page);
11193
+ const requestedPageSize = Number(payload?.pageSize);
11194
+ if (!Number.isFinite(requestedPage) || !Number.isFinite(requestedPageSize)) {
11195
+ ok(ws, type, boards);
11196
+ return true;
11197
+ }
11198
+ const activeSessionIds = Array.isArray(payload?.activeSessionIds) ? payload.activeSessionIds.filter((id) => typeof id === "string") : [];
11199
+ ok(
11200
+ ws,
11201
+ type,
11202
+ paginateKanbanBoards(boards, {
11203
+ page: requestedPage,
11204
+ pageSize: requestedPageSize,
11205
+ activeSessionIds
11206
+ })
11207
+ );
11122
11208
  return true;
11209
+ }
11123
11210
  case "kanban.get": {
11124
11211
  const boardId = payload?.boardId;
11125
11212
  if (!boardId) {
@@ -11185,7 +11272,8 @@ async function handleKanbanRoute(ws, msg, ctx) {
11185
11272
  ...payload?.description ? { description: payload.description } : {},
11186
11273
  ...payload?.tags ? { tags: payload.tags } : {},
11187
11274
  ...payload?.columns ? { columns: payload.columns } : {},
11188
- ...has(payload, "lifecycle") ? { lifecycle: payload?.lifecycle } : {}
11275
+ ...has(payload, "lifecycle") ? { lifecycle: payload?.lifecycle } : {},
11276
+ ...has(payload, "boundary") ? { boundary: payload?.boundary } : {}
11189
11277
  })
11190
11278
  );
11191
11279
  return true;
@@ -11206,6 +11294,9 @@ async function handleKanbanRoute(ws, msg, ctx) {
11206
11294
  } : {},
11207
11295
  ...has(payload, "supervisor") ? {
11208
11296
  supervisor: payload?.supervisor ?? null
11297
+ } : {},
11298
+ ...has(payload, "boundary") ? {
11299
+ boundary: payload?.boundary ?? null
11209
11300
  } : {}
11210
11301
  });
11211
11302
  board ? ok(ws, type, board) : fail(ws, type, `Board not found: ${boardId}`);
@@ -11252,7 +11343,7 @@ async function handleKanbanRoute(ws, msg, ctx) {
11252
11343
  }
11253
11344
  const board = await createBoard(
11254
11345
  ctx.projectRoot,
11255
- generateBoardFromDescription({
11346
+ createBoardFromText({
11256
11347
  description,
11257
11348
  ...payload?.title ? { title: payload.title } : {},
11258
11349
  ...payload?.context ? { context: payload.context } : {}
@@ -11364,7 +11455,8 @@ async function handleKanbanRoute(ws, msg, ctx) {
11364
11455
  ...payload?.dueDate ? { dueDate: payload.dueDate } : {},
11365
11456
  ...payload?.priority ? { priority: payload.priority } : {},
11366
11457
  ...payload?.assignedAgent ? { assignedAgent: payload.assignedAgent } : {},
11367
- ...payload?.labels ? { labels: payload.labels } : {}
11458
+ ...payload?.labels ? { labels: payload.labels } : {},
11459
+ ...has(payload, "boundary") ? { boundary: payload?.boundary } : {}
11368
11460
  },
11369
11461
  activityContext(ctx, "webui", payload?.activityNote)
11370
11462
  );
@@ -11445,6 +11537,9 @@ async function handleKanbanRoute(ws, msg, ctx) {
11445
11537
  } : {},
11446
11538
  ...has(payload, "costCeilingUsd") ? {
11447
11539
  costCeilingUsd: payload?.costCeilingUsd === null || payload?.costCeilingUsd === "" ? null : Number(payload?.costCeilingUsd)
11540
+ } : {},
11541
+ ...has(payload, "boundary") ? {
11542
+ boundary: payload?.boundary ?? null
11448
11543
  } : {}
11449
11544
  },
11450
11545
  activityContext(ctx, "webui", payload?.activityNote)
@@ -12337,7 +12432,7 @@ var chronicleCache = /* @__PURE__ */ new Map();
12337
12432
  async function chronicleEngine(projectRoot) {
12338
12433
  const now = Date.now();
12339
12434
  const cached = chronicleCache.get(projectRoot);
12340
- if (cached && now - cached.loadedAt < 1e3) return cached.engine;
12435
+ if (cached && now - cached.loadedAt < 6e4) return cached.engine;
12341
12436
  const paths = resolveWstackPaths2({ projectRoot, userHome: os2.homedir() });
12342
12437
  const engine = await ChronicleQueryEngine.fromDirectory(
12343
12438
  path19.join(paths.projectDir, "chronicle")
@@ -12854,7 +12949,7 @@ function createMessageDispatcher(opts) {
12854
12949
  case "chronicle.query": {
12855
12950
  const payload = msg.payload ?? {};
12856
12951
  const engine = await chronicleEngine(state.getProjectRoot());
12857
- send(ws, { type: "chronicle.query_result", payload: engine.query(payload.query ?? {}) });
12952
+ send(ws, { type: "chronicle.query_result", payload: await engine.query(payload.query ?? {}) });
12858
12953
  break;
12859
12954
  }
12860
12955
  case "chronicle.facet": {
@@ -12884,7 +12979,7 @@ function createMessageDispatcher(opts) {
12884
12979
  type: "chronicle.facet_result",
12885
12980
  payload: {
12886
12981
  field: payload.field,
12887
- values: engine.facet(payload.field, payload.query ?? {}, payload.limit),
12982
+ values: await engine.facet(payload.field, payload.query ?? {}, payload.limit),
12888
12983
  diagnostics: engine.diagnostics
12889
12984
  }
12890
12985
  });
@@ -12895,7 +12990,7 @@ function createMessageDispatcher(opts) {
12895
12990
  const engine = await chronicleEngine(state.getProjectRoot());
12896
12991
  send(ws, {
12897
12992
  type: "chronicle.graph_result",
12898
- payload: engine.graph(payload.seed ?? {}, payload.hops, payload.maxNodes)
12993
+ payload: await engine.graph(payload.seed ?? {}, payload.hops, payload.maxNodes)
12899
12994
  });
12900
12995
  break;
12901
12996
  }
@@ -12950,9 +13045,9 @@ function createMessageDispatcher(opts) {
12950
13045
  }
12951
13046
 
12952
13047
  // src/server/pref-helpers.ts
12953
- import { atomicWrite as atomicWrite6, FORBIDDEN_PROTO_KEYS as FORBIDDEN_PROTO_KEYS2 } from "@wrongstack/core/utils";
12954
- import { decryptConfigSecrets as decryptConfigSecrets2, encryptConfigSecrets as encryptConfigSecrets2 } from "@wrongstack/core/security";
12955
13048
  import * as fs14 from "node:fs/promises";
13049
+ import { decryptConfigSecrets as decryptConfigSecrets2, encryptConfigSecrets as encryptConfigSecrets2 } from "@wrongstack/core/security";
13050
+ import { atomicWrite as atomicWrite6, FORBIDDEN_PROTO_KEYS as FORBIDDEN_PROTO_KEYS2 } from "@wrongstack/core/utils";
12956
13051
  var PREF_KEYS = [
12957
13052
  "autonomy",
12958
13053
  "autonomyDelayMs",
@@ -12997,6 +13092,7 @@ var PREF_KEYS = [
12997
13092
  "fallbackProfiles",
12998
13093
  "favoriteModels",
12999
13094
  "favoriteModelsOnly",
13095
+ "modelAvailabilitySchedule",
13000
13096
  "modelMatrix",
13001
13097
  "fallbackAuto",
13002
13098
  // Refiner + TUI visual prefs (parity with the CLI's embedded server —
@@ -13069,256 +13165,264 @@ async function updateGlobalConfig(deps2, holder, mutate, errorLabel) {
13069
13165
  try {
13070
13166
  await next;
13071
13167
  } catch (err) {
13072
- logger.warn(`${errorLabel}: failed to persist to config: ${err instanceof Error ? err.message : String(err)}`);
13168
+ logger.warn(
13169
+ `${errorLabel}: failed to persist to config: ${err instanceof Error ? err.message : String(err)}`
13170
+ );
13073
13171
  }
13074
13172
  }
13075
13173
  async function persistPrefsToConfig(deps2, holder, payload) {
13076
- return updateGlobalConfig(deps2, holder, (decrypted) => {
13077
- const autonomyCfg = decrypted.autonomy ?? {};
13078
- let autonomyTouched = false;
13079
- const setAutonomy = (key, val) => {
13080
- autonomyCfg[key] = val;
13081
- autonomyTouched = true;
13082
- };
13083
- if (typeof payload["autonomy"] === "string" && ["off", "suggest", "auto"].includes(payload["autonomy"])) {
13084
- setAutonomy("defaultMode", payload["autonomy"]);
13085
- }
13086
- if (typeof payload["autonomyDelayMs"] === "number")
13087
- setAutonomy("autoProceedDelayMs", payload["autonomyDelayMs"]);
13088
- if (typeof payload["autoProceedMaxIterations"] === "number")
13089
- setAutonomy("autoProceedMaxIterations", payload["autoProceedMaxIterations"]);
13090
- if (typeof payload["yolo"] === "boolean") {
13091
- setAutonomy("yolo", payload["yolo"]);
13092
- decrypted.yolo = payload["yolo"];
13093
- }
13094
- if (typeof payload["chime"] === "boolean") setAutonomy("chime", payload["chime"]);
13095
- if (typeof payload["confirmExit"] === "boolean")
13096
- setAutonomy("confirmExit", payload["confirmExit"]);
13097
- if (typeof payload["streamFleet"] === "boolean")
13098
- setAutonomy("streamFleet", payload["streamFleet"]);
13099
- if (typeof payload["enhanceEnabled"] === "boolean")
13100
- setAutonomy("enhance", payload["enhanceEnabled"]);
13101
- if (typeof payload["enhanceDelayMs"] === "number")
13102
- setAutonomy("enhanceDelayMs", payload["enhanceDelayMs"]);
13103
- if (typeof payload["enhanceLanguage"] === "string")
13104
- setAutonomy("enhanceLanguage", payload["enhanceLanguage"]);
13105
- if (typeof payload["refinerProvider"] === "string")
13106
- setAutonomy("refinerProvider", payload["refinerProvider"]);
13107
- if (typeof payload["refinerModel"] === "string")
13108
- setAutonomy("refinerModel", payload["refinerModel"]);
13109
- if (typeof payload["refinerFallbackProfile"] === "string")
13110
- setAutonomy("refinerFallbackProfile", payload["refinerFallbackProfile"]);
13111
- if (typeof payload["thinkingWord"] === "string")
13112
- setAutonomy("thinkingWord", payload["thinkingWord"]);
13113
- if (typeof payload["statuslineMode"] === "string")
13114
- setAutonomy("statuslineMode", payload["statuslineMode"]);
13115
- if (typeof payload["animationStyle"] === "string")
13116
- setAutonomy("animationStyle", payload["animationStyle"]);
13117
- if (typeof payload["showModelReasoning"] === "boolean")
13118
- setAutonomy("showModelReasoning", payload["showModelReasoning"]);
13119
- if (autonomyTouched) decrypted.autonomy = autonomyCfg;
13120
- if (typeof payload["nextPrediction"] === "boolean")
13121
- decrypted.nextPrediction = payload["nextPrediction"];
13122
- if (typeof payload["uiLocale"] === "string") decrypted.uiLocale = payload["uiLocale"];
13123
- if (Array.isArray(payload["fallbackModels"]))
13124
- decrypted.fallbackModels = payload["fallbackModels"];
13125
- if (payload["fallbackProfiles"] && typeof payload["fallbackProfiles"] === "object" && !Array.isArray(payload["fallbackProfiles"])) {
13126
- decrypted.fallbackProfiles = payload["fallbackProfiles"];
13127
- }
13128
- if (Array.isArray(payload["favoriteModels"]))
13129
- decrypted.favoriteModels = payload["favoriteModels"];
13130
- if (typeof payload["favoriteModelsOnly"] === "boolean")
13131
- decrypted.favoriteModelsOnly = payload["favoriteModelsOnly"];
13132
- if (payload["modelMatrix"] && typeof payload["modelMatrix"] === "object" && !Array.isArray(payload["modelMatrix"])) {
13133
- decrypted.modelMatrix = payload["modelMatrix"];
13134
- }
13135
- if (typeof payload["fallbackAuto"] === "boolean")
13136
- decrypted.fallbackAuto = payload["fallbackAuto"];
13137
- const FEATURE_MAP = {
13138
- featureMcp: "mcp",
13139
- featurePlugins: "plugins",
13140
- featureMemory: "memory",
13141
- featureSkills: "skills",
13142
- featureModelsRegistry: "modelsRegistry"
13143
- };
13144
- for (const [prefKey, cfgKey] of Object.entries(FEATURE_MAP)) {
13145
- if (typeof payload[prefKey] === "boolean") {
13146
- const feats = decrypted.features ?? {};
13147
- feats[cfgKey] = payload[prefKey];
13148
- decrypted.features = feats;
13149
- }
13150
- }
13151
- if (typeof payload["contextAutoCompact"] === "boolean" || typeof payload["contextStrategy"] === "string" || typeof payload["contextMode"] === "string") {
13152
- const ctxCfg = decrypted.context ?? {};
13153
- if (typeof payload["contextAutoCompact"] === "boolean")
13154
- ctxCfg.autoCompact = payload["contextAutoCompact"];
13155
- if (typeof payload["contextStrategy"] === "string")
13156
- ctxCfg.strategy = payload["contextStrategy"];
13157
- if (typeof payload["contextMode"] === "string") ctxCfg.mode = payload["contextMode"];
13158
- decrypted.context = ctxCfg;
13159
- }
13160
- if (typeof payload["tokenSavingTier"] === "string") {
13161
- const featsCfg = decrypted.features ?? {};
13162
- featsCfg.tokenSavingMode = payload["tokenSavingTier"];
13163
- decrypted.features = featsCfg;
13164
- }
13165
- if (typeof payload["maxConcurrent"] === "number") {
13166
- decrypted.maxConcurrent = payload["maxConcurrent"];
13167
- }
13168
- if (typeof payload["titleAnimation"] === "boolean") {
13169
- const autoCfg = decrypted.autonomy ?? {};
13170
- autoCfg.terminalTitleAnimation = payload["titleAnimation"];
13171
- decrypted.autonomy = autoCfg;
13172
- }
13173
- if (typeof payload["logLevel"] === "string") {
13174
- const logCfg = decrypted.log ?? {};
13175
- logCfg.level = payload["logLevel"];
13176
- decrypted.log = logCfg;
13177
- }
13178
- if (typeof payload["auditLevel"] === "string") {
13179
- const sessionCfg = decrypted.session ?? {};
13180
- sessionCfg.auditLevel = payload["auditLevel"];
13181
- decrypted.session = sessionCfg;
13182
- }
13183
- if (typeof payload["indexOnStart"] === "boolean") {
13184
- const indexingCfg = decrypted.indexing ?? {};
13185
- indexingCfg.onSessionStart = payload["indexOnStart"];
13186
- decrypted.indexing = indexingCfg;
13187
- }
13188
- if (typeof payload["maxIterations"] === "number") {
13189
- const toolsCfg = decrypted.tools ?? {};
13190
- toolsCfg.maxIterations = payload["maxIterations"];
13191
- decrypted.tools = toolsCfg;
13192
- }
13193
- const hqTouched = typeof payload["hqEnabled"] === "boolean" || typeof payload["hqUrl"] === "string" || typeof payload["hqToken"] === "string" || typeof payload["hqRawContent"] === "boolean";
13194
- if (hqTouched) {
13195
- const hqCfg = decrypted.hq ?? {};
13196
- if (typeof payload["hqEnabled"] === "boolean") hqCfg.enabled = payload["hqEnabled"];
13197
- if (typeof payload["hqUrl"] === "string") hqCfg.url = payload["hqUrl"];
13198
- if (typeof payload["hqToken"] === "string") hqCfg.token = payload["hqToken"];
13199
- if (typeof payload["hqRawContent"] === "boolean")
13200
- hqCfg.rawContent = payload["hqRawContent"];
13201
- decrypted.hq = hqCfg;
13202
- }
13203
- const tgTouched = typeof payload["tgSessionEnd"] === "boolean" || typeof payload["tgDelegate"] === "boolean" || typeof payload["tgLongToolMs"] === "number";
13204
- if (tgTouched) {
13205
- const ext = decrypted.extensions ?? {};
13206
- const tg = ext["telegram"] ?? {};
13207
- if (typeof payload["tgSessionEnd"] === "boolean") {
13208
- tg["notifyOnSessionEnd"] = payload["tgSessionEnd"];
13209
- }
13210
- if (typeof payload["tgDelegate"] === "boolean") {
13211
- tg["notifyOnDelegate"] = payload["tgDelegate"];
13212
- }
13213
- if (typeof payload["tgLongToolMs"] === "number") {
13214
- tg["longToolThresholdMs"] = payload["tgLongToolMs"];
13215
- }
13216
- ext["telegram"] = tg;
13217
- decrypted.extensions = ext;
13218
- }
13219
- const modelRuntimeTouched = typeof payload["reasoningMode"] === "string" || typeof payload["reasoningEffort"] === "string" || typeof payload["reasoningPreserve"] === "boolean" || typeof payload["cacheTtl"] === "string";
13220
- if (modelRuntimeTouched) {
13221
- const mr = decrypted.modelRuntime ?? {};
13222
- const reasoning = mr.reasoning ?? {};
13223
- if (typeof payload["reasoningMode"] === "string") reasoning.mode = payload["reasoningMode"];
13224
- if (typeof payload["reasoningEffort"] === "string")
13225
- reasoning.effort = payload["reasoningEffort"];
13226
- if (typeof payload["reasoningPreserve"] === "boolean")
13227
- reasoning.preserve = payload["reasoningPreserve"];
13228
- mr.reasoning = reasoning;
13229
- if (typeof payload["cacheTtl"] === "string" && payload["cacheTtl"] !== "default") {
13230
- mr.cache = { ttl: payload["cacheTtl"] };
13231
- } else if (payload["cacheTtl"] === "default") {
13232
- delete mr.cache;
13233
- }
13234
- decrypted.modelRuntime = mr;
13235
- }
13236
- if (typeof payload["breakerEnabled"] === "boolean" || typeof payload["breakerAutoKillResetMs"] === "number") {
13237
- const cb = decrypted.circuitBreaker ?? {};
13238
- if (typeof payload["breakerEnabled"] === "boolean") cb.enabled = payload["breakerEnabled"];
13239
- if (typeof payload["breakerAutoKillResetMs"] === "number")
13240
- cb.autoKillResetMs = payload["breakerAutoKillResetMs"];
13241
- decrypted.circuitBreaker = cb;
13242
- }
13243
- if (payload["fsAccess"] === "unrestricted" || payload["fsAccess"] === "project") {
13244
- const restrict = payload["fsAccess"] === "project";
13245
- const toolsCfg = decrypted.tools ?? {};
13246
- toolsCfg.restrictToProjectRoot = restrict;
13247
- decrypted.tools = toolsCfg;
13248
- const featsCfg = decrypted.features ?? {};
13249
- featsCfg.allowOutsideProjectRoot = !restrict;
13250
- decrypted.features = featsCfg;
13251
- }
13252
- if (typeof payload["debugStream"] === "boolean")
13253
- decrypted.debugStream = payload["debugStream"];
13254
- if (typeof payload["pluginsEnabled"] === "object" && payload["pluginsEnabled"] !== null) {
13255
- const ext = decrypted.extensions ?? {};
13256
- for (const [pluginName, enabled] of Object.entries(
13257
- payload["pluginsEnabled"]
13258
- )) {
13259
- if (FORBIDDEN_PROTO_KEYS2.has(pluginName)) continue;
13260
- const pExt = ext[pluginName] ?? {};
13261
- pExt["enabled"] = enabled;
13262
- ext[pluginName] = pExt;
13263
- }
13264
- decrypted.extensions = ext;
13265
- }
13266
- const chimeraTouched = typeof payload["chimeraEnabled"] === "boolean" || typeof payload["chimeraProvider"] === "string" || typeof payload["chimeraModel"] === "string" || typeof payload["chimeraMaxFiles"] === "number" || typeof payload["chimeraAutoFix"] === "string";
13267
- if (chimeraTouched) {
13268
- const ext = decrypted.extensions ?? {};
13269
- const chimera = ext["wstack-chimera"] ?? {};
13270
- if (typeof payload["chimeraEnabled"] === "boolean")
13271
- chimera["enabled"] = payload["chimeraEnabled"];
13272
- if (typeof payload["chimeraProvider"] === "string")
13273
- chimera["provider"] = payload["chimeraProvider"];
13274
- if (typeof payload["chimeraModel"] === "string")
13275
- chimera["model"] = payload["chimeraModel"];
13276
- if (typeof payload["chimeraMaxFiles"] === "number" && payload["chimeraMaxFiles"] >= 1) {
13277
- chimera["maxFiles"] = payload["chimeraMaxFiles"];
13278
- }
13279
- if (typeof payload["chimeraAutoFix"] === "string") {
13280
- if (payload["chimeraAutoFix"] === "off" || payload["chimeraAutoFix"] === "ask" || payload["chimeraAutoFix"] === "auto") {
13281
- chimera["autoFix"] = payload["chimeraAutoFix"];
13282
- }
13283
- }
13284
- ext["wstack-chimera"] = chimera;
13285
- decrypted.extensions = ext;
13286
- }
13287
- const autoReviewTouched = typeof payload["autoReviewEnabled"] === "boolean" || typeof payload["autoReviewProvider"] === "string" || typeof payload["autoReviewModel"] === "string" || typeof payload["autoReviewFallbackProfile"] === "string" || Array.isArray(payload["autoReviewFallbackModels"]) || typeof payload["autoReviewDebounceMs"] === "number" || typeof payload["autoReviewMaxFilesPerBatch"] === "number" || typeof payload["autoReviewMaxConcurrentReviews"] === "number" || typeof payload["autoReviewCascadeOn"] === "string";
13288
- if (autoReviewTouched) {
13289
- const ext = decrypted.extensions ?? {};
13290
- const ar = ext["wstack-auto-review"] ?? {};
13291
- if (typeof payload["autoReviewEnabled"] === "boolean")
13292
- ar["enabled"] = payload["autoReviewEnabled"];
13293
- if (typeof payload["autoReviewProvider"] === "string")
13294
- ar["provider"] = payload["autoReviewProvider"];
13295
- if (typeof payload["autoReviewModel"] === "string")
13296
- ar["model"] = payload["autoReviewModel"];
13297
- if (typeof payload["autoReviewFallbackProfile"] === "string") {
13298
- if (payload["autoReviewFallbackProfile"] === "") {
13299
- delete ar["fallbackProfile"];
13300
- } else {
13301
- ar["fallbackProfile"] = payload["autoReviewFallbackProfile"];
13302
- }
13174
+ return updateGlobalConfig(
13175
+ deps2,
13176
+ holder,
13177
+ (decrypted) => {
13178
+ const autonomyCfg = decrypted.autonomy ?? {};
13179
+ let autonomyTouched = false;
13180
+ const setAutonomy = (key, val) => {
13181
+ autonomyCfg[key] = val;
13182
+ autonomyTouched = true;
13183
+ };
13184
+ if (typeof payload["autonomy"] === "string" && ["off", "suggest", "auto"].includes(payload["autonomy"])) {
13185
+ setAutonomy("defaultMode", payload["autonomy"]);
13303
13186
  }
13304
- if (typeof payload["autoReviewDebounceMs"] === "number" && payload["autoReviewDebounceMs"] >= 0) {
13305
- ar["debounceMs"] = payload["autoReviewDebounceMs"];
13187
+ if (typeof payload["autonomyDelayMs"] === "number")
13188
+ setAutonomy("autoProceedDelayMs", payload["autonomyDelayMs"]);
13189
+ if (typeof payload["autoProceedMaxIterations"] === "number")
13190
+ setAutonomy("autoProceedMaxIterations", payload["autoProceedMaxIterations"]);
13191
+ if (typeof payload["yolo"] === "boolean") {
13192
+ setAutonomy("yolo", payload["yolo"]);
13193
+ decrypted.yolo = payload["yolo"];
13194
+ }
13195
+ if (typeof payload["chime"] === "boolean") setAutonomy("chime", payload["chime"]);
13196
+ if (typeof payload["confirmExit"] === "boolean")
13197
+ setAutonomy("confirmExit", payload["confirmExit"]);
13198
+ if (typeof payload["streamFleet"] === "boolean")
13199
+ setAutonomy("streamFleet", payload["streamFleet"]);
13200
+ if (typeof payload["enhanceEnabled"] === "boolean")
13201
+ setAutonomy("enhance", payload["enhanceEnabled"]);
13202
+ if (typeof payload["enhanceDelayMs"] === "number")
13203
+ setAutonomy("enhanceDelayMs", payload["enhanceDelayMs"]);
13204
+ if (typeof payload["enhanceLanguage"] === "string")
13205
+ setAutonomy("enhanceLanguage", payload["enhanceLanguage"]);
13206
+ if (typeof payload["refinerProvider"] === "string")
13207
+ setAutonomy("refinerProvider", payload["refinerProvider"]);
13208
+ if (typeof payload["refinerModel"] === "string")
13209
+ setAutonomy("refinerModel", payload["refinerModel"]);
13210
+ if (typeof payload["refinerFallbackProfile"] === "string")
13211
+ setAutonomy("refinerFallbackProfile", payload["refinerFallbackProfile"]);
13212
+ if (typeof payload["thinkingWord"] === "string")
13213
+ setAutonomy("thinkingWord", payload["thinkingWord"]);
13214
+ if (typeof payload["statuslineMode"] === "string")
13215
+ setAutonomy("statuslineMode", payload["statuslineMode"]);
13216
+ if (typeof payload["animationStyle"] === "string")
13217
+ setAutonomy("animationStyle", payload["animationStyle"]);
13218
+ if (typeof payload["showModelReasoning"] === "boolean")
13219
+ setAutonomy("showModelReasoning", payload["showModelReasoning"]);
13220
+ if (autonomyTouched) decrypted.autonomy = autonomyCfg;
13221
+ if (typeof payload["nextPrediction"] === "boolean")
13222
+ decrypted.nextPrediction = payload["nextPrediction"];
13223
+ if (typeof payload["uiLocale"] === "string") decrypted.uiLocale = payload["uiLocale"];
13224
+ if (Array.isArray(payload["fallbackModels"]))
13225
+ decrypted.fallbackModels = payload["fallbackModels"];
13226
+ if (payload["fallbackProfiles"] && typeof payload["fallbackProfiles"] === "object" && !Array.isArray(payload["fallbackProfiles"])) {
13227
+ decrypted.fallbackProfiles = payload["fallbackProfiles"];
13306
13228
  }
13307
- if (typeof payload["autoReviewMaxFilesPerBatch"] === "number" && payload["autoReviewMaxFilesPerBatch"] >= 1) {
13308
- ar["maxFilesPerBatch"] = payload["autoReviewMaxFilesPerBatch"];
13229
+ if (Array.isArray(payload["favoriteModels"]))
13230
+ decrypted.favoriteModels = payload["favoriteModels"];
13231
+ if (typeof payload["favoriteModelsOnly"] === "boolean")
13232
+ decrypted.favoriteModelsOnly = payload["favoriteModelsOnly"];
13233
+ if (Array.isArray(payload["modelAvailabilitySchedule"]))
13234
+ decrypted.modelAvailabilitySchedule = payload["modelAvailabilitySchedule"];
13235
+ if (payload["modelMatrix"] && typeof payload["modelMatrix"] === "object" && !Array.isArray(payload["modelMatrix"])) {
13236
+ decrypted.modelMatrix = payload["modelMatrix"];
13237
+ }
13238
+ if (typeof payload["fallbackAuto"] === "boolean")
13239
+ decrypted.fallbackAuto = payload["fallbackAuto"];
13240
+ const FEATURE_MAP = {
13241
+ featureMcp: "mcp",
13242
+ featurePlugins: "plugins",
13243
+ featureMemory: "memory",
13244
+ featureSkills: "skills",
13245
+ featureModelsRegistry: "modelsRegistry"
13246
+ };
13247
+ for (const [prefKey, cfgKey] of Object.entries(FEATURE_MAP)) {
13248
+ if (typeof payload[prefKey] === "boolean") {
13249
+ const feats = decrypted.features ?? {};
13250
+ feats[cfgKey] = payload[prefKey];
13251
+ decrypted.features = feats;
13252
+ }
13253
+ }
13254
+ if (typeof payload["contextAutoCompact"] === "boolean" || typeof payload["contextStrategy"] === "string" || typeof payload["contextMode"] === "string") {
13255
+ const ctxCfg = decrypted.context ?? {};
13256
+ if (typeof payload["contextAutoCompact"] === "boolean")
13257
+ ctxCfg.autoCompact = payload["contextAutoCompact"];
13258
+ if (typeof payload["contextStrategy"] === "string")
13259
+ ctxCfg.strategy = payload["contextStrategy"];
13260
+ if (typeof payload["contextMode"] === "string") ctxCfg.mode = payload["contextMode"];
13261
+ decrypted.context = ctxCfg;
13262
+ }
13263
+ if (typeof payload["tokenSavingTier"] === "string") {
13264
+ const featsCfg = decrypted.features ?? {};
13265
+ featsCfg.tokenSavingMode = payload["tokenSavingTier"];
13266
+ decrypted.features = featsCfg;
13267
+ }
13268
+ if (typeof payload["maxConcurrent"] === "number") {
13269
+ decrypted.maxConcurrent = payload["maxConcurrent"];
13270
+ }
13271
+ if (typeof payload["titleAnimation"] === "boolean") {
13272
+ const autoCfg = decrypted.autonomy ?? {};
13273
+ autoCfg.terminalTitleAnimation = payload["titleAnimation"];
13274
+ decrypted.autonomy = autoCfg;
13309
13275
  }
13310
- if (typeof payload["autoReviewMaxConcurrentReviews"] === "number" && payload["autoReviewMaxConcurrentReviews"] >= 1) {
13311
- ar["maxConcurrentReviews"] = payload["autoReviewMaxConcurrentReviews"];
13276
+ if (typeof payload["logLevel"] === "string") {
13277
+ const logCfg = decrypted.log ?? {};
13278
+ logCfg.level = payload["logLevel"];
13279
+ decrypted.log = logCfg;
13280
+ }
13281
+ if (typeof payload["auditLevel"] === "string") {
13282
+ const sessionCfg = decrypted.session ?? {};
13283
+ sessionCfg.auditLevel = payload["auditLevel"];
13284
+ decrypted.session = sessionCfg;
13285
+ }
13286
+ if (typeof payload["indexOnStart"] === "boolean") {
13287
+ const indexingCfg = decrypted.indexing ?? {};
13288
+ indexingCfg.onSessionStart = payload["indexOnStart"];
13289
+ decrypted.indexing = indexingCfg;
13290
+ }
13291
+ if (typeof payload["maxIterations"] === "number") {
13292
+ const toolsCfg = decrypted.tools ?? {};
13293
+ toolsCfg.maxIterations = payload["maxIterations"];
13294
+ decrypted.tools = toolsCfg;
13295
+ }
13296
+ const hqTouched = typeof payload["hqEnabled"] === "boolean" || typeof payload["hqUrl"] === "string" || typeof payload["hqToken"] === "string" || typeof payload["hqRawContent"] === "boolean";
13297
+ if (hqTouched) {
13298
+ const hqCfg = decrypted.hq ?? {};
13299
+ if (typeof payload["hqEnabled"] === "boolean") hqCfg.enabled = payload["hqEnabled"];
13300
+ if (typeof payload["hqUrl"] === "string") hqCfg.url = payload["hqUrl"];
13301
+ if (typeof payload["hqToken"] === "string") hqCfg.token = payload["hqToken"];
13302
+ if (typeof payload["hqRawContent"] === "boolean")
13303
+ hqCfg.rawContent = payload["hqRawContent"];
13304
+ decrypted.hq = hqCfg;
13305
+ }
13306
+ const tgTouched = typeof payload["tgSessionEnd"] === "boolean" || typeof payload["tgDelegate"] === "boolean" || typeof payload["tgLongToolMs"] === "number";
13307
+ if (tgTouched) {
13308
+ const ext = decrypted.extensions ?? {};
13309
+ const tg = ext["telegram"] ?? {};
13310
+ if (typeof payload["tgSessionEnd"] === "boolean") {
13311
+ tg["notifyOnSessionEnd"] = payload["tgSessionEnd"];
13312
+ }
13313
+ if (typeof payload["tgDelegate"] === "boolean") {
13314
+ tg["notifyOnDelegate"] = payload["tgDelegate"];
13315
+ }
13316
+ if (typeof payload["tgLongToolMs"] === "number") {
13317
+ tg["longToolThresholdMs"] = payload["tgLongToolMs"];
13318
+ }
13319
+ ext["telegram"] = tg;
13320
+ decrypted.extensions = ext;
13321
+ }
13322
+ const modelRuntimeTouched = typeof payload["reasoningMode"] === "string" || typeof payload["reasoningEffort"] === "string" || typeof payload["reasoningPreserve"] === "boolean" || typeof payload["cacheTtl"] === "string";
13323
+ if (modelRuntimeTouched) {
13324
+ const mr = decrypted.modelRuntime ?? {};
13325
+ const reasoning = mr.reasoning ?? {};
13326
+ if (typeof payload["reasoningMode"] === "string") reasoning.mode = payload["reasoningMode"];
13327
+ if (typeof payload["reasoningEffort"] === "string")
13328
+ reasoning.effort = payload["reasoningEffort"];
13329
+ if (typeof payload["reasoningPreserve"] === "boolean")
13330
+ reasoning.preserve = payload["reasoningPreserve"];
13331
+ mr.reasoning = reasoning;
13332
+ if (typeof payload["cacheTtl"] === "string" && payload["cacheTtl"] !== "default") {
13333
+ mr.cache = { ttl: payload["cacheTtl"] };
13334
+ } else if (payload["cacheTtl"] === "default") {
13335
+ delete mr.cache;
13336
+ }
13337
+ decrypted.modelRuntime = mr;
13312
13338
  }
13313
- if (typeof payload["autoReviewCascadeOn"] === "string") {
13314
- if (payload["autoReviewCascadeOn"] === "off" || payload["autoReviewCascadeOn"] === "critical" || payload["autoReviewCascadeOn"] === "high") {
13315
- ar["cascadeOn"] = payload["autoReviewCascadeOn"];
13339
+ if (typeof payload["breakerEnabled"] === "boolean" || typeof payload["breakerAutoKillResetMs"] === "number") {
13340
+ const cb = decrypted.circuitBreaker ?? {};
13341
+ if (typeof payload["breakerEnabled"] === "boolean") cb.enabled = payload["breakerEnabled"];
13342
+ if (typeof payload["breakerAutoKillResetMs"] === "number")
13343
+ cb.autoKillResetMs = payload["breakerAutoKillResetMs"];
13344
+ decrypted.circuitBreaker = cb;
13345
+ }
13346
+ if (payload["fsAccess"] === "unrestricted" || payload["fsAccess"] === "project") {
13347
+ const restrict = payload["fsAccess"] === "project";
13348
+ const toolsCfg = decrypted.tools ?? {};
13349
+ toolsCfg.restrictToProjectRoot = restrict;
13350
+ decrypted.tools = toolsCfg;
13351
+ const featsCfg = decrypted.features ?? {};
13352
+ featsCfg.allowOutsideProjectRoot = !restrict;
13353
+ decrypted.features = featsCfg;
13354
+ }
13355
+ if (typeof payload["debugStream"] === "boolean")
13356
+ decrypted.debugStream = payload["debugStream"];
13357
+ if (typeof payload["pluginsEnabled"] === "object" && payload["pluginsEnabled"] !== null) {
13358
+ const ext = decrypted.extensions ?? {};
13359
+ for (const [pluginName, enabled] of Object.entries(
13360
+ payload["pluginsEnabled"]
13361
+ )) {
13362
+ if (FORBIDDEN_PROTO_KEYS2.has(pluginName)) continue;
13363
+ const pExt = ext[pluginName] ?? {};
13364
+ pExt["enabled"] = enabled;
13365
+ ext[pluginName] = pExt;
13366
+ }
13367
+ decrypted.extensions = ext;
13368
+ }
13369
+ const chimeraTouched = typeof payload["chimeraEnabled"] === "boolean" || typeof payload["chimeraProvider"] === "string" || typeof payload["chimeraModel"] === "string" || typeof payload["chimeraMaxFiles"] === "number" || typeof payload["chimeraAutoFix"] === "string";
13370
+ if (chimeraTouched) {
13371
+ const ext = decrypted.extensions ?? {};
13372
+ const chimera = ext["wstack-chimera"] ?? {};
13373
+ if (typeof payload["chimeraEnabled"] === "boolean")
13374
+ chimera["enabled"] = payload["chimeraEnabled"];
13375
+ if (typeof payload["chimeraProvider"] === "string")
13376
+ chimera["provider"] = payload["chimeraProvider"];
13377
+ if (typeof payload["chimeraModel"] === "string") chimera["model"] = payload["chimeraModel"];
13378
+ if (typeof payload["chimeraMaxFiles"] === "number" && payload["chimeraMaxFiles"] >= 1) {
13379
+ chimera["maxFiles"] = payload["chimeraMaxFiles"];
13380
+ }
13381
+ if (typeof payload["chimeraAutoFix"] === "string") {
13382
+ if (payload["chimeraAutoFix"] === "off" || payload["chimeraAutoFix"] === "ask" || payload["chimeraAutoFix"] === "auto") {
13383
+ chimera["autoFix"] = payload["chimeraAutoFix"];
13384
+ }
13385
+ }
13386
+ ext["wstack-chimera"] = chimera;
13387
+ decrypted.extensions = ext;
13388
+ }
13389
+ const autoReviewTouched = typeof payload["autoReviewEnabled"] === "boolean" || typeof payload["autoReviewProvider"] === "string" || typeof payload["autoReviewModel"] === "string" || typeof payload["autoReviewFallbackProfile"] === "string" || Array.isArray(payload["autoReviewFallbackModels"]) || typeof payload["autoReviewDebounceMs"] === "number" || typeof payload["autoReviewMaxFilesPerBatch"] === "number" || typeof payload["autoReviewMaxConcurrentReviews"] === "number" || typeof payload["autoReviewCascadeOn"] === "string";
13390
+ if (autoReviewTouched) {
13391
+ const ext = decrypted.extensions ?? {};
13392
+ const ar = ext["wstack-auto-review"] ?? {};
13393
+ if (typeof payload["autoReviewEnabled"] === "boolean")
13394
+ ar["enabled"] = payload["autoReviewEnabled"];
13395
+ if (typeof payload["autoReviewProvider"] === "string")
13396
+ ar["provider"] = payload["autoReviewProvider"];
13397
+ if (typeof payload["autoReviewModel"] === "string")
13398
+ ar["model"] = payload["autoReviewModel"];
13399
+ if (typeof payload["autoReviewFallbackProfile"] === "string") {
13400
+ if (payload["autoReviewFallbackProfile"] === "") {
13401
+ delete ar["fallbackProfile"];
13402
+ } else {
13403
+ ar["fallbackProfile"] = payload["autoReviewFallbackProfile"];
13404
+ }
13405
+ }
13406
+ if (typeof payload["autoReviewDebounceMs"] === "number" && payload["autoReviewDebounceMs"] >= 0) {
13407
+ ar["debounceMs"] = payload["autoReviewDebounceMs"];
13408
+ }
13409
+ if (typeof payload["autoReviewMaxFilesPerBatch"] === "number" && payload["autoReviewMaxFilesPerBatch"] >= 1) {
13410
+ ar["maxFilesPerBatch"] = payload["autoReviewMaxFilesPerBatch"];
13411
+ }
13412
+ if (typeof payload["autoReviewMaxConcurrentReviews"] === "number" && payload["autoReviewMaxConcurrentReviews"] >= 1) {
13413
+ ar["maxConcurrentReviews"] = payload["autoReviewMaxConcurrentReviews"];
13414
+ }
13415
+ if (typeof payload["autoReviewCascadeOn"] === "string") {
13416
+ if (payload["autoReviewCascadeOn"] === "off" || payload["autoReviewCascadeOn"] === "critical" || payload["autoReviewCascadeOn"] === "high") {
13417
+ ar["cascadeOn"] = payload["autoReviewCascadeOn"];
13418
+ }
13316
13419
  }
13420
+ ext["wstack-auto-review"] = ar;
13421
+ decrypted.extensions = ext;
13317
13422
  }
13318
- ext["wstack-auto-review"] = ar;
13319
- decrypted.extensions = ext;
13320
- }
13321
- }, "prefs");
13423
+ },
13424
+ "prefs"
13425
+ );
13322
13426
  }
13323
13427
 
13324
13428
  // src/server/provider-handlers.ts
@@ -13656,6 +13760,7 @@ import {
13656
13760
  gatedEnhancerReasoning,
13657
13761
  nextEnhanceTimeout,
13658
13762
  recentTextTurns,
13763
+ resolveConfiguredRefinerRef,
13659
13764
  resolveEnhanceFallbackRef,
13660
13765
  resolveProviderModelList
13661
13766
  } from "@wrongstack/core";
@@ -14518,6 +14623,26 @@ function buildRoutes(state, deps2, cb) {
14518
14623
  });
14519
14624
  return;
14520
14625
  }
14626
+ } else {
14627
+ const configuredRef = resolveConfiguredRefinerRef({
14628
+ ...cfg,
14629
+ provider: providerId,
14630
+ model
14631
+ });
14632
+ if (configuredRef) {
14633
+ const slash = configuredRef.indexOf("/");
14634
+ const configuredProvider = slash > 0 ? configuredRef.slice(0, slash) : providerId;
14635
+ const configuredModel = slash > 0 ? configuredRef.slice(slash + 1) : configuredRef;
14636
+ try {
14637
+ const providerCfg = cfg.providers?.[configuredProvider] ?? {
14638
+ type: configuredProvider
14639
+ };
14640
+ provider = deps2.providerRegistry.has(configuredProvider) ? deps2.providerRegistry.create({ ...providerCfg, type: configuredProvider }) : makeProviderFromConfig2(configuredProvider, providerCfg);
14641
+ providerId = configuredProvider;
14642
+ model = configuredModel;
14643
+ } catch {
14644
+ }
14645
+ }
14521
14646
  }
14522
14647
  const baseTimeout = 9e4;
14523
14648
  const timeoutMs = typeof payload.timeoutMs === "number" && payload.timeoutMs > 0 ? payload.timeoutMs : baseTimeout;
@@ -14704,19 +14829,27 @@ function buildRoutes(state, deps2, cb) {
14704
14829
  cfg.favoriteModels = payload["favoriteModels"];
14705
14830
  if (typeof payload["favoriteModelsOnly"] === "boolean")
14706
14831
  cfg.favoriteModelsOnly = payload["favoriteModelsOnly"];
14832
+ if (Array.isArray(payload["modelAvailabilitySchedule"]))
14833
+ cfg.modelAvailabilitySchedule = payload["modelAvailabilitySchedule"];
14707
14834
  if (payload["modelMatrix"] && typeof payload["modelMatrix"] === "object" && !Array.isArray(payload["modelMatrix"])) {
14708
14835
  cfg.modelMatrix = payload["modelMatrix"];
14709
14836
  }
14710
14837
  if (typeof payload["fallbackAuto"] === "boolean") cfg.fallbackAuto = payload["fallbackAuto"];
14711
14838
  const routingPatch = {};
14712
- if (Array.isArray(payload["fallbackModels"])) routingPatch.fallbackModels = payload["fallbackModels"];
14839
+ if (Array.isArray(payload["fallbackModels"]))
14840
+ routingPatch.fallbackModels = payload["fallbackModels"];
14713
14841
  if (payload["fallbackProfiles"] && typeof payload["fallbackProfiles"] === "object" && !Array.isArray(payload["fallbackProfiles"]))
14714
14842
  routingPatch.fallbackProfiles = payload["fallbackProfiles"];
14715
- if (Array.isArray(payload["favoriteModels"])) routingPatch.favoriteModels = payload["favoriteModels"];
14716
- if (typeof payload["favoriteModelsOnly"] === "boolean") routingPatch.favoriteModelsOnly = payload["favoriteModelsOnly"];
14843
+ if (Array.isArray(payload["favoriteModels"]))
14844
+ routingPatch.favoriteModels = payload["favoriteModels"];
14845
+ if (typeof payload["favoriteModelsOnly"] === "boolean")
14846
+ routingPatch.favoriteModelsOnly = payload["favoriteModelsOnly"];
14847
+ if (Array.isArray(payload["modelAvailabilitySchedule"]))
14848
+ routingPatch.modelAvailabilitySchedule = payload["modelAvailabilitySchedule"];
14717
14849
  if (payload["modelMatrix"] && typeof payload["modelMatrix"] === "object" && !Array.isArray(payload["modelMatrix"]))
14718
14850
  routingPatch.modelMatrix = payload["modelMatrix"];
14719
- if (typeof payload["fallbackAuto"] === "boolean") routingPatch.fallbackAuto = payload["fallbackAuto"];
14851
+ if (typeof payload["fallbackAuto"] === "boolean")
14852
+ routingPatch.fallbackAuto = payload["fallbackAuto"];
14720
14853
  if (Object.keys(routingPatch).length > 0)
14721
14854
  deps2.configStore.update(routingPatch);
14722
14855
  if (typeof payload["contextAutoCompact"] === "boolean") {