oh-my-opencode 3.2.0 → 3.2.2

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 (177) hide show
  1. package/dist/agents/{atlas.d.ts → atlas/default.d.ts} +8 -19
  2. package/dist/agents/atlas/gpt.d.ts +19 -0
  3. package/dist/agents/atlas/index.d.ts +39 -0
  4. package/dist/agents/atlas/utils.d.ts +13 -0
  5. package/dist/agents/hephaestus.d.ts +1 -1
  6. package/dist/agents/prometheus/identity-constraints.d.ts +1 -1
  7. package/dist/agents/prometheus/index.d.ts +1 -1
  8. package/dist/agents/prometheus/interview-mode.d.ts +1 -1
  9. package/dist/agents/prometheus/plan-generation.d.ts +1 -1
  10. package/dist/agents/prometheus/plan-template.d.ts +1 -1
  11. package/dist/agents/sisyphus-junior/default.d.ts +9 -0
  12. package/dist/agents/sisyphus-junior/gpt.d.ts +18 -0
  13. package/dist/agents/sisyphus-junior/index.d.ts +31 -0
  14. package/dist/agents/sisyphus.d.ts +1 -1
  15. package/dist/cli/index.js +1140 -835
  16. package/dist/cli/run/runner.d.ts +4 -0
  17. package/dist/config/index.d.ts +1 -1
  18. package/dist/config/schema.d.ts +23 -43
  19. package/dist/features/background-agent/manager.d.ts +6 -0
  20. package/dist/features/builtin-commands/templates/init-deep.d.ts +1 -1
  21. package/dist/features/claude-tasks/index.d.ts +2 -0
  22. package/dist/features/claude-tasks/storage.d.ts +12 -0
  23. package/dist/features/claude-tasks/types.d.ts +25 -0
  24. package/dist/hooks/auto-slash-command/detector.d.ts +4 -0
  25. package/dist/hooks/auto-slash-command/index.d.ts +2 -1
  26. package/dist/hooks/auto-slash-command/types.d.ts +12 -0
  27. package/dist/hooks/index.d.ts +2 -0
  28. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +4 -4
  29. package/dist/hooks/keyword-detector/ultrawork/gpt5.2.d.ts +5 -6
  30. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -1
  31. package/dist/hooks/preemptive-compaction.d.ts +30 -0
  32. package/dist/hooks/prometheus-md-only/constants.d.ts +1 -1
  33. package/dist/hooks/task-reminder/index.d.ts +19 -0
  34. package/dist/hooks/tasks-todowrite-disabler/constants.d.ts +3 -0
  35. package/dist/hooks/tasks-todowrite-disabler/index.d.ts +14 -0
  36. package/dist/index.js +26317 -24694
  37. package/dist/tools/delegate-task/constants.d.ts +1 -1
  38. package/dist/tools/delegate-task/types.d.ts +4 -0
  39. package/dist/tools/index.d.ts +1 -0
  40. package/dist/tools/task/index.d.ts +7 -0
  41. package/dist/tools/task/task-create.d.ts +4 -0
  42. package/dist/tools/task/task-get.d.ts +3 -0
  43. package/dist/tools/task/task-list.d.ts +3 -0
  44. package/dist/tools/task/task-update.d.ts +4 -0
  45. package/dist/tools/task/task.d.ts +3 -0
  46. package/dist/tools/task/todo-sync.d.ts +16 -0
  47. package/dist/tools/task/types.d.ts +97 -0
  48. package/package.json +9 -9
  49. package/dist/agents/momus.test.d.ts +0 -1
  50. package/dist/agents/prometheus-prompt.test.d.ts +0 -1
  51. package/dist/agents/sisyphus-junior.d.ts +0 -10
  52. package/dist/agents/sisyphus-junior.test.d.ts +0 -1
  53. package/dist/agents/utils.test.d.ts +0 -1
  54. package/dist/cli/config-manager.test.d.ts +0 -1
  55. package/dist/cli/doctor/checks/auth.test.d.ts +0 -1
  56. package/dist/cli/doctor/checks/config.test.d.ts +0 -1
  57. package/dist/cli/doctor/checks/dependencies.test.d.ts +0 -1
  58. package/dist/cli/doctor/checks/gh.test.d.ts +0 -1
  59. package/dist/cli/doctor/checks/lsp.test.d.ts +0 -1
  60. package/dist/cli/doctor/checks/mcp-oauth.test.d.ts +0 -1
  61. package/dist/cli/doctor/checks/mcp.test.d.ts +0 -1
  62. package/dist/cli/doctor/checks/model-resolution.test.d.ts +0 -1
  63. package/dist/cli/doctor/checks/opencode.test.d.ts +0 -1
  64. package/dist/cli/doctor/checks/plugin.test.d.ts +0 -1
  65. package/dist/cli/doctor/checks/version.test.d.ts +0 -1
  66. package/dist/cli/doctor/formatter.test.d.ts +0 -1
  67. package/dist/cli/doctor/runner.test.d.ts +0 -1
  68. package/dist/cli/index.test.d.ts +0 -1
  69. package/dist/cli/install.test.d.ts +0 -1
  70. package/dist/cli/mcp-oauth/index.test.d.ts +0 -1
  71. package/dist/cli/mcp-oauth/login.test.d.ts +0 -1
  72. package/dist/cli/mcp-oauth/logout.test.d.ts +0 -1
  73. package/dist/cli/mcp-oauth/status.test.d.ts +0 -1
  74. package/dist/cli/model-fallback.test.d.ts +0 -1
  75. package/dist/cli/run/completion.test.d.ts +0 -1
  76. package/dist/cli/run/events.test.d.ts +0 -1
  77. package/dist/config/schema.test.d.ts +0 -1
  78. package/dist/features/background-agent/concurrency.test.d.ts +0 -1
  79. package/dist/features/background-agent/manager.test.d.ts +0 -1
  80. package/dist/features/boulder-state/storage.test.d.ts +0 -1
  81. package/dist/features/builtin-commands/templates/stop-continuation.test.d.ts +0 -1
  82. package/dist/features/builtin-skills/skills.test.d.ts +0 -1
  83. package/dist/features/claude-code-mcp-loader/loader.test.d.ts +0 -1
  84. package/dist/features/claude-code-session-state/state.test.d.ts +0 -1
  85. package/dist/features/context-injector/collector.test.d.ts +0 -1
  86. package/dist/features/context-injector/injector.test.d.ts +0 -1
  87. package/dist/features/mcp-oauth/callback-server.test.d.ts +0 -1
  88. package/dist/features/mcp-oauth/dcr.test.d.ts +0 -1
  89. package/dist/features/mcp-oauth/discovery.test.d.ts +0 -1
  90. package/dist/features/mcp-oauth/provider.test.d.ts +0 -1
  91. package/dist/features/mcp-oauth/resource-indicator.test.d.ts +0 -1
  92. package/dist/features/mcp-oauth/schema.test.d.ts +0 -1
  93. package/dist/features/mcp-oauth/step-up.test.d.ts +0 -1
  94. package/dist/features/mcp-oauth/storage.test.d.ts +0 -1
  95. package/dist/features/opencode-skill-loader/async-loader.test.d.ts +0 -1
  96. package/dist/features/opencode-skill-loader/blocking.test.d.ts +0 -1
  97. package/dist/features/opencode-skill-loader/loader.test.d.ts +0 -1
  98. package/dist/features/opencode-skill-loader/skill-content.test.d.ts +0 -1
  99. package/dist/features/sisyphus-swarm/mailbox/types.d.ts +0 -191
  100. package/dist/features/sisyphus-swarm/mailbox/types.test.d.ts +0 -1
  101. package/dist/features/sisyphus-tasks/storage.d.ts +0 -9
  102. package/dist/features/sisyphus-tasks/storage.test.d.ts +0 -1
  103. package/dist/features/sisyphus-tasks/types.d.ts +0 -47
  104. package/dist/features/sisyphus-tasks/types.test.d.ts +0 -1
  105. package/dist/features/skill-mcp-manager/env-cleaner.test.d.ts +0 -1
  106. package/dist/features/skill-mcp-manager/manager.test.d.ts +0 -1
  107. package/dist/features/task-toast-manager/manager.test.d.ts +0 -1
  108. package/dist/features/tmux-subagent/decision-engine.test.d.ts +0 -1
  109. package/dist/features/tmux-subagent/manager.test.d.ts +0 -1
  110. package/dist/hooks/anthropic-context-window-limit-recovery/executor.test.d.ts +0 -1
  111. package/dist/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.d.ts +0 -1
  112. package/dist/hooks/anthropic-context-window-limit-recovery/storage.test.d.ts +0 -1
  113. package/dist/hooks/atlas/index.test.d.ts +0 -1
  114. package/dist/hooks/auto-slash-command/detector.test.d.ts +0 -1
  115. package/dist/hooks/auto-slash-command/index.test.d.ts +0 -1
  116. package/dist/hooks/auto-update-checker/checker.test.d.ts +0 -1
  117. package/dist/hooks/auto-update-checker/index.test.d.ts +0 -1
  118. package/dist/hooks/category-skill-reminder/index.test.d.ts +0 -1
  119. package/dist/hooks/comment-checker/cli.test.d.ts +0 -1
  120. package/dist/hooks/compaction-context-injector/index.test.d.ts +0 -1
  121. package/dist/hooks/delegate-task-retry/index.test.d.ts +0 -1
  122. package/dist/hooks/edit-error-recovery/index.test.d.ts +0 -1
  123. package/dist/hooks/keyword-detector/index.test.d.ts +0 -1
  124. package/dist/hooks/non-interactive-env/index.test.d.ts +0 -1
  125. package/dist/hooks/prometheus-md-only/index.test.d.ts +0 -1
  126. package/dist/hooks/question-label-truncator/index.test.d.ts +0 -1
  127. package/dist/hooks/ralph-loop/index.test.d.ts +0 -1
  128. package/dist/hooks/rules-injector/finder.test.d.ts +0 -1
  129. package/dist/hooks/rules-injector/output-path.test.d.ts +0 -1
  130. package/dist/hooks/rules-injector/parser.test.d.ts +0 -1
  131. package/dist/hooks/session-notification.test.d.ts +0 -1
  132. package/dist/hooks/session-recovery/index.test.d.ts +0 -1
  133. package/dist/hooks/start-work/index.test.d.ts +0 -1
  134. package/dist/hooks/stop-continuation-guard/index.test.d.ts +0 -1
  135. package/dist/hooks/subagent-question-blocker/index.test.d.ts +0 -1
  136. package/dist/hooks/think-mode/index.test.d.ts +0 -1
  137. package/dist/hooks/think-mode/switcher.test.d.ts +0 -1
  138. package/dist/hooks/todo-continuation-enforcer.test.d.ts +0 -1
  139. package/dist/hooks/tool-output-truncator.test.d.ts +0 -1
  140. package/dist/hooks/unstable-agent-babysitter/index.test.d.ts +0 -1
  141. package/dist/index.test.d.ts +0 -1
  142. package/dist/mcp/index.test.d.ts +0 -1
  143. package/dist/plugin-config.test.d.ts +0 -1
  144. package/dist/plugin-handlers/config-handler.test.d.ts +0 -1
  145. package/dist/shared/agent-config-integration.test.d.ts +0 -1
  146. package/dist/shared/agent-display-names.test.d.ts +0 -1
  147. package/dist/shared/agent-variant.test.d.ts +0 -1
  148. package/dist/shared/claude-config-dir.test.d.ts +0 -1
  149. package/dist/shared/deep-merge.test.d.ts +0 -1
  150. package/dist/shared/external-plugin-detector.test.d.ts +0 -1
  151. package/dist/shared/first-message-variant.test.d.ts +0 -1
  152. package/dist/shared/frontmatter.test.d.ts +0 -1
  153. package/dist/shared/jsonc-parser.test.d.ts +0 -1
  154. package/dist/shared/migration.test.d.ts +0 -1
  155. package/dist/shared/model-availability.test.d.ts +0 -1
  156. package/dist/shared/model-requirements.test.d.ts +0 -1
  157. package/dist/shared/model-resolver.test.d.ts +0 -1
  158. package/dist/shared/model-suggestion-retry.test.d.ts +0 -1
  159. package/dist/shared/opencode-config-dir.test.d.ts +0 -1
  160. package/dist/shared/opencode-version.test.d.ts +0 -1
  161. package/dist/shared/permission-compat.test.d.ts +0 -1
  162. package/dist/shared/session-cursor.test.d.ts +0 -1
  163. package/dist/shared/shell-env.test.d.ts +0 -1
  164. package/dist/shared/system-directive.test.d.ts +0 -1
  165. package/dist/shared/tmux/tmux-utils.test.d.ts +0 -1
  166. package/dist/tools/background-task/tools.test.d.ts +0 -1
  167. package/dist/tools/delegate-task/tools.test.d.ts +0 -1
  168. package/dist/tools/glob/cli.test.d.ts +0 -1
  169. package/dist/tools/grep/downloader.test.d.ts +0 -1
  170. package/dist/tools/look-at/tools.test.d.ts +0 -1
  171. package/dist/tools/lsp/config.test.d.ts +0 -1
  172. package/dist/tools/session-manager/storage.test.d.ts +0 -1
  173. package/dist/tools/session-manager/tools.test.d.ts +0 -1
  174. package/dist/tools/session-manager/utils.test.d.ts +0 -1
  175. package/dist/tools/skill/tools.test.d.ts +0 -1
  176. package/dist/tools/skill-mcp/tools.test.d.ts +0 -1
  177. package/dist/tools/slashcommand/tools.test.d.ts +0 -1
package/dist/cli/index.js CHANGED
@@ -4892,7 +4892,35 @@ var init_logger = __esm(() => {
4892
4892
  });
4893
4893
 
4894
4894
  // src/shared/deep-merge.ts
4895
- var DANGEROUS_KEYS;
4895
+ function isPlainObject(value) {
4896
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
4897
+ }
4898
+ function deepMerge(base, override, depth = 0) {
4899
+ if (!base && !override)
4900
+ return;
4901
+ if (!base)
4902
+ return override;
4903
+ if (!override)
4904
+ return base;
4905
+ if (depth > MAX_DEPTH)
4906
+ return override ?? base;
4907
+ const result = { ...base };
4908
+ for (const key of Object.keys(override)) {
4909
+ if (DANGEROUS_KEYS.has(key))
4910
+ continue;
4911
+ const baseValue = base[key];
4912
+ const overrideValue = override[key];
4913
+ if (overrideValue === undefined)
4914
+ continue;
4915
+ if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
4916
+ result[key] = deepMerge(baseValue, overrideValue, depth + 1);
4917
+ } else {
4918
+ result[key] = overrideValue;
4919
+ }
4920
+ }
4921
+ return result;
4922
+ }
4923
+ var DANGEROUS_KEYS, MAX_DEPTH = 50;
4896
4924
  var init_deep_merge = __esm(() => {
4897
4925
  DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
4898
4926
  });
