evil-omo 3.11.7 → 3.12.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.
@@ -1,6 +1,8 @@
1
1
  type BunInstallOutputMode = "inherit" | "pipe";
2
2
  interface RunBunInstallOptions {
3
3
  outputMode?: BunInstallOutputMode;
4
+ /** Workspace directory to install to. Defaults to cache dir if not provided. */
5
+ workspaceDir?: string;
4
6
  }
5
7
  export interface BunInstallResult {
6
8
  success: boolean;
package/dist/cli/index.js CHANGED
@@ -5837,10 +5837,10 @@ function detectManagedConfigFile(directory) {
5837
5837
  baseName: CONFIG_BASENAME
5838
5838
  };
5839
5839
  }
5840
- var PLUGIN_NAME = "evil-omo", ALL_PLUGIN_NAMES, CONFIG_BASENAME = "evil-omo", ALL_CONFIG_BASENAMES, LOG_FILENAME = "evil-omo.log", CACHE_DIR_NAME = "evil-omo", SCHEMA_FILENAME = "evil-omo.schema.json";
5840
+ var PLUGIN_NAME = "evil-omo", LEGACY_PLUGIN_NAME = "oh-my-opencode", ALL_PLUGIN_NAMES, CONFIG_BASENAME = "evil-omo", ALL_CONFIG_BASENAMES, LOG_FILENAME = "evil-omo.log", CACHE_DIR_NAME = "evil-omo", SCHEMA_FILENAME = "evil-omo.schema.json";
5841
5841
  var init_plugin_identity = __esm(() => {
5842
5842
  init_jsonc_parser();
5843
- ALL_PLUGIN_NAMES = [PLUGIN_NAME];
5843
+ ALL_PLUGIN_NAMES = [PLUGIN_NAME, LEGACY_PLUGIN_NAME];
5844
5844
  ALL_CONFIG_BASENAMES = [CONFIG_BASENAME];
5845
5845
  });
5846
5846
 
@@ -7894,7 +7894,7 @@ function logCapturedOutputOnFailure(outputMode, output) {
7894
7894
  }
