oh-my-opencode 3.0.0-beta.9 → 3.0.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 (92) hide show
  1. package/README.ja.md +52 -804
  2. package/README.ko.md +377 -0
  3. package/README.md +61 -933
  4. package/README.zh-cn.md +53 -928
  5. package/dist/agents/atlas.d.ts +19 -0
  6. package/dist/agents/{sisyphus-prompt-builder.d.ts → dynamic-agent-prompt-builder.d.ts} +10 -6
  7. package/dist/agents/explore.d.ts +1 -2
  8. package/dist/agents/index.d.ts +9 -3
  9. package/dist/agents/librarian.d.ts +1 -2
  10. package/dist/agents/metis.d.ts +1 -2
  11. package/dist/agents/momus.d.ts +15 -3
  12. package/dist/agents/multimodal-looker.d.ts +1 -2
  13. package/dist/agents/oracle.d.ts +1 -2
  14. package/dist/agents/prometheus-prompt.d.ts +1 -1
  15. package/dist/agents/sisyphus-junior.d.ts +1 -2
  16. package/dist/agents/sisyphus.d.ts +2 -3
  17. package/dist/agents/types.d.ts +2 -2
  18. package/dist/agents/utils.d.ts +4 -3
  19. package/dist/cli/doctor/checks/dependencies.d.ts +1 -1
  20. package/dist/cli/doctor/checks/index.d.ts +1 -0
  21. package/dist/cli/doctor/checks/model-resolution.d.ts +33 -0
  22. package/dist/cli/doctor/constants.d.ts +1 -0
  23. package/dist/cli/index.js +886 -401
  24. package/dist/cli/install.test.d.ts +1 -0
  25. package/dist/cli/model-fallback.d.ts +18 -0
  26. package/dist/cli/model-fallback.test.d.ts +1 -0
  27. package/dist/cli/types.d.ts +9 -3
  28. package/dist/config/schema.d.ts +50 -246
  29. package/dist/features/background-agent/manager.d.ts +10 -0
  30. package/dist/features/background-agent/types.d.ts +4 -3
  31. package/dist/features/builtin-commands/templates/init-deep.d.ts +1 -1
  32. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  33. package/dist/features/builtin-commands/types.d.ts +1 -1
  34. package/dist/features/skill-mcp-manager/manager.d.ts +1 -0
  35. package/dist/features/task-toast-manager/manager.d.ts +1 -0
  36. package/dist/features/task-toast-manager/types.d.ts +3 -0
  37. package/dist/hooks/{sisyphus-orchestrator → atlas}/index.d.ts +3 -3
  38. package/dist/hooks/atlas/index.test.d.ts +1 -0
  39. package/dist/hooks/auto-update-checker/constants.d.ts +0 -3
  40. package/dist/hooks/index.d.ts +2 -2
  41. package/dist/hooks/prometheus-md-only/constants.d.ts +1 -0
  42. package/dist/hooks/question-label-truncator/index.d.ts +7 -0
  43. package/dist/hooks/question-label-truncator/index.test.d.ts +1 -0
  44. package/dist/hooks/ralph-loop/index.d.ts +1 -0
  45. package/dist/hooks/ralph-loop/types.d.ts +1 -0
  46. package/dist/index.js +12781 -13070
  47. package/dist/index.test.d.ts +1 -0
  48. package/dist/mcp/context7.d.ts +1 -0
  49. package/dist/mcp/grep-app.d.ts +1 -0
  50. package/dist/mcp/index.d.ts +1 -0
  51. package/dist/mcp/websearch.d.ts +1 -0
  52. package/dist/plugin-handlers/config-handler.d.ts +1 -0
  53. package/dist/shared/agent-config-integration.test.d.ts +1 -0
  54. package/dist/shared/agent-display-names.d.ts +12 -0
  55. package/dist/shared/agent-display-names.test.d.ts +1 -0
  56. package/dist/shared/case-insensitive.d.ts +24 -0
  57. package/dist/shared/case-insensitive.test.d.ts +1 -0
  58. package/dist/shared/config-path.d.ts +1 -5
  59. package/dist/shared/index.d.ts +4 -0
  60. package/dist/shared/migration.d.ts +15 -1
  61. package/dist/shared/model-availability.d.ts +8 -0
  62. package/dist/shared/model-availability.test.d.ts +1 -0
  63. package/dist/shared/model-requirements.d.ts +11 -0
  64. package/dist/shared/model-requirements.test.d.ts +1 -0
  65. package/dist/shared/model-resolver.d.ts +20 -0
  66. package/dist/shared/model-resolver.test.d.ts +1 -0
  67. package/dist/tools/delegate-task/constants.d.ts +3 -4
  68. package/dist/tools/delegate-task/tools.d.ts +11 -1
  69. package/dist/tools/delegate-task/types.d.ts +1 -1
  70. package/dist/tools/skill/types.d.ts +1 -1
  71. package/package.json +8 -12
  72. package/dist/agents/build-prompt.d.ts +0 -31
  73. package/dist/agents/document-writer.d.ts +0 -5
  74. package/dist/agents/frontend-ui-ux-engineer.d.ts +0 -5
  75. package/dist/agents/orchestrator-sisyphus.d.ts +0 -20
  76. package/dist/agents/plan-prompt.d.ts +0 -64
  77. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-executor.d.ts +0 -3
  78. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-purge-errors.d.ts +0 -7
  79. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-storage.d.ts +0 -2
  80. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-supersede.d.ts +0 -6
  81. package/dist/hooks/comment-checker/constants.d.ts +0 -3
  82. package/dist/hooks/comment-checker/filters/bdd.d.ts +0 -2
  83. package/dist/hooks/comment-checker/filters/directive.d.ts +0 -2
  84. package/dist/hooks/comment-checker/filters/docstring.d.ts +0 -2
  85. package/dist/hooks/comment-checker/filters/index.d.ts +0 -7
  86. package/dist/hooks/comment-checker/filters/shebang.d.ts +0 -2
  87. package/dist/hooks/comment-checker/output/formatter.d.ts +0 -2
  88. package/dist/hooks/comment-checker/output/index.d.ts +0 -2
  89. package/dist/hooks/comment-checker/output/xml-builder.d.ts +0 -2
  90. package/dist/tools/ast-grep/napi.d.ts +0 -13
  91. package/dist/tools/interactive-bash/types.d.ts +0 -3
  92. /package/dist/{hooks/sisyphus-orchestrator/index.test.d.ts → cli/doctor/checks/model-resolution.test.d.ts} +0 -0
package/dist/cli/index.js CHANGED
@@ -4917,6 +4917,11 @@ var init_dynamic_truncator = __esm(() => {
4917
4917
  var init_config_path = () => {};
4918
4918
 
4919
4919
  // src/shared/data-path.ts
4920
+ import * as path2 from "path";
4921
+ import * as os2 from "os";
4922
+ function getDataDir() {
4923
+ return process.env.XDG_DATA_HOME ?? path2.join(os2.homedir(), ".local", "share");
4924
+ }
4920
4925
  var init_data_path = () => {};
4921
4926
 
4922
4927
  // src/shared/config-errors.ts
@@ -5832,25 +5837,23 @@ var BUILTIN_AGENT_NAMES;
5832
5837
  var init_migration = __esm(() => {
5833
5838
  init_logger();
5834
5839
  BUILTIN_AGENT_NAMES = new Set([
5835
- "Sisyphus",
5840
+ "sisyphus",
5836
5841
  "oracle",
5837
5842
  "librarian",
5838
5843
  "explore",
5839
- "frontend-ui-ux-engineer",
5840
- "document-writer",
5841
5844
  "multimodal-looker",
5842
- "Metis (Plan Consultant)",
5843
- "Momus (Plan Reviewer)",
5844
- "Prometheus (Planner)",
5845
- "orchestrator-sisyphus",
5845
+ "metis",
5846
+ "momus",
5847
+ "prometheus",
5848
+ "atlas",
5846
5849
  "build"
5847
5850
  ]);
5848
5851
  });
5849
5852
 
5850
5853
  // src/shared/opencode-config-dir.ts
5851
5854
  import { existsSync as existsSync2 } from "fs";
5852
- import { homedir } from "os";
5853
- import { join as join2, resolve } from "path";
5855
+ import { homedir as homedir2 } from "os";
5856
+ import { join as join3, resolve } from "path";
5854
5857
  function isDevBuild(version) {
5855
5858
  if (!version)
5856
5859
  return false;
@@ -5860,15 +5863,15 @@ function getTauriConfigDir(identifier) {
5860
5863
  const platform = process.platform;
5861
5864
  switch (platform) {
5862
5865
  case "darwin":
5863
- return join2(homedir(), "Library", "Application Support", identifier);
5866
+ return join3(homedir2(), "Library", "Application Support", identifier);
5864
5867
  case "win32": {
5865
- const appData = process.env.APPDATA || join2(homedir(), "AppData", "Roaming");
5866
- return join2(appData, identifier);
5868
+ const appData = process.env.APPDATA || join3(homedir2(), "AppData", "Roaming");
5869
+ return join3(appData, identifier);
5867
5870
  }
5868
5871
  case "linux":
5869
5872
  default: {
5870
- const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir(), ".config");
5871
- return join2(xdgConfig, identifier);
5873
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join3(homedir2(), ".config");
5874
+ return join3(xdgConfig, identifier);
5872
5875
  }
5873
5876
  }
5874
5877
  }
@@ -5878,21 +5881,21 @@ function getCliConfigDir() {
5878
5881
  return resolve(envConfigDir);
5879
5882
  }
5880
5883
  if (process.platform === "win32") {
5881
- const crossPlatformDir = join2(homedir(), ".config", "opencode");
5882
- const crossPlatformConfig = join2(crossPlatformDir, "opencode.json");
5884
+ const crossPlatformDir = join3(homedir2(), ".config", "opencode");
5885
+ const crossPlatformConfig = join3(crossPlatformDir, "opencode.json");
5883
5886
  if (existsSync2(crossPlatformConfig)) {
5884
5887
  return crossPlatformDir;
5885
5888
  }
5886
- const appData = process.env.APPDATA || join2(homedir(), "AppData", "Roaming");
5887
- const appdataDir = join2(appData, "opencode");
5888
- const appdataConfig = join2(appdataDir, "opencode.json");
5889
+ const appData = process.env.APPDATA || join3(homedir2(), "AppData", "Roaming");
5890
+ const appdataDir = join3(appData, "opencode");
5891
+ const appdataConfig = join3(appdataDir, "opencode.json");
5889
5892
  if (existsSync2(appdataConfig)) {
5890
5893
  return appdataDir;
5891
5894
  }
5892
5895
  return crossPlatformDir;
5893
5896
  }
5894
- const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir(), ".config");
5895
- return join2(xdgConfig, "opencode");
5897
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join3(homedir2(), ".config");
5898
+ return join3(xdgConfig, "opencode");
5896
5899
  }