@@ -4940,6 +4968,9 @@ function getConfigLoadErrors() {
4940
4968
  function clearConfigLoadErrors() {
4941
4969
  configLoadErrors = [];
4942
4970
  }
4971
+ function addConfigLoadError(error) {
4972
+ configLoadErrors.push(error);
4973
+ }
4943
4974
  var configLoadErrors;
4944
4975
  var init_config_errors = __esm(() => {
4945
4976
  configLoadErrors = [];
@@ -5842,9 +5873,127 @@ var init_jsonc_parser = __esm(() => {
5842
5873
  });
5843
5874
 
5844
5875
  // src/shared/migration.ts
5845
- var BUILTIN_AGENT_NAMES;
5876
+ import * as fs2 from "fs";
5877
+ function migrateAgentNames(agents) {
5878
+ const migrated = {};
5879
+ let changed = false;
5880
+ for (const [key, value] of Object.entries(agents)) {
5881
+ const newKey = AGENT_NAME_MAP[key.toLowerCase()] ?? AGENT_NAME_MAP[key] ?? key;
5882
+ if (newKey !== key) {
5883
+ changed = true;
5884
+ }
5885
+ migrated[newKey] = value;
5886
+ }
5887
+ return { migrated, changed };
5888
+ }
5889
+ function migrateHookNames(hooks) {
5890
+ const migrated = [];
5891
+ const removed = [];
5892
+ let changed = false;
5893
+ for (const hook of hooks) {
5894
+ const mapping = HOOK_NAME_MAP[hook];
5895
+ if (mapping === null) {
5896
+ removed.push(hook);
5897
+ changed = true;
5898
+ continue;
5899
+ }
5900
+ const newHook = mapping ?? hook;
5901
+ if (newHook !== hook) {
5902
+ changed = true;
5903
+ }
5904
+ migrated.push(newHook);
5905
+ }
5906
+ return { migrated, changed, removed };
5907
+ }
5908
+ function migrateConfigFile(configPath, rawConfig) {
5909
+ let needsWrite = false;
5910
+ if (rawConfig.agents && typeof rawConfig.agents === "object") {
5911
+ const { migrated, changed } = migrateAgentNames(rawConfig.agents);
5912
+ if (changed) {
5913
+ rawConfig.agents = migrated;
5914
+ needsWrite = true;
5915
+ }
5916
+ }
5917
+ if (rawConfig.omo_agent) {
5918
+ rawConfig.sisyphus_agent = rawConfig.omo_agent;
5919
+ delete rawConfig.omo_agent;
5920
+ needsWrite = true;
5921
+ }
5922
+ if (rawConfig.disabled_agents && Array.isArray(rawConfig.disabled_agents)) {
5923
+ const migrated = [];
5924
+ let changed = false;
5925
+ for (const agent of rawConfig.disabled_agents) {
5926
+ const newAgent = AGENT_NAME_MAP[agent.toLowerCase()] ?? AGENT_NAME_MAP[agent] ?? agent;
5927
+ if (newAgent !== agent) {
5928
+ changed = true;
5929
+ }
5930
+ migrated.push(newAgent);
5931
+ }
5932
+ if (changed) {
5933
+ rawConfig.disabled_agents = migrated;
5934
+ needsWrite = true;
5935
+ }
5936
+ }
5937
+ if (rawConfig.disabled_hooks && Array.isArray(rawConfig.disabled_hooks)) {
5938
+ const { migrated, changed, removed } = migrateHookNames(rawConfig.disabled_hooks);
5939
+ if (changed) {
5940
+ rawConfig.disabled_hooks = migrated;
5941
+ needsWrite = true;
5942
+ }
5943
+ if (removed.length > 0) {
5944
+ log(`Removed obsolete hooks from disabled_hooks: ${removed.join(", ")} (these hooks no longer exist in v3.0.0)`);
5945
+ }
5946
+ }
5947
+ if (rawConfig.experimental && typeof rawConfig.experimental === "object") {
5948
+ const exp = rawConfig.experimental;
5949
+ if ("task_system" in exp && exp.task_system !== undefined) {
5950
+ needsWrite = true;
5951
+ }
5952
+ }
5953
+ if (needsWrite) {
5954
+ try {
5955
+ const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-");
5956
+ const backupPath = `${configPath}.bak.${timestamp2}`;
5957
+ fs2.copyFileSync(configPath, backupPath);
5958
+ fs2.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + `
5959
+ `, "utf-8");
5960
+ log(`Migrated config file: ${configPath} (backup: ${backupPath})`);
5961
+ } catch (err) {
5962
+ log(`Failed to write migrated config to ${configPath}:`, err);
5963
+ }
5964
+ }
5965
+ return needsWrite;
5966
+ }
5967
+ var AGENT_NAME_MAP, BUILTIN_AGENT_NAMES, HOOK_NAME_MAP;
5846
5968
  var init_migration = __esm(() => {
5847
5969
  init_logger();
5970
+ AGENT_NAME_MAP = {
5971
+ omo: "sisyphus",
5972
+ OmO: "sisyphus",
5973
+ Sisyphus: "sisyphus",
5974
+ sisyphus: "sisyphus",
5975
+ "OmO-Plan": "prometheus",
5976
+ "omo-plan": "prometheus",
5977
+ "Planner-Sisyphus": "prometheus",
5978
+ "planner-sisyphus": "prometheus",
5979
+ "Prometheus (Planner)": "prometheus",
5980
+ prometheus: "prometheus",
5981
+ "orchestrator-sisyphus": "atlas",
5982
+ Atlas: "atlas",
5983
+ atlas: "atlas",
5984
+ "plan-consultant": "metis",
5985
+ "Metis (Plan Consultant)": "metis",
5986
+ metis: "metis",
5987
+ "Momus (Plan Reviewer)": "momus",
5988
+ momus: "momus",
5989
+ "Sisyphus-Junior": "sisyphus-junior",
5990
+ "sisyphus-junior": "sisyphus-junior",
5991
+ build: "build",
5992
+ oracle: "oracle",
5993
+ librarian: "librarian",
5994
+ explore: "explore",
5995
+ "multimodal-looker": "multimodal-looker"
5996
+ };
5848
5997
  BUILTIN_AGENT_NAMES = new Set([
5849
5998
  "sisyphus",
5850
5999
  "oracle",
@@ -5857,6 +6006,11 @@ var init_migration = __esm(() => {
5857
6006
  "atlas",
5858
6007
  "build"
5859
6008
  ]);
6009
+ HOOK_NAME_MAP = {
6010
+ "anthropic-auto-compact": "anthropic-context-window-limit-recovery",
6011
+ "sisyphus-orchestrator": "atlas",
6012
+ "empty-message-sanitizer": null
6013
+ };
5860
6014
  });
5861
6015
 
5862
6016
  // src/shared/opencode-config-dir.ts
@@ -5991,8 +6145,8 @@ var init_model_requirements = __esm(() => {
5991
6145
  },
5992
6146
  explore: {
5993
6147
  fallbackChain: [
6148
+ { providers: ["github-copilot"], model: "grok-code-fast-1" },
5994
6149
  { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
5995
- { providers: ["github-copilot"], model: "gpt-5-mini" },
5996
6150
  { providers: ["opencode"], model: "gpt-5-nano" }
5997
6151
  ]
5998
6152
  },
@@ -6122,7 +6276,7 @@ var init_system_directive = () => {};
6122
6276
  var init_agent_tool_restrictions = () => {};
6123
6277
 
6124
6278
  // src/shared/connected-providers-cache.ts
6125
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
6279
+ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync } from "fs";
6126
6280
  import { join as join4 } from "path";
6127
6281
  function getCacheFilePath(filename) {
6128
6282
  return join4(getOmoOpenCodeCacheDir(), filename);
@@ -6145,7 +6299,7 @@ function writeConnectedProvidersCache(connected) {
6145
6299
  updatedAt: new Date().toISOString()
6146
6300
  };
6147
6301
  try {
6148
- writeFileSync(cacheFile, JSON.stringify(data, null, 2));
6302
+ writeFileSync2(cacheFile, JSON.stringify(data, null, 2));
6149
6303
  log("[connected-providers-cache] Cache written", { count: connected.length });
6150
6304
  } catch (err) {
6151
6305
  log("[connected-providers-cache] Error writing cache", { error: String(err) });
@@ -6163,7 +6317,7 @@ function writeProviderModelsCache(data) {
6163
6317
  updatedAt: new Date().toISOString()
6164
6318
  };
6165
6319
  try {
6166
- writeFileSync(cacheFile, JSON.stringify(cacheData, null, 2));
6320
+ writeFileSync2(cacheFile, JSON.stringify(cacheData, null, 2));
6167
6321
  log("[connected-providers-cache] Provider-models cache written", {
6168
6322
  providerCount: Object.keys(data.models).length
6169
6323
  });
@@ -6359,7 +6513,7 @@ function isProviderAvailable(provider, avail) {
6359
6513
  }
6360
6514
  function transformModelForProvider(provider, model) {
6361
6515
  if (provider === "github-copilot") {
6362
- 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");
6516
+ 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").replace("gemini-3-pro", "gemini-3-pro-preview").replace("gemini-3-flash", "gemini-3-flash-preview");
6363
6517
  }
6364
6518
  return model;
6365
6519
  }
@@ -6466,7 +6620,7 @@ var init_model_fallback = __esm(() => {
6466
6620
  });
6467
6621
 
6468
6622
  // src/cli/config-manager.ts
6469
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, statSync } from "fs";
6623
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3, statSync } from "fs";
6470
6624
  function initConfigContext(binary2, version) {
6471
6625
  const paths = getOpenCodeConfigPaths({ binary: binary2, version });
6472
6626
  configContext = { binary: binary2, version, paths };
@@ -6606,7 +6760,7 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6606
6760
  try {
6607
6761
  if (format2 === "none") {
6608
6762
  const config2 = { plugin: [pluginEntry] };
6609
- writeFileSync2(path3, JSON.stringify(config2, null, 2) + `
6763
+ writeFileSync3(path3, JSON.stringify(config2, null, 2) + `
6610
6764
  `);
6611
6765
  return { success: true, configPath: path3 };
6612
6766
  }
@@ -6636,14 +6790,14 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6636
6790
  const newContent = content.replace(pluginArrayRegex, `"plugin": [
6637
6791
  ${formattedPlugins}
6638
6792
  ]`);
6639
- writeFileSync2(path3, newContent);
6793
+ writeFileSync3(path3, newContent);
6640
6794
  } else {
6641
6795
  const newContent = content.replace(/^(\s*\{)/, `$1
6642
6796
  "plugin": ["${pluginEntry}"],`);
6643
- writeFileSync2(path3, newContent);
6797
+ writeFileSync3(path3, newContent);
6644
6798
  }
6645
6799
  } else {
6646
- writeFileSync2(path3, JSON.stringify(config, null, 2) + `
6800
+ writeFileSync3(path3, JSON.stringify(config, null, 2) + `
6647
6801
  `);
6648
6802
  }
6649
6803
  return { success: true, configPath: path3 };
@@ -6651,13 +6805,13 @@ async function addPluginToOpenCodeConfig(currentVersion) {
6651
6805
  return { success: false, configPath: path3, error: formatErrorWithSuggestion(err, "update opencode config") };
6652
6806
  }
6653
6807
  }
6654
- function deepMerge(target, source) {
6808
+ function deepMerge2(target, source) {
6655
6809
  const result = { ...target };
6656
6810
  for (const key of Object.keys(source)) {
6657
6811
  const sourceValue = source[key];
6658
6812
  const targetValue = result[key];
6659
6813
  if (sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) {
6660
- result[key] = deepMerge(targetValue, sourceValue);
6814
+ result[key] = deepMerge2(targetValue, sourceValue);
6661
6815
  } else if (sourceValue !== undefined) {
6662
6816
  result[key] = sourceValue;
6663
6817
  }
@@ -6681,29 +6835,29 @@ function writeOmoConfig(installConfig) {
6681
6835
  const stat = statSync(omoConfigPath);
6682
6836
  const content = readFileSync4(omoConfigPath, "utf-8");
6683
6837
  if (stat.size === 0 || isEmptyOrWhitespace(content)) {
6684
- writeFileSync2(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6838
+ writeFileSync3(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6685
6839
  `);
6686
6840
  return { success: true, configPath: omoConfigPath };
6687
6841
  }
6688
6842
  const existing = parseJsonc(content);
6689
6843
  if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
6690
- writeFileSync2(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6844
+ writeFileSync3(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6691
6845
  `);
6692
6846
  return { success: true, configPath: omoConfigPath };
6693
6847
  }
6694
- const merged = deepMerge(existing, newConfig);
6695
- writeFileSync2(omoConfigPath, JSON.stringify(merged, null, 2) + `
6848
+ const merged = deepMerge2(existing, newConfig);
6849
+ writeFileSync3(omoConfigPath, JSON.stringify(merged, null, 2) + `
6696
6850
  `);
6697
6851
  } catch (parseErr) {
6698
6852
  if (parseErr instanceof SyntaxError) {
6699
- writeFileSync2(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6853
+ writeFileSync3(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6700
6854
  `);
6701
6855
  return { success: true, configPath: omoConfigPath };
6702
6856
  }
6703
6857
  throw parseErr;
6704
6858
  }
6705
6859
  } else {
6706
- writeFileSync2(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6860
+ writeFileSync3(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
6707
6861
  `);
6708
6862
  }
6709
6863
  return { success: true, configPath: omoConfigPath };
@@ -6765,7 +6919,7 @@ async function addAuthPlugins(config) {
6765
6919
  }
6766
6920
  }
6767
6921
  const newConfig = { ...existingConfig ?? {}, plugin: plugins };
6768
- writeFileSync2(path3, JSON.stringify(newConfig, null, 2) + `
6922
+ writeFileSync3(path3, JSON.stringify(newConfig, null, 2) + `
6769
6923
  `);
6770
6924
  return { success: true, configPath: path3 };
6771
6925
  } catch (err) {
@@ -6837,7 +6991,7 @@ function addProviderConfig(config) {
6837
6991
  if (Object.keys(providers).length > 0) {
6838
6992
  newConfig.provider = providers;
6839
6993
  }
6840
- writeFileSync2(path3, JSON.stringify(newConfig, null, 2) + `
6994
+ writeFileSync3(path3, JSON.stringify(newConfig, null, 2) + `
6841
6995
  `);
6842
6996
  return { success: true, configPath: path3 };
6843
6997
  } catch (err) {
@@ -6959,43 +7113,43 @@ var init_config_manager = __esm(() => {
6959
7113
  });
6960
7114
 
6961
7115
  // src/hooks/auto-update-checker/constants.ts
6962
- import * as path3 from "path";
7116
+ import * as path4 from "path";
6963
7117
  import * as os3 from "os";
6964
7118
  function getCacheDir2() {
6965
7119
  if (process.platform === "win32") {
6966
- return path3.join(process.env.LOCALAPPDATA ?? os3.homedir(), "opencode");
7120
+ return path4.join(process.env.LOCALAPPDATA ?? os3.homedir(), "opencode");
6967
7121
  }
6968
- return path3.join(os3.homedir(), ".cache", "opencode");
7122
+ return path4.join(os3.homedir(), ".cache", "opencode");
6969
7123
  }
6970
7124
  function getWindowsAppdataDir() {
6971
7125
  if (process.platform !== "win32")
6972
7126
  return null;
6973
- return process.env.APPDATA ?? path3.join(os3.homedir(), "AppData", "Roaming");
7127
+ return process.env.APPDATA ?? path4.join(os3.homedir(), "AppData", "Roaming");
6974
7128
  }
6975
7129
  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;
6976
7130
  var init_constants3 = __esm(() => {
6977
7131
  init_shared();
6978
7132
  NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME2}/dist-tags`;
6979
7133
  CACHE_DIR = getCacheDir2();
6980
- VERSION_FILE = path3.join(CACHE_DIR, "version");
6981
- INSTALLED_PACKAGE_JSON = path3.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
7134
+ VERSION_FILE = path4.join(CACHE_DIR, "version");
7135
+ INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME2, "package.json");
6982
7136
  USER_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
6983
- USER_OPENCODE_CONFIG = path3.join(USER_CONFIG_DIR, "opencode.json");
6984
- USER_OPENCODE_CONFIG_JSONC = path3.join(USER_CONFIG_DIR, "opencode.jsonc");
7137
+ USER_OPENCODE_CONFIG = path4.join(USER_CONFIG_DIR, "opencode.json");
7138
+ USER_OPENCODE_CONFIG_JSONC = path4.join(USER_CONFIG_DIR, "opencode.jsonc");
6985
7139
  });
6986
7140
 
6987
7141
  // src/hooks/auto-update-checker/cache.ts
6988
- import * as fs2 from "fs";
6989
- import * as path4 from "path";
6990
- function stripTrailingCommas(json2) {
6991
- return json2.replace(/,(\s*[}\]])/g, "$1");
7142
+ import * as fs4 from "fs";
7143
+ import * as path5 from "path";
7144
+ function stripTrailingCommas(json3) {
7145
+ return json3.replace(/,(\s*[}\]])/g, "$1");
6992
7146
  }
6993
7147
  function removeFromBunLock(packageName) {
6994
- const lockPath = path4.join(CACHE_DIR, "bun.lock");
6995
- if (!fs2.existsSync(lockPath))
7148
+ const lockPath = path5.join(CACHE_DIR, "bun.lock");
7149
+ if (!fs4.existsSync(lockPath))
6996
7150
  return false;
6997
7151
  try {
6998
- const content = fs2.readFileSync(lockPath, "utf-8");
7152
+ const content = fs4.readFileSync(lockPath, "utf-8");
6999
7153
  const lock = JSON.parse(stripTrailingCommas(content));
7000
7154
  let modified = false;
7001
7155
  if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
@@ -7007,7 +7161,7 @@ function removeFromBunLock(packageName) {
7007
7161
  modified = true;
7008
7162
  }
7009
7163
  if (modified) {
7010
- fs2.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
7164
+ fs4.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
7011
7165
  log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
7012
7166
  }
7013
7167
  return modified;
@@ -7017,22 +7171,22 @@ function removeFromBunLock(packageName) {
7017
7171
  }
7018
7172
  function invalidatePackage(packageName = PACKAGE_NAME2) {
7019
7173
  try {
7020
- const pkgDir = path4.join(CACHE_DIR, "node_modules", packageName);
7021
- const pkgJsonPath = path4.join(CACHE_DIR, "package.json");
7174
+ const pkgDir = path5.join(CACHE_DIR, "node_modules", packageName);
7175
+ const pkgJsonPath = path5.join(CACHE_DIR, "package.json");
7022
7176
  let packageRemoved = false;
7023
7177
  let dependencyRemoved = false;
7024
7178
  let lockRemoved = false;
7025
- if (fs2.existsSync(pkgDir)) {
7026
- fs2.rmSync(pkgDir, { recursive: true, force: true });
7179
+ if (fs4.existsSync(pkgDir)) {
7180
+ fs4.rmSync(pkgDir, { recursive: true, force: true });
7027
7181
  log(`[auto-update-checker] Package removed: ${pkgDir}`);
7028
7182
  packageRemoved = true;
7029
7183
  }
7030
- if (fs2.existsSync(pkgJsonPath)) {
7031
- const content = fs2.readFileSync(pkgJsonPath, "utf-8");
7184
+ if (fs4.existsSync(pkgJsonPath)) {
7185
+ const content = fs4.readFileSync(pkgJsonPath, "utf-8");
7032
7186
  const pkgJson = JSON.parse(content);
7033
7187
  if (pkgJson.dependencies?.[packageName]) {
7034
7188
  delete pkgJson.dependencies[packageName];
7035
- fs2.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
7189
+ fs4.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
7036
7190
  log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
7037
7191
  dependencyRemoved = true;
7038
7192
  }
@@ -7069,11 +7223,11 @@ __export(exports_auto_update_checker, {
7069
7223
  createAutoUpdateCheckerHook: () => createAutoUpdateCheckerHook,
7070
7224
  checkForUpdate: () => checkForUpdate
7071
7225
  });
7072
- function isPrereleaseVersion(version) {
7073
- return version.includes("-");
7226
+ function isPrereleaseVersion(version2) {
7227
+ return version2.includes("-");
7074
7228
  }
7075
- function isDistTag(version) {
7076
- const startsWithDigit = /^\d/.test(version);
7229
+ function isDistTag(version2) {
7230
+ const startsWithDigit = /^\d/.test(version2);
7077
7231
  return !startsWithDigit;
7078
7232
  }
7079
7233
  function isPrereleaseOrDistTag(pinnedVersion) {
@@ -7081,14 +7235,14 @@ function isPrereleaseOrDistTag(pinnedVersion) {
7081
7235
  return false;
7082
7236
  return isPrereleaseVersion(pinnedVersion) || isDistTag(pinnedVersion);
7083
7237
  }
7084
- function extractChannel(version) {
7085
- if (!version)
7238
+ function extractChannel(version2) {
7239
+ if (!version2)
7086
7240
  return "latest";
7087
- if (isDistTag(version)) {
7088
- return version;
7241
+ if (isDistTag(version2)) {
7242
+ return version2;
7089
7243
  }
7090
- if (isPrereleaseVersion(version)) {
7091
- const prereleasePart = version.split("-")[1];
7244
+ if (isPrereleaseVersion(version2)) {
7245
+ const prereleasePart = version2.split("-")[1];
7092
7246
  if (prereleasePart) {
7093
7247
  const channelMatch = prereleasePart.match(/^(alpha|beta|rc|canary|next)/);
7094
7248
  if (channelMatch) {
@@ -7230,10 +7384,10 @@ async function updateAndShowConnectedProvidersCacheStatus(ctx) {
7230
7384
  }
7231
7385
  }
7232
7386
  async function showConfigErrorsIfAny(ctx) {
7233
- const errors = getConfigLoadErrors();
7234
- if (errors.length === 0)
7387
+ const errors3 = getConfigLoadErrors();
7388
+ if (errors3.length === 0)
7235
7389
  return;
7236
- const errorMessages = errors.map((e2) => `${e2.path}: ${e2.error}`).join(`
7390
+ const errorMessages = errors3.map((e2) => `${e2.path}: ${e2.error}`).join(`
7237
7391
  `);
7238
7392
  await ctx.client.tui.showToast({
7239
7393
  body: {
@@ -7244,15 +7398,15 @@ ${errorMessages}`,
7244
7398
  duration: 1e4
7245
7399
  }
7246
7400
  }).catch(() => {});
7247
- log(`[auto-update-checker] Config load errors shown: ${errors.length} error(s)`);
7401
+ log(`[auto-update-checker] Config load errors shown: ${errors3.length} error(s)`);
7248
7402
  clearConfigLoadErrors();
7249
7403
  }
7250
- async function showVersionToast(ctx, version, message) {
7251
- const displayVersion = version ?? "unknown";
7404
+ async function showVersionToast(ctx, version2, message) {
7405
+ const displayVersion = version2 ?? "unknown";
7252
7406
  await showSpinnerToast(ctx, displayVersion, message);
7253
7407
  log(`[auto-update-checker] Startup toast shown: v${displayVersion}`);
7254
7408
  }
7255
- async function showSpinnerToast(ctx, version, message) {
7409
+ async function showSpinnerToast(ctx, version2, message) {
7256
7410
  const totalDuration = 5000;
7257
7411
  const frameInterval = 100;
7258
7412
  const totalFrames = Math.floor(totalDuration / frameInterval);
@@ -7260,7 +7414,7 @@ async function showSpinnerToast(ctx, version, message) {
7260
7414
  const spinner = SISYPHUS_SPINNER[i2 % SISYPHUS_SPINNER.length];
7261
7415
  await ctx.client.tui.showToast({
7262
7416
  body: {
7263
- title: `${spinner} OhMyOpenCode ${version}`,
7417
+ title: `${spinner} OhMyOpenCode ${version2}`,
7264
7418
  message,
7265
7419
  variant: "info",
7266
7420
  duration: frameInterval + 50
@@ -7292,8 +7446,8 @@ Restart OpenCode to apply.`,
7292
7446
  }).catch(() => {});
7293
7447
  log(`[auto-update-checker] Auto-updated toast shown: v${oldVersion} \u2192 v${newVersion}`);
7294
7448
  }
7295
- async function showLocalDevToast(ctx, version, isSisyphusEnabled) {
7296
- const displayVersion = version ?? "dev";
7449
+ async function showLocalDevToast(ctx, version2, isSisyphusEnabled) {
7450
+ const displayVersion = version2 ?? "dev";
7297
7451
  const message = isSisyphusEnabled ? "Sisyphus running in local development mode." : "Running in local development mode. oMoMoMo...";
7298
7452
  await showSpinnerToast(ctx, `${displayVersion} (dev)`, message);
7299
7453
  log(`[auto-update-checker] Local dev toast shown: v${displayVersion}`);
@@ -7314,30 +7468,30 @@ var init_auto_update_checker = __esm(() => {
7314
7468
  });
7315
7469
 
7316
7470
  // src/hooks/auto-update-checker/checker.ts
7317
- import * as fs3 from "fs";
7318
- import * as path5 from "path";
7471
+ import * as fs5 from "fs";
7472
+ import * as path6 from "path";
7319
7473
  import { fileURLToPath } from "url";
7320
7474
  import * as os4 from "os";
7321
7475
  function isLocalDevMode(directory) {
7322
7476
  return getLocalDevPath(directory) !== null;
7323
7477
  }
7324
- function stripJsonComments(json2) {
7325
- return json2.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m2, g2) => g2 ? "" : m2).replace(/,(\s*[}\]])/g, "$1");
7478
+ function stripJsonComments(json3) {
7479
+ return json3.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m2, g2) => g2 ? "" : m2).replace(/,(\s*[}\]])/g, "$1");
7326
7480
  }
7327
7481
  function getConfigPaths(directory) {
7328
7482
  const paths = [
7329
- path5.join(directory, ".opencode", "opencode.json"),
7330
- path5.join(directory, ".opencode", "opencode.jsonc"),
7483
+ path6.join(directory, ".opencode", "opencode.json"),
7484
+ path6.join(directory, ".opencode", "opencode.jsonc"),
7331
7485
  USER_OPENCODE_CONFIG,
7332
7486
  USER_OPENCODE_CONFIG_JSONC
7333
7487
  ];
7334
7488
  if (process.platform === "win32") {
7335
- const crossPlatformDir = path5.join(os4.homedir(), ".config");
7489
+ const crossPlatformDir = path6.join(os4.homedir(), ".config");
7336
7490
  const appdataDir = getWindowsAppdataDir();
7337
7491
  if (appdataDir) {
7338
7492
  const alternateDir = USER_CONFIG_DIR === crossPlatformDir ? appdataDir : crossPlatformDir;
7339
- const alternateConfig = path5.join(alternateDir, "opencode", "opencode.json");
7340
- const alternateConfigJsonc = path5.join(alternateDir, "opencode", "opencode.jsonc");
7493
+ const alternateConfig = path6.join(alternateDir, "opencode", "opencode.json");
7494
+ const alternateConfigJsonc = path6.join(alternateDir, "opencode", "opencode.jsonc");
7341
7495
  if (!paths.includes(alternateConfig)) {
7342
7496
  paths.push(alternateConfig);
7343
7497
  }
@@ -7351,11 +7505,11 @@ function getConfigPaths(directory) {
7351
7505
  function getLocalDevPath(directory) {
7352
7506
  for (const configPath of getConfigPaths(directory)) {
7353
7507
  try {
7354
- if (!fs3.existsSync(configPath))
7508
+ if (!fs5.existsSync(configPath))
7355
7509
  continue;
7356
- const content = fs3.readFileSync(configPath, "utf-8");
7357
- const config = JSON.parse(stripJsonComments(content));
7358
- const plugins = config.plugin ?? [];
7510
+ const content = fs5.readFileSync(configPath, "utf-8");
7511
+ const config2 = JSON.parse(stripJsonComments(content));
7512
+ const plugins = config2.plugin ?? [];
7359
7513
  for (const entry of plugins) {
7360
7514
  if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME2)) {
7361
7515
  try {
@@ -7373,19 +7527,19 @@ function getLocalDevPath(directory) {
7373
7527
  }
7374
7528
  function findPackageJsonUp(startPath) {
7375
7529
  try {
7376
- const stat = fs3.statSync(startPath);
7377
- let dir = stat.isDirectory() ? startPath : path5.dirname(startPath);
7530
+ const stat = fs5.statSync(startPath);
7531
+ let dir = stat.isDirectory() ? startPath : path6.dirname(startPath);
7378
7532
  for (let i2 = 0;i2 < 10; i2++) {
7379
- const pkgPath = path5.join(dir, "package.json");
7380
- if (fs3.existsSync(pkgPath)) {
7533
+ const pkgPath = path6.join(dir, "package.json");
7534
+ if (fs5.existsSync(pkgPath)) {
7381
7535
  try {
7382
- const content = fs3.readFileSync(pkgPath, "utf-8");
7536
+ const content = fs5.readFileSync(pkgPath, "utf-8");
7383
7537
  const pkg = JSON.parse(content);
7384
7538
  if (pkg.name === PACKAGE_NAME2)
7385
7539
  return pkgPath;
7386
7540
  } catch {}
7387
7541
  }
7388
- const parent = path5.dirname(dir);
7542
+ const parent = path6.dirname(dir);
7389
7543
  if (parent === dir)
7390
7544
  break;
7391
7545
  dir = parent;
@@ -7401,7 +7555,7 @@ function getLocalDevVersion(directory) {
7401
7555
  const pkgPath = findPackageJsonUp(localPath);
7402
7556
  if (!pkgPath)
7403
7557
  return null;
7404
- const content = fs3.readFileSync(pkgPath, "utf-8");
7558
+ const content = fs5.readFileSync(pkgPath, "utf-8");
7405
7559
  const pkg = JSON.parse(content);
7406
7560
  return pkg.version ?? null;
7407
7561
  } catch {
@@ -7411,11 +7565,11 @@ function getLocalDevVersion(directory) {
7411
7565
  function findPluginEntry(directory) {
7412
7566
  for (const configPath of getConfigPaths(directory)) {
7413
7567
  try {
7414
- if (!fs3.existsSync(configPath))
7568
+ if (!fs5.existsSync(configPath))
7415
7569
  continue;
7416
- const content = fs3.readFileSync(configPath, "utf-8");
7417
- const config = JSON.parse(stripJsonComments(content));
7418
- const plugins = config.plugin ?? [];
7570
+ const content = fs5.readFileSync(configPath, "utf-8");
7571
+ const config2 = JSON.parse(stripJsonComments(content));
7572
+ const plugins = config2.plugin ?? [];
7419
7573
  for (const entry of plugins) {
7420
7574
  if (entry === PACKAGE_NAME2) {
7421
7575
  return { entry, isPinned: false, pinnedVersion: null, configPath };
@@ -7434,18 +7588,18 @@ function findPluginEntry(directory) {
7434
7588
  }
7435
7589
  function getCachedVersion() {
7436
7590
  try {
7437
- if (fs3.existsSync(INSTALLED_PACKAGE_JSON)) {
7438
- const content = fs3.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
7591
+ if (fs5.existsSync(INSTALLED_PACKAGE_JSON)) {
7592
+ const content = fs5.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
7439
7593
  const pkg = JSON.parse(content);
7440
7594
  if (pkg.version)
7441
7595
  return pkg.version;
7442
7596
  }
7443
7597
  } catch {}
7444
7598
  try {
7445
- const currentDir = path5.dirname(fileURLToPath(import.meta.url));
7599
+ const currentDir = path6.dirname(fileURLToPath(import.meta.url));
7446
7600
  const pkgPath = findPackageJsonUp(currentDir);
7447
7601
  if (pkgPath) {
7448
- const content = fs3.readFileSync(pkgPath, "utf-8");
7602
+ const content = fs5.readFileSync(pkgPath, "utf-8");
7449
7603
  const pkg = JSON.parse(content);
7450
7604
  if (pkg.version)
7451
7605
  return pkg.version;
@@ -7454,10 +7608,10 @@ function getCachedVersion() {
7454
7608
  log("[auto-update-checker] Failed to resolve version from current directory:", err);
7455
7609
  }
7456
7610
  try {
7457
- const execDir = path5.dirname(fs3.realpathSync(process.execPath));
7611
+ const execDir = path6.dirname(fs5.realpathSync(process.execPath));
7458
7612
  const pkgPath = findPackageJsonUp(execDir);
7459
7613
  if (pkgPath) {
7460
- const content = fs3.readFileSync(pkgPath, "utf-8");
7614
+ const content = fs5.readFileSync(pkgPath, "utf-8");
7461
7615
  const pkg = JSON.parse(content);
7462
7616
  if (pkg.version)
7463
7617
  return pkg.version;
@@ -7469,7 +7623,7 @@ function getCachedVersion() {
7469
7623
  }
7470
7624
  function updatePinnedVersion(configPath, oldEntry, newVersion) {
7471
7625
  try {
7472
- const content = fs3.readFileSync(configPath, "utf-8");
7626
+ const content = fs5.readFileSync(configPath, "utf-8");
7473
7627
  const newEntry = `${PACKAGE_NAME2}@${newVersion}`;
7474
7628
  const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
7475
7629
  if (!pluginMatch || pluginMatch.index === undefined) {
@@ -7501,7 +7655,7 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
7501
7655
  log(`[auto-update-checker] No changes made to ${configPath}`);
7502
7656
  return false;
7503
7657
  }
7504
- fs3.writeFileSync(configPath, updatedContent, "utf-8");
7658
+ fs5.writeFileSync(configPath, updatedContent, "utf-8");
7505
7659
  log(`[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
7506
7660
  return true;
7507
7661
  } catch (err) {
@@ -8160,7 +8314,7 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
8160
8314
  // package.json
8161
8315
  var package_default = {
8162
8316
  name: "oh-my-opencode",
8163
- version: "3.2.0",
8317
+ version: "3.2.2",
8164
8318
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8165
8319
  main: "dist/index.js",
8166
8320
  types: "dist/index.d.ts",
@@ -8230,17 +8384,17 @@ var package_default = {
8230
8384
  devDependencies: {
8231
8385
  "@types/js-yaml": "^4.0.9",
8232
8386
  "@types/picomatch": "^3.0.2",
8233
- "bun-types": "latest",
8387
+ "bun-types": "1.3.6",
8234
8388
  typescript: "^5.7.3"
8235
8389
  },
8236
8390
  optionalDependencies: {
8237
- "oh-my-opencode-darwin-arm64": "3.2.0",
8238
- "oh-my-opencode-darwin-x64": "3.2.0",
8239
- "oh-my-opencode-linux-arm64": "3.2.0",
8240
- "oh-my-opencode-linux-arm64-musl": "3.2.0",
8241
- "oh-my-opencode-linux-x64": "3.2.0",
8242
- "oh-my-opencode-linux-x64-musl": "3.2.0",
8243
- "oh-my-opencode-windows-x64": "3.2.0"
8391
+ "oh-my-opencode-darwin-arm64": "3.2.2",
8392
+ "oh-my-opencode-darwin-x64": "3.2.2",
8393
+ "oh-my-opencode-linux-arm64": "3.2.2",
8394
+ "oh-my-opencode-linux-arm64-musl": "3.2.2",
8395
+ "oh-my-opencode-linux-x64": "3.2.2",
8396
+ "oh-my-opencode-linux-x64-musl": "3.2.2",
8397
+ "oh-my-opencode-windows-x64": "3.2.2"
8244
8398
  },
8245
8399
  trustedDependencies: [
8246
8400
  "@ast-grep/cli",
@@ -10421,649 +10575,9 @@ function handleToolResult(ctx, payload, state) {
10421
10575
  state.lastPartText = "";
10422
10576
  }
10423
10577
 
10424
- // src/cli/run/runner.ts
10425
- var POLL_INTERVAL_MS = 500;
10426
- var DEFAULT_TIMEOUT_MS = 0;
10427
- var SESSION_CREATE_MAX_RETRIES = 3;
10428
- var SESSION_CREATE_RETRY_DELAY_MS = 1000;
10429
- async function run(options) {
10430
- const {
10431
- message,
10432
- agent,
10433
- directory = process.cwd(),
10434
- timeout = DEFAULT_TIMEOUT_MS
10435
- } = options;
10436
- console.log(import_picocolors5.default.cyan("Starting opencode server..."));
10437
- const abortController = new AbortController;
10438
- let timeoutId = null;
10439
- if (timeout > 0) {
10440
- timeoutId = setTimeout(() => {
10441
- console.log(import_picocolors5.default.yellow(`
10442
- Timeout reached. Aborting...`));
10443
- abortController.abort();
10444
- }, timeout);
10445
- }
10446
- try {
10447
- const serverPort = process.env.OPENCODE_SERVER_PORT ? parseInt(process.env.OPENCODE_SERVER_PORT, 10) : undefined;
10448
- const serverHostname = process.env.OPENCODE_SERVER_HOSTNAME || undefined;
10449
- const { client: client3, server: server2 } = await createOpencode({
10450
- signal: abortController.signal,
10451
- ...serverPort && !isNaN(serverPort) ? { port: serverPort } : {},
10452
- ...serverHostname ? { hostname: serverHostname } : {}
10453
- });
10454
- const cleanup = () => {
10455
- if (timeoutId)
10456
- clearTimeout(timeoutId);
10457
- server2.close();
10458
- };
10459
- process.on("SIGINT", () => {
10460
- console.log(import_picocolors5.default.yellow(`
10461
- Interrupted. Shutting down...`));
10462
- cleanup();
10463
- process.exit(130);
10464
- });
10465
- try {
10466
- let sessionID;
10467
- let lastError;
10468
- for (let attempt = 1;attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) {
10469
- const sessionRes = await client3.session.create({
10470
- body: { title: "oh-my-opencode run" }
10471
- });
10472
- if (sessionRes.error) {
10473
- lastError = sessionRes.error;
10474
- console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
10475
- console.error(import_picocolors5.default.dim(` Error: ${serializeError(sessionRes.error)}`));
10476
- if (attempt < SESSION_CREATE_MAX_RETRIES) {
10477
- const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
10478
- console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
10479
- await new Promise((resolve2) => setTimeout(resolve2, delay));
10480
- continue;
10481
- }
10482
- }
10483
- sessionID = sessionRes.data?.id;
10484
- if (sessionID) {
10485
- break;
10486
- }
10487
- lastError = new Error(`Unexpected response: ${JSON.stringify(sessionRes, null, 2)}`);
10488
- console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`));
10489
- if (attempt < SESSION_CREATE_MAX_RETRIES) {
10490
- const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
10491
- console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
10492
- await new Promise((resolve2) => setTimeout(resolve2, delay));
10493
- }
10494
- }
10495
- if (!sessionID) {
10496
- console.error(import_picocolors5.default.red("Failed to create session after all retries"));
10497
- console.error(import_picocolors5.default.dim(`Last error: ${serializeError(lastError)}`));
10498
- cleanup();
10499
- return 1;
10500
- }
10501
- console.log(import_picocolors5.default.dim(`Session: ${sessionID}`));
10502
- const ctx = {
10503
- client: client3,
10504
- sessionID,
10505
- directory,
10506
- abortController
10507
- };
10508
- const events = await client3.event.subscribe();
10509
- const eventState = createEventState();
10510
- const eventProcessor = processEvents(ctx, events.stream, eventState);
10511
- console.log(import_picocolors5.default.dim(`
10512
- Sending prompt...`));
10513
- await client3.session.promptAsync({
10514
- path: { id: sessionID },
10515
- body: {
10516
- agent,
10517
- parts: [{ type: "text", text: message }]
10518
- },
10519
- query: { directory }
10520
- });
10521
- console.log(import_picocolors5.default.dim(`Waiting for completion...
10522
- `));
10523
- while (!abortController.signal.aborted) {
10524
- await new Promise((resolve2) => setTimeout(resolve2, POLL_INTERVAL_MS));
10525
- if (!eventState.mainSessionIdle) {
10526
- continue;
10527
- }
10528
- if (eventState.mainSessionError) {
10529
- console.error(import_picocolors5.default.red(`
10530
-
10531
- Session ended with error: ${eventState.lastError}`));
10532
- console.error(import_picocolors5.default.yellow("Check if todos were completed before the error."));
10533
- cleanup();
10534
- process.exit(1);
10535
- }
10536
- if (!eventState.hasReceivedMeaningfulWork) {
10537
- continue;
10538
- }
10539
- const shouldExit = await checkCompletionConditions(ctx);
10540
- if (shouldExit) {
10541
- console.log(import_picocolors5.default.green(`
10542
-
10543
- All tasks completed.`));
10544
- cleanup();
10545
- process.exit(0);
10546
- }
10547
- }
10548
- await eventProcessor.catch(() => {});
10549
- cleanup();
10550
- return 130;
10551
- } catch (err) {
10552
- cleanup();
10553
- throw err;
10554
- }
10555
- } catch (err) {
10556
- if (timeoutId)
10557
- clearTimeout(timeoutId);
10558
- if (err instanceof Error && err.name === "AbortError") {
10559
- return 130;
10560
- }
10561
- console.error(import_picocolors5.default.red(`Error: ${serializeError(err)}`));
10562
- return 1;
10563
- }
10564
- }
10565
- // src/cli/get-local-version/index.ts
10566
- init_checker();
10567
-
10568
- // src/cli/get-local-version/formatter.ts
10569
- var import_picocolors6 = __toESM(require_picocolors(), 1);
10570
- var SYMBOLS2 = {
10571
- check: import_picocolors6.default.green("[OK]"),
10572
- cross: import_picocolors6.default.red("[X]"),
10573
- arrow: import_picocolors6.default.cyan("->"),
10574
- info: import_picocolors6.default.blue("[i]"),
10575
- warn: import_picocolors6.default.yellow("[!]"),
10576
- pin: import_picocolors6.default.magenta("[PINNED]"),
10577
- dev: import_picocolors6.default.cyan("[DEV]")
10578
- };
10579
- function formatVersionOutput(info) {
10580
- const lines = [];
10581
- lines.push("");
10582
- lines.push(import_picocolors6.default.bold(import_picocolors6.default.white("oh-my-opencode Version Information")));
10583
- lines.push(import_picocolors6.default.dim("\u2500".repeat(50)));
10584
- lines.push("");
10585
- if (info.currentVersion) {
10586
- lines.push(` Current Version: ${import_picocolors6.default.cyan(info.currentVersion)}`);
10587
- } else {
10588
- lines.push(` Current Version: ${import_picocolors6.default.dim("unknown")}`);
10589
- }
10590
- if (!info.isLocalDev && info.latestVersion) {
10591
- lines.push(` Latest Version: ${import_picocolors6.default.cyan(info.latestVersion)}`);
10592
- }
10593
- lines.push("");
10594
- switch (info.status) {
10595
- case "up-to-date":
10596
- lines.push(` ${SYMBOLS2.check} ${import_picocolors6.default.green("You're up to date!")}`);
10597
- break;
10598
- case "outdated":
10599
- lines.push(` ${SYMBOLS2.warn} ${import_picocolors6.default.yellow("Update available")}`);
10600
- lines.push(` ${import_picocolors6.default.dim("Run:")} ${import_picocolors6.default.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`);
10601
- break;
10602
- case "local-dev":
10603
- lines.push(` ${SYMBOLS2.dev} ${import_picocolors6.default.cyan("Running in local development mode")}`);
10604
- lines.push(` ${import_picocolors6.default.dim("Using file:// protocol from config")}`);
10605
- break;
10606
- case "pinned":
10607
- lines.push(` ${SYMBOLS2.pin} ${import_picocolors6.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
10608
- lines.push(` ${import_picocolors6.default.dim("Update check skipped for pinned versions")}`);
10609
- break;
10610
- case "error":
10611
- lines.push(` ${SYMBOLS2.cross} ${import_picocolors6.default.red("Unable to check for updates")}`);
10612
- lines.push(` ${import_picocolors6.default.dim("Network error or npm registry unavailable")}`);
10613
- break;
10614
- case "unknown":
10615
- lines.push(` ${SYMBOLS2.info} ${import_picocolors6.default.yellow("Version information unavailable")}`);
10616
- break;
10617
- }
10618
- lines.push("");
10619
- return lines.join(`
10620
- `);
10621
- }
10622
- function formatJsonOutput(info) {
10623
- return JSON.stringify(info, null, 2);
10624
- }
10625
-
10626
- // src/cli/get-local-version/index.ts
10627
- async function getLocalVersion(options = {}) {
10628
- const directory = options.directory ?? process.cwd();
10629
- try {
10630
- if (isLocalDevMode(directory)) {
10631
- const currentVersion2 = getCachedVersion();
10632
- const info2 = {
10633
- currentVersion: currentVersion2,
10634
- latestVersion: null,
10635
- isUpToDate: false,
10636
- isLocalDev: true,
10637
- isPinned: false,
10638
- pinnedVersion: null,
10639
- status: "local-dev"
10640
- };
10641
- console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
10642
- return 0;
10643
- }
10644
- const pluginInfo = findPluginEntry(directory);
10645
- if (pluginInfo?.isPinned) {
10646
- const info2 = {
10647
- currentVersion: pluginInfo.pinnedVersion,
10648
- latestVersion: null,
10649
- isUpToDate: false,
10650
- isLocalDev: false,
10651
- isPinned: true,
10652
- pinnedVersion: pluginInfo.pinnedVersion,
10653
- status: "pinned"
10654
- };
10655
- console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
10656
- return 0;
10657
- }
10658
- const currentVersion = getCachedVersion();
10659
- if (!currentVersion) {
10660
- const info2 = {
10661
- currentVersion: null,
10662
- latestVersion: null,
10663
- isUpToDate: false,
10664
- isLocalDev: false,
10665
- isPinned: false,
10666
- pinnedVersion: null,
10667
- status: "unknown"
10668
- };
10669
- console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
10670
- return 1;
10671
- }
10672
- const { extractChannel: extractChannel2 } = await Promise.resolve().then(() => (init_auto_update_checker(), exports_auto_update_checker));
10673
- const channel = extractChannel2(pluginInfo?.pinnedVersion ?? currentVersion);
10674
- const latestVersion = await getLatestVersion(channel);
10675
- if (!latestVersion) {
10676
- const info2 = {
10677
- currentVersion,
10678
- latestVersion: null,
10679
- isUpToDate: false,
10680
- isLocalDev: false,
10681
- isPinned: false,
10682
- pinnedVersion: null,
10683
- status: "error"
10684
- };
10685
- console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
10686
- return 0;
10687
- }
10688
- const isUpToDate = currentVersion === latestVersion;
10689
- const info = {
10690
- currentVersion,
10691
- latestVersion,
10692
- isUpToDate,
10693
- isLocalDev: false,
10694
- isPinned: false,
10695
- pinnedVersion: null,
10696
- status: isUpToDate ? "up-to-date" : "outdated"
10697
- };
10698
- console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
10699
- return 0;
10700
- } catch (error) {
10701
- const info = {
10702
- currentVersion: null,
10703
- latestVersion: null,
10704
- isUpToDate: false,
10705
- isLocalDev: false,
10706
- isPinned: false,
10707
- pinnedVersion: null,
10708
- status: "error"
10709
- };
10710
- console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
10711
- return 1;
10712
- }
10713
- }
10714
-
10715
- // src/cli/doctor/checks/opencode.ts
10716
- import { existsSync as existsSync8 } from "fs";
10717
- import { homedir as homedir5 } from "os";
10718
- import { join as join10 } from "path";
10719
-
10720
- // src/cli/doctor/constants.ts
10721
- var import_picocolors7 = __toESM(require_picocolors(), 1);
10722
- var SYMBOLS3 = {
10723
- check: import_picocolors7.default.green("\u2713"),
10724
- cross: import_picocolors7.default.red("\u2717"),
10725
- warn: import_picocolors7.default.yellow("\u26A0"),
10726
- info: import_picocolors7.default.blue("\u2139"),
10727
- arrow: import_picocolors7.default.cyan("\u2192"),
10728
- bullet: import_picocolors7.default.dim("\u2022"),
10729
- skip: import_picocolors7.default.dim("\u25CB")
10730
- };
10731
- var STATUS_COLORS = {
10732
- pass: import_picocolors7.default.green,
10733
- fail: import_picocolors7.default.red,
10734
- warn: import_picocolors7.default.yellow,
10735
- skip: import_picocolors7.default.dim
10736
- };
10737
- var CHECK_IDS = {
10738
- OPENCODE_INSTALLATION: "opencode-installation",
10739
- PLUGIN_REGISTRATION: "plugin-registration",
10740
- CONFIG_VALIDATION: "config-validation",
10741
- MODEL_RESOLUTION: "model-resolution",
10742
- AUTH_ANTHROPIC: "auth-anthropic",
10743
- AUTH_OPENAI: "auth-openai",
10744
- AUTH_GOOGLE: "auth-google",
10745
- DEP_AST_GREP_CLI: "dep-ast-grep-cli",
10746
- DEP_AST_GREP_NAPI: "dep-ast-grep-napi",
10747
- DEP_COMMENT_CHECKER: "dep-comment-checker",
10748
- GH_CLI: "gh-cli",
10749
- LSP_SERVERS: "lsp-servers",
10750
- MCP_BUILTIN: "mcp-builtin",
10751
- MCP_USER: "mcp-user",
10752
- MCP_OAUTH_TOKENS: "mcp-oauth-tokens",
10753
- VERSION_STATUS: "version-status"
10754
- };
10755
- var CHECK_NAMES = {
10756
- [CHECK_IDS.OPENCODE_INSTALLATION]: "OpenCode Installation",
10757
- [CHECK_IDS.PLUGIN_REGISTRATION]: "Plugin Registration",
10758
- [CHECK_IDS.CONFIG_VALIDATION]: "Configuration Validity",
10759
- [CHECK_IDS.MODEL_RESOLUTION]: "Model Resolution",
10760
- [CHECK_IDS.AUTH_ANTHROPIC]: "Anthropic (Claude) Auth",
10761
- [CHECK_IDS.AUTH_OPENAI]: "OpenAI (ChatGPT) Auth",
10762
- [CHECK_IDS.AUTH_GOOGLE]: "Google (Gemini) Auth",
10763
- [CHECK_IDS.DEP_AST_GREP_CLI]: "AST-Grep CLI",
10764
- [CHECK_IDS.DEP_AST_GREP_NAPI]: "AST-Grep NAPI",
10765
- [CHECK_IDS.DEP_COMMENT_CHECKER]: "Comment Checker",
10766
- [CHECK_IDS.GH_CLI]: "GitHub CLI",
10767
- [CHECK_IDS.LSP_SERVERS]: "LSP Servers",
10768
- [CHECK_IDS.MCP_BUILTIN]: "Built-in MCP Servers",
10769
- [CHECK_IDS.MCP_USER]: "User MCP Configuration",
10770
- [CHECK_IDS.MCP_OAUTH_TOKENS]: "MCP OAuth Tokens",
10771
- [CHECK_IDS.VERSION_STATUS]: "Version Status"
10772
- };
10773
- var CATEGORY_NAMES = {
10774
- installation: "Installation",
10775
- configuration: "Configuration",
10776
- authentication: "Authentication",
10777
- dependencies: "Dependencies",
10778
- tools: "Tools & Servers",
10779
- updates: "Updates"
10780
- };
10781
- var EXIT_CODES = {
10782
- SUCCESS: 0,
10783
- FAILURE: 1
10784
- };
10785
- var MIN_OPENCODE_VERSION = "1.0.150";
10786
- var PACKAGE_NAME3 = "oh-my-opencode";
10787
- var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
10788
-
10789
- // src/cli/doctor/checks/opencode.ts
10790
- function getDesktopAppPaths(platform) {
10791
- const home = homedir5();
10792
- switch (platform) {
10793
- case "darwin":
10794
- return [
10795
- "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
10796
- join10(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
10797
- ];
10798
- case "win32": {
10799
- const programFiles = process.env.ProgramFiles;
10800
- const localAppData = process.env.LOCALAPPDATA;
10801
- const paths = [];
10802
- if (programFiles) {
10803
- paths.push(join10(programFiles, "OpenCode", "OpenCode.exe"));
10804
- }
10805
- if (localAppData) {
10806
- paths.push(join10(localAppData, "OpenCode", "OpenCode.exe"));
10807
- }
10808
- return paths;
10809
- }
10810
- case "linux":
10811
- return [
10812
- "/usr/bin/opencode",
10813
- "/usr/lib/opencode/opencode",
10814
- join10(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
10815
- join10(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
10816
- ];
10817
- default:
10818
- return [];
10819
- }
10820
- }
10821
- function buildVersionCommand(binaryPath, platform) {
10822
- if (platform === "win32" && binaryPath.toLowerCase().endsWith(".ps1")) {
10823
- return [
10824
- "powershell",
10825
- "-NoProfile",
10826
- "-ExecutionPolicy",
10827
- "Bypass",
10828
- "-File",
10829
- binaryPath,
10830
- "--version"
10831
- ];
10832
- }
10833
- return [binaryPath, "--version"];
10834
- }
10835
- function findDesktopBinary(platform = process.platform, checkExists = existsSync8) {
10836
- const desktopPaths = getDesktopAppPaths(platform);
10837
- for (const desktopPath of desktopPaths) {
10838
- if (checkExists(desktopPath)) {
10839
- return { binary: "opencode", path: desktopPath };
10840
- }
10841
- }
10842
- return null;
10843
- }
10844
- async function findOpenCodeBinary() {
10845
- for (const binary2 of OPENCODE_BINARIES2) {
10846
- try {
10847
- const path6 = Bun.which(binary2);
10848
- if (path6) {
10849
- return { binary: binary2, path: path6 };
10850
- }
10851
- } catch {
10852
- continue;
10853
- }
10854
- }
10855
- const desktopResult = findDesktopBinary();
10856
- if (desktopResult) {
10857
- return desktopResult;
10858
- }
10859
- return null;
10860
- }
10861
- async function getOpenCodeVersion2(binaryPath, platform = process.platform) {
10862
- try {
10863
- const command = buildVersionCommand(binaryPath, platform);
10864
- const proc = Bun.spawn(command, { stdout: "pipe", stderr: "pipe" });
10865
- const output = await new Response(proc.stdout).text();
10866
- await proc.exited;
10867
- if (proc.exitCode === 0) {
10868
- return output.trim();
10869
- }
10870
- } catch {
10871
- return null;
10872
- }
10873
- return null;
10874
- }
10875
- function compareVersions(current, minimum) {
10876
- const parseVersion = (v) => {
10877
- const cleaned = v.replace(/^v/, "").split("-")[0];
10878
- return cleaned.split(".").map((n) => parseInt(n, 10) || 0);
10879
- };
10880
- const curr = parseVersion(current);
10881
- const min = parseVersion(minimum);
10882
- for (let i2 = 0;i2 < Math.max(curr.length, min.length); i2++) {
10883
- const c = curr[i2] ?? 0;
10884
- const m2 = min[i2] ?? 0;
10885
- if (c > m2)
10886
- return true;
10887
- if (c < m2)
10888
- return false;
10889
- }
10890
- return true;
10891
- }
10892
- async function getOpenCodeInfo() {
10893
- const binaryInfo = await findOpenCodeBinary();
10894
- if (!binaryInfo) {
10895
- return {
10896
- installed: false,
10897
- version: null,
10898
- path: null,
10899
- binary: null
10900
- };
10901
- }
10902
- const version = await getOpenCodeVersion2(binaryInfo.path ?? binaryInfo.binary);
10903
- return {
10904
- installed: true,
10905
- version,
10906
- path: binaryInfo.path,
10907
- binary: binaryInfo.binary
10908
- };
10909
- }
10910
- async function checkOpenCodeInstallation() {
10911
- const info = await getOpenCodeInfo();
10912
- if (!info.installed) {
10913
- return {
10914
- name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
10915
- status: "fail",
10916
- message: "OpenCode is not installed",
10917
- details: [
10918
- "Visit: https://opencode.ai/docs for installation instructions",
10919
- "Run: npm install -g opencode"
10920
- ]
10921
- };
10922
- }
10923
- if (info.version && !compareVersions(info.version, MIN_OPENCODE_VERSION)) {
10924
- return {
10925
- name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
10926
- status: "warn",
10927
- message: `Version ${info.version} is below minimum ${MIN_OPENCODE_VERSION}`,
10928
- details: [
10929
- `Current: ${info.version}`,
10930
- `Required: >= ${MIN_OPENCODE_VERSION}`,
10931
- "Run: npm update -g opencode"
10932
- ]
10933
- };
10934
- }
10935
- return {
10936
- name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
10937
- status: "pass",
10938
- message: info.version ?? "installed",
10939
- details: info.path ? [`Path: ${info.path}`] : undefined
10940
- };
10941
- }
10942
- function getOpenCodeCheckDefinition() {
10943
- return {
10944
- id: CHECK_IDS.OPENCODE_INSTALLATION,
10945
- name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
10946
- category: "installation",
10947
- check: checkOpenCodeInstallation,
10948
- critical: true
10949
- };
10950
- }
10951
-
10952
- // src/cli/doctor/checks/plugin.ts
10953
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
10954
- init_shared();
10955
- function detectConfigPath() {
10956
- const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
10957
- if (existsSync9(paths.configJsonc)) {
10958
- return { path: paths.configJsonc, format: "jsonc" };
10959
- }
10960
- if (existsSync9(paths.configJson)) {
10961
- return { path: paths.configJson, format: "json" };
10962
- }
10963
- return null;
10964
- }
10965
- function findPluginEntry2(plugins) {
10966
- for (const plugin of plugins) {
10967
- if (plugin === PACKAGE_NAME3 || plugin.startsWith(`${PACKAGE_NAME3}@`)) {
10968
- const isPinned = plugin.includes("@");
10969
- const version = isPinned ? plugin.split("@")[1] : null;
10970
- return { entry: plugin, isPinned, version };
10971
- }
10972
- if (plugin.startsWith("file://") && plugin.includes(PACKAGE_NAME3)) {
10973
- return { entry: plugin, isPinned: false, version: "local-dev" };
10974
- }
10975
- }
10976
- return null;
10977
- }
10978
- function getPluginInfo() {
10979
- const configInfo = detectConfigPath();
10980
- if (!configInfo) {
10981
- return {
10982
- registered: false,
10983
- configPath: null,
10984
- entry: null,
10985
- isPinned: false,
10986
- pinnedVersion: null
10987
- };
10988
- }
10989
- try {
10990
- const content = readFileSync7(configInfo.path, "utf-8");
10991
- const config = parseJsonc(content);
10992
- const plugins = config.plugin ?? [];
10993
- const pluginEntry = findPluginEntry2(plugins);
10994
- if (!pluginEntry) {
10995
- return {
10996
- registered: false,
10997
- configPath: configInfo.path,
10998
- entry: null,
10999
- isPinned: false,
11000
- pinnedVersion: null
11001
- };
11002
- }
11003
- return {
11004
- registered: true,
11005
- configPath: configInfo.path,
11006
- entry: pluginEntry.entry,
11007
- isPinned: pluginEntry.isPinned,
11008
- pinnedVersion: pluginEntry.version
11009
- };
11010
- } catch {
11011
- return {
11012
- registered: false,
11013
- configPath: configInfo.path,
11014
- entry: null,
11015
- isPinned: false,
11016
- pinnedVersion: null
11017
- };
11018
- }
11019
- }
11020
- async function checkPluginRegistration() {
11021
- const info = getPluginInfo();
11022
- if (!info.configPath) {
11023
- const expectedPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
11024
- return {
11025
- name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
11026
- status: "fail",
11027
- message: "OpenCode config file not found",
11028
- details: [
11029
- "Run: bunx oh-my-opencode install",
11030
- `Expected: ${expectedPaths.configJson} or ${expectedPaths.configJsonc}`
11031
- ]
11032
- };
11033
- }
11034
- if (!info.registered) {
11035
- return {
11036
- name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
11037
- status: "fail",
11038
- message: "Plugin not registered in config",
11039
- details: [
11040
- "Run: bunx oh-my-opencode install",
11041
- `Config: ${info.configPath}`
11042
- ]
11043
- };
11044
- }
11045
- const message = info.isPinned ? `Registered (pinned: ${info.pinnedVersion})` : "Registered";
11046
- return {
11047
- name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
11048
- status: "pass",
11049
- message,
11050
- details: [`Config: ${info.configPath}`]
11051
- };
11052
- }
11053
- function getPluginCheckDefinition() {
11054
- return {
11055
- id: CHECK_IDS.PLUGIN_REGISTRATION,
11056
- name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
11057
- category: "installation",
11058
- check: checkPluginRegistration,
11059
- critical: true
11060
- };
11061
- }
11062
-
11063
- // src/cli/doctor/checks/config.ts
11064
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
11065
- import { join as join11 } from "path";
11066
- init_shared();
10578
+ // src/plugin-config.ts
10579
+ import * as fs3 from "fs";
10580
+ import * as path3 from "path";
11067
10581
 
11068
10582
  // node_modules/zod/v4/classic/external.js
11069
10583
  var exports_external = {};
@@ -11830,10 +11344,10 @@ function mergeDefs(...defs) {
11830
11344
  function cloneDef(schema2) {
11831
11345
  return mergeDefs(schema2._zod.def);
11832
11346
  }
11833
- function getElementAtPath(obj, path6) {
11834
- if (!path6)
11347
+ function getElementAtPath(obj, path3) {
11348
+ if (!path3)
11835
11349
  return obj;
11836
- return path6.reduce((acc, key) => acc?.[key], obj);
11350
+ return path3.reduce((acc, key) => acc?.[key], obj);
11837
11351
  }
11838
11352
  function promiseAllObject(promisesObj) {
11839
11353
  const keys = Object.keys(promisesObj);
@@ -12214,11 +11728,11 @@ function aborted(x2, startIndex = 0) {
12214
11728
  }
12215
11729
  return false;
12216
11730
  }
12217
- function prefixIssues(path6, issues) {
11731
+ function prefixIssues(path3, issues) {
12218
11732
  return issues.map((iss) => {
12219
11733
  var _a;
12220
11734
  (_a = iss).path ?? (_a.path = []);
12221
- iss.path.unshift(path6);
11735
+ iss.path.unshift(path3);
12222
11736
  return iss;
12223
11737
  });
12224
11738
  }
@@ -12401,7 +11915,7 @@ function formatError2(error, mapper = (issue2) => issue2.message) {
12401
11915
  }
12402
11916
  function treeifyError(error, mapper = (issue2) => issue2.message) {
12403
11917
  const result = { errors: [] };
12404
- const processError = (error2, path6 = []) => {
11918
+ const processError = (error2, path3 = []) => {
12405
11919
  var _a, _b;
12406
11920
  for (const issue2 of error2.issues) {
12407
11921
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -12411,7 +11925,7 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
12411
11925
  } else if (issue2.code === "invalid_element") {
12412
11926
  processError({ issues: issue2.issues }, issue2.path);
12413
11927
  } else {
12414
- const fullpath = [...path6, ...issue2.path];
11928
+ const fullpath = [...path3, ...issue2.path];
12415
11929
  if (fullpath.length === 0) {
12416
11930
  result.errors.push(mapper(issue2));
12417
11931
  continue;
@@ -12443,8 +11957,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
12443
11957
  }
12444
11958
  function toDotPath(_path) {
12445
11959
  const segs = [];
12446
- const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12447
- for (const seg of path6) {
11960
+ const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11961
+ for (const seg of path3) {
12448
11962
  if (typeof seg === "number")
12449
11963
  segs.push(`[${seg}]`);
12450
11964
  else if (typeof seg === "symbol")
@@ -21423,10 +20937,10 @@ function _property(property, schema2, params) {
21423
20937
  ...normalizeParams(params)
21424
20938
  });
21425
20939
  }
21426
- function _mime(types3, params) {
20940
+ function _mime(types2, params) {
21427
20941
  return new $ZodCheckMimeType({
21428
20942
  check: "mime_type",
21429
- mime: types3,
20943
+ mime: types2,
21430
20944
  ...normalizeParams(params)
21431
20945
  });
21432
20946
  }
@@ -23779,7 +23293,7 @@ var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
23779
23293
  inst._zod.processJSONSchema = (ctx, json2, params) => fileProcessor(inst, ctx, json2, params);
23780
23294
  inst.min = (size, params) => inst.check(_minSize(size, params));
23781
23295
  inst.max = (size, params) => inst.check(_maxSize(size, params));
23782
- inst.mime = (types3, params) => inst.check(_mime(Array.isArray(types3) ? types3 : [types3], params));
23296
+ inst.mime = (types2, params) => inst.check(_mime(Array.isArray(types2) ? types2 : [types2], params));
23783
23297
  });
23784
23298
  function file(params) {
23785
23299
  return _file(ZodFile, params);
@@ -24191,13 +23705,13 @@ function resolveRef(ref, ctx) {
24191
23705
  if (!ref.startsWith("#")) {
24192
23706
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24193
23707
  }
24194
- const path6 = ref.slice(1).split("/").filter(Boolean);
24195
- if (path6.length === 0) {
23708
+ const path3 = ref.slice(1).split("/").filter(Boolean);
23709
+ if (path3.length === 0) {
24196
23710
  return ctx.rootSchema;
24197
23711
  }
24198
23712
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24199
- if (path6[0] === defsKey) {
24200
- const key = path6[1];
23713
+ if (path3[0] === defsKey) {
23714
+ const key = path3[1];
24201
23715
  if (!key || !ctx.defs[key]) {
24202
23716
  throw new Error(`Reference not found: ${ref}`);
24203
23717
  }
@@ -24661,6 +24175,7 @@ var HookNameSchema = exports_external.enum([
24661
24175
  "empty-task-response-detector",
24662
24176
  "think-mode",
24663
24177
  "anthropic-context-window-limit-recovery",
24178
+ "preemptive-compaction",
24664
24179
  "rules-injector",
24665
24180
  "background-notification",
24666
24181
  "auto-update-checker",
@@ -24682,7 +24197,8 @@ var HookNameSchema = exports_external.enum([
24682
24197
  "start-work",
24683
24198
  "atlas",
24684
24199
  "unstable-agent-babysitter",
24685
- "stop-continuation-guard"
24200
+ "stop-continuation-guard",
24201
+ "tasks-todowrite-disabler"
24686
24202
  ]);
24687
24203
  var BuiltinCommandNameSchema = exports_external.enum([
24688
24204
  "init-deep",
@@ -24807,8 +24323,10 @@ var DynamicContextPruningConfigSchema = exports_external.object({
24807
24323
  var ExperimentalConfigSchema = exports_external.object({
24808
24324
  aggressive_truncation: exports_external.boolean().optional(),
24809
24325
  auto_resume: exports_external.boolean().optional(),
24326
+ preemptive_compaction: exports_external.boolean().optional(),
24810
24327
  truncate_all_tool_outputs: exports_external.boolean().optional(),
24811
- dynamic_context_pruning: DynamicContextPruningConfigSchema.optional()
24328
+ dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
24329
+ task_system: exports_external.boolean().optional()
24812
24330
  });
24813
24331
  var SkillSourceSchema = exports_external.union([
24814
24332
  exports_external.string(),
@@ -24884,26 +24402,22 @@ var TmuxConfigSchema = exports_external.object({
24884
24402
  agent_pane_min_width: exports_external.number().min(20).default(40)
24885
24403
  });
24886
24404
  var SisyphusTasksConfigSchema = exports_external.object({
24887
- enabled: exports_external.boolean().default(false),
24888
24405
  storage_path: exports_external.string().default(".sisyphus/tasks"),
24889
24406
  claude_code_compat: exports_external.boolean().default(false)
24890
24407
  });
24891
- var SisyphusSwarmConfigSchema = exports_external.object({
24892
- enabled: exports_external.boolean().default(false),
24893
- storage_path: exports_external.string().default(".sisyphus/teams"),
24894
- ui_mode: exports_external.enum(["toast", "tmux", "both"]).default("toast")
24895
- });
24896
24408
  var SisyphusConfigSchema = exports_external.object({
24897
- tasks: SisyphusTasksConfigSchema.optional(),
24898
- swarm: SisyphusSwarmConfigSchema.optional()
24409
+ tasks: SisyphusTasksConfigSchema.optional()
24899
24410
  });
24900
24411
  var OhMyOpenCodeConfigSchema = exports_external.object({
24901
24412
  $schema: exports_external.string().optional(),
24413
+ new_task_system_enabled: exports_external.boolean().optional(),
24414
+ default_run_agent: exports_external.string().optional(),
24902
24415
  disabled_mcps: exports_external.array(AnyMcpNameSchema).optional(),
24903
24416
  disabled_agents: exports_external.array(BuiltinAgentNameSchema).optional(),
24904
24417
  disabled_skills: exports_external.array(BuiltinSkillNameSchema).optional(),
24905
24418
  disabled_hooks: exports_external.array(HookNameSchema).optional(),
24906
24419
  disabled_commands: exports_external.array(BuiltinCommandNameSchema).optional(),
24420
+ disabled_tools: exports_external.array(exports_external.string()).optional(),
24907
24421
  agents: AgentOverridesSchema.optional(),
24908
24422
  categories: CategoriesConfigSchema.optional(),
24909
24423
  claude_code: ClaudeCodeConfigSchema.optional(),
@@ -24921,10 +24435,792 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
24921
24435
  tmux: TmuxConfigSchema.optional(),
24922
24436
  sisyphus: SisyphusConfigSchema.optional()
24923
24437
  });
24438
+ // src/plugin-config.ts
24439
+ init_shared();
24440
+ function loadConfigFromPath(configPath, ctx) {
24441
+ try {
24442
+ if (fs3.existsSync(configPath)) {
24443
+ const content = fs3.readFileSync(configPath, "utf-8");
24444
+ const rawConfig = parseJsonc(content);
24445
+ migrateConfigFile(configPath, rawConfig);
24446
+ const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
24447
+ if (!result.success) {
24448
+ const errorMsg = result.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join(", ");
24449
+ log(`Config validation error in ${configPath}:`, result.error.issues);
24450
+ addConfigLoadError({
24451
+ path: configPath,
24452
+ error: `Validation error: ${errorMsg}`
24453
+ });
24454
+ return null;
24455
+ }
24456
+ log(`Config loaded from ${configPath}`, { agents: result.data.agents });
24457
+ return result.data;
24458
+ }
24459
+ } catch (err) {
24460
+ const errorMsg = err instanceof Error ? err.message : String(err);
24461
+ log(`Error loading config from ${configPath}:`, err);
24462
+ addConfigLoadError({ path: configPath, error: errorMsg });
24463
+ }
24464
+ return null;
24465
+ }
24466
+ function mergeConfigs2(base, override) {
24467
+ return {
24468
+ ...base,
24469
+ ...override,
24470
+ agents: deepMerge(base.agents, override.agents),
24471
+ categories: deepMerge(base.categories, override.categories),
24472
+ disabled_agents: [
24473
+ ...new Set([
24474
+ ...base.disabled_agents ?? [],
24475
+ ...override.disabled_agents ?? []
24476
+ ])
24477
+ ],
24478
+ disabled_mcps: [
24479
+ ...new Set([
24480
+ ...base.disabled_mcps ?? [],
24481
+ ...override.disabled_mcps ?? []
24482
+ ])
24483
+ ],
24484
+ disabled_hooks: [
24485
+ ...new Set([
24486
+ ...base.disabled_hooks ?? [],
24487
+ ...override.disabled_hooks ?? []
24488
+ ])
24489
+ ],
24490
+ disabled_commands: [
24491
+ ...new Set([
24492
+ ...base.disabled_commands ?? [],
24493
+ ...override.disabled_commands ?? []
24494
+ ])
24495
+ ],
24496
+ disabled_skills: [
24497
+ ...new Set([
24498
+ ...base.disabled_skills ?? [],
24499
+ ...override.disabled_skills ?? []
24500
+ ])
24501
+ ],
24502
+ claude_code: deepMerge(base.claude_code, override.claude_code)
24503
+ };
24504
+ }
24505
+ function loadPluginConfig(directory, ctx) {
24506
+ const configDir = getOpenCodeConfigDir({ binary: "opencode" });
24507
+ const userBasePath = path3.join(configDir, "oh-my-opencode");
24508
+ const userDetected = detectConfigFile(userBasePath);
24509
+ const userConfigPath = userDetected.format !== "none" ? userDetected.path : userBasePath + ".json";
24510
+ const projectBasePath = path3.join(directory, ".opencode", "oh-my-opencode");
24511
+ const projectDetected = detectConfigFile(projectBasePath);
24512
+ const projectConfigPath = projectDetected.format !== "none" ? projectDetected.path : projectBasePath + ".json";
24513
+ let config2 = loadConfigFromPath(userConfigPath, ctx) ?? {};
24514
+ const projectConfig = loadConfigFromPath(projectConfigPath, ctx);
24515
+ if (projectConfig) {
24516
+ config2 = mergeConfigs2(config2, projectConfig);
24517
+ }
24518
+ config2 = {
24519
+ ...config2
24520
+ };
24521
+ log("Final merged config", {
24522
+ agents: config2.agents,
24523
+ disabled_agents: config2.disabled_agents,
24524
+ disabled_mcps: config2.disabled_mcps,
24525
+ disabled_hooks: config2.disabled_hooks,
24526
+ claude_code: config2.claude_code
24527
+ });
24528
+ return config2;
24529
+ }
24530
+
24531
+ // src/cli/run/runner.ts
24532
+ var POLL_INTERVAL_MS = 500;
24533
+ var DEFAULT_TIMEOUT_MS = 0;
24534
+ var SESSION_CREATE_MAX_RETRIES = 3;
24535
+ var SESSION_CREATE_RETRY_DELAY_MS = 1000;
24536
+ var CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"];
24537
+ var DEFAULT_AGENT = "sisyphus";
24538
+ var normalizeAgentName = (agent) => {
24539
+ if (!agent)
24540
+ return;
24541
+ const trimmed = agent.trim();
24542
+ if (!trimmed)
24543
+ return;
24544
+ const lowered = trimmed.toLowerCase();
24545
+ const coreMatch = CORE_AGENT_ORDER.find((name) => name.toLowerCase() === lowered);
24546
+ return coreMatch ?? trimmed;
24547
+ };
24548
+ var isAgentDisabled = (agent, config2) => {
24549
+ const lowered = agent.toLowerCase();
24550
+ if (lowered === "sisyphus" && config2.sisyphus_agent?.disabled === true) {
24551
+ return true;
24552
+ }
24553
+ return (config2.disabled_agents ?? []).some((disabled) => disabled.toLowerCase() === lowered);
24554
+ };
24555
+ var pickFallbackAgent = (config2) => {
24556
+ for (const agent of CORE_AGENT_ORDER) {
24557
+ if (!isAgentDisabled(agent, config2)) {
24558
+ return agent;
24559
+ }
24560
+ }
24561
+ return DEFAULT_AGENT;
24562
+ };
24563
+ var resolveRunAgent = (options, pluginConfig, env = process.env) => {
24564
+ const cliAgent = normalizeAgentName(options.agent);
24565
+ const envAgent = normalizeAgentName(env.OPENCODE_DEFAULT_AGENT);
24566
+ const configAgent = normalizeAgentName(pluginConfig.default_run_agent);
24567
+ const resolved = cliAgent ?? envAgent ?? configAgent ?? DEFAULT_AGENT;
24568
+ const normalized = normalizeAgentName(resolved) ?? DEFAULT_AGENT;
24569
+ if (isAgentDisabled(normalized, pluginConfig)) {
24570
+ const fallback = pickFallbackAgent(pluginConfig);
24571
+ const fallbackDisabled = isAgentDisabled(fallback, pluginConfig);
24572
+ if (fallbackDisabled) {
24573
+ console.log(import_picocolors5.default.yellow(`Requested agent "${normalized}" is disabled and no enabled core agent was found. Proceeding with "${fallback}".`));
24574
+ return fallback;
24575
+ }
24576
+ console.log(import_picocolors5.default.yellow(`Requested agent "${normalized}" is disabled. Falling back to "${fallback}".`));
24577
+ return fallback;
24578
+ }
24579
+ return normalized;
24580
+ };
24581
+ async function run(options) {
24582
+ process.env.OPENCODE_CLI_RUN_MODE = "true";
24583
+ const {
24584
+ message,
24585
+ directory = process.cwd(),
24586
+ timeout = DEFAULT_TIMEOUT_MS
24587
+ } = options;
24588
+ const pluginConfig = loadPluginConfig(directory, { command: "run" });
24589
+ const resolvedAgent = resolveRunAgent(options, pluginConfig);
24590
+ console.log(import_picocolors5.default.cyan("Starting opencode server..."));
24591
+ const abortController = new AbortController;
24592
+ let timeoutId = null;
24593
+ if (timeout > 0) {
24594
+ timeoutId = setTimeout(() => {
24595
+ console.log(import_picocolors5.default.yellow(`
24596
+ Timeout reached. Aborting...`));
24597
+ abortController.abort();
24598
+ }, timeout);
24599
+ }
24600
+ try {
24601
+ const serverPort = process.env.OPENCODE_SERVER_PORT ? parseInt(process.env.OPENCODE_SERVER_PORT, 10) : undefined;
24602
+ const serverHostname = process.env.OPENCODE_SERVER_HOSTNAME || undefined;
24603
+ const { client: client3, server: server2 } = await createOpencode({
24604
+ signal: abortController.signal,
24605
+ ...serverPort && !isNaN(serverPort) ? { port: serverPort } : {},
24606
+ ...serverHostname ? { hostname: serverHostname } : {}
24607
+ });
24608
+ const cleanup = () => {
24609
+ if (timeoutId)
24610
+ clearTimeout(timeoutId);
24611
+ server2.close();
24612
+ };
24613
+ process.on("SIGINT", () => {
24614
+ console.log(import_picocolors5.default.yellow(`
24615
+ Interrupted. Shutting down...`));
24616
+ cleanup();
24617
+ process.exit(130);
24618
+ });
24619
+ try {
24620
+ let sessionID;
24621
+ let lastError;
24622
+ for (let attempt = 1;attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) {
24623
+ const sessionRes = await client3.session.create({
24624
+ body: { title: "oh-my-opencode run" }
24625
+ });
24626
+ if (sessionRes.error) {
24627
+ lastError = sessionRes.error;
24628
+ console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`));
24629
+ console.error(import_picocolors5.default.dim(` Error: ${serializeError(sessionRes.error)}`));
24630
+ if (attempt < SESSION_CREATE_MAX_RETRIES) {
24631
+ const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
24632
+ console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
24633
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
24634
+ continue;
24635
+ }
24636
+ }
24637
+ sessionID = sessionRes.data?.id;
24638
+ if (sessionID) {
24639
+ break;
24640
+ }
24641
+ lastError = new Error(`Unexpected response: ${JSON.stringify(sessionRes, null, 2)}`);
24642
+ console.error(import_picocolors5.default.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`));
24643
+ if (attempt < SESSION_CREATE_MAX_RETRIES) {
24644
+ const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt;
24645
+ console.log(import_picocolors5.default.dim(` Retrying in ${delay}ms...`));
24646
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
24647
+ }
24648
+ }
24649
+ if (!sessionID) {
24650
+ console.error(import_picocolors5.default.red("Failed to create session after all retries"));
24651
+ console.error(import_picocolors5.default.dim(`Last error: ${serializeError(lastError)}`));
24652
+ cleanup();
24653
+ return 1;
24654
+ }
24655
+ console.log(import_picocolors5.default.dim(`Session: ${sessionID}`));
24656
+ const ctx = {
24657
+ client: client3,
24658
+ sessionID,
24659
+ directory,
24660
+ abortController
24661
+ };
24662
+ const events = await client3.event.subscribe();
24663
+ const eventState = createEventState();
24664
+ const eventProcessor = processEvents(ctx, events.stream, eventState);
24665
+ console.log(import_picocolors5.default.dim(`
24666
+ Sending prompt...`));
24667
+ await client3.session.promptAsync({
24668
+ path: { id: sessionID },
24669
+ body: {
24670
+ agent: resolvedAgent,
24671
+ parts: [{ type: "text", text: message }]
24672
+ },
24673
+ query: { directory }
24674
+ });
24675
+ console.log(import_picocolors5.default.dim(`Waiting for completion...
24676
+ `));
24677
+ while (!abortController.signal.aborted) {
24678
+ await new Promise((resolve2) => setTimeout(resolve2, POLL_INTERVAL_MS));
24679
+ if (!eventState.mainSessionIdle) {
24680
+ continue;
24681
+ }
24682
+ if (eventState.mainSessionError) {
24683
+ console.error(import_picocolors5.default.red(`
24684
+
24685
+ Session ended with error: ${eventState.lastError}`));
24686
+ console.error(import_picocolors5.default.yellow("Check if todos were completed before the error."));
24687
+ cleanup();
24688
+ process.exit(1);
24689
+ }
24690
+ if (!eventState.hasReceivedMeaningfulWork) {
24691
+ continue;
24692
+ }
24693
+ const shouldExit = await checkCompletionConditions(ctx);
24694
+ if (shouldExit) {
24695
+ console.log(import_picocolors5.default.green(`
24696
+
24697
+ All tasks completed.`));
24698
+ cleanup();
24699
+ process.exit(0);
24700
+ }
24701
+ }
24702
+ await eventProcessor.catch(() => {});
24703
+ cleanup();
24704
+ return 130;
24705
+ } catch (err) {
24706
+ cleanup();
24707
+ throw err;
24708
+ }
24709
+ } catch (err) {
24710
+ if (timeoutId)
24711
+ clearTimeout(timeoutId);
24712
+ if (err instanceof Error && err.name === "AbortError") {
24713
+ return 130;
24714
+ }
24715
+ console.error(import_picocolors5.default.red(`Error: ${serializeError(err)}`));
24716
+ return 1;
24717
+ }
24718
+ }
24719
+ // src/cli/get-local-version/index.ts
24720
+ init_checker();
24721
+
24722
+ // src/cli/get-local-version/formatter.ts
24723
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
24724
+ var SYMBOLS2 = {
24725
+ check: import_picocolors6.default.green("[OK]"),
24726
+ cross: import_picocolors6.default.red("[X]"),
24727
+ arrow: import_picocolors6.default.cyan("->"),
24728
+ info: import_picocolors6.default.blue("[i]"),
24729
+ warn: import_picocolors6.default.yellow("[!]"),
24730
+ pin: import_picocolors6.default.magenta("[PINNED]"),
24731
+ dev: import_picocolors6.default.cyan("[DEV]")
24732
+ };
24733
+ function formatVersionOutput(info) {
24734
+ const lines = [];
24735
+ lines.push("");
24736
+ lines.push(import_picocolors6.default.bold(import_picocolors6.default.white("oh-my-opencode Version Information")));
24737
+ lines.push(import_picocolors6.default.dim("\u2500".repeat(50)));
24738
+ lines.push("");
24739
+ if (info.currentVersion) {
24740
+ lines.push(` Current Version: ${import_picocolors6.default.cyan(info.currentVersion)}`);
24741
+ } else {
24742
+ lines.push(` Current Version: ${import_picocolors6.default.dim("unknown")}`);
24743
+ }
24744
+ if (!info.isLocalDev && info.latestVersion) {
24745
+ lines.push(` Latest Version: ${import_picocolors6.default.cyan(info.latestVersion)}`);
24746
+ }
24747
+ lines.push("");
24748
+ switch (info.status) {
24749
+ case "up-to-date":
24750
+ lines.push(` ${SYMBOLS2.check} ${import_picocolors6.default.green("You're up to date!")}`);
24751
+ break;
24752
+ case "outdated":
24753
+ lines.push(` ${SYMBOLS2.warn} ${import_picocolors6.default.yellow("Update available")}`);
24754
+ lines.push(` ${import_picocolors6.default.dim("Run:")} ${import_picocolors6.default.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`);
24755
+ break;
24756
+ case "local-dev":
24757
+ lines.push(` ${SYMBOLS2.dev} ${import_picocolors6.default.cyan("Running in local development mode")}`);
24758
+ lines.push(` ${import_picocolors6.default.dim("Using file:// protocol from config")}`);
24759
+ break;
24760
+ case "pinned":
24761
+ lines.push(` ${SYMBOLS2.pin} ${import_picocolors6.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
24762
+ lines.push(` ${import_picocolors6.default.dim("Update check skipped for pinned versions")}`);
24763
+ break;
24764
+ case "error":
24765
+ lines.push(` ${SYMBOLS2.cross} ${import_picocolors6.default.red("Unable to check for updates")}`);
24766
+ lines.push(` ${import_picocolors6.default.dim("Network error or npm registry unavailable")}`);
24767
+ break;
24768
+ case "unknown":
24769
+ lines.push(` ${SYMBOLS2.info} ${import_picocolors6.default.yellow("Version information unavailable")}`);
24770
+ break;
24771
+ }
24772
+ lines.push("");
24773
+ return lines.join(`
24774
+ `);
24775
+ }
24776
+ function formatJsonOutput(info) {
24777
+ return JSON.stringify(info, null, 2);
24778
+ }
24779
+
24780
+ // src/cli/get-local-version/index.ts
24781
+ async function getLocalVersion(options = {}) {
24782
+ const directory = options.directory ?? process.cwd();
24783
+ try {
24784
+ if (isLocalDevMode(directory)) {
24785
+ const currentVersion2 = getCachedVersion();
24786
+ const info2 = {
24787
+ currentVersion: currentVersion2,
24788
+ latestVersion: null,
24789
+ isUpToDate: false,
24790
+ isLocalDev: true,
24791
+ isPinned: false,
24792
+ pinnedVersion: null,
24793
+ status: "local-dev"
24794
+ };
24795
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
24796
+ return 0;
24797
+ }
24798
+ const pluginInfo = findPluginEntry(directory);
24799
+ if (pluginInfo?.isPinned) {
24800
+ const info2 = {
24801
+ currentVersion: pluginInfo.pinnedVersion,
24802
+ latestVersion: null,
24803
+ isUpToDate: false,
24804
+ isLocalDev: false,
24805
+ isPinned: true,
24806
+ pinnedVersion: pluginInfo.pinnedVersion,
24807
+ status: "pinned"
24808
+ };
24809
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
24810
+ return 0;
24811
+ }
24812
+ const currentVersion = getCachedVersion();
24813
+ if (!currentVersion) {
24814
+ const info2 = {
24815
+ currentVersion: null,
24816
+ latestVersion: null,
24817
+ isUpToDate: false,
24818
+ isLocalDev: false,
24819
+ isPinned: false,
24820
+ pinnedVersion: null,
24821
+ status: "unknown"
24822
+ };
24823
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
24824
+ return 1;
24825
+ }
24826
+ const { extractChannel: extractChannel2 } = await Promise.resolve().then(() => (init_auto_update_checker(), exports_auto_update_checker));
24827
+ const channel = extractChannel2(pluginInfo?.pinnedVersion ?? currentVersion);
24828
+ const latestVersion = await getLatestVersion(channel);
24829
+ if (!latestVersion) {
24830
+ const info2 = {
24831
+ currentVersion,
24832
+ latestVersion: null,
24833
+ isUpToDate: false,
24834
+ isLocalDev: false,
24835
+ isPinned: false,
24836
+ pinnedVersion: null,
24837
+ status: "error"
24838
+ };
24839
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
24840
+ return 0;
24841
+ }
24842
+ const isUpToDate = currentVersion === latestVersion;
24843
+ const info = {
24844
+ currentVersion,
24845
+ latestVersion,
24846
+ isUpToDate,
24847
+ isLocalDev: false,
24848
+ isPinned: false,
24849
+ pinnedVersion: null,
24850
+ status: isUpToDate ? "up-to-date" : "outdated"
24851
+ };
24852
+ console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
24853
+ return 0;
24854
+ } catch (error48) {
24855
+ const info = {
24856
+ currentVersion: null,
24857
+ latestVersion: null,
24858
+ isUpToDate: false,
24859
+ isLocalDev: false,
24860
+ isPinned: false,
24861
+ pinnedVersion: null,
24862
+ status: "error"
24863
+ };
24864
+ console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
24865
+ return 1;
24866
+ }
24867
+ }
24868
+
24869
+ // src/cli/doctor/checks/opencode.ts
24870
+ import { existsSync as existsSync9 } from "fs";
24871
+ import { homedir as homedir5 } from "os";
24872
+ import { join as join11 } from "path";
24873
+
24874
+ // src/cli/doctor/constants.ts
24875
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
24876
+ var SYMBOLS3 = {
24877
+ check: import_picocolors7.default.green("\u2713"),
24878
+ cross: import_picocolors7.default.red("\u2717"),
24879
+ warn: import_picocolors7.default.yellow("\u26A0"),
24880
+ info: import_picocolors7.default.blue("\u2139"),
24881
+ arrow: import_picocolors7.default.cyan("\u2192"),
24882
+ bullet: import_picocolors7.default.dim("\u2022"),
24883
+ skip: import_picocolors7.default.dim("\u25CB")
24884
+ };
24885
+ var STATUS_COLORS = {
24886
+ pass: import_picocolors7.default.green,
24887
+ fail: import_picocolors7.default.red,
24888
+ warn: import_picocolors7.default.yellow,
24889
+ skip: import_picocolors7.default.dim
24890
+ };
24891
+ var CHECK_IDS = {
24892
+ OPENCODE_INSTALLATION: "opencode-installation",
24893
+ PLUGIN_REGISTRATION: "plugin-registration",
24894
+ CONFIG_VALIDATION: "config-validation",
24895
+ MODEL_RESOLUTION: "model-resolution",
24896
+ AUTH_ANTHROPIC: "auth-anthropic",
24897
+ AUTH_OPENAI: "auth-openai",
24898
+ AUTH_GOOGLE: "auth-google",
24899
+ DEP_AST_GREP_CLI: "dep-ast-grep-cli",
24900
+ DEP_AST_GREP_NAPI: "dep-ast-grep-napi",
24901
+ DEP_COMMENT_CHECKER: "dep-comment-checker",
24902
+ GH_CLI: "gh-cli",
24903
+ LSP_SERVERS: "lsp-servers",
24904
+ MCP_BUILTIN: "mcp-builtin",
24905
+ MCP_USER: "mcp-user",
24906
+ MCP_OAUTH_TOKENS: "mcp-oauth-tokens",
24907
+ VERSION_STATUS: "version-status"
24908
+ };
24909
+ var CHECK_NAMES = {
24910
+ [CHECK_IDS.OPENCODE_INSTALLATION]: "OpenCode Installation",
24911
+ [CHECK_IDS.PLUGIN_REGISTRATION]: "Plugin Registration",
24912
+ [CHECK_IDS.CONFIG_VALIDATION]: "Configuration Validity",
24913
+ [CHECK_IDS.MODEL_RESOLUTION]: "Model Resolution",
24914
+ [CHECK_IDS.AUTH_ANTHROPIC]: "Anthropic (Claude) Auth",
24915
+ [CHECK_IDS.AUTH_OPENAI]: "OpenAI (ChatGPT) Auth",
24916
+ [CHECK_IDS.AUTH_GOOGLE]: "Google (Gemini) Auth",
24917
+ [CHECK_IDS.DEP_AST_GREP_CLI]: "AST-Grep CLI",
24918
+ [CHECK_IDS.DEP_AST_GREP_NAPI]: "AST-Grep NAPI",
24919
+ [CHECK_IDS.DEP_COMMENT_CHECKER]: "Comment Checker",
24920
+ [CHECK_IDS.GH_CLI]: "GitHub CLI",
24921
+ [CHECK_IDS.LSP_SERVERS]: "LSP Servers",
24922
+ [CHECK_IDS.MCP_BUILTIN]: "Built-in MCP Servers",
24923
+ [CHECK_IDS.MCP_USER]: "User MCP Configuration",
24924
+ [CHECK_IDS.MCP_OAUTH_TOKENS]: "MCP OAuth Tokens",
24925
+ [CHECK_IDS.VERSION_STATUS]: "Version Status"
24926
+ };
24927
+ var CATEGORY_NAMES = {
24928
+ installation: "Installation",
24929
+ configuration: "Configuration",
24930
+ authentication: "Authentication",
24931
+ dependencies: "Dependencies",
24932
+ tools: "Tools & Servers",
24933
+ updates: "Updates"
24934
+ };
24935
+ var EXIT_CODES = {
24936
+ SUCCESS: 0,
24937
+ FAILURE: 1
24938
+ };
24939
+ var MIN_OPENCODE_VERSION = "1.0.150";
24940
+ var PACKAGE_NAME3 = "oh-my-opencode";
24941
+ var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
24942
+
24943
+ // src/cli/doctor/checks/opencode.ts
24944
+ function getDesktopAppPaths(platform) {
24945
+ const home = homedir5();
24946
+ switch (platform) {
24947
+ case "darwin":
24948
+ return [
24949
+ "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
24950
+ join11(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
24951
+ ];
24952
+ case "win32": {
24953
+ const programFiles = process.env.ProgramFiles;
24954
+ const localAppData = process.env.LOCALAPPDATA;
24955
+ const paths = [];
24956
+ if (programFiles) {
24957
+ paths.push(join11(programFiles, "OpenCode", "OpenCode.exe"));
24958
+ }
24959
+ if (localAppData) {
24960
+ paths.push(join11(localAppData, "OpenCode", "OpenCode.exe"));
24961
+ }
24962
+ return paths;
24963
+ }
24964
+ case "linux":
24965
+ return [
24966
+ "/usr/bin/opencode",
24967
+ "/usr/lib/opencode/opencode",
24968
+ join11(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
24969
+ join11(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
24970
+ ];
24971
+ default:
24972
+ return [];
24973
+ }
24974
+ }
24975
+ function buildVersionCommand(binaryPath, platform) {
24976
+ if (platform === "win32" && binaryPath.toLowerCase().endsWith(".ps1")) {
24977
+ return [
24978
+ "powershell",
24979
+ "-NoProfile",
24980
+ "-ExecutionPolicy",
24981
+ "Bypass",
24982
+ "-File",
24983
+ binaryPath,
24984
+ "--version"
24985
+ ];
24986
+ }
24987
+ return [binaryPath, "--version"];
24988
+ }
24989
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync9) {
24990
+ const desktopPaths = getDesktopAppPaths(platform);
24991
+ for (const desktopPath of desktopPaths) {
24992
+ if (checkExists(desktopPath)) {
24993
+ return { binary: "opencode", path: desktopPath };
24994
+ }
24995
+ }
24996
+ return null;
24997
+ }
24998
+ async function findOpenCodeBinary() {
24999
+ for (const binary2 of OPENCODE_BINARIES2) {
25000
+ try {
25001
+ const path7 = Bun.which(binary2);
25002
+ if (path7) {
25003
+ return { binary: binary2, path: path7 };
25004
+ }
25005
+ } catch {
25006
+ continue;
25007
+ }
25008
+ }
25009
+ const desktopResult = findDesktopBinary();
25010
+ if (desktopResult) {
25011
+ return desktopResult;
25012
+ }
25013
+ return null;
25014
+ }
25015
+ async function getOpenCodeVersion2(binaryPath, platform = process.platform) {
25016
+ try {
25017
+ const command = buildVersionCommand(binaryPath, platform);
25018
+ const proc = Bun.spawn(command, { stdout: "pipe", stderr: "pipe" });
25019
+ const output = await new Response(proc.stdout).text();
25020
+ await proc.exited;
25021
+ if (proc.exitCode === 0) {
25022
+ return output.trim();
25023
+ }
25024
+ } catch {
25025
+ return null;
25026
+ }
25027
+ return null;
25028
+ }
25029
+ function compareVersions(current, minimum) {
25030
+ const parseVersion = (v) => {
25031
+ const cleaned = v.replace(/^v/, "").split("-")[0];
25032
+ return cleaned.split(".").map((n) => parseInt(n, 10) || 0);
25033
+ };
25034
+ const curr = parseVersion(current);
25035
+ const min = parseVersion(minimum);
25036
+ for (let i2 = 0;i2 < Math.max(curr.length, min.length); i2++) {
25037
+ const c = curr[i2] ?? 0;
25038
+ const m2 = min[i2] ?? 0;
25039
+ if (c > m2)
25040
+ return true;
25041
+ if (c < m2)
25042
+ return false;
25043
+ }
25044
+ return true;
25045
+ }
25046
+ async function getOpenCodeInfo() {
25047
+ const binaryInfo = await findOpenCodeBinary();
25048
+ if (!binaryInfo) {
25049
+ return {
25050
+ installed: false,
25051
+ version: null,
25052
+ path: null,
25053
+ binary: null
25054
+ };
25055
+ }
25056
+ const version2 = await getOpenCodeVersion2(binaryInfo.path ?? binaryInfo.binary);
25057
+ return {
25058
+ installed: true,
25059
+ version: version2,
25060
+ path: binaryInfo.path,
25061
+ binary: binaryInfo.binary
25062
+ };
25063
+ }
25064
+ async function checkOpenCodeInstallation() {
25065
+ const info = await getOpenCodeInfo();
25066
+ if (!info.installed) {
25067
+ return {
25068
+ name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
25069
+ status: "fail",
25070
+ message: "OpenCode is not installed",
25071
+ details: [
25072
+ "Visit: https://opencode.ai/docs for installation instructions",
25073
+ "Run: npm install -g opencode"
25074
+ ]
25075
+ };
25076
+ }
25077
+ if (info.version && !compareVersions(info.version, MIN_OPENCODE_VERSION)) {
25078
+ return {
25079
+ name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
25080
+ status: "warn",
25081
+ message: `Version ${info.version} is below minimum ${MIN_OPENCODE_VERSION}`,
25082
+ details: [
25083
+ `Current: ${info.version}`,
25084
+ `Required: >= ${MIN_OPENCODE_VERSION}`,
25085
+ "Run: npm update -g opencode"
25086
+ ]
25087
+ };
25088
+ }
25089
+ return {
25090
+ name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
25091
+ status: "pass",
25092
+ message: info.version ?? "installed",
25093
+ details: info.path ? [`Path: ${info.path}`] : undefined
25094
+ };
25095
+ }
25096
+ function getOpenCodeCheckDefinition() {
25097
+ return {
25098
+ id: CHECK_IDS.OPENCODE_INSTALLATION,
25099
+ name: CHECK_NAMES[CHECK_IDS.OPENCODE_INSTALLATION],
25100
+ category: "installation",
25101
+ check: checkOpenCodeInstallation,
25102
+ critical: true
25103
+ };
25104
+ }
25105
+
25106
+ // src/cli/doctor/checks/plugin.ts
25107
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
25108
+ init_shared();
25109
+ function detectConfigPath() {
25110
+ const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
25111
+ if (existsSync10(paths.configJsonc)) {
25112
+ return { path: paths.configJsonc, format: "jsonc" };
25113
+ }
25114
+ if (existsSync10(paths.configJson)) {
25115
+ return { path: paths.configJson, format: "json" };
25116
+ }
25117
+ return null;
25118
+ }
25119
+ function findPluginEntry2(plugins) {
25120
+ for (const plugin of plugins) {
25121
+ if (plugin === PACKAGE_NAME3 || plugin.startsWith(`${PACKAGE_NAME3}@`)) {
25122
+ const isPinned = plugin.includes("@");
25123
+ const version2 = isPinned ? plugin.split("@")[1] : null;
25124
+ return { entry: plugin, isPinned, version: version2 };
25125
+ }
25126
+ if (plugin.startsWith("file://") && plugin.includes(PACKAGE_NAME3)) {
25127
+ return { entry: plugin, isPinned: false, version: "local-dev" };
25128
+ }
25129
+ }
25130
+ return null;
25131
+ }
25132
+ function getPluginInfo() {
25133
+ const configInfo = detectConfigPath();
25134
+ if (!configInfo) {
25135
+ return {
25136
+ registered: false,
25137
+ configPath: null,
25138
+ entry: null,
25139
+ isPinned: false,
25140
+ pinnedVersion: null
25141
+ };
25142
+ }
25143
+ try {
25144
+ const content = readFileSync8(configInfo.path, "utf-8");
25145
+ const config2 = parseJsonc(content);
25146
+ const plugins = config2.plugin ?? [];
25147
+ const pluginEntry = findPluginEntry2(plugins);
25148
+ if (!pluginEntry) {
25149
+ return {
25150
+ registered: false,
25151
+ configPath: configInfo.path,
25152
+ entry: null,
25153
+ isPinned: false,
25154
+ pinnedVersion: null
25155
+ };
25156
+ }
25157
+ return {
25158
+ registered: true,
25159
+ configPath: configInfo.path,
25160
+ entry: pluginEntry.entry,
25161
+ isPinned: pluginEntry.isPinned,
25162
+ pinnedVersion: pluginEntry.version
25163
+ };
25164
+ } catch {
25165
+ return {
25166
+ registered: false,
25167
+ configPath: configInfo.path,
25168
+ entry: null,
25169
+ isPinned: false,
25170
+ pinnedVersion: null
25171
+ };
25172
+ }
25173
+ }
25174
+ async function checkPluginRegistration() {
25175
+ const info = getPluginInfo();
25176
+ if (!info.configPath) {
25177
+ const expectedPaths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
25178
+ return {
25179
+ name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
25180
+ status: "fail",
25181
+ message: "OpenCode config file not found",
25182
+ details: [
25183
+ "Run: bunx oh-my-opencode install",
25184
+ `Expected: ${expectedPaths.configJson} or ${expectedPaths.configJsonc}`
25185
+ ]
25186
+ };
25187
+ }
25188
+ if (!info.registered) {
25189
+ return {
25190
+ name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
25191
+ status: "fail",
25192
+ message: "Plugin not registered in config",
25193
+ details: [
25194
+ "Run: bunx oh-my-opencode install",
25195
+ `Config: ${info.configPath}`
25196
+ ]
25197
+ };
25198
+ }
25199
+ const message = info.isPinned ? `Registered (pinned: ${info.pinnedVersion})` : "Registered";
25200
+ return {
25201
+ name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
25202
+ status: "pass",
25203
+ message,
25204
+ details: [`Config: ${info.configPath}`]
25205
+ };
25206
+ }
25207
+ function getPluginCheckDefinition() {
25208
+ return {
25209
+ id: CHECK_IDS.PLUGIN_REGISTRATION,
25210
+ name: CHECK_NAMES[CHECK_IDS.PLUGIN_REGISTRATION],
25211
+ category: "installation",
25212
+ check: checkPluginRegistration,
25213
+ critical: true
25214
+ };
25215
+ }
25216
+
24924
25217
  // src/cli/doctor/checks/config.ts
25218
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
25219
+ import { join as join12 } from "path";
25220
+ init_shared();
24925
25221
  var USER_CONFIG_DIR2 = getOpenCodeConfigDir({ binary: "opencode" });
24926
- var USER_CONFIG_BASE = join11(USER_CONFIG_DIR2, `${PACKAGE_NAME3}`);
24927
- var PROJECT_CONFIG_BASE = join11(process.cwd(), ".opencode", PACKAGE_NAME3);
25222
+ var USER_CONFIG_BASE = join12(USER_CONFIG_DIR2, `${PACKAGE_NAME3}`);
25223
+ var PROJECT_CONFIG_BASE = join12(process.cwd(), ".opencode", PACKAGE_NAME3);
24928
25224
  function findConfigPath() {
24929
25225
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE);
24930
25226
  if (projectDetected.format !== "none") {
@@ -24938,7 +25234,7 @@ function findConfigPath() {
24938
25234
  }
24939
25235
  function validateConfig(configPath) {
24940
25236
  try {
24941
- const content = readFileSync8(configPath, "utf-8");
25237
+ const content = readFileSync9(configPath, "utf-8");
24942
25238
  const rawConfig = parseJsonc(content);
24943
25239
  const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
24944
25240
  if (!result.success) {
@@ -24964,7 +25260,7 @@ function getConfigInfo() {
24964
25260
  errors: []
24965
25261
  };
24966
25262
  }
24967
- if (!existsSync10(configPath.path)) {
25263
+ if (!existsSync11(configPath.path)) {
24968
25264
  return {
24969
25265
  exists: false,
24970
25266
  path: configPath.path,
@@ -25021,24 +25317,24 @@ function getConfigCheckDefinition() {
25021
25317
  }
25022
25318
 
25023
25319
  // src/cli/doctor/checks/model-resolution.ts
25024
- import { readFileSync as readFileSync9, existsSync as existsSync11 } from "fs";
25320
+ import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
25025
25321
  init_shared();
25026
25322
  init_model_requirements();
25027
25323
  import { homedir as homedir6 } from "os";
25028
- import { join as join12 } from "path";
25324
+ import { join as join13 } from "path";
25029
25325
  function getOpenCodeCacheDir2() {
25030
25326
  const xdgCache = process.env.XDG_CACHE_HOME;
25031
25327
  if (xdgCache)
25032
- return join12(xdgCache, "opencode");
25033
- return join12(homedir6(), ".cache", "opencode");
25328
+ return join13(xdgCache, "opencode");
25329
+ return join13(homedir6(), ".cache", "opencode");
25034
25330
  }
25035
25331
  function loadAvailableModels() {
25036
- const cacheFile = join12(getOpenCodeCacheDir2(), "models.json");
25037
- if (!existsSync11(cacheFile)) {
25332
+ const cacheFile = join13(getOpenCodeCacheDir2(), "models.json");
25333
+ if (!existsSync12(cacheFile)) {
25038
25334
  return { providers: [], modelCount: 0, cacheExists: false };
25039
25335
  }
25040
25336
  try {
25041
- const content = readFileSync9(cacheFile, "utf-8");
25337
+ const content = readFileSync10(cacheFile, "utf-8");
25042
25338
  const data = JSON.parse(content);
25043
25339
  const providers = Object.keys(data);
25044
25340
  let modelCount = 0;
@@ -25054,14 +25350,14 @@ function loadAvailableModels() {
25054
25350
  }
25055
25351
  }
25056
25352
  var PACKAGE_NAME4 = "oh-my-opencode";
25057
- var USER_CONFIG_DIR3 = join12(homedir6(), ".config", "opencode");
25058
- var USER_CONFIG_BASE2 = join12(USER_CONFIG_DIR3, PACKAGE_NAME4);
25059
- var PROJECT_CONFIG_BASE2 = join12(process.cwd(), ".opencode", PACKAGE_NAME4);
25353
+ var USER_CONFIG_DIR3 = join13(homedir6(), ".config", "opencode");
25354
+ var USER_CONFIG_BASE2 = join13(USER_CONFIG_DIR3, PACKAGE_NAME4);
25355
+ var PROJECT_CONFIG_BASE2 = join13(process.cwd(), ".opencode", PACKAGE_NAME4);
25060
25356
  function loadConfig() {
25061
25357
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE2);
25062
25358
  if (projectDetected.format !== "none") {
25063
25359
  try {
25064
- const content = readFileSync9(projectDetected.path, "utf-8");
25360
+ const content = readFileSync10(projectDetected.path, "utf-8");
25065
25361
  return parseJsonc(content);
25066
25362
  } catch {
25067
25363
  return null;
@@ -25070,7 +25366,7 @@ function loadConfig() {
25070
25366
  const userDetected = detectConfigFile(USER_CONFIG_BASE2);
25071
25367
  if (userDetected.format !== "none") {
25072
25368
  try {
25073
- const content = readFileSync9(userDetected.path, "utf-8");
25369
+ const content = readFileSync10(userDetected.path, "utf-8");
25074
25370
  return parseJsonc(content);
25075
25371
  } catch {
25076
25372
  return null;
@@ -25194,23 +25490,23 @@ function getModelResolutionCheckDefinition() {
25194
25490
  }
25195
25491
 
25196
25492
  // src/cli/doctor/checks/auth.ts
25197
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
25198
- import { join as join13 } from "path";
25493
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
25494
+ import { join as join14 } from "path";
25199
25495
  init_shared();
25200
25496
  var OPENCODE_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
25201
- var OPENCODE_JSON = join13(OPENCODE_CONFIG_DIR, "opencode.json");
25202
- var OPENCODE_JSONC = join13(OPENCODE_CONFIG_DIR, "opencode.jsonc");
25497
+ var OPENCODE_JSON = join14(OPENCODE_CONFIG_DIR, "opencode.json");
25498
+ var OPENCODE_JSONC = join14(OPENCODE_CONFIG_DIR, "opencode.jsonc");
25203
25499
  var AUTH_PLUGINS = {
25204
25500
  anthropic: { plugin: "builtin", name: "Anthropic (Claude)" },
25205
25501
  openai: { plugin: "opencode-openai-codex-auth", name: "OpenAI (ChatGPT)" },
25206
25502
  google: { plugin: "opencode-antigravity-auth", name: "Google (Gemini)" }
25207
25503
  };
25208
25504
  function getOpenCodeConfig() {
25209
- const configPath = existsSync12(OPENCODE_JSONC) ? OPENCODE_JSONC : OPENCODE_JSON;
25210
- if (!existsSync12(configPath))
25505
+ const configPath = existsSync13(OPENCODE_JSONC) ? OPENCODE_JSONC : OPENCODE_JSON;
25506
+ if (!existsSync13(configPath))
25211
25507
  return null;
25212
25508
  try {
25213
- const content = readFileSync10(configPath, "utf-8");
25509
+ const content = readFileSync11(configPath, "utf-8");
25214
25510
  return parseJsonc(content);
25215
25511
  } catch {
25216
25512
  return null;
@@ -25295,9 +25591,9 @@ function getAuthCheckDefinitions() {
25295
25591
  // src/cli/doctor/checks/dependencies.ts
25296
25592
  async function checkBinaryExists(binary2) {
25297
25593
  try {
25298
- const path6 = Bun.which(binary2);
25299
- if (path6) {
25300
- return { exists: true, path: path6 };
25594
+ const path7 = Bun.which(binary2);
25595
+ if (path7) {
25596
+ return { exists: true, path: path7 };
25301
25597
  }
25302
25598
  } catch {}
25303
25599
  return { exists: false, path: null };
@@ -25348,15 +25644,15 @@ async function checkAstGrepNapi() {
25348
25644
  path: null
25349
25645
  };
25350
25646
  } catch {
25351
- const { existsSync: existsSync13 } = await import("fs");
25352
- const { join: join14 } = await import("path");
25647
+ const { existsSync: existsSync14 } = await import("fs");
25648
+ const { join: join15 } = await import("path");
25353
25649
  const { homedir: homedir7 } = await import("os");
25354
25650
  const pathsToCheck = [
25355
- join14(homedir7(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
25356
- join14(process.cwd(), "node_modules", "@ast-grep", "napi")
25651
+ join15(homedir7(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
25652
+ join15(process.cwd(), "node_modules", "@ast-grep", "napi")
25357
25653
  ];
25358
25654
  for (const napiPath of pathsToCheck) {
25359
- if (existsSync13(napiPath)) {
25655
+ if (existsSync14(napiPath)) {
25360
25656
  return {
25361
25657
  name: "AST-Grep NAPI",
25362
25658
  required: false,
@@ -25585,15 +25881,15 @@ function getGhCliCheckDefinition() {
25585
25881
  }
25586
25882
 
25587
25883
  // src/tools/lsp/config.ts
25588
- import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
25589
- import { join as join14 } from "path";
25884
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
25885
+ import { join as join15 } from "path";
25590
25886
  init_shared();
25591
25887
  function isServerInstalled(command) {
25592
25888
  if (command.length === 0)
25593
25889
  return false;
25594
25890
  const cmd = command[0];
25595
25891
  if (cmd.includes("/") || cmd.includes("\\")) {
25596
- if (existsSync13(cmd))
25892
+ if (existsSync14(cmd))
25597
25893
  return true;
25598
25894
  }
25599
25895
  const isWindows = process.platform === "win32";
@@ -25615,23 +25911,23 @@ function isServerInstalled(command) {
25615
25911
  const paths = pathEnv.split(pathSeparator);
25616
25912
  for (const p2 of paths) {
25617
25913
  for (const suffix of exts) {
25618
- if (existsSync13(join14(p2, cmd + suffix))) {
25914
+ if (existsSync14(join15(p2, cmd + suffix))) {
25619
25915
  return true;
25620
25916
  }
25621
25917
  }
25622
25918
  }
25623
25919
  const cwd = process.cwd();
25624
25920
  const configDir = getOpenCodeConfigDir({ binary: "opencode" });
25625
- const dataDir = join14(getDataDir(), "opencode");
25921
+ const dataDir = join15(getDataDir(), "opencode");
25626
25922
  const additionalBases = [
25627
- join14(cwd, "node_modules", ".bin"),
25628
- join14(configDir, "bin"),
25629
- join14(configDir, "node_modules", ".bin"),
25630
- join14(dataDir, "bin")
25923
+ join15(cwd, "node_modules", ".bin"),
25924
+ join15(configDir, "bin"),
25925
+ join15(configDir, "node_modules", ".bin"),
25926
+ join15(dataDir, "bin")
25631
25927
  ];
25632
25928
  for (const base of additionalBases) {
25633
25929
  for (const suffix of exts) {
25634
- if (existsSync13(join14(base, cmd + suffix))) {
25930
+ if (existsSync14(join15(base, cmd + suffix))) {
25635
25931
  return true;
25636
25932
  }
25637
25933
  }
@@ -25704,23 +26000,23 @@ function getLspCheckDefinition() {
25704
26000
  }
25705
26001
 
25706
26002
  // src/cli/doctor/checks/mcp.ts
25707
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
26003
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
25708
26004
  import { homedir as homedir7 } from "os";
25709
- import { join as join15 } from "path";
26005
+ import { join as join16 } from "path";
25710
26006
  init_shared();
25711
26007
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
25712
26008
  var MCP_CONFIG_PATHS = [
25713
- join15(homedir7(), ".claude", ".mcp.json"),
25714
- join15(process.cwd(), ".mcp.json"),
25715
- join15(process.cwd(), ".claude", ".mcp.json")
26009
+ join16(homedir7(), ".claude", ".mcp.json"),
26010
+ join16(process.cwd(), ".mcp.json"),
26011
+ join16(process.cwd(), ".claude", ".mcp.json")
25716
26012
  ];
25717
26013
  function loadUserMcpConfig() {
25718
26014
  const servers = {};
25719
26015
  for (const configPath of MCP_CONFIG_PATHS) {
25720
- if (!existsSync14(configPath))
26016
+ if (!existsSync15(configPath))
25721
26017
  continue;
25722
26018
  try {
25723
- const content = readFileSync12(configPath, "utf-8");
26019
+ const content = readFileSync13(configPath, "utf-8");
25724
26020
  const config2 = parseJsonc(content);
25725
26021
  if (config2.mcpServers) {
25726
26022
  Object.assign(servers, config2.mcpServers);
@@ -25811,11 +26107,11 @@ function getMcpCheckDefinitions() {
25811
26107
 
25812
26108
  // src/features/mcp-oauth/storage.ts
25813
26109
  init_shared();
25814
- import { chmodSync, existsSync as existsSync15, mkdirSync as mkdirSync3, readFileSync as readFileSync13, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
25815
- import { dirname as dirname2, join as join16 } from "path";
26110
+ import { chmodSync, existsSync as existsSync16, mkdirSync as mkdirSync3, readFileSync as readFileSync14, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
26111
+ import { dirname as dirname2, join as join17 } from "path";
25816
26112
  var STORAGE_FILE_NAME = "mcp-oauth.json";
25817
26113
  function getMcpOauthStoragePath() {
25818
- return join16(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
26114
+ return join17(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
25819
26115
  }
25820
26116
  function normalizeHost(serverHost) {
25821
26117
  let host = serverHost.trim();
@@ -25852,11 +26148,11 @@ function buildKey(serverHost, resource) {
25852
26148
  }
25853
26149
  function readStore() {
25854
26150
  const filePath = getMcpOauthStoragePath();
25855
- if (!existsSync15(filePath)) {
26151
+ if (!existsSync16(filePath)) {
25856
26152
  return null;
25857
26153
  }
25858
26154
  try {
25859
- const content = readFileSync13(filePath, "utf-8");
26155
+ const content = readFileSync14(filePath, "utf-8");
25860
26156
  return JSON.parse(content);
25861
26157
  } catch {
25862
26158
  return null;
@@ -25866,10 +26162,10 @@ function writeStore(store) {
25866
26162
  const filePath = getMcpOauthStoragePath();
25867
26163
  try {
25868
26164
  const dir = dirname2(filePath);
25869
- if (!existsSync15(dir)) {
26165
+ if (!existsSync16(dir)) {
25870
26166
  mkdirSync3(dir, { recursive: true });
25871
26167
  }
25872
- writeFileSync5(filePath, JSON.stringify(store, null, 2), { encoding: "utf-8", mode: 384 });
26168
+ writeFileSync6(filePath, JSON.stringify(store, null, 2), { encoding: "utf-8", mode: 384 });
25873
26169
  chmodSync(filePath, 384);
25874
26170
  return true;
25875
26171
  } catch {
@@ -25901,7 +26197,7 @@ function deleteToken(serverHost, resource) {
25901
26197
  if (Object.keys(store).length === 0) {
25902
26198
  try {
25903
26199
  const filePath = getMcpOauthStoragePath();
25904
- if (existsSync15(filePath)) {
26200
+ if (existsSync16(filePath)) {
25905
26201
  unlinkSync(filePath);
25906
26202
  }
25907
26203
  return true;
@@ -25930,14 +26226,14 @@ function listAllTokens() {
25930
26226
  }
25931
26227
 
25932
26228
  // src/cli/doctor/checks/mcp-oauth.ts
25933
- import { existsSync as existsSync16, readFileSync as readFileSync14 } from "fs";
26229
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
25934
26230
  function readTokenStore() {
25935
26231
  const filePath = getMcpOauthStoragePath();
25936
- if (!existsSync16(filePath)) {
26232
+ if (!existsSync17(filePath)) {
25937
26233
  return null;
25938
26234
  }
25939
26235
  try {
25940
- const content = readFileSync14(filePath, "utf-8");
26236
+ const content = readFileSync15(filePath, "utf-8");
25941
26237
  return JSON.parse(content);
25942
26238
  } catch {
25943
26239
  return null;
@@ -26835,12 +27131,21 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
26835
27131
  const exitCode = await install(args);
26836
27132
  process.exit(exitCode);
26837
27133
  });
26838
- program2.command("run <message>").description("Run opencode with todo/background task completion enforcement").option("-a, --agent <name>", "Agent to use (default: Sisyphus)").option("-d, --directory <path>", "Working directory").option("-t, --timeout <ms>", "Timeout in milliseconds (default: 30 minutes)", parseInt).addHelpText("after", `
27134
+ program2.command("run <message>").description("Run opencode with todo/background task completion enforcement").option("-a, --agent <name>", "Agent to use (default: from CLI/env/config, fallback: Sisyphus)").option("-d, --directory <path>", "Working directory").option("-t, --timeout <ms>", "Timeout in milliseconds (default: 30 minutes)", parseInt).addHelpText("after", `
26839
27135
  Examples:
26840
27136
  $ bunx oh-my-opencode run "Fix the bug in index.ts"
26841
27137
  $ bunx oh-my-opencode run --agent Sisyphus "Implement feature X"
26842
27138
  $ bunx oh-my-opencode run --timeout 3600000 "Large refactoring task"
26843
27139
 
27140
+ Agent resolution order:
27141
+ 1) --agent flag
27142
+ 2) OPENCODE_DEFAULT_AGENT
27143
+ 3) oh-my-opencode.json "default_run_agent"
27144
+ 4) Sisyphus (fallback)
27145
+
27146
+ Available core agents:
27147
+ Sisyphus, Hephaestus, Prometheus, Atlas
27148
+
26844
27149
  Unlike 'opencode run', this command waits until:
26845
27150
  - All todos are completed or cancelled
26846
27151
  - All child sessions (background tasks) are idle