7895
7895
  async function runBunInstallWithDetails(options) {
7896
7896
  const outputMode = options?.outputMode ?? "pipe";
7897
- const cacheDir = getOpenCodeCacheDir();
7897
+ const cacheDir = options?.workspaceDir ?? getOpenCodeCacheDir();
7898
7898
  const packageJsonPath = `${cacheDir}/package.json`;
7899
7899
  if (!existsSync9(packageJsonPath)) {
7900
7900
  return {
@@ -8568,12 +8568,30 @@ var init_update_toasts = __esm(() => {
8568
8568
  });
8569
8569
 
8570
8570
  // src/hooks/auto-update-checker/hook/background-update-check.ts
8571
+ import { existsSync as existsSync20 } from "fs";
8572
+ import { join as join18 } from "path";
8571
8573
  function getPinnedVersionToastMessage(latestVersion) {
8572
8574
  return `Update available: ${latestVersion} (version pinned, update manually)`;
8573
8575
  }
8574
- async function runBunInstallSafe() {
8576
+ function resolveActiveInstallWorkspace() {
8577
+ const configPaths = getOpenCodeConfigPaths({ binary: "opencode" });
8578
+ const cacheDir = getOpenCodeCacheDir();
8579
+ const configInstallPath = join18(configPaths.configDir, "node_modules", PACKAGE_NAME2, "package.json");
8580
+ const cacheInstallPath = join18(cacheDir, "node_modules", PACKAGE_NAME2, "package.json");
8581
+ if (existsSync20(configInstallPath)) {
8582
+ log(`[auto-update-checker] Active workspace: config-dir (${configPaths.configDir})`);
8583
+ return configPaths.configDir;
8584
+ }
8585
+ if (existsSync20(cacheInstallPath)) {
8586
+ log(`[auto-update-checker] Active workspace: cache-dir (${cacheDir})`);
8587
+ return cacheDir;
8588
+ }
8589
+ log(`[auto-update-checker] Active workspace: config-dir (default, no install detected)`);
8590
+ return configPaths.configDir;
8591
+ }
8592
+ async function runBunInstallSafe(workspaceDir) {
8575
8593
  try {
8576
- const result = await runBunInstallWithDetails({ outputMode: "pipe" });
8594
+ const result = await runBunInstallWithDetails({ outputMode: "pipe", workspaceDir });
8577
8595
  if (!result.success && result.error) {
8578
8596
  log("[auto-update-checker] bun install error:", result.error);
8579
8597
  }
@@ -8624,7 +8642,8 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
8624
8642
  return;
8625
8643
  }
8626
8644
  invalidatePackage(PACKAGE_NAME2);
8627
- const installSuccess = await runBunInstallSafe();
8645
+ const activeWorkspace = resolveActiveInstallWorkspace();
8646
+ const installSuccess = await runBunInstallSafe(activeWorkspace);
8628
8647
  if (installSuccess) {
8629
8648
  await showAutoUpdatedToast(ctx, currentVersion, latestVersion);
8630
8649
  log(`[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`);
@@ -8636,6 +8655,7 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
8636
8655
  var init_background_update_check = __esm(() => {
8637
8656
  init_config_manager();
8638
8657
  init_logger();
8658
+ init_shared();
8639
8659
  init_cache();
8640
8660
  init_constants3();
8641
8661
  init_checker();
@@ -8865,7 +8885,7 @@ var {
8865
8885
  // package.json
8866
8886
  var package_default = {
8867
8887
  name: "evil-omo",
8868
- version: "3.11.7",
8888
+ version: "3.12.0",
8869
8889
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8870
8890
  main: "dist/index.js",
8871
8891
  types: "dist/index.d.ts",
@@ -8941,17 +8961,17 @@ var package_default = {
8941
8961
  typescript: "^5.7.3"
8942
8962
  },
8943
8963
  optionalDependencies: {
8944
- "evil-omo-darwin-arm64": "3.11.7",
8945
- "evil-omo-darwin-x64": "3.11.7",
8946
- "evil-omo-darwin-x64-baseline": "3.11.7",
8947
- "evil-omo-linux-x64": "3.11.7",
8948
- "evil-omo-linux-x64-baseline": "3.11.7",
8949
- "evil-omo-linux-arm64": "3.11.7",
8950
- "evil-omo-linux-x64-musl": "3.11.7",
8951
- "evil-omo-linux-x64-musl-baseline": "3.11.7",
8952
- "evil-omo-linux-arm64-musl": "3.11.7",
8953
- "evil-omo-windows-x64": "3.11.7",
8954
- "evil-omo-windows-x64-baseline": "3.11.7"
8964
+ "evil-omo-darwin-arm64": "3.12.0",
8965
+ "evil-omo-darwin-x64": "3.12.0",
8966
+ "evil-omo-darwin-x64-baseline": "3.12.0",
8967
+ "evil-omo-linux-x64": "3.12.0",
8968
+ "evil-omo-linux-x64-baseline": "3.12.0",
8969
+ "evil-omo-linux-arm64": "3.12.0",
8970
+ "evil-omo-linux-x64-musl": "3.12.0",
8971
+ "evil-omo-linux-x64-musl-baseline": "3.12.0",
8972
+ "evil-omo-linux-arm64-musl": "3.12.0",
8973
+ "evil-omo-windows-x64": "3.12.0",
8974
+ "evil-omo-windows-x64-baseline": "3.12.0"
8955
8975
  },
8956
8976
  overrides: {
8957
8977
  "@opencode-ai/sdk": "^1.2.24"
@@ -24329,6 +24349,11 @@ var BabysittingConfigSchema = exports_external.object({
24329
24349
  timeout_ms: exports_external.number().default(120000)
24330
24350
  });
24331
24351
  // src/config/schema/background-task.ts
24352
+ var CircuitBreakerConfigSchema = exports_external.object({
24353
+ maxToolCalls: exports_external.number().int().min(10).optional(),
24354
+ windowSize: exports_external.number().int().min(5).optional(),
24355
+ repetitionThresholdPercent: exports_external.number().gt(0).max(100).optional()
24356
+ });
24332
24357
  var BackgroundTaskConfigSchema = exports_external.object({
24333
24358
  defaultConcurrency: exports_external.number().min(1).optional(),
24334
24359
  providerConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(0)).optional(),
@@ -24337,7 +24362,9 @@ var BackgroundTaskConfigSchema = exports_external.object({
24337
24362
  maxDescendants: exports_external.number().int().min(1).optional(),
24338
24363
  staleTimeoutMs: exports_external.number().min(60000).optional(),
24339
24364
  messageStalenessTimeoutMs: exports_external.number().min(60000).optional(),
24340
- syncPollTimeoutMs: exports_external.number().min(60000).optional()
24365
+ syncPollTimeoutMs: exports_external.number().min(60000).optional(),
24366
+ maxToolCalls: exports_external.number().int().min(10).optional(),
24367
+ circuitBreaker: CircuitBreakerConfigSchema.optional()
24341
24368
  });
24342
24369
  // src/config/schema/browser-automation.ts
24343
24370
  var BrowserAutomationProviderSchema = exports_external.enum([
@@ -27154,9 +27181,9 @@ async function run(options) {
27154
27181
  timestampOutput?.enable();
27155
27182
  const pluginConfig = loadPluginConfig(directory, { command: "run" });
27156
27183
  const resolvedAgent = resolveRunAgent(options, pluginConfig);
27157
- const resolvedModel = resolveRunModel(options.model);
27158
27184
  const abortController = new AbortController;
27159
27185
  try {
27186
+ const resolvedModel = resolveRunModel(options.model);
27160
27187
  const { client: client3, cleanup: serverCleanup } = await createServerConnection({
27161
27188
  port: options.port,
27162
27189
  attach: options.attach,
@@ -27439,30 +27466,30 @@ var PACKAGE_NAME3 = PLUGIN_NAME;
27439
27466
  var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
27440
27467
 
27441
27468
  // src/cli/doctor/checks/system.ts
27442
- import { existsSync as existsSync23, readFileSync as readFileSync21 } from "fs";
27469
+ import { existsSync as existsSync24, readFileSync as readFileSync21 } from "fs";
27443
27470
 
27444
27471
  // src/cli/doctor/checks/system-binary.ts
27445
27472
  init_spawn_with_windows_hide();
27446
- import { existsSync as existsSync20 } from "fs";
27473
+ import { existsSync as existsSync21 } from "fs";
27447
27474
  import { homedir as homedir5 } from "os";
27448
- import { join as join18 } from "path";
27475
+ import { join as join19 } from "path";
27449
27476
  function getDesktopAppPaths(platform) {
27450
27477
  const home = homedir5();
27451
27478
  switch (platform) {
27452
27479
  case "darwin":
27453
27480
  return [
27454
27481
  "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
27455
- join18(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
27482
+ join19(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
27456
27483
  ];
27457
27484
  case "win32": {
27458
27485
  const programFiles = process.env.ProgramFiles;
27459
27486
  const localAppData = process.env.LOCALAPPDATA;
27460
27487
  const paths = [];
27461
27488
  if (programFiles) {
27462
- paths.push(join18(programFiles, "OpenCode", "OpenCode.exe"));
27489
+ paths.push(join19(programFiles, "OpenCode", "OpenCode.exe"));
27463
27490
  }
27464
27491
  if (localAppData) {
27465
- paths.push(join18(localAppData, "OpenCode", "OpenCode.exe"));
27492
+ paths.push(join19(localAppData, "OpenCode", "OpenCode.exe"));
27466
27493
  }
27467
27494
  return paths;
27468
27495
  }
@@ -27470,8 +27497,8 @@ function getDesktopAppPaths(platform) {
27470
27497
  return [
27471
27498
  "/usr/bin/opencode",
27472
27499
  "/usr/lib/opencode/opencode",
27473
- join18(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
27474
- join18(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
27500
+ join19(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
27501
+ join19(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
27475
27502
  ];
27476
27503
  default:
27477
27504
  return [];
@@ -27483,7 +27510,7 @@ function buildVersionCommand(binaryPath, platform) {
27483
27510
  }
27484
27511
  return [binaryPath, "--version"];
27485
27512
  }
27486
- function findDesktopBinary(platform = process.platform, checkExists = existsSync20) {
27513
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync21) {
27487
27514
  for (const desktopPath of getDesktopAppPaths(platform)) {
27488
27515
  if (checkExists(desktopPath)) {
27489
27516
  return { binary: "opencode", path: desktopPath };
@@ -27530,30 +27557,40 @@ function compareVersions(current, minimum) {
27530
27557
  }
27531
27558
 
27532
27559
  // src/cli/doctor/checks/system-plugin.ts
27533
- import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
27534
27560
  init_shared();
27561
+ import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
27535
27562
  function detectConfigPath() {
27536
27563
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
27537
- if (existsSync21(paths.configJsonc))
27564
+ if (existsSync22(paths.configJsonc))
27538
27565
  return paths.configJsonc;
27539
- if (existsSync21(paths.configJson))
27566
+ if (existsSync22(paths.configJson))
27540
27567
  return paths.configJson;
27541
27568
  return null;
27542
27569
  }
27543
27570
  function parsePluginVersion(entry) {
27544
- if (!entry.startsWith(`${PACKAGE_NAME3}@`))
27545
- return null;
27546
- const value = entry.slice(PACKAGE_NAME3.length + 1);
27547
- if (!value || value === "latest")
27548
- return null;
27549
- return value;
27571
+ if (entry.startsWith(`${PLUGIN_NAME}@`)) {
27572
+ const value = entry.slice(PLUGIN_NAME.length + 1);
27573
+ if (!value || value === "latest")
27574
+ return null;
27575
+ return value;
27576
+ }
27577
+ if (entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) {
27578
+ const value = entry.slice(LEGACY_PLUGIN_NAME.length + 1);
27579
+ if (!value || value === "latest")
27580
+ return null;
27581
+ return value;
27582
+ }
27583
+ return null;
27550
27584
  }
27551
27585
  function findPluginEntry2(entries) {
27552
27586
  for (const entry of entries) {
27553
- if (entry === PACKAGE_NAME3 || entry.startsWith(`${PACKAGE_NAME3}@`)) {
27587
+ if (entry === PLUGIN_NAME || entry.startsWith(`${PLUGIN_NAME}@`)) {
27554
27588
  return { entry, isLocalDev: false };
27555
27589
  }
27556
- if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME3)) {
27590
+ if (entry === LEGACY_PLUGIN_NAME || entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) {
27591
+ return { entry, isLocalDev: false };
27592
+ }
27593
+ if (entry.startsWith("file://") && (entry.includes(PLUGIN_NAME) || entry.includes(LEGACY_PLUGIN_NAME))) {
27557
27594
  return { entry, isLocalDev: true };
27558
27595
  }
27559
27596
  }
@@ -27590,7 +27627,7 @@ function getPluginInfo() {
27590
27627
  registered: true,
27591
27628
  configPath,
27592
27629
  entry: pluginEntry.entry,
27593
- isPinned: pinnedVersion !== null && /^\d+\.\d+\.\d+/.test(pinnedVersion),
27630
+ isPinned: pinnedVersion !== null && /^\d+\.\d+\.\d+/.test(pinnedVersion ?? ""),
27594
27631
  pinnedVersion,
27595
27632
  isLocalDev: pluginEntry.isLocalDev
27596
27633
  };
@@ -27609,29 +27646,29 @@ function getPluginInfo() {
27609
27646
  // src/cli/doctor/checks/system-loaded-version.ts
27610
27647
  init_checker();
27611
27648
  init_auto_update_checker();
27612
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
27649
+ import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
27613
27650
  import { homedir as homedir6 } from "os";
27614
- import { join as join19 } from "path";
27651
+ import { join as join20 } from "path";
27615
27652
  init_shared();
27616
27653
  function getPlatformDefaultCacheDir(platform = process.platform) {
27617
27654
  if (platform === "darwin")
27618
- return join19(homedir6(), "Library", "Caches");
27655
+ return join20(homedir6(), "Library", "Caches");
27619
27656
  if (platform === "win32")
27620
- return process.env.LOCALAPPDATA ?? join19(homedir6(), "AppData", "Local");
27621
- return join19(homedir6(), ".cache");
27657
+ return process.env.LOCALAPPDATA ?? join20(homedir6(), "AppData", "Local");
27658
+ return join20(homedir6(), ".cache");
27622
27659
  }
27623
27660
  function resolveOpenCodeCacheDir() {
27624
27661
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
27625
27662
  if (xdgCacheHome)
27626
- return join19(xdgCacheHome, "opencode");
27663
+ return join20(xdgCacheHome, "opencode");
27627
27664
  const fromShared = getOpenCodeCacheDir();
27628
- const platformDefault = join19(getPlatformDefaultCacheDir(), "opencode");
27629
- if (existsSync22(fromShared) || !existsSync22(platformDefault))
27665
+ const platformDefault = join20(getPlatformDefaultCacheDir(), "opencode");
27666
+ if (existsSync23(fromShared) || !existsSync23(platformDefault))
27630
27667
  return fromShared;
27631
27668
  return platformDefault;
27632
27669
  }
27633
27670
  function readPackageJson(filePath) {
27634
- if (!existsSync22(filePath))
27671
+ if (!existsSync23(filePath))
27635
27672
  return null;
27636
27673
  try {
27637
27674
  const content = readFileSync20(filePath, "utf-8");
@@ -27653,15 +27690,15 @@ function getLoadedPluginVersion() {
27653
27690
  {
27654
27691
  cacheDir: configPaths.configDir,
27655
27692
  cachePackagePath: configPaths.packageJson,
27656
- installedPackagePath: join19(configPaths.configDir, "node_modules", PACKAGE_NAME3, "package.json")
27693
+ installedPackagePath: join20(configPaths.configDir, "node_modules", PACKAGE_NAME3, "package.json")
27657
27694
  },
27658
27695
  {
27659
27696
  cacheDir,
27660
- cachePackagePath: join19(cacheDir, "package.json"),
27661
- installedPackagePath: join19(cacheDir, "node_modules", PACKAGE_NAME3, "package.json")
27697
+ cachePackagePath: join20(cacheDir, "package.json"),
27698
+ installedPackagePath: join20(cacheDir, "node_modules", PACKAGE_NAME3, "package.json")
27662
27699
  }
27663
27700
  ];
27664
- const selectedCandidate = candidates.find((candidate) => existsSync22(candidate.installedPackagePath)) ?? candidates[0];
27701
+ const selectedCandidate = candidates.find((candidate) => existsSync23(candidate.installedPackagePath)) ?? candidates[0];
27665
27702
  const { cacheDir: selectedDir, cachePackagePath, installedPackagePath } = selectedCandidate;
27666
27703
  const cachePackage = readPackageJson(cachePackagePath);
27667
27704
  const installedPackage = readPackageJson(installedPackagePath);
@@ -27688,7 +27725,7 @@ init_shared();
27688
27725
  function isConfigValid(configPath) {
27689
27726
  if (!configPath)
27690
27727
  return true;
27691
- if (!existsSync23(configPath))
27728
+ if (!existsSync24(configPath))
27692
27729
  return false;
27693
27730
  try {
27694
27731
  parseJsonc(readFileSync21(configPath, "utf-8"));
@@ -27795,24 +27832,24 @@ async function checkSystem() {
27795
27832
 
27796
27833
  // src/cli/doctor/checks/config.ts
27797
27834
  import { readFileSync as readFileSync24 } from "fs";
27798
- import { join as join23 } from "path";
27835
+ import { join as join24 } from "path";
27799
27836
  init_shared();
27800
27837
  init_plugin_identity();
27801
27838
 
27802
27839
  // src/cli/doctor/checks/model-resolution-cache.ts
27803
27840
  init_shared();
27804
- import { existsSync as existsSync24, readFileSync as readFileSync22 } from "fs";
27841
+ import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
27805
27842
  import { homedir as homedir7 } from "os";
27806
- import { join as join20 } from "path";
27843
+ import { join as join21 } from "path";
27807
27844
  function getOpenCodeCacheDir2() {
27808
27845
  const xdgCache = process.env.XDG_CACHE_HOME;
27809
27846
  if (xdgCache)
27810
- return join20(xdgCache, "opencode");
27811
- return join20(homedir7(), ".cache", "opencode");
27847
+ return join21(xdgCache, "opencode");
27848
+ return join21(homedir7(), ".cache", "opencode");
27812
27849
  }
27813
27850
  function loadAvailableModelsFromCache() {
27814
- const cacheFile = join20(getOpenCodeCacheDir2(), "models.json");
27815
- if (!existsSync24(cacheFile)) {
27851
+ const cacheFile = join21(getOpenCodeCacheDir2(), "models.json");
27852
+ if (!existsSync25(cacheFile)) {
27816
27853
  return { providers: [], modelCount: 0, cacheExists: false };
27817
27854
  }
27818
27855
  try {
@@ -27839,9 +27876,9 @@ init_model_requirements();
27839
27876
  init_shared();
27840
27877
  init_plugin_identity();
27841
27878
  import { readFileSync as readFileSync23 } from "fs";
27842
- import { join as join21 } from "path";
27879
+ import { join as join22 } from "path";
27843
27880
  var USER_CONFIG_DIR2 = getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir;
27844
- var PROJECT_CONFIG_DIR = join21(process.cwd(), ".opencode");
27881
+ var PROJECT_CONFIG_DIR = join22(process.cwd(), ".opencode");
27845
27882
  function loadOmoConfig() {
27846
27883
  const projectDetected = detectManagedConfigFile(PROJECT_CONFIG_DIR);
27847
27884
  if (projectDetected.format !== "none") {
@@ -27866,7 +27903,7 @@ function loadOmoConfig() {
27866
27903
 
27867
27904
  // src/cli/doctor/checks/model-resolution-details.ts
27868
27905
  init_shared();
27869
- import { join as join22 } from "path";
27906
+ import { join as join23 } from "path";
27870
27907
 
27871
27908
  // src/cli/doctor/checks/model-resolution-variant.ts
27872
27909
  function formatModelWithVariant(model, variant) {
@@ -27905,7 +27942,7 @@ function getCategoryEffectiveVariant(categoryName, requirement, config2) {
27905
27942
  // src/cli/doctor/checks/model-resolution-details.ts
27906
27943
  function buildModelResolutionDetails(options) {
27907
27944
  const details = [];
27908
- const cacheFile = join22(getOpenCodeCacheDir(), "models.json");
27945
+ const cacheFile = join23(getOpenCodeCacheDir(), "models.json");
27909
27946
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
27910
27947
  details.push("");
27911
27948
  if (options.available.cacheExists) {
@@ -28018,7 +28055,7 @@ async function checkModels() {
28018
28055
 
28019
28056
  // src/cli/doctor/checks/config.ts
28020
28057
  function findConfigPath() {
28021
- const projectConfig = detectManagedConfigFile(join23(process.cwd(), ".opencode"));
28058
+ const projectConfig = detectManagedConfigFile(join24(process.cwd(), ".opencode"));
28022
28059
  if (projectConfig.format !== "none")
28023
28060
  return projectConfig.path;
28024
28061
  const userConfig = detectManagedConfigFile(getOpenCodeConfigDir({ binary: "opencode" }));
@@ -28136,9 +28173,9 @@ async function checkConfig() {
28136
28173
 
28137
28174
  // src/cli/doctor/checks/dependencies.ts
28138
28175
  init_spawn_with_windows_hide();
28139
- import { existsSync as existsSync25 } from "fs";
28176
+ import { existsSync as existsSync26 } from "fs";
28140
28177
  import { createRequire } from "module";
28141
- import { dirname as dirname6, join as join24 } from "path";
28178
+ import { dirname as dirname6, join as join25 } from "path";
28142
28179
  async function checkBinaryExists(binary2) {
28143
28180
  try {
28144
28181
  const path10 = Bun.which(binary2);
@@ -28194,15 +28231,15 @@ async function checkAstGrepNapi() {
28194
28231
  path: null
28195
28232
  };
28196
28233
  } catch {
28197
- const { existsSync: existsSync26 } = await import("fs");
28198
- const { join: join25 } = await import("path");
28234
+ const { existsSync: existsSync27 } = await import("fs");
28235
+ const { join: join26 } = await import("path");
28199
28236
  const { homedir: homedir8 } = await import("os");
28200
28237
  const pathsToCheck = [
28201
- join25(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
28202
- join25(process.cwd(), "node_modules", "@ast-grep", "napi")
28238
+ join26(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
28239
+ join26(process.cwd(), "node_modules", "@ast-grep", "napi")
28203
28240
  ];
28204
28241
  for (const napiPath of pathsToCheck) {
28205
- if (existsSync26(napiPath)) {
28242
+ if (existsSync27(napiPath)) {
28206
28243
  return {
28207
28244
  name: "AST-Grep NAPI",
28208
28245
  required: false,
@@ -28227,8 +28264,8 @@ function findCommentCheckerPackageBinary() {
28227
28264
  try {
28228
28265
  const require2 = createRequire(import.meta.url);
28229
28266
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
28230
- const binaryPath = join24(dirname6(pkgPath), "bin", binaryName);
28231
- if (existsSync25(binaryPath))
28267
+ const binaryPath = join25(dirname6(pkgPath), "bin", binaryName);
28268
+ if (existsSync26(binaryPath))
28232
28269
  return binaryPath;
28233
28270
  } catch {}
28234
28271
  return null;
@@ -28385,13 +28422,13 @@ var BUILTIN_SERVERS = {
28385
28422
  "kotlin-ls": { command: ["kotlin-lsp"], extensions: [".kt", ".kts"] }
28386
28423
  };
28387
28424
  // src/tools/lsp/server-config-loader.ts
28388
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "fs";
28389
- import { join as join25 } from "path";
28425
+ import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
28426
+ import { join as join26 } from "path";
28390
28427
  init_shared();
28391
28428
  init_jsonc_parser();
28392
28429
  init_plugin_identity();
28393
28430
  function loadJsonFile(path10) {
28394
- if (!existsSync26(path10))
28431
+ if (!existsSync27(path10))
28395
28432
  return null;
28396
28433
  try {
28397
28434
  return parseJsonc(readFileSync25(path10, "utf-8"));
@@ -28403,9 +28440,9 @@ function getConfigPaths2() {
28403
28440
  const cwd = process.cwd();
28404
28441
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
28405
28442
  return {
28406
- project: detectManagedConfigFile(join25(cwd, ".opencode")).path,
28443
+ project: detectManagedConfigFile(join26(cwd, ".opencode")).path,
28407
28444
  user: detectManagedConfigFile(configDir).path,
28408
- opencode: detectConfigFile(join25(configDir, "opencode")).path
28445
+ opencode: detectConfigFile(join26(configDir, "opencode")).path
28409
28446
  };
28410
28447
  }
28411
28448
  function loadAllConfigs() {
@@ -28474,21 +28511,21 @@ function getMergedServers() {
28474
28511
  }
28475
28512
 
28476
28513
  // src/tools/lsp/server-installation.ts
28477
- import { existsSync as existsSync27 } from "fs";
28478
- import { delimiter as delimiter2, join as join27 } from "path";
28514
+ import { existsSync as existsSync28 } from "fs";
28515
+ import { delimiter as delimiter2, join as join28 } from "path";
28479
28516
 
28480
28517
  // src/tools/lsp/server-path-bases.ts
28481
28518
  init_shared();
28482
- import { join as join26 } from "path";
28519
+ import { join as join27 } from "path";
28483
28520
  function getLspServerAdditionalPathBases(workingDirectory) {
28484
28521
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
28485
- const dataDir = join26(getDataDir(), "opencode");
28522
+ const dataDir = join27(getDataDir(), "opencode");
28486
28523
  return [
28487
- join26(workingDirectory, "node_modules", ".bin"),
28488
- join26(configDir, "bin"),
28489
- join26(configDir, "node_modules", ".bin"),
28490
- join26(dataDir, "bin"),
28491
- join26(dataDir, "bin", "node_modules", ".bin")
28524
+ join27(workingDirectory, "node_modules", ".bin"),
28525
+ join27(configDir, "bin"),
28526
+ join27(configDir, "node_modules", ".bin"),
28527
+ join27(dataDir, "bin"),
28528
+ join27(dataDir, "bin", "node_modules", ".bin")
28492
28529
  ];
28493
28530
  }
28494
28531
 
@@ -28498,7 +28535,7 @@ function isServerInstalled(command) {
28498
28535
  return false;
28499
28536
  const cmd = command[0];
28500
28537
  if (cmd.includes("/") || cmd.includes("\\")) {
28501
- if (existsSync27(cmd))
28538
+ if (existsSync28(cmd))
28502
28539
  return true;
28503
28540
  }
28504
28541
  const isWindows = process.platform === "win32";
@@ -28519,14 +28556,14 @@ function isServerInstalled(command) {
28519
28556
  const paths = pathEnv.split(delimiter2);
28520
28557
  for (const p2 of paths) {
28521
28558
  for (const suffix of exts) {
28522
- if (existsSync27(join27(p2, cmd + suffix))) {
28559
+ if (existsSync28(join28(p2, cmd + suffix))) {
28523
28560
  return true;
28524
28561
  }
28525
28562
  }
28526
28563
  }
28527
28564
  for (const base of getLspServerAdditionalPathBases(process.cwd())) {
28528
28565
  for (const suffix of exts) {
28529
- if (existsSync27(join27(base, cmd + suffix))) {
28566
+ if (existsSync28(join28(base, cmd + suffix))) {
28530
28567
  return true;
28531
28568
  }
28532
28569
  }
@@ -28588,21 +28625,21 @@ function getInstalledLspServers() {
28588
28625
 
28589
28626
  // src/cli/doctor/checks/tools-mcp.ts
28590
28627
  init_shared();
28591
- import { existsSync as existsSync28, readFileSync as readFileSync26 } from "fs";
28628
+ import { existsSync as existsSync29, readFileSync as readFileSync26 } from "fs";
28592
28629
  import { homedir as homedir8 } from "os";
28593
- import { join as join28 } from "path";
28630
+ import { join as join29 } from "path";
28594
28631
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
28595
28632
  function getMcpConfigPaths() {
28596
28633
  return [
28597
- join28(homedir8(), ".claude", ".mcp.json"),
28598
- join28(process.cwd(), ".mcp.json"),
28599
- join28(process.cwd(), ".claude", ".mcp.json")
28634
+ join29(homedir8(), ".claude", ".mcp.json"),
28635
+ join29(process.cwd(), ".mcp.json"),
28636
+ join29(process.cwd(), ".claude", ".mcp.json")
28600
28637
  ];
28601
28638
  }
28602
28639
  function loadUserMcpConfig() {
28603
28640
  const servers = {};
28604
28641
  for (const configPath of getMcpConfigPaths()) {
28605
- if (!existsSync28(configPath))
28642
+ if (!existsSync29(configPath))
28606
28643
  continue;
28607
28644
  try {
28608
28645
  const content = readFileSync26(configPath, "utf-8");
@@ -29028,11 +29065,11 @@ async function doctor(options = { mode: "default" }) {
29028
29065
 
29029
29066
  // src/features/mcp-oauth/storage.ts
29030
29067
  init_shared();
29031
- import { chmodSync, existsSync as existsSync29, mkdirSync as mkdirSync6, readFileSync as readFileSync27, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
29032
- import { dirname as dirname7, join as join29 } from "path";
29068
+ import { chmodSync, existsSync as existsSync30, mkdirSync as mkdirSync6, readFileSync as readFileSync27, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
29069
+ import { dirname as dirname7, join as join30 } from "path";
29033
29070
  var STORAGE_FILE_NAME = "mcp-oauth.json";
29034
29071
  function getMcpOauthStoragePath() {
29035
- return join29(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
29072
+ return join30(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
29036
29073
  }
29037
29074
  function normalizeHost(serverHost) {
29038
29075
  let host = serverHost.trim();
@@ -29069,7 +29106,7 @@ function buildKey(serverHost, resource) {
29069
29106
  }
29070
29107
  function readStore() {
29071
29108
  const filePath = getMcpOauthStoragePath();
29072
- if (!existsSync29(filePath)) {
29109
+ if (!existsSync30(filePath)) {
29073
29110
  return null;
29074
29111
  }
29075
29112
  try {
@@ -29083,7 +29120,7 @@ function writeStore(store2) {
29083
29120
  const filePath = getMcpOauthStoragePath();
29084
29121
  try {
29085
29122
  const dir = dirname7(filePath);
29086
- if (!existsSync29(dir)) {
29123
+ if (!existsSync30(dir)) {
29087
29124
  mkdirSync6(dir, { recursive: true });
29088
29125
  }
29089
29126
  writeFileSync10(filePath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
@@ -29118,7 +29155,7 @@ function deleteToken(serverHost, resource) {
29118
29155
  if (Object.keys(store2).length === 0) {
29119
29156
  try {
29120
29157
  const filePath = getMcpOauthStoragePath();
29121
- if (existsSync29(filePath)) {
29158
+ if (existsSync30(filePath)) {
29122
29159
  unlinkSync4(filePath);
29123
29160
  }
29124
29161
  return true;
@@ -8,5 +8,11 @@ export declare const BackgroundTaskConfigSchema: z.ZodObject<{
8
8
  staleTimeoutMs: z.ZodOptional<z.ZodNumber>;
9
9
  messageStalenessTimeoutMs: z.ZodOptional<z.ZodNumber>;
10
10
  syncPollTimeoutMs: z.ZodOptional<z.ZodNumber>;
11
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
12
+ circuitBreaker: z.ZodOptional<z.ZodObject<{
13
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
14
+ windowSize: z.ZodOptional<z.ZodNumber>;
15
+ repetitionThresholdPercent: z.ZodOptional<z.ZodNumber>;
16
+ }, z.core.$strip>>;
11
17
  }, z.core.$strip>;
12
18
  export type BackgroundTaskConfig = z.infer<typeof BackgroundTaskConfigSchema>;
@@ -1341,6 +1341,12 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
1341
1341
  staleTimeoutMs: z.ZodOptional<z.ZodNumber>;
1342
1342
  messageStalenessTimeoutMs: z.ZodOptional<z.ZodNumber>;
1343
1343
  syncPollTimeoutMs: z.ZodOptional<z.ZodNumber>;
1344
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
1345
+ circuitBreaker: z.ZodOptional<z.ZodObject<{
1346
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
1347
+ windowSize: z.ZodOptional<z.ZodNumber>;
1348
+ repetitionThresholdPercent: z.ZodOptional<z.ZodNumber>;
1349
+ }, z.core.$strip>>;
1344
1350
  }, z.core.$strip>>;
1345
1351
  notification: z.ZodOptional<z.ZodObject<{
1346
1352
  force_enable: z.ZodOptional<z.ZodBoolean>;
@@ -3699,6 +3699,32 @@
3699
3699
  "syncPollTimeoutMs": {
3700
3700
  "type": "number",
3701
3701
  "minimum": 60000
3702
+ },
3703
+ "maxToolCalls": {
3704
+ "type": "integer",
3705
+ "minimum": 10,
3706
+ "maximum": 9007199254740991
3707
+ },
3708
+ "circuitBreaker": {
3709
+ "type": "object",
3710
+ "properties": {
3711
+ "maxToolCalls": {
3712
+ "type": "integer",
3713
+ "minimum": 10,
3714
+ "maximum": 9007199254740991
3715
+ },
3716
+ "windowSize": {
3717
+ "type": "integer",
3718
+ "minimum": 5,
3719
+ "maximum": 9007199254740991
3720
+ },
3721
+ "repetitionThresholdPercent": {
3722
+ "type": "number",
3723
+ "exclusiveMinimum": 0,
3724
+ "maximum": 100
3725
+ }
3726
+ },
3727
+ "additionalProperties": false
3702
3728
  }
3703
3729
  },
3704
3730
  "additionalProperties": false