5897
5900
  function getOpenCodeConfigDir(options) {
5898
5901
  const { binary: binary2, version, checkExisting = true } = options;
@@ -5903,8 +5906,8 @@ function getOpenCodeConfigDir(options) {
5903
5906
  const tauriDir = getTauriConfigDir(identifier);
5904
5907
  if (checkExisting) {
5905
5908
  const legacyDir = getCliConfigDir();
5906
- const legacyConfig = join2(legacyDir, "opencode.json");
5907
- const legacyConfigC = join2(legacyDir, "opencode.jsonc");
5909
+ const legacyConfig = join3(legacyDir, "opencode.json");
5910
+ const legacyConfigC = join3(legacyDir, "opencode.jsonc");
5908
5911
  if (existsSync2(legacyConfig) || existsSync2(legacyConfigC)) {
5909
5912
  return legacyDir;
5910
5913
  }
@@ -5915,10 +5918,10 @@ function getOpenCodeConfigPaths(options) {
5915
5918
  const configDir = getOpenCodeConfigDir(options);
5916
5919
  return {
5917
5920
  configDir,
5918
- configJson: join2(configDir, "opencode.json"),
5919
- configJsonc: join2(configDir, "opencode.jsonc"),
5920
- packageJson: join2(configDir, "package.json"),
5921
- omoConfig: join2(configDir, "oh-my-opencode.json")
5921
+ configJson: join3(configDir, "opencode.json"),
5922
+ configJsonc: join3(configDir, "opencode.jsonc"),
5923
+ packageJson: join3(configDir, "package.json"),
5924
+ omoConfig: join3(configDir, "oh-my-opencode.json")
5922
5925
  };
5923
5926
  }
5924
5927
  var TAURI_APP_IDENTIFIER = "ai.opencode.desktop", TAURI_APP_IDENTIFIER_DEV = "ai.opencode.desktop.dev";
@@ -5937,6 +5940,9 @@ var init_external_plugin_detector = __esm(() => {
5937
5940
 
5938
5941
  // src/shared/zip-extractor.ts
5939
5942
  var init_zip_extractor = () => {};
5943
+ // src/shared/agent-variant.ts
5944
+ var init_agent_variant = () => {};
5945
+
5940
5946
  // src/shared/session-cursor.ts
5941
5947
  var sessionCursors;
5942
5948
  var init_session_cursor = __esm(() => {
@@ -5948,6 +5954,154 @@ var init_system_directive = () => {};
5948
5954
  // src/shared/agent-tool-restrictions.ts
5949
5955
  var init_agent_tool_restrictions = () => {};
5950
5956
 
5957
+ // src/shared/model-requirements.ts
5958
+ var AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS;
5959
+ var init_model_requirements = __esm(() => {
5960
+ AGENT_MODEL_REQUIREMENTS = {
5961
+ sisyphus: {
5962
+ fallbackChain: [
5963
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5964
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
5965
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
5966
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
5967
+ ]
5968
+ },
5969
+ oracle: {
5970
+ fallbackChain: [
5971
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
5972
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5973
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
5974
+ ]
5975
+ },
5976
+ librarian: {
5977
+ fallbackChain: [
5978
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
5979
+ { providers: ["opencode"], model: "big-pickle" },
5980
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
5981
+ ]
5982
+ },
5983
+ explore: {
5984
+ fallbackChain: [
5985
+ { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
5986
+ { providers: ["opencode"], model: "gpt-5-nano" }
5987
+ ]
5988
+ },
5989
+ "multimodal-looker": {
5990
+ fallbackChain: [
5991
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
5992
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
5993
+ { providers: ["zai-coding-plan"], model: "glm-4.6v" },
5994
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
5995
+ { providers: ["opencode"], model: "gpt-5-nano" }
5996
+ ]
5997
+ },
5998
+ prometheus: {
5999
+ fallbackChain: [
6000
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6001
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6002
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6003
+ ]
6004
+ },
6005
+ metis: {
6006
+ fallbackChain: [
6007
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6008
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6009
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
6010
+ ]
6011
+ },
6012
+ momus: {
6013
+ fallbackChain: [
6014
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
6015
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5" },
6016
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
6017
+ ]
6018
+ },
6019
+ atlas: {
6020
+ fallbackChain: [
6021
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6022
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
6023
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6024
+ ]
6025
+ }
6026
+ };
6027
+ CATEGORY_MODEL_REQUIREMENTS = {
6028
+ "visual-engineering": {
6029
+ fallbackChain: [
6030
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
6031
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6032
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" }
6033
+ ]
6034
+ },
6035
+ ultrabrain: {
6036
+ fallbackChain: [
6037
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
6038
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6039
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6040
+ ]
6041
+ },
6042
+ artistry: {
6043
+ fallbackChain: [
6044
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
6045
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6046
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
6047
+ ]
6048
+ },
6049
+ quick: {
6050
+ fallbackChain: [
6051
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
6052
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
6053
+ { providers: ["opencode"], model: "gpt-5-nano" }
6054
+ ]
6055
+ },
6056
+ "unspecified-low": {
6057
+ fallbackChain: [
6058
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6059
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
6060
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
6061
+ ]
6062
+ },
6063
+ "unspecified-high": {
6064
+ fallbackChain: [
6065
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
6066
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6067
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6068
+ ]
6069
+ },
6070
+ writing: {
6071
+ fallbackChain: [
6072
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
6073
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6074
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
6075
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
6076
+ ]
6077
+ }
6078
+ };
6079
+ });
6080
+
6081
+ // src/shared/model-availability.ts
6082
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
6083
+ import { homedir as homedir3 } from "os";
6084
+ import { join as join4 } from "path";
6085
+ function getOpenCodeCacheDir() {
6086
+ const xdgCache = process.env.XDG_CACHE_HOME;
6087
+ if (xdgCache)
6088
+ return join4(xdgCache, "opencode");
6089
+ return join4(homedir3(), ".cache", "opencode");
6090
+ }
6091
+ function isModelCacheAvailable() {
6092
+ const cacheFile = join4(getOpenCodeCacheDir(), "models.json");
6093
+ return existsSync3(cacheFile);
6094
+ }
6095
+ var init_model_availability = __esm(() => {
6096
+ init_logger();
6097
+ });
6098
+
6099
+ // src/shared/model-resolver.ts
6100
+ var init_model_resolver = __esm(() => {
6101
+ init_logger();
6102
+ init_model_availability();
6103
+ });
6104
+
5951
6105
  // src/shared/index.ts
5952
6106
  var init_shared = __esm(() => {
5953
6107
  init_frontmatter();
@@ -5969,13 +6123,129 @@ var init_shared = __esm(() => {
5969
6123
  init_opencode_version();
5970
6124
  init_external_plugin_detector();
5971
6125
  init_zip_extractor();
6126
+ init_agent_variant();
5972
6127
  init_session_cursor();
5973
6128
  init_system_directive();
5974
6129
  init_agent_tool_restrictions();
6130
+ init_model_requirements();
6131
+ init_model_resolver();
6132
+ init_model_availability();
6133
+ });
6134
+
6135
+ // src/cli/model-fallback.ts
6136
+ function toProviderAvailability(config) {
6137
+ return {
6138
+ native: {
6139
+ claude: config.hasClaude,
6140
+ openai: config.hasOpenAI,
6141
+ gemini: config.hasGemini
6142
+ },
6143
+ opencodeZen: config.hasOpencodeZen,
6144
+ copilot: config.hasCopilot,
6145
+ zai: config.hasZaiCodingPlan,
6146
+ isMaxPlan: config.isMax20
6147
+ };
6148
+ }
6149
+ function isProviderAvailable(provider, avail) {
6150
+ const mapping = {
6151
+ anthropic: avail.native.claude,
6152
+ openai: avail.native.openai,
6153
+ google: avail.native.gemini,
6154
+ "github-copilot": avail.copilot,
6155
+ opencode: avail.opencodeZen,
6156
+ "zai-coding-plan": avail.zai
6157
+ };
6158
+ return mapping[provider] ?? false;
6159
+ }
6160
+ function transformModelForProvider(provider, model) {
6161
+ if (provider === "github-copilot") {
6162
+ return model.replace("claude-opus-4-5", "claude-opus-4.5").replace("claude-sonnet-4-5", "claude-sonnet-4.5").replace("claude-haiku-4-5", "claude-haiku-4.5").replace("claude-sonnet-4", "claude-sonnet-4");
6163
+ }
6164
+ return model;
6165
+ }
6166
+ function resolveModelFromChain(fallbackChain, avail) {
6167
+ for (const entry of fallbackChain) {
6168
+ for (const provider of entry.providers) {
6169
+ if (isProviderAvailable(provider, avail)) {
6170
+ const transformedModel = transformModelForProvider(provider, entry.model);
6171
+ return {
6172
+ model: `${provider}/${transformedModel}`,
6173
+ variant: entry.variant
6174
+ };
6175
+ }
6176
+ }
6177
+ }
6178
+ return null;
6179
+ }
6180
+ function getSisyphusFallbackChain(isMaxPlan) {
6181
+ if (isMaxPlan) {
6182
+ return AGENT_MODEL_REQUIREMENTS.sisyphus.fallbackChain;
6183
+ }
6184
+ return [
6185
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6186
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6187
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6188
+ ];
6189
+ }
6190
+ function generateModelConfig(config) {
6191
+ const avail = toProviderAvailability(config);
6192
+ const hasAnyProvider = avail.native.claude || avail.native.openai || avail.native.gemini || avail.opencodeZen || avail.copilot || avail.zai;
6193
+ if (!hasAnyProvider) {
6194
+ return {
6195
+ $schema: SCHEMA_URL,
6196
+ agents: Object.fromEntries(Object.keys(AGENT_MODEL_REQUIREMENTS).map((role) => [role, { model: ULTIMATE_FALLBACK }])),
6197
+ categories: Object.fromEntries(Object.keys(CATEGORY_MODEL_REQUIREMENTS).map((cat) => [cat, { model: ULTIMATE_FALLBACK }]))
6198
+ };
6199
+ }
6200
+ const agents = {};
6201
+ const categories = {};
6202
+ for (const [role, req] of Object.entries(AGENT_MODEL_REQUIREMENTS)) {
6203
+ if (role === "librarian" && avail.zai) {
6204
+ agents[role] = { model: ZAI_MODEL };
6205
+ continue;
6206
+ }
6207
+ if (role === "explore") {
6208
+ if (avail.native.claude) {
6209
+ agents[role] = { model: "anthropic/claude-haiku-4-5" };
6210
+ } else if (avail.opencodeZen) {
6211
+ agents[role] = { model: "opencode/claude-haiku-4-5" };
6212
+ } else {
6213
+ agents[role] = { model: "opencode/gpt-5-nano" };
6214
+ }
6215
+ continue;
6216
+ }
6217
+ const fallbackChain = role === "sisyphus" ? getSisyphusFallbackChain(avail.isMaxPlan) : req.fallbackChain;
6218
+ const resolved = resolveModelFromChain(fallbackChain, avail);
6219
+ if (resolved) {
6220
+ const variant = resolved.variant ?? req.variant;
6221
+ agents[role] = variant ? { model: resolved.model, variant } : { model: resolved.model };
6222
+ } else {
6223
+ agents[role] = { model: ULTIMATE_FALLBACK };
6224
+ }
6225
+ }
6226
+ for (const [cat, req] of Object.entries(CATEGORY_MODEL_REQUIREMENTS)) {
6227
+ const fallbackChain = cat === "unspecified-high" && !avail.isMaxPlan ? CATEGORY_MODEL_REQUIREMENTS["unspecified-low"].fallbackChain : req.fallbackChain;
6228
+ const resolved = resolveModelFromChain(fallbackChain, avail);
6229
+ if (resolved) {
6230
+ const variant = resolved.variant ?? req.variant;
6231
+ categories[cat] = variant ? { model: resolved.model, variant } : { model: resolved.model };
6232
+ } else {
6233
+ categories[cat] = { model: ULTIMATE_FALLBACK };
6234
+ }
6235
+ }
6236
+ return {
6237
+ $schema: SCHEMA_URL,
6238
+ agents,
6239
+ categories
6240
+ };
6241
+ }
6242
+ var ZAI_MODEL = "zai-coding-plan/glm-4.7", ULTIMATE_FALLBACK = "opencode/big-pickle", SCHEMA_URL = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
6243
+ var init_model_fallback = __esm(() => {
6244
+ init_model_requirements();
5975
6245
  });
5976
6246
 
5977
6247
  // src/cli/config-manager.ts
5978
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync } from "fs";
6248
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3, writeFileSync, statSync } from "fs";
5979
6249
  function initConfigContext(binary2, version) {
5980
6250
  const paths = getOpenCodeConfigPaths({ binary: binary2, version });
5981
6251
  configContext = { binary: binary2, version, paths };
@@ -6065,10 +6335,10 @@ async function getPluginNameWithVersion(currentVersion) {
6065
6335
  function detectConfigFormat() {
6066
6336
  const configJsonc = getConfigJsonc();
6067
6337
  const configJson = getConfigJson();
6068
- if (existsSync3(configJsonc)) {
6338
+ if (existsSync4(configJsonc)) {
6069
6339
  return { format: "jsonc", path: configJsonc };
6070
6340
  }
6071
- if (existsSync3(configJson)) {
6341
+ if (existsSync4(configJson)) {
6072
6342
  return { format: "json", path: configJson };
6073
6343
  }
6074
6344
  return { format: "none", path: configJson };
@@ -6076,31 +6346,31 @@ function detectConfigFormat() {
6076
6346
  function isEmptyOrWhitespace(content) {
6077
6347
  return content.trim().length === 0;
6078
6348
  }
6079
- function parseConfigWithError(path2) {
6349
+ function parseConfigWithError(path3) {
6080
6350
  try {
6081
- const stat = statSync(path2);
6351
+ const stat = statSync(path3);
6082
6352
  if (stat.size === 0) {
6083
- return { config: null, error: `Config file is empty: ${path2}. Delete it or add valid JSON content.` };
6353
+ return { config: null, error: `Config file is empty: ${path3}. Delete it or add valid JSON content.` };
6084
6354
  }
6085
- const content = readFileSync2(path2, "utf-8");
6355
+ const content = readFileSync3(path3, "utf-8");
6086
6356
  if (isEmptyOrWhitespace(content)) {
6087
- return { config: null, error: `Config file contains only whitespace: ${path2}. Delete it or add valid JSON content.` };
6357
+ return { config: null, error: `Config file contains only whitespace: ${path3}. Delete it or add valid JSON content.` };
6088
6358
  }
6089
6359
  const config = parseJsonc(content);
6090
6360
  if (config === null || config === undefined) {
6091
- return { config: null, error: `Config file parsed to null/undefined: ${path2}. Ensure it contains valid JSON.` };
6361
+ return { config: null, error: `Config file parsed to null/undefined: ${path3}. Ensure it contains valid JSON.` };
6092
6362
  }
6093
6363
  if (typeof config !== "object" || Array.isArray(config)) {
6094
- return { config: null, error: `Config file must contain a JSON object, not ${Array.isArray(config) ? "an array" : typeof config}: ${path2}` };
6364
+ return { config: null, error: `Config file must contain a JSON object, not ${Array.isArray(config) ? "an array" : typeof config}: ${path3}` };
6095
6365
  }
6096
6366
  return { config };
6097
6367
  } catch (err) {
6098
- return { config: null, error: formatErrorWithSuggestion(err, `parse config file ${path2}`) };
6368
+ return { config: null, error: formatErrorWithSuggestion(err, `parse config file ${path3}`) };
6099
6369
  }
6100
6370
  }
6101
6371
  function ensureConfigDir() {
6102
6372
  const configDir = getConfigDir();
6103
- if (!existsSync3(configDir)) {
6373
+ if (!existsSync4(configDir)) {
6104
6374
  mkdirSync(configDir, { recursive: true });
6105
6375
  }
6106
6376
  }
@@ -6110,25 +6380,25 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6110
6380
  } catch (err) {
6111
6381
  return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
6112
6382
  }
6113
- const { format: format2, path: path2 } = detectConfigFormat();
6383
+ const { format: format2, path: path3 } = detectConfigFormat();
6114
6384
  const pluginEntry = await getPluginNameWithVersion(currentVersion);
6115
6385
  try {
6116
6386
  if (format2 === "none") {
6117
6387
  const config2 = { plugin: [pluginEntry] };
6118
- writeFileSync(path2, JSON.stringify(config2, null, 2) + `
6388
+ writeFileSync(path3, JSON.stringify(config2, null, 2) + `
6119
6389
  `);
6120
- return { success: true, configPath: path2 };
6390
+ return { success: true, configPath: path3 };
6121
6391
  }
6122
- const parseResult = parseConfigWithError(path2);
6392
+ const parseResult = parseConfigWithError(path3);
6123
6393
  if (!parseResult.config) {
6124
- return { success: false, configPath: path2, error: parseResult.error ?? "Failed to parse config file" };
6394
+ return { success: false, configPath: path3, error: parseResult.error ?? "Failed to parse config file" };
6125
6395
  }
6126
6396
  const config = parseResult.config;
6127
6397
  const plugins = config.plugin ?? [];
6128
6398
  const existingIndex = plugins.findIndex((p2) => p2 === PACKAGE_NAME || p2.startsWith(`${PACKAGE_NAME}@`));
6129
6399
  if (existingIndex !== -1) {
6130
6400
  if (plugins[existingIndex] === pluginEntry) {
6131
- return { success: true, configPath: path2 };
6401
+ return { success: true, configPath: path3 };
6132
6402
  }
6133
6403
  plugins[existingIndex] = pluginEntry;
6134
6404
  } else {
@@ -6136,7 +6406,7 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6136
6406
  }
6137
6407
  config.plugin = plugins;
6138
6408
  if (format2 === "jsonc") {
6139
- const content = readFileSync2(path2, "utf-8");
6409
+ const content = readFileSync3(path3, "utf-8");
6140
6410
  const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/;
6141
6411
  const match = content.match(pluginArrayRegex);
6142
6412
  if (match) {
@@ -6145,19 +6415,19 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6145
6415
  const newContent = content.replace(pluginArrayRegex, `"plugin": [
6146
6416
  ${formattedPlugins}
6147
6417
  ]`);
6148
- writeFileSync(path2, newContent);
6418
+ writeFileSync(path3, newContent);
6149
6419
  } else {
6150
6420
  const newContent = content.replace(/^(\s*\{)/, `$1
6151
6421
  "plugin": ["${pluginEntry}"],`);
6152
- writeFileSync(path2, newContent);
6422
+ writeFileSync(path3, newContent);
6153
6423
  }
6154
6424
  } else {
6155
- writeFileSync(path2, JSON.stringify(config, null, 2) + `
6425
+ writeFileSync(path3, JSON.stringify(config, null, 2) + `
6156
6426
  `);
6157
6427
  }
6158
- return { success: true, configPath: path2 };
6428
+ return { success: true, configPath: path3 };
6159
6429
  } catch (err) {
6160
- return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "update opencode config") };
6430
+ return { success: false, configPath: path3, error: formatErrorWithSuggestion(err, "update opencode config") };
6161
6431
  }
6162
6432
  }
6163
6433
  function deepMerge(target, source) {
@@ -6174,63 +6444,7 @@ function deepMerge(target, source) {
6174
6444
  return result;
6175
6445
  }
6176
6446
  function generateOmoConfig(installConfig) {
6177
- const config = {
6178
- $schema: "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json"
6179
- };
6180
- const agents = {};
6181
- if (!installConfig.hasClaude) {
6182
- agents["Sisyphus"] = {
6183
- model: installConfig.hasCopilot ? "github-copilot/claude-opus-4.5" : "opencode/glm-4.7-free"
6184
- };
6185
- }
6186
- agents["librarian"] = { model: "opencode/glm-4.7-free" };
6187
- if (installConfig.hasGemini) {
6188
- agents["explore"] = { model: "google/antigravity-gemini-3-flash" };
6189
- } else if (installConfig.hasClaude && installConfig.isMax20) {
6190
- agents["explore"] = { model: "anthropic/claude-haiku-4-5" };
6191
- } else if (installConfig.hasCopilot) {
6192
- agents["explore"] = { model: "github-copilot/grok-code-fast-1" };
6193
- } else {
6194
- agents["explore"] = { model: "opencode/glm-4.7-free" };
6195
- }
6196
- if (!installConfig.hasChatGPT) {
6197
- const oracleFallback = installConfig.hasCopilot ? "github-copilot/gpt-5.2" : installConfig.hasClaude ? "anthropic/claude-opus-4-5" : "opencode/glm-4.7-free";
6198
- agents["oracle"] = { model: oracleFallback };
6199
- }
6200
- if (installConfig.hasGemini) {
6201
- agents["frontend-ui-ux-engineer"] = { model: "google/antigravity-gemini-3-pro-high" };
6202
- agents["document-writer"] = { model: "google/antigravity-gemini-3-flash" };
6203
- agents["multimodal-looker"] = { model: "google/antigravity-gemini-3-flash" };
6204
- } else if (installConfig.hasClaude) {
6205
- agents["frontend-ui-ux-engineer"] = { model: "anthropic/claude-opus-4-5" };
6206
- agents["document-writer"] = { model: "anthropic/claude-opus-4-5" };
6207
- agents["multimodal-looker"] = { model: "anthropic/claude-opus-4-5" };
6208
- } else if (installConfig.hasCopilot) {
6209
- agents["frontend-ui-ux-engineer"] = { model: "github-copilot/gemini-3-pro-preview" };
6210
- agents["document-writer"] = { model: "github-copilot/gemini-3-flash-preview" };
6211
- agents["multimodal-looker"] = { model: "github-copilot/gemini-3-flash-preview" };
6212
- } else {
6213
- agents["frontend-ui-ux-engineer"] = { model: "opencode/glm-4.7-free" };
6214
- agents["document-writer"] = { model: "opencode/glm-4.7-free" };
6215
- agents["multimodal-looker"] = { model: "opencode/glm-4.7-free" };
6216
- }
6217
- if (Object.keys(agents).length > 0) {
6218
- config.agents = agents;
6219
- }
6220
- if (installConfig.hasGemini) {
6221
- config.categories = {
6222
- "visual-engineering": { model: "google/gemini-3-pro-high" },
6223
- artistry: { model: "google/gemini-3-pro-high" },
6224
- writing: { model: "google/gemini-3-flash-high" }
6225
- };
6226
- } else if (installConfig.hasCopilot) {
6227
- config.categories = {
6228
- "visual-engineering": { model: "github-copilot/gemini-3-pro-preview" },
6229
- artistry: { model: "github-copilot/gemini-3-pro-preview" },
6230
- writing: { model: "github-copilot/gemini-3-flash-preview" }
6231
- };
6232
- }
6233
- return config;
6447
+ return generateModelConfig(installConfig);
6234
6448
  }
6235
6449
  function writeOmoConfig(installConfig) {
6236
6450
  try {
@@ -6241,10 +6455,10 @@ function writeOmoConfig(installConfig) {
6241
6455
  const omoConfigPath = getOmoConfig();
6242
6456
  try {
6243
6457
  const newConfig = generateOmoConfig(installConfig);
6244
- if (existsSync3(omoConfigPath)) {
6458
+ if (existsSync4(omoConfigPath)) {
6245
6459
  try {
6246
6460
  const stat = statSync(omoConfigPath);
6247
- const content = readFileSync2(omoConfigPath, "utf-8");
6461
+ const content = readFileSync3(omoConfigPath, "utf-8");
6248
6462
  if (stat.size === 0 || isEmptyOrWhitespace(content)) {
6249
6463
  writeFileSync(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6250
6464
  `);
@@ -6310,11 +6524,11 @@ async function addAuthPlugins(config) {
6310
6524
  } catch (err) {
6311
6525
  return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
6312
6526
  }
6313
- const { format: format2, path: path2 } = detectConfigFormat();
6527
+ const { format: format2, path: path3 } = detectConfigFormat();
6314
6528
  try {
6315
6529
  let existingConfig = null;
6316
6530
  if (format2 !== "none") {
6317
- const parseResult = parseConfigWithError(path2);
6531
+ const parseResult = parseConfigWithError(path3);
6318
6532
  if (parseResult.error && !parseResult.config) {
6319
6533
  existingConfig = {};
6320
6534
  } else {
@@ -6330,11 +6544,11 @@ async function addAuthPlugins(config) {
6330
6544
  }
6331
6545
  }
6332
6546
  const newConfig = { ...existingConfig ?? {}, plugin: plugins };
6333
- writeFileSync(path2, JSON.stringify(newConfig, null, 2) + `
6547
+ writeFileSync(path3, JSON.stringify(newConfig, null, 2) + `
6334
6548
  `);
6335
- return { success: true, configPath: path2 };
6549
+ return { success: true, configPath: path3 };
6336
6550
  } catch (err) {
6337
- return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "add auth plugins to config") };
6551
+ return { success: false, configPath: path3, error: formatErrorWithSuggestion(err, "add auth plugins to config") };
6338
6552
  }
6339
6553
  }
6340
6554
  async function runBunInstall() {
@@ -6383,11 +6597,11 @@ function addProviderConfig(config) {
6383
6597
  } catch (err) {
6384
6598
  return { success: false, configPath: getConfigDir(), error: formatErrorWithSuggestion(err, "create config directory") };
6385
6599
  }
6386
- const { format: format2, path: path2 } = detectConfigFormat();
6600
+ const { format: format2, path: path3 } = detectConfigFormat();
6387
6601
  try {
6388
6602
  let existingConfig = null;
6389
6603
  if (format2 !== "none") {
6390
- const parseResult = parseConfigWithError(path2);
6604
+ const parseResult = parseConfigWithError(path3);
6391
6605
  if (parseResult.error && !parseResult.config) {
6392
6606
  existingConfig = {};
6393
6607
  } else {
@@ -6402,11 +6616,31 @@ function addProviderConfig(config) {
6402
6616
  if (Object.keys(providers).length > 0) {
6403
6617
  newConfig.provider = providers;
6404
6618
  }
6405
- writeFileSync(path2, JSON.stringify(newConfig, null, 2) + `
6619
+ writeFileSync(path3, JSON.stringify(newConfig, null, 2) + `
6406
6620
  `);
6407
- return { success: true, configPath: path2 };
6621
+ return { success: true, configPath: path3 };
6408
6622
  } catch (err) {
6409
- return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "add provider config") };
6623
+ return { success: false, configPath: path3, error: formatErrorWithSuggestion(err, "add provider config") };
6624
+ }
6625
+ }
6626
+ function detectProvidersFromOmoConfig() {
6627
+ const omoConfigPath = getOmoConfig();
6628
+ if (!existsSync4(omoConfigPath)) {
6629
+ return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false };
6630
+ }
6631
+ try {
6632
+ const content = readFileSync3(omoConfigPath, "utf-8");
6633
+ const omoConfig = parseJsonc(content);
6634
+ if (!omoConfig || typeof omoConfig !== "object") {
6635
+ return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false };
6636
+ }
6637
+ const configStr = JSON.stringify(omoConfig);
6638
+ const hasOpenAI = configStr.includes('"openai/');
6639
+ const hasOpencodeZen = configStr.includes('"opencode/');
6640
+ const hasZaiCodingPlan = configStr.includes('"zai-coding-plan/');
6641
+ return { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan };
6642
+ } catch {
6643
+ return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false };
6410
6644
  }
6411
6645
  }
6412
6646
  function detectCurrentConfig() {
@@ -6414,15 +6648,17 @@ function detectCurrentConfig() {
6414
6648
  isInstalled: false,
6415
6649
  hasClaude: true,
6416
6650
  isMax20: true,
6417
- hasChatGPT: true,
6651
+ hasOpenAI: true,
6418
6652
  hasGemini: false,
6419
- hasCopilot: false
6653
+ hasCopilot: false,
6654
+ hasOpencodeZen: true,
6655
+ hasZaiCodingPlan: false
6420
6656
  };
6421
- const { format: format2, path: path2 } = detectConfigFormat();
6657
+ const { format: format2, path: path3 } = detectConfigFormat();
6422
6658
  if (format2 === "none") {
6423
6659
  return result;
6424
6660
  }
6425
- const parseResult = parseConfigWithError(path2);
6661
+ const parseResult = parseConfigWithError(path3);
6426
6662
  if (!parseResult.config) {
6427
6663
  return result;
6428
6664
  }
@@ -6433,44 +6669,16 @@ function detectCurrentConfig() {
6433
6669
  return result;
6434
6670
  }
6435
6671
  result.hasGemini = plugins.some((p2) => p2.startsWith("opencode-antigravity-auth"));
6436
- const omoConfigPath = getOmoConfig();
6437
- if (!existsSync3(omoConfigPath)) {
6438
- return result;
6439
- }
6440
- try {
6441
- const stat = statSync(omoConfigPath);
6442
- if (stat.size === 0) {
6443
- return result;
6444
- }
6445
- const content = readFileSync2(omoConfigPath, "utf-8");
6446
- if (isEmptyOrWhitespace(content)) {
6447
- return result;
6448
- }
6449
- const omoConfig = parseJsonc(content);
6450
- if (!omoConfig || typeof omoConfig !== "object") {
6451
- return result;
6452
- }
6453
- const agents = omoConfig.agents ?? {};
6454
- if (agents["Sisyphus"]?.model === "opencode/glm-4.7-free") {
6455
- result.hasClaude = false;
6456
- result.isMax20 = false;
6457
- } else if (agents["librarian"]?.model === "opencode/glm-4.7-free") {
6458
- result.hasClaude = true;
6459
- result.isMax20 = false;
6460
- }
6461
- if (agents["oracle"]?.model?.startsWith("anthropic/")) {
6462
- result.hasChatGPT = false;
6463
- } else if (agents["oracle"]?.model === "opencode/glm-4.7-free") {
6464
- result.hasChatGPT = false;
6465
- }
6466
- const hasAnyCopilotModel = Object.values(agents).some((agent) => agent?.model?.startsWith("github-copilot/"));
6467
- result.hasCopilot = hasAnyCopilotModel;
6468
- } catch {}
6672
+ const { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan } = detectProvidersFromOmoConfig();
6673
+ result.hasOpenAI = hasOpenAI;
6674
+ result.hasOpencodeZen = hasOpencodeZen;
6675
+ result.hasZaiCodingPlan = hasZaiCodingPlan;
6469
6676
  return result;
6470
6677
  }
6471
6678
  var OPENCODE_BINARIES, configContext = null, BUN_INSTALL_TIMEOUT_SECONDS = 60, BUN_INSTALL_TIMEOUT_MS, NPM_FETCH_TIMEOUT_MS = 5000, PACKAGE_NAME = "oh-my-opencode", PRIORITIZED_TAGS, ANTIGRAVITY_PROVIDER_CONFIG;
6472
6679
  var init_config_manager = __esm(() => {
6473
6680
  init_shared();
6681
+ init_model_fallback();
6474
6682
  OPENCODE_BINARIES = ["opencode", "opencode-desktop"];
6475
6683
  BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
6476
6684
  PRIORITIZED_TAGS = ["latest", "beta", "next"];
@@ -6504,56 +6712,43 @@ var init_config_manager = __esm(() => {
6504
6712
  });
6505
6713
 
6506
6714
  // src/hooks/auto-update-checker/constants.ts
6507
- import * as path2 from "path";
6508
- import * as os2 from "os";
6509
- import * as fs2 from "fs";
6715
+ import * as path3 from "path";
6716
+ import * as os3 from "os";
6510
6717
  function getCacheDir() {
6511
6718
  if (process.platform === "win32") {
6512
- return path2.join(process.env.LOCALAPPDATA ?? os2.homedir(), "opencode");
6719
+ return path3.join(process.env.LOCALAPPDATA ?? os3.homedir(), "opencode");
6513
6720
  }
6514
- return path2.join(os2.homedir(), ".cache", "opencode");
6515
- }
6516
- function getUserConfigDir() {
6517
- if (process.platform === "win32") {
6518
- const crossPlatformDir = path2.join(os2.homedir(), ".config");
6519
- const appdataDir = process.env.APPDATA ?? path2.join(os2.homedir(), "AppData", "Roaming");
6520
- const crossPlatformConfig = path2.join(crossPlatformDir, "opencode", "opencode.json");
6521
- const crossPlatformConfigJsonc = path2.join(crossPlatformDir, "opencode", "opencode.jsonc");
6522
- if (fs2.existsSync(crossPlatformConfig) || fs2.existsSync(crossPlatformConfigJsonc)) {
6523
- return crossPlatformDir;
6524
- }
6525
- return appdataDir;
6526
- }
6527
- return process.env.XDG_CONFIG_HOME ?? path2.join(os2.homedir(), ".config");
6721
+ return path3.join(os3.homedir(), ".cache", "opencode");
6528
6722
  }
6529
6723
  function getWindowsAppdataDir() {
6530
6724
  if (process.platform !== "win32")
6531
6725
  return null;
6532
- return process.env.APPDATA ?? path2.join(os2.homedir(), "AppData", "Roaming");
6726
+ return process.env.APPDATA ?? path3.join(os3.homedir(), "AppData", "Roaming");
6533
6727
  }
6534
6728
  var PACKAGE_NAME2 = "oh-my-opencode", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_DIR, VERSION_FILE, INSTALLED_PACKAGE_JSON, USER_CONFIG_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
6535
6729
  var init_constants = __esm(() => {
6730
+ init_shared();
6536
6731
  NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME2}/dist-tags`;
6537
6732
  CACHE_DIR = getCacheDir();
6538
- VERSION_FILE = path2.join(CACHE_DIR, "version");
6539
- INSTALLED_PACKAGE_JSON = path2.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
6540
- USER_CONFIG_DIR = getUserConfigDir();
6541
- USER_OPENCODE_CONFIG = path2.join(USER_CONFIG_DIR, "opencode", "opencode.json");
6542
- USER_OPENCODE_CONFIG_JSONC = path2.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
6733
+ VERSION_FILE = path3.join(CACHE_DIR, "version");
6734
+ INSTALLED_PACKAGE_JSON = path3.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
6735
+ USER_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
6736
+ USER_OPENCODE_CONFIG = path3.join(USER_CONFIG_DIR, "opencode.json");
6737
+ USER_OPENCODE_CONFIG_JSONC = path3.join(USER_CONFIG_DIR, "opencode.jsonc");
6543
6738
  });
6544
6739
 
6545
6740
  // src/hooks/auto-update-checker/cache.ts
6546
- import * as fs3 from "fs";
6547
- import * as path3 from "path";
6741
+ import * as fs2 from "fs";
6742
+ import * as path4 from "path";
6548
6743
  function stripTrailingCommas(json2) {
6549
6744
  return json2.replace(/,(\s*[}\]])/g, "$1");
6550
6745
  }
6551
6746
  function removeFromBunLock(packageName) {
6552
- const lockPath = path3.join(CACHE_DIR, "bun.lock");
6553
- if (!fs3.existsSync(lockPath))
6747
+ const lockPath = path4.join(CACHE_DIR, "bun.lock");
6748
+ if (!fs2.existsSync(lockPath))
6554
6749
  return false;
6555
6750
  try {
6556
- const content = fs3.readFileSync(lockPath, "utf-8");
6751
+ const content = fs2.readFileSync(lockPath, "utf-8");
6557
6752
  const lock = JSON.parse(stripTrailingCommas(content));
6558
6753
  let modified = false;
6559
6754
  if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
@@ -6565,7 +6760,7 @@ function removeFromBunLock(packageName) {
6565
6760
  modified = true;
6566
6761
  }
6567
6762
  if (modified) {
6568
- fs3.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
6763
+ fs2.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
6569
6764
  log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
6570
6765
  }
6571
6766
  return modified;
@@ -6575,22 +6770,22 @@ function removeFromBunLock(packageName) {
6575
6770
  }
6576
6771
  function invalidatePackage(packageName = PACKAGE_NAME2) {
6577
6772
  try {
6578
- const pkgDir = path3.join(CACHE_DIR, "node_modules", packageName);
6579
- const pkgJsonPath = path3.join(CACHE_DIR, "package.json");
6773
+ const pkgDir = path4.join(CACHE_DIR, "node_modules", packageName);
6774
+ const pkgJsonPath = path4.join(CACHE_DIR, "package.json");
6580
6775
  let packageRemoved = false;
6581
6776
  let dependencyRemoved = false;
6582
6777
  let lockRemoved = false;
6583
- if (fs3.existsSync(pkgDir)) {
6584
- fs3.rmSync(pkgDir, { recursive: true, force: true });
6778
+ if (fs2.existsSync(pkgDir)) {
6779
+ fs2.rmSync(pkgDir, { recursive: true, force: true });
6585
6780
  log(`[auto-update-checker] Package removed: ${pkgDir}`);
6586
6781
  packageRemoved = true;
6587
6782
  }
6588
- if (fs3.existsSync(pkgJsonPath)) {
6589
- const content = fs3.readFileSync(pkgJsonPath, "utf-8");
6783
+ if (fs2.existsSync(pkgJsonPath)) {
6784
+ const content = fs2.readFileSync(pkgJsonPath, "utf-8");
6590
6785
  const pkgJson = JSON.parse(content);
6591
6786
  if (pkgJson.dependencies?.[packageName]) {
6592
6787
  delete pkgJson.dependencies[packageName];
6593
- fs3.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
6788
+ fs2.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
6594
6789
  log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
6595
6790
  dependencyRemoved = true;
6596
6791
  }
@@ -6682,6 +6877,7 @@ v${latestVersion} available. Restart OpenCode to apply.` : `OpenCode is now on S
6682
6877
  const localDevVersion = getLocalDevVersion(ctx.directory);
6683
6878
  const displayVersion = localDevVersion ?? cachedVersion;
6684
6879
  await showConfigErrorsIfAny(ctx);
6880
+ await showModelCacheWarningIfNeeded(ctx);
6685
6881
  if (localDevVersion) {
6686
6882
  if (showStartupToast) {
6687
6883
  showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {});
@@ -6755,6 +6951,19 @@ async function runBunInstallSafe() {
6755
6951
  return false;
6756
6952
  }
6757
6953
  }
6954
+ async function showModelCacheWarningIfNeeded(ctx) {
6955
+ if (isModelCacheAvailable())
6956
+ return;
6957
+ await ctx.client.tui.showToast({
6958
+ body: {
6959
+ title: "Model Cache Not Found",
6960
+ message: "Run 'opencode models --refresh' or restart OpenCode to populate the models cache for optimal agent model selection.",
6961
+ variant: "warning",
6962
+ duration: 1e4
6963
+ }
6964
+ }).catch(() => {});
6965
+ log("[auto-update-checker] Model cache warning shown");
6966
+ }
6758
6967
  async function showConfigErrorsIfAny(ctx) {
6759
6968
  const errors = getConfigLoadErrors();
6760
6969
  if (errors.length === 0)
@@ -6832,16 +7041,17 @@ var init_auto_update_checker = __esm(() => {
6832
7041
  init_logger();
6833
7042
  init_config_errors();
6834
7043
  init_config_manager();
7044
+ init_model_availability();
6835
7045
  init_checker();
6836
7046
  init_cache();
6837
7047
  SISYPHUS_SPINNER = ["\xB7", "\u2022", "\u25CF", "\u25CB", "\u25CC", "\u25E6", " "];
6838
7048
  });
6839
7049
 
6840
7050
  // src/hooks/auto-update-checker/checker.ts
6841
- import * as fs4 from "fs";
6842
- import * as path4 from "path";
7051
+ import * as fs3 from "fs";
7052
+ import * as path5 from "path";
6843
7053
  import { fileURLToPath } from "url";
6844
- import * as os3 from "os";
7054
+ import * as os4 from "os";
6845
7055
  function isLocalDevMode(directory) {
6846
7056
  return getLocalDevPath(directory) !== null;
6847
7057
  }
@@ -6850,18 +7060,18 @@ function stripJsonComments(json2) {
6850
7060
  }
6851
7061
  function getConfigPaths(directory) {
6852
7062
  const paths = [
6853
- path4.join(directory, ".opencode", "opencode.json"),
6854
- path4.join(directory, ".opencode", "opencode.jsonc"),
7063
+ path5.join(directory, ".opencode", "opencode.json"),
7064
+ path5.join(directory, ".opencode", "opencode.jsonc"),
6855
7065
  USER_OPENCODE_CONFIG,
6856
7066
  USER_OPENCODE_CONFIG_JSONC
6857
7067
  ];
6858
7068
  if (process.platform === "win32") {
6859
- const crossPlatformDir = path4.join(os3.homedir(), ".config");
7069
+ const crossPlatformDir = path5.join(os4.homedir(), ".config");
6860
7070
  const appdataDir = getWindowsAppdataDir();
6861
7071
  if (appdataDir) {
6862
7072
  const alternateDir = USER_CONFIG_DIR === crossPlatformDir ? appdataDir : crossPlatformDir;
6863
- const alternateConfig = path4.join(alternateDir, "opencode", "opencode.json");
6864
- const alternateConfigJsonc = path4.join(alternateDir, "opencode", "opencode.jsonc");
7073
+ const alternateConfig = path5.join(alternateDir, "opencode", "opencode.json");
7074
+ const alternateConfigJsonc = path5.join(alternateDir, "opencode", "opencode.jsonc");
6865
7075
  if (!paths.includes(alternateConfig)) {
6866
7076
  paths.push(alternateConfig);
6867
7077
  }
@@ -6875,9 +7085,9 @@ function getConfigPaths(directory) {
6875
7085
  function getLocalDevPath(directory) {
6876
7086
  for (const configPath of getConfigPaths(directory)) {
6877
7087
  try {
6878
- if (!fs4.existsSync(configPath))
7088
+ if (!fs3.existsSync(configPath))
6879
7089
  continue;
6880
- const content = fs4.readFileSync(configPath, "utf-8");
7090
+ const content = fs3.readFileSync(configPath, "utf-8");
6881
7091
  const config = JSON.parse(stripJsonComments(content));
6882
7092
  const plugins = config.plugin ?? [];
6883
7093
  for (const entry of plugins) {
@@ -6897,19 +7107,19 @@ function getLocalDevPath(directory) {
6897
7107
  }
6898
7108
  function findPackageJsonUp(startPath) {
6899
7109
  try {
6900
- const stat = fs4.statSync(startPath);
6901
- let dir = stat.isDirectory() ? startPath : path4.dirname(startPath);
7110
+ const stat = fs3.statSync(startPath);
7111
+ let dir = stat.isDirectory() ? startPath : path5.dirname(startPath);
6902
7112
  for (let i2 = 0;i2 < 10; i2++) {
6903
- const pkgPath = path4.join(dir, "package.json");
6904
- if (fs4.existsSync(pkgPath)) {
7113
+ const pkgPath = path5.join(dir, "package.json");
7114
+ if (fs3.existsSync(pkgPath)) {
6905
7115
  try {
6906
- const content = fs4.readFileSync(pkgPath, "utf-8");
7116
+ const content = fs3.readFileSync(pkgPath, "utf-8");
6907
7117
  const pkg = JSON.parse(content);
6908
7118
  if (pkg.name === PACKAGE_NAME2)
6909
7119
  return pkgPath;
6910
7120
  } catch {}
6911
7121
  }
6912
- const parent = path4.dirname(dir);
7122
+ const parent = path5.dirname(dir);
6913
7123
  if (parent === dir)
6914
7124
  break;
6915
7125
  dir = parent;
@@ -6925,7 +7135,7 @@ function getLocalDevVersion(directory) {
6925
7135
  const pkgPath = findPackageJsonUp(localPath);
6926
7136
  if (!pkgPath)
6927
7137
  return null;
6928
- const content = fs4.readFileSync(pkgPath, "utf-8");
7138
+ const content = fs3.readFileSync(pkgPath, "utf-8");
6929
7139
  const pkg = JSON.parse(content);
6930
7140
  return pkg.version ?? null;
6931
7141
  } catch {
@@ -6935,9 +7145,9 @@ function getLocalDevVersion(directory) {
6935
7145
  function findPluginEntry(directory) {
6936
7146
  for (const configPath of getConfigPaths(directory)) {
6937
7147
  try {
6938
- if (!fs4.existsSync(configPath))
7148
+ if (!fs3.existsSync(configPath))
6939
7149
  continue;
6940
- const content = fs4.readFileSync(configPath, "utf-8");
7150
+ const content = fs3.readFileSync(configPath, "utf-8");
6941
7151
  const config = JSON.parse(stripJsonComments(content));
6942
7152
  const plugins = config.plugin ?? [];
6943
7153
  for (const entry of plugins) {
@@ -6958,18 +7168,18 @@ function findPluginEntry(directory) {
6958
7168
  }
6959
7169
  function getCachedVersion() {
6960
7170
  try {
6961
- if (fs4.existsSync(INSTALLED_PACKAGE_JSON)) {
6962
- const content = fs4.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
7171
+ if (fs3.existsSync(INSTALLED_PACKAGE_JSON)) {
7172
+ const content = fs3.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
6963
7173
  const pkg = JSON.parse(content);
6964
7174
  if (pkg.version)
6965
7175
  return pkg.version;
6966
7176
  }
6967
7177
  } catch {}
6968
7178
  try {
6969
- const currentDir = path4.dirname(fileURLToPath(import.meta.url));
7179
+ const currentDir = path5.dirname(fileURLToPath(import.meta.url));
6970
7180
  const pkgPath = findPackageJsonUp(currentDir);
6971
7181
  if (pkgPath) {
6972
- const content = fs4.readFileSync(pkgPath, "utf-8");
7182
+ const content = fs3.readFileSync(pkgPath, "utf-8");
6973
7183
  const pkg = JSON.parse(content);
6974
7184
  if (pkg.version)
6975
7185
  return pkg.version;
@@ -6981,7 +7191,7 @@ function getCachedVersion() {
6981
7191
  }
6982
7192
  function updatePinnedVersion(configPath, oldEntry, newVersion) {
6983
7193
  try {
6984
- const content = fs4.readFileSync(configPath, "utf-8");
7194
+ const content = fs3.readFileSync(configPath, "utf-8");
6985
7195
  const newEntry = `${PACKAGE_NAME2}@${newVersion}`;
6986
7196
  const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
6987
7197
  if (!pluginMatch || pluginMatch.index === undefined) {
@@ -7013,7 +7223,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
7013
7223
  log(`[auto-update-checker] No changes made to ${configPath}`);
7014
7224
  return false;
7015
7225
  }
7016
- fs4.writeFileSync(configPath, updatedContent, "utf-8");
7226
+ fs3.writeFileSync(configPath, updatedContent, "utf-8");
7017
7227
  log(`[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
7018
7228
  return true;
7019
7229
  } catch (err) {
@@ -7672,7 +7882,7 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
7672
7882
  // package.json
7673
7883
  var package_default = {
7674
7884
  name: "oh-my-opencode",
7675
- version: "3.0.0-beta.9",
7885
+ version: "3.0.0",
7676
7886
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
7677
7887
  main: "dist/index.js",
7678
7888
  types: "dist/index.d.ts",
@@ -7728,18 +7938,14 @@ var package_default = {
7728
7938
  "@clack/prompts": "^0.11.0",
7729
7939
  "@code-yeongyu/comment-checker": "^0.6.1",
7730
7940
  "@modelcontextprotocol/sdk": "^1.25.1",
7731
- "@openauthjs/openauth": "^0.4.3",
7732
7941
  "@opencode-ai/plugin": "^1.1.19",
7733
7942
  "@opencode-ai/sdk": "^1.1.19",
7734
7943
  commander: "^14.0.2",
7735
7944
  "detect-libc": "^2.0.0",
7736
- hono: "^4.10.4",
7737
7945
  "js-yaml": "^4.1.1",
7738
7946
  "jsonc-parser": "^3.3.1",
7739
- open: "^11.0.0",
7740
7947
  picocolors: "^1.1.1",
7741
7948
  picomatch: "^4.0.2",
7742
- "xdg-basedir": "^5.1.0",
7743
7949
  zod: "^4.1.8"
7744
7950
  },
7745
7951
  devDependencies: {
@@ -7749,13 +7955,13 @@ var package_default = {
7749
7955
  typescript: "^5.7.3"
7750
7956
  },
7751
7957
  optionalDependencies: {
7752
- "oh-my-opencode-darwin-arm64": "3.0.0-beta.9",
7753
- "oh-my-opencode-darwin-x64": "3.0.0-beta.9",
7754
- "oh-my-opencode-linux-arm64": "3.0.0-beta.9",
7755
- "oh-my-opencode-linux-arm64-musl": "3.0.0-beta.9",
7756
- "oh-my-opencode-linux-x64": "3.0.0-beta.9",
7757
- "oh-my-opencode-linux-x64-musl": "3.0.0-beta.9",
7758
- "oh-my-opencode-windows-x64": "3.0.0-beta.9"
7958
+ "oh-my-opencode-darwin-arm64": "3.0.0",
7959
+ "oh-my-opencode-darwin-x64": "3.0.0",
7960
+ "oh-my-opencode-linux-arm64": "3.0.0",
7961
+ "oh-my-opencode-linux-arm64-musl": "3.0.0",
7962
+ "oh-my-opencode-linux-x64": "3.0.0",
7963
+ "oh-my-opencode-linux-x64-musl": "3.0.0",
7964
+ "oh-my-opencode-windows-x64": "3.0.0"
7759
7965
  },
7760
7966
  trustedDependencies: [
7761
7967
  "@ast-grep/cli",
@@ -7767,13 +7973,13 @@ var package_default = {
7767
7973
  // src/cli/install.ts
7768
7974
  var VERSION = package_default.version;
7769
7975
  var SYMBOLS = {
7770
- check: import_picocolors2.default.green("\u2713"),
7771
- cross: import_picocolors2.default.red("\u2717"),
7772
- arrow: import_picocolors2.default.cyan("\u2192"),
7773
- bullet: import_picocolors2.default.dim("\u2022"),
7774
- info: import_picocolors2.default.blue("\u2139"),
7775
- warn: import_picocolors2.default.yellow("\u26A0"),
7776
- star: import_picocolors2.default.yellow("\u2605")
7976
+ check: import_picocolors2.default.green("[OK]"),
7977
+ cross: import_picocolors2.default.red("[X]"),
7978
+ arrow: import_picocolors2.default.cyan("->"),
7979
+ bullet: import_picocolors2.default.dim("*"),
7980
+ info: import_picocolors2.default.blue("[i]"),
7981
+ warn: import_picocolors2.default.yellow("[!]"),
7982
+ star: import_picocolors2.default.yellow("*")
7777
7983
  };
7778
7984
  function formatProvider(name, enabled, detail) {
7779
7985
  const status = enabled ? SYMBOLS.check : import_picocolors2.default.dim("\u25CB");
@@ -7787,22 +7993,18 @@ function formatConfigSummary(config) {
7787
7993
  lines.push("");
7788
7994
  const claudeDetail = config.hasClaude ? config.isMax20 ? "max20" : "standard" : undefined;
7789
7995
  lines.push(formatProvider("Claude", config.hasClaude, claudeDetail));
7790
- lines.push(formatProvider("ChatGPT", config.hasChatGPT));
7996
+ lines.push(formatProvider("OpenAI/ChatGPT", config.hasOpenAI, "GPT-5.2 for Oracle"));
7791
7997
  lines.push(formatProvider("Gemini", config.hasGemini));
7792
- lines.push(formatProvider("GitHub Copilot", config.hasCopilot, "fallback provider"));
7998
+ lines.push(formatProvider("GitHub Copilot", config.hasCopilot, "fallback"));
7999
+ lines.push(formatProvider("OpenCode Zen", config.hasOpencodeZen, "opencode/ models"));
8000
+ lines.push(formatProvider("Z.ai Coding Plan", config.hasZaiCodingPlan, "Librarian/Multimodal"));
7793
8001
  lines.push("");
7794
8002
  lines.push(import_picocolors2.default.dim("\u2500".repeat(40)));
7795
8003
  lines.push("");
7796
- lines.push(import_picocolors2.default.bold(import_picocolors2.default.white("Agent Configuration")));
8004
+ lines.push(import_picocolors2.default.bold(import_picocolors2.default.white("Model Assignment")));
7797
8005
  lines.push("");
7798
- const sisyphusModel = config.hasClaude ? "claude-opus-4-5" : config.hasCopilot ? "github-copilot/claude-opus-4.5" : "glm-4.7-free";
7799
- const oracleModel = config.hasChatGPT ? "gpt-5.2" : config.hasCopilot ? "github-copilot/gpt-5.2" : config.hasClaude ? "claude-opus-4-5" : "glm-4.7-free";
7800
- const librarianModel = "glm-4.7-free";
7801
- const frontendModel = config.hasGemini ? "antigravity-gemini-3-pro-high" : config.hasClaude ? "claude-opus-4-5" : "glm-4.7-free";
7802
- lines.push(` ${SYMBOLS.bullet} Sisyphus ${SYMBOLS.arrow} ${import_picocolors2.default.cyan(sisyphusModel)}`);
7803
- lines.push(` ${SYMBOLS.bullet} Oracle ${SYMBOLS.arrow} ${import_picocolors2.default.cyan(oracleModel)}`);
7804
- lines.push(` ${SYMBOLS.bullet} Librarian ${SYMBOLS.arrow} ${import_picocolors2.default.cyan(librarianModel)}`);
7805
- lines.push(` ${SYMBOLS.bullet} Frontend ${SYMBOLS.arrow} ${import_picocolors2.default.cyan(frontendModel)}`);
8006
+ lines.push(` ${SYMBOLS.info} Models auto-configured based on provider priority`);
8007
+ lines.push(` ${SYMBOLS.bullet} Priority: Native > Copilot > OpenCode Zen > Z.ai`);
7806
8008
  return lines.join(`
7807
8009
  `);
7808
8010
  }
@@ -7854,11 +8056,6 @@ function validateNonTuiArgs(args) {
7854
8056
  } else if (!["no", "yes", "max20"].includes(args.claude)) {
7855
8057
  errors.push(`Invalid --claude value: ${args.claude} (expected: no, yes, max20)`);
7856
8058
  }
7857
- if (args.chatgpt === undefined) {
7858
- errors.push("--chatgpt is required (values: no, yes)");
7859
- } else if (!["no", "yes"].includes(args.chatgpt)) {
7860
- errors.push(`Invalid --chatgpt value: ${args.chatgpt} (expected: no, yes)`);
7861
- }
7862
8059
  if (args.gemini === undefined) {
7863
8060
  errors.push("--gemini is required (values: no, yes)");
7864
8061
  } else if (!["no", "yes"].includes(args.gemini)) {
@@ -7869,15 +8066,26 @@ function validateNonTuiArgs(args) {
7869
8066
  } else if (!["no", "yes"].includes(args.copilot)) {
7870
8067
  errors.push(`Invalid --copilot value: ${args.copilot} (expected: no, yes)`);
7871
8068
  }
8069
+ if (args.openai !== undefined && !["no", "yes"].includes(args.openai)) {
8070
+ errors.push(`Invalid --openai value: ${args.openai} (expected: no, yes)`);
8071
+ }
8072
+ if (args.opencodeZen !== undefined && !["no", "yes"].includes(args.opencodeZen)) {
8073
+ errors.push(`Invalid --opencode-zen value: ${args.opencodeZen} (expected: no, yes)`);
8074
+ }
8075
+ if (args.zaiCodingPlan !== undefined && !["no", "yes"].includes(args.zaiCodingPlan)) {
8076
+ errors.push(`Invalid --zai-coding-plan value: ${args.zaiCodingPlan} (expected: no, yes)`);
8077
+ }
7872
8078
  return { valid: errors.length === 0, errors };
7873
8079
  }
7874
8080
  function argsToConfig(args) {
7875
8081
  return {
7876
8082
  hasClaude: args.claude !== "no",
7877
8083
  isMax20: args.claude === "max20",
7878
- hasChatGPT: args.chatgpt === "yes",
8084
+ hasOpenAI: args.openai === "yes",
7879
8085
  hasGemini: args.gemini === "yes",
7880
- hasCopilot: args.copilot === "yes"
8086
+ hasCopilot: args.copilot === "yes",
8087
+ hasOpencodeZen: args.opencodeZen === "yes",
8088
+ hasZaiCodingPlan: args.zaiCodingPlan === "yes"
7881
8089
  };
7882
8090
  }
7883
8091
  function detectedToInitialValues(detected) {
@@ -7887,9 +8095,11 @@ function detectedToInitialValues(detected) {
7887
8095
  }
7888
8096
  return {
7889
8097
  claude,
7890
- chatgpt: detected.hasChatGPT ? "yes" : "no",
8098
+ openai: detected.hasOpenAI ? "yes" : "no",
7891
8099
  gemini: detected.hasGemini ? "yes" : "no",
7892
- copilot: detected.hasCopilot ? "yes" : "no"
8100
+ copilot: detected.hasCopilot ? "yes" : "no",
8101
+ opencodeZen: detected.hasOpencodeZen ? "yes" : "no",
8102
+ zaiCodingPlan: detected.hasZaiCodingPlan ? "yes" : "no"
7893
8103
  };
7894
8104
  }
7895
8105
  async function runTuiMode(detected) {
@@ -7897,7 +8107,7 @@ async function runTuiMode(detected) {
7897
8107
  const claude = await ve({
7898
8108
  message: "Do you have a Claude Pro/Max subscription?",
7899
8109
  options: [
7900
- { value: "no", label: "No", hint: "Will use opencode/glm-4.7-free as fallback" },
8110
+ { value: "no", label: "No", hint: "Will use opencode/big-pickle as fallback" },
7901
8111
  { value: "yes", label: "Yes (standard)", hint: "Claude Opus 4.5 for orchestration" },
7902
8112
  { value: "max20", label: "Yes (max20 mode)", hint: "Full power with Claude Sonnet 4.5 for Librarian" }
7903
8113
  ],
@@ -7907,15 +8117,15 @@ async function runTuiMode(detected) {
7907
8117
  xe("Installation cancelled.");
7908
8118
  return null;
7909
8119
  }
7910
- const chatgpt = await ve({
7911
- message: "Do you have a ChatGPT Plus/Pro subscription?",
8120
+ const openai = await ve({
8121
+ message: "Do you have an OpenAI/ChatGPT Plus subscription?",
7912
8122
  options: [
7913
- { value: "no", label: "No", hint: "Oracle will use fallback model" },
7914
- { value: "yes", label: "Yes", hint: "GPT-5.2 for debugging and architecture" }
8123
+ { value: "no", label: "No", hint: "Oracle will use fallback models" },
8124
+ { value: "yes", label: "Yes", hint: "GPT-5.2 for Oracle (high-IQ debugging)" }
7915
8125
  ],
7916
- initialValue: initial.chatgpt
8126
+ initialValue: initial.openai
7917
8127
  });
7918
- if (pD(chatgpt)) {
8128
+ if (pD(openai)) {
7919
8129
  xe("Installation cancelled.");
7920
8130
  return null;
7921
8131
  }
@@ -7943,12 +8153,38 @@ async function runTuiMode(detected) {
7943
8153
  xe("Installation cancelled.");
7944
8154
  return null;
7945
8155
  }
8156
+ const opencodeZen = await ve({
8157
+ message: "Do you have access to OpenCode Zen (opencode/ models)?",
8158
+ options: [
8159
+ { value: "no", label: "No", hint: "Will use other configured providers" },
8160
+ { value: "yes", label: "Yes", hint: "opencode/claude-opus-4-5, opencode/gpt-5.2, etc." }
8161
+ ],
8162
+ initialValue: initial.opencodeZen
8163
+ });
8164
+ if (pD(opencodeZen)) {
8165
+ xe("Installation cancelled.");
8166
+ return null;
8167
+ }
8168
+ const zaiCodingPlan = await ve({
8169
+ message: "Do you have a Z.ai Coding Plan subscription?",
8170
+ options: [
8171
+ { value: "no", label: "No", hint: "Will use other configured providers" },
8172
+ { value: "yes", label: "Yes", hint: "Fallback for Librarian and Multimodal Looker" }
8173
+ ],
8174
+ initialValue: initial.zaiCodingPlan
8175
+ });
8176
+ if (pD(zaiCodingPlan)) {
8177
+ xe("Installation cancelled.");
8178
+ return null;
8179
+ }
7946
8180
  return {
7947
8181
  hasClaude: claude !== "no",
7948
8182
  isMax20: claude === "max20",
7949
- hasChatGPT: chatgpt === "yes",
8183
+ hasOpenAI: openai === "yes",
7950
8184
  hasGemini: gemini === "yes",
7951
- hasCopilot: copilot === "yes"
8185
+ hasCopilot: copilot === "yes",
8186
+ hasOpencodeZen: opencodeZen === "yes",
8187
+ hasZaiCodingPlan: zaiCodingPlan === "yes"
7952
8188
  };
7953
8189
  }
7954
8190
  async function runNonTuiInstall(args) {
@@ -7960,7 +8196,7 @@ async function runNonTuiInstall(args) {
7960
8196
  console.log(` ${SYMBOLS.bullet} ${err}`);
7961
8197
  }
7962
8198
  console.log();
7963
- printInfo("Usage: bunx oh-my-opencode install --no-tui --claude=<no|yes|max20> --chatgpt=<no|yes> --gemini=<no|yes> --copilot=<no|yes>");
8199
+ printInfo("Usage: bunx oh-my-opencode install --no-tui --claude=<no|yes|max20> --gemini=<no|yes> --copilot=<no|yes>");
7964
8200
  console.log();
7965
8201
  return 1;
7966
8202
  }
@@ -7971,16 +8207,16 @@ async function runNonTuiInstall(args) {
7971
8207
  let step = 1;
7972
8208
  printStep(step++, totalSteps, "Checking OpenCode installation...");
7973
8209
  const installed = await isOpenCodeInstalled();
8210
+ const version = await getOpenCodeVersion();
7974
8211
  if (!installed) {
7975
- printError("OpenCode is not installed on this system.");
8212
+ printWarning("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.");
7976
8213
  printInfo("Visit https://opencode.ai/docs for installation instructions");
7977
- return 1;
8214
+ } else {
8215
+ printSuccess(`OpenCode ${version ?? ""} detected`);
7978
8216
  }
7979
- const version = await getOpenCodeVersion();
7980
- printSuccess(`OpenCode ${version ?? ""} detected`);
7981
8217
  if (isUpdate) {
7982
8218
  const initial = detectedToInitialValues(detected);
7983
- printInfo(`Current config: Claude=${initial.claude}, ChatGPT=${initial.chatgpt}, Gemini=${initial.gemini}`);
8219
+ printInfo(`Current config: Claude=${initial.claude}, Gemini=${initial.gemini}`);
7984
8220
  }
7985
8221
  const config = argsToConfig(args);
7986
8222
  printStep(step++, totalSteps, "Adding oh-my-opencode plugin...");
@@ -8016,26 +8252,38 @@ async function runNonTuiInstall(args) {
8016
8252
  }
8017
8253
  printSuccess(`Config written ${SYMBOLS.arrow} ${import_picocolors2.default.dim(omoResult.configPath)}`);
8018
8254
  printBox(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
8019
- if (!config.hasClaude && !config.hasChatGPT && !config.hasGemini && !config.hasCopilot) {
8020
- printWarning("No model providers configured. Using opencode/glm-4.7-free as fallback.");
8255
+ if (!config.hasClaude) {
8256
+ console.log();
8257
+ console.log(import_picocolors2.default.bgRed(import_picocolors2.default.white(import_picocolors2.default.bold(" CRITICAL WARNING "))));
8258
+ console.log();
8259
+ console.log(import_picocolors2.default.red(import_picocolors2.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
8260
+ console.log(import_picocolors2.default.red(" Without Claude, you may experience significantly degraded performance:"));
8261
+ console.log(import_picocolors2.default.dim(" \u2022 Reduced orchestration quality"));
8262
+ console.log(import_picocolors2.default.dim(" \u2022 Weaker tool selection and delegation"));
8263
+ console.log(import_picocolors2.default.dim(" \u2022 Less reliable task completion"));
8264
+ console.log();
8265
+ console.log(import_picocolors2.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
8266
+ console.log();
8267
+ }
8268
+ if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
8269
+ printWarning("No model providers configured. Using opencode/big-pickle as fallback.");
8021
8270
  }
8022
8271
  console.log(`${SYMBOLS.star} ${import_picocolors2.default.bold(import_picocolors2.default.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`);
8023
8272
  console.log(` Run ${import_picocolors2.default.cyan("opencode")} to start!`);
8024
8273
  console.log();
8025
8274
  printBox(`${import_picocolors2.default.bold("Pro Tip:")} Include ${import_picocolors2.default.cyan("ultrawork")} (or ${import_picocolors2.default.cyan("ulw")}) in your prompt.
8026
8275
  ` + `All features work like magic\u2014parallel agents, background tasks,
8027
- ` + `deep exploration, and relentless execution until completion.`, "\uD83E\uDE84 The Magic Word");
8276
+ ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
8028
8277
  console.log(`${SYMBOLS.star} ${import_picocolors2.default.yellow("If you found this helpful, consider starring the repo!")}`);
8029
8278
  console.log(` ${import_picocolors2.default.dim("gh repo star code-yeongyu/oh-my-opencode")}`);
8030
8279
  console.log();
8031
8280
  console.log(import_picocolors2.default.dim("oMoMoMoMo... Enjoy!"));
8032
8281
  console.log();
8033
- if ((config.hasClaude || config.hasChatGPT || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
8282
+ if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
8034
8283
  printBox(`Run ${import_picocolors2.default.cyan("opencode auth login")} and select your provider:
8035
8284
  ` + (config.hasClaude ? ` ${SYMBOLS.bullet} Anthropic ${import_picocolors2.default.gray("\u2192 Claude Pro/Max")}
8036
- ` : "") + (config.hasChatGPT ? ` ${SYMBOLS.bullet} OpenAI ${import_picocolors2.default.gray("\u2192 ChatGPT Plus/Pro")}
8037
8285
  ` : "") + (config.hasGemini ? ` ${SYMBOLS.bullet} Google ${import_picocolors2.default.gray("\u2192 OAuth with Antigravity")}
8038
- ` : "") + (config.hasCopilot ? ` ${SYMBOLS.bullet} GitHub ${import_picocolors2.default.gray("\u2192 Copilot")}` : ""), "\uD83D\uDD10 Authenticate Your Providers");
8286
+ ` : "") + (config.hasCopilot ? ` ${SYMBOLS.bullet} GitHub ${import_picocolors2.default.gray("\u2192 Copilot")}` : ""), "Authenticate Your Providers");
8039
8287
  }
8040
8288
  return 0;
8041
8289
  }
@@ -8048,20 +8296,19 @@ async function install(args) {
8048
8296
  Ie(import_picocolors2.default.bgMagenta(import_picocolors2.default.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... ")));
8049
8297
  if (isUpdate) {
8050
8298
  const initial = detectedToInitialValues(detected);
8051
- M2.info(`Existing configuration detected: Claude=${initial.claude}, ChatGPT=${initial.chatgpt}, Gemini=${initial.gemini}`);
8299
+ M2.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`);
8052
8300
  }
8053
8301
  const s = Y2();
8054
8302
  s.start("Checking OpenCode installation");
8055
8303
  const installed = await isOpenCodeInstalled();
8304
+ const version = await getOpenCodeVersion();
8056
8305
  if (!installed) {
8057
- s.stop("OpenCode is not installed");
8058
- M2.error("OpenCode is not installed on this system.");
8306
+ s.stop(`OpenCode binary not found ${import_picocolors2.default.yellow("[!]")}`);
8307
+ M2.warn("OpenCode binary not found. Plugin will be configured, but you'll need to install OpenCode to use it.");
8059
8308
  Me("Visit https://opencode.ai/docs for installation instructions", "Installation Guide");
8060
- Se(import_picocolors2.default.red("Please install OpenCode first."));
8061
- return 1;
8309
+ } else {
8310
+ s.stop(`OpenCode ${version ?? "installed"} ${import_picocolors2.default.green("[OK]")}`);
8062
8311
  }
8063
- const version = await getOpenCodeVersion();
8064
- s.stop(`OpenCode ${version ?? "installed"} ${import_picocolors2.default.green("\u2713")}`);
8065
8312
  const config = await runTuiMode(detected);
8066
8313
  if (!config)
8067
8314
  return 1;
@@ -8099,30 +8346,41 @@ async function install(args) {
8099
8346
  return 1;
8100
8347
  }
8101
8348
  s.stop(`Config written to ${import_picocolors2.default.cyan(omoResult.configPath)}`);
8102
- if (!config.hasClaude && !config.hasChatGPT && !config.hasGemini && !config.hasCopilot) {
8103
- M2.warn("No model providers configured. Using opencode/glm-4.7-free as fallback.");
8349
+ if (!config.hasClaude) {
8350
+ console.log();
8351
+ console.log(import_picocolors2.default.bgRed(import_picocolors2.default.white(import_picocolors2.default.bold(" CRITICAL WARNING "))));
8352
+ console.log();
8353
+ console.log(import_picocolors2.default.red(import_picocolors2.default.bold(" Sisyphus agent is STRONGLY optimized for Claude Opus 4.5.")));
8354
+ console.log(import_picocolors2.default.red(" Without Claude, you may experience significantly degraded performance:"));
8355
+ console.log(import_picocolors2.default.dim(" \u2022 Reduced orchestration quality"));
8356
+ console.log(import_picocolors2.default.dim(" \u2022 Weaker tool selection and delegation"));
8357
+ console.log(import_picocolors2.default.dim(" \u2022 Less reliable task completion"));
8358
+ console.log();
8359
+ console.log(import_picocolors2.default.yellow(" Consider subscribing to Claude Pro/Max for the best experience."));
8360
+ console.log();
8361
+ }
8362
+ if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
8363
+ M2.warn("No model providers configured. Using opencode/big-pickle as fallback.");
8104
8364
  }
8105
8365
  Me(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
8106
8366
  M2.success(import_picocolors2.default.bold(isUpdate ? "Configuration updated!" : "Installation complete!"));
8107
8367
  M2.message(`Run ${import_picocolors2.default.cyan("opencode")} to start!`);
8108
8368
  Me(`Include ${import_picocolors2.default.cyan("ultrawork")} (or ${import_picocolors2.default.cyan("ulw")}) in your prompt.
8109
8369
  ` + `All features work like magic\u2014parallel agents, background tasks,
8110
- ` + `deep exploration, and relentless execution until completion.`, "\uD83E\uDE84 The Magic Word");
8370
+ ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
8111
8371
  M2.message(`${import_picocolors2.default.yellow("\u2605")} If you found this helpful, consider starring the repo!`);
8112
8372
  M2.message(` ${import_picocolors2.default.dim("gh repo star code-yeongyu/oh-my-opencode")}`);
8113
8373
  Se(import_picocolors2.default.green("oMoMoMoMo... Enjoy!"));
8114
- if ((config.hasClaude || config.hasChatGPT || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
8374
+ if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
8115
8375
  const providers = [];
8116
8376
  if (config.hasClaude)
8117
8377
  providers.push(`Anthropic ${import_picocolors2.default.gray("\u2192 Claude Pro/Max")}`);
8118
- if (config.hasChatGPT)
8119
- providers.push(`OpenAI ${import_picocolors2.default.gray("\u2192 ChatGPT Plus/Pro")}`);
8120
8378
  if (config.hasGemini)
8121
8379
  providers.push(`Google ${import_picocolors2.default.gray("\u2192 OAuth with Antigravity")}`);
8122
8380
  if (config.hasCopilot)
8123
8381
  providers.push(`GitHub ${import_picocolors2.default.gray("\u2192 Copilot")}`);
8124
8382
  console.log();
8125
- console.log(import_picocolors2.default.bold("\uD83D\uDD10 Authenticate Your Providers"));
8383
+ console.log(import_picocolors2.default.bold("Authenticate Your Providers"));
8126
8384
  console.log();
8127
8385
  console.log(` Run ${import_picocolors2.default.cyan("opencode auth login")} and select:`);
8128
8386
  for (const provider of providers) {
@@ -8366,7 +8624,7 @@ var serializeObjectParam = ({ allowReserved, explode, name, style, value, valueO
8366
8624
 
8367
8625
  // node_modules/@opencode-ai/sdk/dist/gen/core/utils.gen.js
8368
8626
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
8369
- var defaultPathSerializer = ({ path: path2, url: _url }) => {
8627
+ var defaultPathSerializer = ({ path: path3, url: _url }) => {
8370
8628
  let url = _url;
8371
8629
  const matches = _url.match(PATH_PARAM_RE);
8372
8630
  if (matches) {
@@ -8385,7 +8643,7 @@ var defaultPathSerializer = ({ path: path2, url: _url }) => {
8385
8643
  name = name.substring(1);
8386
8644
  style = "matrix";
8387
8645
  }
8388
- const value = path2[name];
8646
+ const value = path3[name];
8389
8647
  if (value === undefined || value === null) {
8390
8648
  continue;
8391
8649
  }
@@ -8416,11 +8674,11 @@ var defaultPathSerializer = ({ path: path2, url: _url }) => {
8416
8674
  }
8417
8675
  return url;
8418
8676
  };
8419
- var getUrl = ({ baseUrl, path: path2, query, querySerializer, url: _url }) => {
8677
+ var getUrl = ({ baseUrl, path: path3, query, querySerializer, url: _url }) => {
8420
8678
  const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
8421
8679
  let url = (baseUrl ?? "") + pathUrl;
8422
- if (path2) {
8423
- url = defaultPathSerializer({ path: path2, url });
8680
+ if (path3) {
8681
+ url = defaultPathSerializer({ path: path3, url });
8424
8682
  }
8425
8683
  let search = query ? querySerializer(query) : "";
8426
8684
  if (search.startsWith("?")) {
@@ -9736,7 +9994,7 @@ function logEventVerbose(ctx, payload) {
9736
9994
  const toolName = toolProps?.name ?? "unknown";
9737
9995
  const input = toolProps?.input ?? {};
9738
9996
  const inputStr = JSON.stringify(input).slice(0, 150);
9739
- console.error(import_picocolors4.default.cyan(`${sessionTag} \u26A1 TOOL.EXECUTE: ${import_picocolors4.default.bold(toolName)}`));
9997
+ console.error(import_picocolors4.default.cyan(`${sessionTag} TOOL.EXECUTE: ${import_picocolors4.default.bold(toolName)}`));
9740
9998
  console.error(import_picocolors4.default.dim(` input: ${inputStr}${inputStr.length >= 150 ? "..." : ""}`));
9741
9999
  break;
9742
10000
  }
@@ -9744,13 +10002,13 @@ function logEventVerbose(ctx, payload) {
9744
10002
  const resultProps = props;
9745
10003
  const output = resultProps?.output ?? "";
9746
10004
  const preview = output.slice(0, 200).replace(/\n/g, "\\n");
9747
- console.error(import_picocolors4.default.green(`${sessionTag} \u2713 TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
10005
+ console.error(import_picocolors4.default.green(`${sessionTag} TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
9748
10006
  break;
9749
10007
  }
9750
10008
  case "session.error": {
9751
10009
  const errorProps = props;
9752
10010
  const errorMsg = serializeError(errorProps?.error);
9753
- console.error(import_picocolors4.default.red(`${sessionTag} \u274C SESSION.ERROR: ${errorMsg}`));
10011
+ console.error(import_picocolors4.default.red(`${sessionTag} SESSION.ERROR: ${errorMsg}`));
9754
10012
  break;
9755
10013
  }
9756
10014
  default:
@@ -9844,7 +10102,7 @@ function handleToolExecute(ctx, payload, state) {
9844
10102
  }
9845
10103
  }
9846
10104
  process.stdout.write(`
9847
- ${import_picocolors4.default.cyan("\u26A1")} ${import_picocolors4.default.bold(toolName)}${inputPreview}
10105
+ ${import_picocolors4.default.cyan(">")} ${import_picocolors4.default.bold(toolName)}${inputPreview}
9848
10106
  `);
9849
10107
  }
9850
10108
  function handleToolResult(ctx, payload, state) {
@@ -9870,6 +10128,8 @@ function handleToolResult(ctx, payload, state) {
9870
10128
  // src/cli/run/runner.ts
9871
10129
  var POLL_INTERVAL_MS = 500;
9872
10130
  var DEFAULT_TIMEOUT_MS = 0;
10131
+ var SESSION_CREATE_MAX_RETRIES = 3;
10132
+ var SESSION_CREATE_RETRY_DELAY_MS = 1000;
9873
10133
  async function run(options) {
9874
10134
  const {
9875
10135
  message,
@@ -9903,12 +10163,39 @@ Interrupted. Shutting down...`));
9903
10163
  process.exit(130);
9904
10164
  });
9905
10165
  try {
9906
- const sessionRes = await client3.session.create({
9907
- body: { title: "oh-my-opencode run" }
9908
- });
9909
- const sessionID = sessionRes.data?.id;
10166
+ let sessionID;
10167
+ let lastError;
10168
+ for (let attempt = 1;attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) {
10169
+ const sessionRes = await client3.session.create({
10170
+ body: { title: "oh-my-opencode run" }
10171
+ });
10172
+ if (sessionRes.error) {
10173
+ lastError = sessionRes.error;
10174
+ console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
10175
+ console.error(import_picocolors5.default.dim(` Error: ${serializeError(sessionRes.error)}`));
10176
+ if (attempt < SESSION_CREATE_MAX_RETRIES) {
10177
+ const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
10178
+ console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
10179
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
10180
+ continue;
10181
+ }
10182
+ }
10183
+ sessionID = sessionRes.data?.id;
10184
+ if (sessionID) {
10185
+ break;
10186
+ }
10187
+ lastError = new Error(`Unexpected response: ${JSON.stringify(sessionRes, null, 2)}`);
10188
+ console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`));
10189
+ if (attempt < SESSION_CREATE_MAX_RETRIES) {
10190
+ const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
10191
+ console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
10192
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
10193
+ }
10194
+ }
9910
10195
  if (!sessionID) {
9911
- console.error(import_picocolors5.default.red("Failed to create session"));
10196
+ console.error(import_picocolors5.default.red("Failed to create session after all retries"));
10197
+ console.error(import_picocolors5.default.dim(`Last error: ${serializeError(lastError)}`));
10198
+ cleanup();
9912
10199
  return 1;
9913
10200
  }
9914
10201
  console.log(import_picocolors5.default.dim(`Session: ${sessionID}`));
@@ -9978,13 +10265,13 @@ init_checker();
9978
10265
  // src/cli/get-local-version/formatter.ts
9979
10266
  var import_picocolors6 = __toESM(require_picocolors(), 1);
9980
10267
  var SYMBOLS2 = {
9981
- check: import_picocolors6.default.green("\u2713"),
9982
- cross: import_picocolors6.default.red("\u2717"),
9983
- arrow: import_picocolors6.default.cyan("\u2192"),
9984
- info: import_picocolors6.default.blue("\u2139"),
9985
- warn: import_picocolors6.default.yellow("\u26A0"),
9986
- pin: import_picocolors6.default.magenta("\uD83D\uDCCC"),
9987
- dev: import_picocolors6.default.cyan("\uD83D\uDD27")
10268
+ check: import_picocolors6.default.green("[OK]"),
10269
+ cross: import_picocolors6.default.red("[X]"),
10270
+ arrow: import_picocolors6.default.cyan("->"),
10271
+ info: import_picocolors6.default.blue("[i]"),
10272
+ warn: import_picocolors6.default.yellow("[!]"),
10273
+ pin: import_picocolors6.default.magenta("[PINNED]"),
10274
+ dev: import_picocolors6.default.cyan("[DEV]")
9988
10275
  };
9989
10276
  function formatVersionOutput(info) {
9990
10277
  const lines = [];
@@ -10143,6 +10430,7 @@ var CHECK_IDS = {
10143
10430
  OPENCODE_INSTALLATION: "opencode-installation",
10144
10431
  PLUGIN_REGISTRATION: "plugin-registration",
10145
10432
  CONFIG_VALIDATION: "config-validation",
10433
+ MODEL_RESOLUTION: "model-resolution",
10146
10434
  AUTH_ANTHROPIC: "auth-anthropic",
10147
10435
  AUTH_OPENAI: "auth-openai",
10148
10436
  AUTH_GOOGLE: "auth-google",
@@ -10159,6 +10447,7 @@ var CHECK_NAMES = {
10159
10447
  [CHECK_IDS.OPENCODE_INSTALLATION]: "OpenCode Installation",
10160
10448
  [CHECK_IDS.PLUGIN_REGISTRATION]: "Plugin Registration",
10161
10449
  [CHECK_IDS.CONFIG_VALIDATION]: "Configuration Validity",
10450
+ [CHECK_IDS.MODEL_RESOLUTION]: "Model Resolution",
10162
10451
  [CHECK_IDS.AUTH_ANTHROPIC]: "Anthropic (Claude) Auth",
10163
10452
  [CHECK_IDS.AUTH_OPENAI]: "OpenAI (ChatGPT) Auth",
10164
10453
  [CHECK_IDS.AUTH_GOOGLE]: "Google (Gemini) Auth",
@@ -10200,9 +10489,9 @@ function selectBinaryPath(paths, platform) {
10200
10489
  return null;
10201
10490
  if (platform !== "win32")
10202
10491
  return paths[0];
10203
- const normalized = paths.map((path5) => path5.toLowerCase());
10492
+ const normalized = paths.map((path6) => path6.toLowerCase());
10204
10493
  for (const ext of WINDOWS_EXECUTABLE_EXTS) {
10205
- const index = normalized.findIndex((path5) => path5.endsWith(ext));
10494
+ const index = normalized.findIndex((path6) => path6.endsWith(ext));
10206
10495
  if (index !== -1)
10207
10496
  return paths[index];
10208
10497
  }
@@ -10334,7 +10623,7 @@ function getOpenCodeCheckDefinition() {
10334
10623
  }
10335
10624
 
10336
10625
  // src/cli/doctor/checks/plugin.ts
10337
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
10626
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
10338
10627
  init_shared();
10339
10628
  function detectConfigPath() {
10340
10629
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
@@ -10353,6 +10642,9 @@ function findPluginEntry2(plugins) {
10353
10642
  const version = isPinned ? plugin.split("@")[1] : null;
10354
10643
  return { entry: plugin, isPinned, version };
10355
10644
  }
10645
+ if (plugin.startsWith("file://") && plugin.includes(PACKAGE_NAME3)) {
10646
+ return { entry: plugin, isPinned: false, version: "local-dev" };
10647
+ }
10356
10648
  }
10357
10649
  return null;
10358
10650
  }
@@ -10368,7 +10660,7 @@ function getPluginInfo() {
10368
10660
  };
10369
10661
  }
10370
10662
  try {
10371
- const content = readFileSync5(configInfo.path, "utf-8");
10663
+ const content = readFileSync6(configInfo.path, "utf-8");
10372
10664
  const config = parseJsonc(content);
10373
10665
  const plugins = config.plugin ?? [];
10374
10666
  const pluginEntry = findPluginEntry2(plugins);
@@ -10442,9 +10734,8 @@ function getPluginCheckDefinition() {
10442
10734
  }
10443
10735
 
10444
10736
  // src/cli/doctor/checks/config.ts
10445
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
10446
- import { homedir as homedir4 } from "os";
10447
- import { join as join6 } from "path";
10737
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
10738
+ import { join as join8 } from "path";
10448
10739
  init_shared();
10449
10740
 
10450
10741
  // node_modules/zod/v4/classic/external.js
@@ -11176,10 +11467,10 @@ function mergeDefs(...defs) {
11176
11467
  function cloneDef(schema2) {
11177
11468
  return mergeDefs(schema2._zod.def);
11178
11469
  }
11179
- function getElementAtPath(obj, path5) {
11180
- if (!path5)
11470
+ function getElementAtPath(obj, path6) {
11471
+ if (!path6)
11181
11472
  return obj;
11182
- return path5.reduce((acc, key) => acc?.[key], obj);
11473
+ return path6.reduce((acc, key) => acc?.[key], obj);
11183
11474
  }
11184
11475
  function promiseAllObject(promisesObj) {
11185
11476
  const keys = Object.keys(promisesObj);
@@ -11538,11 +11829,11 @@ function aborted(x2, startIndex = 0) {
11538
11829
  }
11539
11830
  return false;
11540
11831
  }
11541
- function prefixIssues(path5, issues) {
11832
+ function prefixIssues(path6, issues) {
11542
11833
  return issues.map((iss) => {
11543
11834
  var _a;
11544
11835
  (_a = iss).path ?? (_a.path = []);
11545
- iss.path.unshift(path5);
11836
+ iss.path.unshift(path6);
11546
11837
  return iss;
11547
11838
  });
11548
11839
  }
@@ -11710,7 +12001,7 @@ function treeifyError(error, _mapper) {
11710
12001
  return issue2.message;
11711
12002
  };
11712
12003
  const result = { errors: [] };
11713
- const processError = (error2, path5 = []) => {
12004
+ const processError = (error2, path6 = []) => {
11714
12005
  var _a, _b;
11715
12006
  for (const issue2 of error2.issues) {
11716
12007
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -11720,7 +12011,7 @@ function treeifyError(error, _mapper) {
11720
12011
  } else if (issue2.code === "invalid_element") {
11721
12012
  processError({ issues: issue2.issues }, issue2.path);
11722
12013
  } else {
11723
- const fullpath = [...path5, ...issue2.path];
12014
+ const fullpath = [...path6, ...issue2.path];
11724
12015
  if (fullpath.length === 0) {
11725
12016
  result.errors.push(mapper(issue2));
11726
12017
  continue;
@@ -11752,8 +12043,8 @@ function treeifyError(error, _mapper) {
11752
12043
  }
11753
12044
  function toDotPath(_path) {
11754
12045
  const segs = [];
11755
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11756
- for (const seg of path5) {
12046
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12047
+ for (const seg of path6) {
11757
12048
  if (typeof seg === "number")
11758
12049
  segs.push(`[${seg}]`);
11759
12050
  else if (typeof seg === "symbol")
@@ -22780,16 +23071,15 @@ var AgentPermissionSchema = exports_external.object({
22780
23071
  external_directory: PermissionValue.optional()
22781
23072
  });
22782
23073
  var BuiltinAgentNameSchema = exports_external.enum([
22783
- "Sisyphus",
23074
+ "sisyphus",
23075
+ "prometheus",
22784
23076
  "oracle",
22785
23077
  "librarian",
22786
23078
  "explore",
22787
- "frontend-ui-ux-engineer",
22788
- "document-writer",
22789
23079
  "multimodal-looker",
22790
- "Metis (Plan Consultant)",
22791
- "Momus (Plan Reviewer)",
22792
- "orchestrator-sisyphus"
23080
+ "metis",
23081
+ "momus",
23082
+ "atlas"
22793
23083
  ]);
22794
23084
  var BuiltinSkillNameSchema = exports_external.enum([
22795
23085
  "playwright",
@@ -22799,19 +23089,17 @@ var BuiltinSkillNameSchema = exports_external.enum([
22799
23089
  var OverridableAgentNameSchema = exports_external.enum([
22800
23090
  "build",
22801
23091
  "plan",
22802
- "Sisyphus",
22803
- "Sisyphus-Junior",
23092
+ "sisyphus",
23093
+ "sisyphus-junior",
22804
23094
  "OpenCode-Builder",
22805
- "Prometheus (Planner)",
22806
- "Metis (Plan Consultant)",
22807
- "Momus (Plan Reviewer)",
23095
+ "prometheus",
23096
+ "metis",
23097
+ "momus",
22808
23098
  "oracle",
22809
23099
  "librarian",
22810
23100
  "explore",
22811
- "frontend-ui-ux-engineer",
22812
- "document-writer",
22813
23101
  "multimodal-looker",
22814
- "orchestrator-sisyphus"
23102
+ "atlas"
22815
23103
  ]);
22816
23104
  var HookNameSchema = exports_external.enum([
22817
23105
  "todo-continuation-enforcer",
@@ -22843,7 +23131,7 @@ var HookNameSchema = exports_external.enum([
22843
23131
  "delegate-task-retry",
22844
23132
  "prometheus-md-only",
22845
23133
  "start-work",
22846
- "sisyphus-orchestrator"
23134
+ "atlas"
22847
23135
  ]);
22848
23136
  var BuiltinCommandNameSchema = exports_external.enum([
22849
23137
  "init-deep",
@@ -22868,19 +23156,17 @@ var AgentOverrideConfigSchema = exports_external.object({
22868
23156
  var AgentOverridesSchema = exports_external.object({
22869
23157
  build: AgentOverrideConfigSchema.optional(),
22870
23158
  plan: AgentOverrideConfigSchema.optional(),
22871
- Sisyphus: AgentOverrideConfigSchema.optional(),
22872
- "Sisyphus-Junior": AgentOverrideConfigSchema.optional(),
23159
+ sisyphus: AgentOverrideConfigSchema.optional(),
23160
+ "sisyphus-junior": AgentOverrideConfigSchema.optional(),
22873
23161
  "OpenCode-Builder": AgentOverrideConfigSchema.optional(),
22874
- "Prometheus (Planner)": AgentOverrideConfigSchema.optional(),
22875
- "Metis (Plan Consultant)": AgentOverrideConfigSchema.optional(),
22876
- "Momus (Plan Reviewer)": AgentOverrideConfigSchema.optional(),
23162
+ prometheus: AgentOverrideConfigSchema.optional(),
23163
+ metis: AgentOverrideConfigSchema.optional(),
23164
+ momus: AgentOverrideConfigSchema.optional(),
22877
23165
  oracle: AgentOverrideConfigSchema.optional(),
22878
23166
  librarian: AgentOverrideConfigSchema.optional(),
22879
23167
  explore: AgentOverrideConfigSchema.optional(),
22880
- "frontend-ui-ux-engineer": AgentOverrideConfigSchema.optional(),
22881
- "document-writer": AgentOverrideConfigSchema.optional(),
22882
23168
  "multimodal-looker": AgentOverrideConfigSchema.optional(),
22883
- "orchestrator-sisyphus": AgentOverrideConfigSchema.optional()
23169
+ atlas: AgentOverrideConfigSchema.optional()
22884
23170
  });
22885
23171
  var ClaudeCodeConfigSchema = exports_external.object({
22886
23172
  mcp: exports_external.boolean().optional(),
@@ -22898,7 +23184,8 @@ var SisyphusAgentConfigSchema = exports_external.object({
22898
23184
  replace_plan: exports_external.boolean().optional()
22899
23185
  });
22900
23186
  var CategoryConfigSchema = exports_external.object({
22901
- model: exports_external.string(),
23187
+ description: exports_external.string().optional(),
23188
+ model: exports_external.string().optional(),
22902
23189
  variant: exports_external.string().optional(),
22903
23190
  temperature: exports_external.number().min(0).max(2).optional(),
22904
23191
  top_p: exports_external.number().min(0).max(1).optional(),
@@ -22907,19 +23194,20 @@ var CategoryConfigSchema = exports_external.object({
22907
23194
  type: exports_external.enum(["enabled", "disabled"]),
22908
23195
  budgetTokens: exports_external.number().optional()
22909
23196
  }).optional(),
22910
- reasoningEffort: exports_external.enum(["low", "medium", "high"]).optional(),
23197
+ reasoningEffort: exports_external.enum(["low", "medium", "high", "xhigh"]).optional(),
22911
23198
  textVerbosity: exports_external.enum(["low", "medium", "high"]).optional(),
22912
23199
  tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional(),
22913
- prompt_append: exports_external.string().optional()
23200
+ prompt_append: exports_external.string().optional(),
23201
+ is_unstable_agent: exports_external.boolean().optional()
22914
23202
  });
22915
23203
  var BuiltinCategoryNameSchema = exports_external.enum([
22916
23204
  "visual-engineering",
22917
23205
  "ultrabrain",
22918
23206
  "artistry",
22919
23207
  "quick",
22920
- "most-capable",
22921
- "writing",
22922
- "general"
23208
+ "unspecified-low",
23209
+ "unspecified-high",
23210
+ "writing"
22923
23211
  ]);
22924
23212
  var CategoriesConfigSchema = exports_external.record(exports_external.string(), CategoryConfigSchema);
22925
23213
  var CommentCheckerConfigSchema = exports_external.object({
@@ -23002,8 +23290,8 @@ var RalphLoopConfigSchema = exports_external.object({
23002
23290
  });
23003
23291
  var BackgroundTaskConfigSchema = exports_external.object({
23004
23292
  defaultConcurrency: exports_external.number().min(1).optional(),
23005
- providerConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(1)).optional(),
23006
- modelConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(1)).optional(),
23293
+ providerConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(0)).optional(),
23294
+ modelConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(0)).optional(),
23007
23295
  staleTimeoutMs: exports_external.number().min(60000).optional()
23008
23296
  });
23009
23297
  var NotificationConfigSchema = exports_external.object({
@@ -23034,9 +23322,9 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
23034
23322
  git_master: GitMasterConfigSchema.optional()
23035
23323
  });
23036
23324
  // src/cli/doctor/checks/config.ts
23037
- var USER_CONFIG_DIR2 = join6(homedir4(), ".config", "opencode");
23038
- var USER_CONFIG_BASE = join6(USER_CONFIG_DIR2, `${PACKAGE_NAME3}`);
23039
- var PROJECT_CONFIG_BASE = join6(process.cwd(), ".opencode", PACKAGE_NAME3);
23325
+ var USER_CONFIG_DIR2 = getOpenCodeConfigDir({ binary: "opencode" });
23326
+ var USER_CONFIG_BASE = join8(USER_CONFIG_DIR2, `${PACKAGE_NAME3}`);
23327
+ var PROJECT_CONFIG_BASE = join8(process.cwd(), ".opencode", PACKAGE_NAME3);
23040
23328
  function findConfigPath() {
23041
23329
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE);
23042
23330
  if (projectDetected.format !== "none") {
@@ -23050,7 +23338,7 @@ function findConfigPath() {
23050
23338
  }
23051
23339
  function validateConfig(configPath) {
23052
23340
  try {
23053
- const content = readFileSync6(configPath, "utf-8");
23341
+ const content = readFileSync7(configPath, "utf-8");
23054
23342
  const rawConfig = parseJsonc(content);
23055
23343
  const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
23056
23344
  if (!result.success) {
@@ -23132,25 +23420,195 @@ function getConfigCheckDefinition() {
23132
23420
  };
23133
23421
  }
23134
23422
 
23423
+ // src/cli/doctor/checks/model-resolution.ts
23424
+ import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
23425
+ init_shared();
23426
+ init_model_requirements();
23427
+ import { homedir as homedir6 } from "os";
23428
+ import { join as join9 } from "path";
23429
+ function getOpenCodeCacheDir2() {
23430
+ const xdgCache = process.env.XDG_CACHE_HOME;
23431
+ if (xdgCache)
23432
+ return join9(xdgCache, "opencode");
23433
+ return join9(homedir6(), ".cache", "opencode");
23434
+ }
23435
+ function loadAvailableModels() {
23436
+ const cacheFile = join9(getOpenCodeCacheDir2(), "models.json");
23437
+ if (!existsSync9(cacheFile)) {
23438
+ return { providers: [], modelCount: 0, cacheExists: false };
23439
+ }
23440
+ try {
23441
+ const content = readFileSync8(cacheFile, "utf-8");
23442
+ const data = JSON.parse(content);
23443
+ const providers = Object.keys(data);
23444
+ let modelCount = 0;
23445
+ for (const providerId of providers) {
23446
+ const models = data[providerId]?.models;
23447
+ if (models && typeof models === "object") {
23448
+ modelCount += Object.keys(models).length;
23449
+ }
23450
+ }
23451
+ return { providers, modelCount, cacheExists: true };
23452
+ } catch {
23453
+ return { providers: [], modelCount: 0, cacheExists: false };
23454
+ }
23455
+ }
23456
+ var PACKAGE_NAME4 = "oh-my-opencode";
23457
+ var USER_CONFIG_DIR3 = join9(homedir6(), ".config", "opencode");
23458
+ var USER_CONFIG_BASE2 = join9(USER_CONFIG_DIR3, PACKAGE_NAME4);
23459
+ var PROJECT_CONFIG_BASE2 = join9(process.cwd(), ".opencode", PACKAGE_NAME4);
23460
+ function loadConfig() {
23461
+ const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE2);
23462
+ if (projectDetected.format !== "none") {
23463
+ try {
23464
+ const content = readFileSync8(projectDetected.path, "utf-8");
23465
+ return parseJsonc(content);
23466
+ } catch {
23467
+ return null;
23468
+ }
23469
+ }
23470
+ const userDetected = detectConfigFile(USER_CONFIG_BASE2);
23471
+ if (userDetected.format !== "none") {
23472
+ try {
23473
+ const content = readFileSync8(userDetected.path, "utf-8");
23474
+ return parseJsonc(content);
23475
+ } catch {
23476
+ return null;
23477
+ }
23478
+ }
23479
+ return null;
23480
+ }
23481
+ function formatProviderChain(providers) {
23482
+ return providers.join(" \u2192 ");
23483
+ }
23484
+ function getEffectiveModel(requirement, userOverride) {
23485
+ if (userOverride) {
23486
+ return userOverride;
23487
+ }
23488
+ const firstEntry = requirement.fallbackChain[0];
23489
+ if (!firstEntry) {
23490
+ return "unknown";
23491
+ }
23492
+ return `${firstEntry.providers[0]}/${firstEntry.model}`;
23493
+ }
23494
+ function buildEffectiveResolution(requirement, userOverride) {
23495
+ if (userOverride) {
23496
+ return `User override: ${userOverride}`;
23497
+ }
23498
+ const firstEntry = requirement.fallbackChain[0];
23499
+ if (!firstEntry) {
23500
+ return "No fallback chain defined";
23501
+ }
23502
+ return `Provider fallback: ${formatProviderChain(firstEntry.providers)} \u2192 ${firstEntry.model}`;
23503
+ }
23504
+ function getModelResolutionInfoWithOverrides(config2) {
23505
+ const agents = Object.entries(AGENT_MODEL_REQUIREMENTS).map(([name, requirement]) => {
23506
+ const userOverride = config2.agents?.[name]?.model;
23507
+ return {
23508
+ name,
23509
+ requirement,
23510
+ userOverride,
23511
+ effectiveModel: getEffectiveModel(requirement, userOverride),
23512
+ effectiveResolution: buildEffectiveResolution(requirement, userOverride)
23513
+ };
23514
+ });
23515
+ const categories = Object.entries(CATEGORY_MODEL_REQUIREMENTS).map(([name, requirement]) => {
23516
+ const userOverride = config2.categories?.[name]?.model;
23517
+ return {
23518
+ name,
23519
+ requirement,
23520
+ userOverride,
23521
+ effectiveModel: getEffectiveModel(requirement, userOverride),
23522
+ effectiveResolution: buildEffectiveResolution(requirement, userOverride)
23523
+ };
23524
+ });
23525
+ return { agents, categories };
23526
+ }
23527
+ function formatModelWithVariant(model, variant) {
23528
+ return variant ? `${model} (${variant})` : model;
23529
+ }
23530
+ function getEffectiveVariant(requirement) {
23531
+ const firstEntry = requirement.fallbackChain[0];
23532
+ return firstEntry?.variant ?? requirement.variant;
23533
+ }
23534
+ function buildDetailsArray(info, available) {
23535
+ const details = [];
23536
+ details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
23537
+ details.push("");
23538
+ if (available.cacheExists) {
23539
+ details.push(` Providers: ${available.providers.length} (${available.providers.slice(0, 8).join(", ")}${available.providers.length > 8 ? "..." : ""})`);
23540
+ details.push(` Total models: ${available.modelCount}`);
23541
+ details.push(` Cache: ~/.cache/opencode/models.json`);
23542
+ details.push(` Refresh: opencode models --refresh`);
23543
+ } else {
23544
+ details.push(" \u26A0 Cache not found. Run 'opencode' to populate.");
23545
+ }
23546
+ details.push("");
23547
+ details.push("\u2550\u2550\u2550 Configured Models \u2550\u2550\u2550");
23548
+ details.push("");
23549
+ details.push("Agents:");
23550
+ for (const agent of info.agents) {
23551
+ const marker = agent.userOverride ? "\u25CF" : "\u25CB";
23552
+ const display = formatModelWithVariant(agent.effectiveModel, getEffectiveVariant(agent.requirement));
23553
+ details.push(` ${marker} ${agent.name}: ${display}`);
23554
+ }
23555
+ details.push("");
23556
+ details.push("Categories:");
23557
+ for (const category of info.categories) {
23558
+ const marker = category.userOverride ? "\u25CF" : "\u25CB";
23559
+ const display = formatModelWithVariant(category.effectiveModel, getEffectiveVariant(category.requirement));
23560
+ details.push(` ${marker} ${category.name}: ${display}`);
23561
+ }
23562
+ details.push("");
23563
+ details.push("\u25CF = user override, \u25CB = provider fallback");
23564
+ return details;
23565
+ }
23566
+ async function checkModelResolution() {
23567
+ const config2 = loadConfig() ?? {};
23568
+ const info = getModelResolutionInfoWithOverrides(config2);
23569
+ const available = loadAvailableModels();
23570
+ const agentCount = info.agents.length;
23571
+ const categoryCount = info.categories.length;
23572
+ const agentOverrides = info.agents.filter((a) => a.userOverride).length;
23573
+ const categoryOverrides = info.categories.filter((c) => c.userOverride).length;
23574
+ const totalOverrides = agentOverrides + categoryOverrides;
23575
+ const overrideNote = totalOverrides > 0 ? ` (${totalOverrides} override${totalOverrides > 1 ? "s" : ""})` : "";
23576
+ const cacheNote = available.cacheExists ? `, ${available.modelCount} available` : ", cache not found";
23577
+ return {
23578
+ name: CHECK_NAMES[CHECK_IDS.MODEL_RESOLUTION],
23579
+ status: available.cacheExists ? "pass" : "warn",
23580
+ message: `${agentCount} agents, ${categoryCount} categories${overrideNote}${cacheNote}`,
23581
+ details: buildDetailsArray(info, available)
23582
+ };
23583
+ }
23584
+ function getModelResolutionCheckDefinition() {
23585
+ return {
23586
+ id: CHECK_IDS.MODEL_RESOLUTION,
23587
+ name: CHECK_NAMES[CHECK_IDS.MODEL_RESOLUTION],
23588
+ category: "configuration",
23589
+ check: checkModelResolution,
23590
+ critical: false
23591
+ };
23592
+ }
23593
+
23135
23594
  // src/cli/doctor/checks/auth.ts
23136
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
23137
- import { homedir as homedir5 } from "os";
23138
- import { join as join7 } from "path";
23595
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
23596
+ import { join as join10 } from "path";
23139
23597
  init_shared();
23140
- var OPENCODE_CONFIG_DIR = join7(homedir5(), ".config", "opencode");
23141
- var OPENCODE_JSON = join7(OPENCODE_CONFIG_DIR, "opencode.json");
23142
- var OPENCODE_JSONC = join7(OPENCODE_CONFIG_DIR, "opencode.jsonc");
23598
+ var OPENCODE_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
23599
+ var OPENCODE_JSON = join10(OPENCODE_CONFIG_DIR, "opencode.json");
23600
+ var OPENCODE_JSONC = join10(OPENCODE_CONFIG_DIR, "opencode.jsonc");
23143
23601
  var AUTH_PLUGINS = {
23144
23602
  anthropic: { plugin: "builtin", name: "Anthropic (Claude)" },
23145
23603
  openai: { plugin: "opencode-openai-codex-auth", name: "OpenAI (ChatGPT)" },
23146
23604
  google: { plugin: "opencode-antigravity-auth", name: "Google (Gemini)" }
23147
23605
  };
23148
23606
  function getOpenCodeConfig() {
23149
- const configPath = existsSync9(OPENCODE_JSONC) ? OPENCODE_JSONC : OPENCODE_JSON;
23150
- if (!existsSync9(configPath))
23607
+ const configPath = existsSync10(OPENCODE_JSONC) ? OPENCODE_JSONC : OPENCODE_JSON;
23608
+ if (!existsSync10(configPath))
23151
23609
  return null;
23152
23610
  try {
23153
- const content = readFileSync7(configPath, "utf-8");
23611
+ const content = readFileSync9(configPath, "utf-8");
23154
23612
  return parseJsonc(content);
23155
23613
  } catch {
23156
23614
  return null;
@@ -23279,9 +23737,9 @@ async function checkAstGrepCli() {
23279
23737
  path: binary2.path
23280
23738
  };
23281
23739
  }
23282
- function checkAstGrepNapi() {
23740
+ async function checkAstGrepNapi() {
23283
23741
  try {
23284
- __require.resolve("@ast-grep/napi");
23742
+ await import("@ast-grep/napi");
23285
23743
  return {
23286
23744
  name: "AST-Grep NAPI",
23287
23745
  required: false,
@@ -23290,6 +23748,24 @@ function checkAstGrepNapi() {
23290
23748
  path: null
23291
23749
  };
23292
23750
  } catch {
23751
+ const { existsSync: existsSync11 } = await import("fs");
23752
+ const { join: join11 } = await import("path");
23753
+ const { homedir: homedir7 } = await import("os");
23754
+ const pathsToCheck = [
23755
+ join11(homedir7(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
23756
+ join11(process.cwd(), "node_modules", "@ast-grep", "napi")
23757
+ ];
23758
+ for (const napiPath of pathsToCheck) {
23759
+ if (existsSync11(napiPath)) {
23760
+ return {
23761
+ name: "AST-Grep NAPI",
23762
+ required: false,
23763
+ installed: true,
23764
+ version: null,
23765
+ path: napiPath
23766
+ };
23767
+ }
23768
+ }
23293
23769
  return {
23294
23770
  name: "AST-Grep NAPI",
23295
23771
  required: false,
@@ -23342,7 +23818,7 @@ async function checkDependencyAstGrepCli() {
23342
23818
  return dependencyToCheckResult(info, CHECK_NAMES[CHECK_IDS.DEP_AST_GREP_CLI]);
23343
23819
  }
23344
23820
  async function checkDependencyAstGrepNapi() {
23345
- const info = checkAstGrepNapi();
23821
+ const info = await checkAstGrepNapi();
23346
23822
  return dependencyToCheckResult(info, CHECK_NAMES[CHECK_IDS.DEP_AST_GREP_NAPI]);
23347
23823
  }
23348
23824
  async function checkDependencyCommentChecker() {
@@ -23509,15 +23985,15 @@ function getGhCliCheckDefinition() {
23509
23985
  }
23510
23986
 
23511
23987
  // src/tools/lsp/config.ts
23512
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
23513
- import { join as join8 } from "path";
23514
- import { homedir as homedir6 } from "os";
23988
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
23989
+ import { join as join11 } from "path";
23990
+ init_shared();
23515
23991
  function isServerInstalled(command) {
23516
23992
  if (command.length === 0)
23517
23993
  return false;
23518
23994
  const cmd = command[0];
23519
23995
  if (cmd.includes("/") || cmd.includes("\\")) {
23520
- if (existsSync10(cmd))
23996
+ if (existsSync11(cmd))
23521
23997
  return true;
23522
23998
  }
23523
23999
  const isWindows = process.platform === "win32";
@@ -23539,20 +24015,23 @@ function isServerInstalled(command) {
23539
24015
  const paths = pathEnv.split(pathSeparator);
23540
24016
  for (const p2 of paths) {
23541
24017
  for (const suffix of exts) {
23542
- if (existsSync10(join8(p2, cmd + suffix))) {
24018
+ if (existsSync11(join11(p2, cmd + suffix))) {
23543
24019
  return true;
23544
24020
  }
23545
24021
  }
23546
24022
  }
23547
24023
  const cwd = process.cwd();
24024
+ const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24025
+ const dataDir = join11(getDataDir(), "opencode");
23548
24026
  const additionalBases = [
23549
- join8(cwd, "node_modules", ".bin"),
23550
- join8(homedir6(), ".config", "opencode", "bin"),
23551
- join8(homedir6(), ".config", "opencode", "node_modules", ".bin")
24027
+ join11(cwd, "node_modules", ".bin"),
24028
+ join11(configDir, "bin"),
24029
+ join11(configDir, "node_modules", ".bin"),
24030
+ join11(dataDir, "bin")
23552
24031
  ];
23553
24032
  for (const base of additionalBases) {
23554
24033
  for (const suffix of exts) {
23555
- if (existsSync10(join8(base, cmd + suffix))) {
24034
+ if (existsSync11(join11(base, cmd + suffix))) {
23556
24035
  return true;
23557
24036
  }
23558
24037
  }
@@ -23625,23 +24104,23 @@ function getLspCheckDefinition() {
23625
24104
  }
23626
24105
 
23627
24106
  // src/cli/doctor/checks/mcp.ts
23628
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
24107
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
23629
24108
  import { homedir as homedir7 } from "os";
23630
- import { join as join9 } from "path";
24109
+ import { join as join12 } from "path";
23631
24110
  init_shared();
23632
24111
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
23633
24112
  var MCP_CONFIG_PATHS = [
23634
- join9(homedir7(), ".claude", ".mcp.json"),
23635
- join9(process.cwd(), ".mcp.json"),
23636
- join9(process.cwd(), ".claude", ".mcp.json")
24113
+ join12(homedir7(), ".claude", ".mcp.json"),
24114
+ join12(process.cwd(), ".mcp.json"),
24115
+ join12(process.cwd(), ".claude", ".mcp.json")
23637
24116
  ];
23638
24117
  function loadUserMcpConfig() {
23639
24118
  const servers = {};
23640
24119
  for (const configPath of MCP_CONFIG_PATHS) {
23641
- if (!existsSync11(configPath))
24120
+ if (!existsSync12(configPath))
23642
24121
  continue;
23643
24122
  try {
23644
- const content = readFileSync9(configPath, "utf-8");
24123
+ const content = readFileSync11(configPath, "utf-8");
23645
24124
  const config2 = parseJsonc(content);
23646
24125
  if (config2.mcpServers) {
23647
24126
  Object.assign(servers, config2.mcpServers);
@@ -23848,6 +24327,7 @@ function getAllCheckDefinitions() {
23848
24327
  getOpenCodeCheckDefinition(),
23849
24328
  getPluginCheckDefinition(),
23850
24329
  getConfigCheckDefinition(),
24330
+ getModelResolutionCheckDefinition(),
23851
24331
  ...getAuthCheckDefinitions(),
23852
24332
  ...getDependencyCheckDefinitions(),
23853
24333
  getGhCliCheckDefinition(),
@@ -24039,23 +24519,28 @@ async function doctor(options = {}) {
24039
24519
  var VERSION2 = package_default.version;
24040
24520
  var program2 = new Command;
24041
24521
  program2.name("oh-my-opencode").description("The ultimate OpenCode plugin - multi-model orchestration, LSP tools, and more").version(VERSION2, "-v, --version", "Show version number");
24042
- program2.command("install").description("Install and configure oh-my-opencode with interactive setup").option("--no-tui", "Run in non-interactive mode (requires all options)").option("--claude <value>", "Claude subscription: no, yes, max20").option("--chatgpt <value>", "ChatGPT subscription: no, yes").option("--gemini <value>", "Gemini integration: no, yes").option("--copilot <value>", "GitHub Copilot subscription: no, yes").option("--skip-auth", "Skip authentication setup hints").addHelpText("after", `
24522
+ program2.command("install").description("Install and configure oh-my-opencode with interactive setup").option("--no-tui", "Run in non-interactive mode (requires all options)").option("--claude <value>", "Claude subscription: no, yes, max20").option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)").option("--gemini <value>", "Gemini integration: no, yes").option("--copilot <value>", "GitHub Copilot subscription: no, yes").option("--opencode-zen <value>", "OpenCode Zen access: no, yes (default: no)").option("--zai-coding-plan <value>", "Z.ai Coding Plan subscription: no, yes (default: no)").option("--skip-auth", "Skip authentication setup hints").addHelpText("after", `
24043
24523
  Examples:
24044
24524
  $ bunx oh-my-opencode install
24045
- $ bunx oh-my-opencode install --no-tui --claude=max20 --chatgpt=yes --gemini=yes --copilot=no
24046
- $ bunx oh-my-opencode install --no-tui --claude=no --chatgpt=no --gemini=no --copilot=yes
24525
+ $ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
24526
+ $ bunx oh-my-opencode install --no-tui --claude=no --gemini=no --copilot=yes --opencode-zen=yes
24047
24527
 
24048
- Model Providers:
24049
- Claude Required for Sisyphus (main orchestrator) and Librarian agents
24050
- ChatGPT Powers the Oracle agent for debugging and architecture
24051
- Gemini Powers frontend, documentation, and multimodal agents
24528
+ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai):
24529
+ Claude Native anthropic/ models (Opus, Sonnet, Haiku)
24530
+ OpenAI Native openai/ models (GPT-5.2 for Oracle)
24531
+ Gemini Native google/ models (Gemini 3 Pro, Flash)
24532
+ Copilot github-copilot/ models (fallback)
24533
+ OpenCode Zen opencode/ models (opencode/claude-opus-4-5, etc.)
24534
+ Z.ai zai-coding-plan/glm-4.7 (Librarian priority)
24052
24535
  `).action(async (options) => {
24053
24536
  const args = {
24054
24537
  tui: options.tui !== false,
24055
24538
  claude: options.claude,
24056
- chatgpt: options.chatgpt,
24539
+ openai: options.openai,
24057
24540
  gemini: options.gemini,
24058
24541
  copilot: options.copilot,
24542
+ opencodeZen: options.opencodeZen,
24543
+ zaiCodingPlan: options.zaiCodingPlan,
24059
24544
  skipAuth: options.skipAuth ?? false
24060
24545
  };
24061
24546
  const exitCode = await install(args);