oh-my-opencode 3.11.2 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.ja.md +18 -12
  2. package/README.ko.md +18 -12
  3. package/README.md +16 -16
  4. package/README.ru.md +12 -6
  5. package/README.zh-cn.md +18 -12
  6. package/dist/agents/atlas/default.d.ts +1 -1
  7. package/dist/agents/atlas/gemini.d.ts +1 -1
  8. package/dist/agents/atlas/gpt.d.ts +1 -1
  9. package/dist/agents/builtin-agents/general-agents.d.ts +1 -0
  10. package/dist/agents/dynamic-agent-prompt-builder.d.ts +2 -0
  11. package/dist/agents/env-context.d.ts +1 -1
  12. package/dist/agents/index.d.ts +1 -0
  13. package/dist/agents/metis.d.ts +1 -1
  14. package/dist/agents/prometheus/gemini.d.ts +1 -1
  15. package/dist/agents/prometheus/gpt.d.ts +1 -1
  16. package/dist/agents/prometheus/interview-mode.d.ts +1 -1
  17. package/dist/agents/prometheus/plan-generation.d.ts +1 -1
  18. package/dist/agents/prometheus/plan-template.d.ts +1 -1
  19. package/dist/agents/prometheus/system-prompt.d.ts +1 -1
  20. package/dist/agents/types.d.ts +1 -1
  21. package/dist/cli/config-manager/bun-install.d.ts +8 -1
  22. package/dist/cli/config-manager/plugin-name-with-version.d.ts +1 -1
  23. package/dist/cli/doctor/checks/tools-lsp.d.ts +4 -6
  24. package/dist/cli/doctor/types.d.ts +4 -8
  25. package/dist/cli/index.js +953 -731
  26. package/dist/cli/install-validators.d.ts +1 -0
  27. package/dist/cli/model-fallback-requirements.d.ts +1 -1
  28. package/dist/cli/model-fallback-types.d.ts +1 -0
  29. package/dist/cli/openai-only-model-catalog.d.ts +3 -0
  30. package/dist/cli/run/index.d.ts +1 -0
  31. package/dist/cli/run/model-resolver.d.ts +4 -0
  32. package/dist/cli/run/types.d.ts +1 -0
  33. package/dist/cli/types.d.ts +3 -0
  34. package/dist/config/schema/agent-names.d.ts +3 -1
  35. package/dist/config/schema/background-task.d.ts +8 -0
  36. package/dist/config/schema/git-env-prefix.d.ts +5 -0
  37. package/dist/config/schema/git-master.d.ts +1 -0
  38. package/dist/config/schema/hooks.d.ts +1 -0
  39. package/dist/config/schema/oh-my-opencode-config.d.ts +9 -0
  40. package/dist/config/schema.d.ts +1 -0
  41. package/dist/create-hooks.d.ts +12 -0
  42. package/dist/features/background-agent/compaction-aware-message-resolver.d.ts +16 -1
  43. package/dist/features/background-agent/constants.d.ts +6 -2
  44. package/dist/features/background-agent/loop-detector.d.ts +17 -0
  45. package/dist/features/background-agent/manager.d.ts +20 -4
  46. package/dist/features/background-agent/process-cleanup.d.ts +1 -1
  47. package/dist/features/background-agent/remove-task-toast-tracking.d.ts +1 -0
  48. package/dist/features/background-agent/subagent-spawn-limits.d.ts +23 -0
  49. package/dist/features/background-agent/task-history.d.ts +1 -0
  50. package/dist/features/background-agent/task-poller.d.ts +1 -0
  51. package/dist/features/background-agent/types.d.ts +11 -0
  52. package/dist/features/claude-code-agent-loader/claude-model-mapper.d.ts +4 -0
  53. package/dist/features/claude-code-agent-loader/loader.d.ts +3 -3
  54. package/dist/features/claude-code-agent-loader/types.d.ts +8 -1
  55. package/dist/features/claude-code-plugin-loader/agent-loader.d.ts +2 -2
  56. package/dist/features/claude-code-plugin-loader/loader.d.ts +2 -2
  57. package/dist/features/claude-code-plugin-loader/types.d.ts +22 -3
  58. package/dist/features/opencode-skill-loader/git-master-template-injection.d.ts +1 -1
  59. package/dist/features/skill-mcp-manager/types.d.ts +4 -0
  60. package/dist/features/tmux-subagent/index.d.ts +1 -0
  61. package/dist/features/tmux-subagent/manager.d.ts +5 -0
  62. package/dist/features/tmux-subagent/pane-state-parser.d.ts +8 -0
  63. package/dist/features/tmux-subagent/tracked-session-state.d.ts +8 -0
  64. package/dist/features/tmux-subagent/types.d.ts +2 -0
  65. package/dist/hooks/atlas/boulder-session-lineage.d.ts +6 -0
  66. package/dist/hooks/atlas/final-wave-approval-gate.d.ts +6 -0
  67. package/dist/hooks/atlas/final-wave-plan-state.d.ts +5 -0
  68. package/dist/hooks/atlas/idle-event.d.ts +8 -0
  69. package/dist/hooks/atlas/resolve-active-boulder-session.d.ts +11 -0
  70. package/dist/hooks/atlas/tool-execute-after.d.ts +2 -0
  71. package/dist/hooks/atlas/types.d.ts +4 -0
  72. package/dist/hooks/atlas/verification-reminders.d.ts +4 -0
  73. package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
  74. package/dist/hooks/auto-slash-command/hook.d.ts +7 -0
  75. package/dist/hooks/auto-slash-command/processed-command-store.d.ts +7 -0
  76. package/dist/hooks/auto-slash-command/types.d.ts +9 -0
  77. package/dist/hooks/auto-update-checker/checker/sync-package-json.d.ts +7 -0
  78. package/dist/hooks/auto-update-checker/checker.d.ts +3 -1
  79. package/dist/hooks/compaction-context-injector/compaction-context-prompt.d.ts +1 -0
  80. package/dist/hooks/compaction-context-injector/constants.d.ts +5 -0
  81. package/dist/hooks/compaction-context-injector/hook.d.ts +5 -1
  82. package/dist/hooks/compaction-context-injector/recovery-prompt-config.d.ts +6 -0
  83. package/dist/hooks/compaction-context-injector/recovery.d.ts +6 -0
  84. package/dist/hooks/compaction-context-injector/session-id.d.ts +2 -0
  85. package/dist/hooks/compaction-context-injector/session-prompt-config-resolver.d.ts +16 -0
  86. package/dist/hooks/compaction-context-injector/tail-monitor.d.ts +13 -0
  87. package/dist/hooks/compaction-context-injector/types.d.ts +43 -0
  88. package/dist/hooks/compaction-context-injector/validated-model.d.ts +13 -0
  89. package/dist/hooks/context-window-monitor.d.ts +2 -5
  90. package/dist/hooks/gpt-permission-continuation/assistant-message.d.ts +23 -0
  91. package/dist/hooks/gpt-permission-continuation/constants.d.ts +4 -0
  92. package/dist/hooks/gpt-permission-continuation/detector.d.ts +1 -0
  93. package/dist/hooks/gpt-permission-continuation/handler.d.ts +12 -0
  94. package/dist/hooks/gpt-permission-continuation/index.d.ts +13 -0
  95. package/dist/hooks/gpt-permission-continuation/session-state.d.ts +15 -0
  96. package/dist/hooks/index.d.ts +1 -0
  97. package/dist/hooks/keyword-detector/hook.d.ts +1 -0
  98. package/dist/hooks/preemptive-compaction.d.ts +2 -5
  99. package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +17 -0
  100. package/dist/hooks/runtime-fallback/fallback-bootstrap-model.d.ts +10 -0
  101. package/dist/hooks/runtime-fallback/fallback-retry-dispatcher.d.ts +11 -0
  102. package/dist/hooks/runtime-fallback/hook.d.ts +2 -3
  103. package/dist/hooks/runtime-fallback/last-user-retry-parts.d.ts +4 -0
  104. package/dist/hooks/runtime-fallback/message-update-handler.d.ts +1 -2
  105. package/dist/hooks/runtime-fallback/retry-model-payload.d.ts +7 -0
  106. package/dist/hooks/runtime-fallback/session-messages.d.ts +9 -0
  107. package/dist/hooks/runtime-fallback/session-status-handler.d.ts +3 -0
  108. package/dist/hooks/runtime-fallback/types.d.ts +57 -3
  109. package/dist/hooks/runtime-fallback/visible-assistant-response.d.ts +3 -0
  110. package/dist/hooks/session-notification-content.d.ts +30 -0
  111. package/dist/hooks/session-notification-scheduler.d.ts +1 -3
  112. package/dist/hooks/start-work/index.d.ts +1 -1
  113. package/dist/hooks/start-work/worktree-detector.d.ts +7 -0
  114. package/dist/hooks/todo-continuation-enforcer/compaction-guard.d.ts +2 -0
  115. package/dist/hooks/todo-continuation-enforcer/constants.d.ts +2 -0
  116. package/dist/hooks/todo-continuation-enforcer/handler.d.ts +1 -0
  117. package/dist/hooks/todo-continuation-enforcer/idle-event.d.ts +1 -0
  118. package/dist/hooks/todo-continuation-enforcer/resolve-message-info.d.ts +3 -0
  119. package/dist/hooks/todo-continuation-enforcer/session-state.d.ts +10 -1
  120. package/dist/hooks/todo-continuation-enforcer/stagnation-detection.d.ts +6 -0
  121. package/dist/hooks/todo-continuation-enforcer/types.d.ts +10 -0
  122. package/dist/hooks/tool-output-truncator.d.ts +1 -0
  123. package/dist/index.js +10452 -6721
  124. package/dist/oh-my-opencode.schema.json +43 -2
  125. package/dist/plugin/hooks/create-continuation-hooks.d.ts +2 -1
  126. package/dist/plugin/normalize-tool-arg-schemas.d.ts +2 -0
  127. package/dist/plugin/ultrawork-model-override.d.ts +1 -15
  128. package/dist/plugin/ultrawork-variant-availability.d.ts +6 -0
  129. package/dist/plugin-dispose.d.ts +10 -0
  130. package/dist/plugin-handlers/agent-override-protection.d.ts +3 -0
  131. package/dist/plugin-state.d.ts +5 -0
  132. package/dist/shared/compaction-agent-config-checkpoint.d.ts +11 -0
  133. package/dist/shared/context-limit-resolver.d.ts +5 -0
  134. package/dist/shared/dynamic-truncator.d.ts +4 -7
  135. package/dist/shared/fallback-chain-from-models.d.ts +3 -0
  136. package/dist/shared/index.d.ts +3 -0
  137. package/dist/shared/model-error-classifier.d.ts +2 -1
  138. package/dist/shared/opencode-command-dirs.d.ts +3 -0
  139. package/dist/shared/plugin-identity.d.ts +5 -0
  140. package/dist/shared/question-denied-session-permission.d.ts +6 -0
  141. package/dist/shared/retry-status-utils.d.ts +2 -0
  142. package/dist/shared/shell-env.d.ts +27 -0
  143. package/dist/shared/tmux/tmux-utils/environment.d.ts +1 -0
  144. package/dist/shared/vision-capable-models-cache.d.ts +4 -0
  145. package/dist/tools/call-omo-agent/background-executor.d.ts +2 -1
  146. package/dist/tools/call-omo-agent/constants.d.ts +1 -1
  147. package/dist/tools/call-omo-agent/sync-executor.d.ts +11 -3
  148. package/dist/tools/call-omo-agent/tools.d.ts +2 -1
  149. package/dist/tools/delegate-task/cancel-unstable-agent-task.d.ts +2 -0
  150. package/dist/tools/delegate-task/model-selection.d.ts +3 -0
  151. package/dist/tools/delegate-task/model-string-parser.d.ts +5 -3
  152. package/dist/tools/hashline-edit/hash-computation.d.ts +1 -0
  153. package/dist/tools/hashline-edit/tool-description.d.ts +1 -1
  154. package/dist/tools/look-at/constants.d.ts +1 -1
  155. package/dist/tools/look-at/multimodal-fallback-chain.d.ts +4 -0
  156. package/dist/tools/lsp/constants.d.ts +1 -0
  157. package/dist/tools/lsp/directory-diagnostics.d.ts +1 -0
  158. package/dist/tools/lsp/lsp-client-transport.d.ts +4 -2
  159. package/dist/tools/lsp/lsp-client-wrapper.d.ts +2 -1
  160. package/dist/tools/lsp/server-path-bases.d.ts +1 -0
  161. package/package.json +18 -18
package/dist/cli/index.js CHANGED
@@ -4977,6 +4977,9 @@ var init_tool_name = () => {};
4977
4977
  // src/shared/file-utils.ts
4978
4978
  var init_file_utils = () => {};
4979
4979
 
4980
+ // src/shared/context-limit-resolver.ts
4981
+ var init_context_limit_resolver = () => {};
4982
+
4980
4983
  // src/shared/normalize-sdk-response.ts
4981
4984
  function normalizeSDKResponse(response, fallback, options) {
4982
4985
  if (response === null || response === undefined) {
@@ -5002,7 +5005,9 @@ function normalizeSDKResponse(response, fallback, options) {
5002
5005
  }
5003
5006
 
5004
5007
  // src/shared/dynamic-truncator.ts
5005
- var init_dynamic_truncator = () => {};
5008
+ var init_dynamic_truncator = __esm(() => {
5009
+ init_context_limit_resolver();
5010
+ });
5006
5011
 
5007
5012
  // src/shared/data-path.ts
5008
5013
  import * as path2 from "path";
@@ -6017,7 +6022,8 @@ var init_hook_names = __esm(() => {
6017
6022
  "anthropic-auto-compact": "anthropic-context-window-limit-recovery",
6018
6023
  "sisyphus-orchestrator": "atlas",
6019
6024
  "sisyphus-gpt-hephaestus-reminder": "no-sisyphus-gpt",
6020
- "empty-message-sanitizer": null
6025
+ "empty-message-sanitizer": null,
6026
+ "delegate-task-english-directive": null
6021
6027
  };
6022
6028
  });
6023
6029
 
@@ -6218,20 +6224,6 @@ function getCliConfigDir() {
6218
6224
  if (envConfigDir) {
6219
6225
  return resolve(envConfigDir);
6220
6226
  }
6221
- if (process.platform === "win32") {
6222
- const crossPlatformDir = join3(homedir2(), ".config", "opencode");
6223
- const crossPlatformConfig = join3(crossPlatformDir, "opencode.json");
6224
- if (existsSync2(crossPlatformConfig)) {
6225
- return crossPlatformDir;
6226
- }
6227
- const appData = process.env.APPDATA || join3(homedir2(), "AppData", "Roaming");
6228
- const appdataDir = join3(appData, "opencode");
6229
- const appdataConfig = join3(appdataDir, "opencode.json");
6230
- if (existsSync2(appdataConfig)) {
6231
- return appdataDir;
6232
- }
6233
- return crossPlatformDir;
6234
- }
6235
6227
  const xdgConfig = process.env.XDG_CONFIG_HOME || join3(homedir2(), ".config");
6236
6228
  return join3(xdgConfig, "opencode");
6237
6229
  }
@@ -6304,6 +6296,7 @@ var init_model_requirements = __esm(() => {
6304
6296
  model: "claude-opus-4-6",
6305
6297
  variant: "max"
6306
6298
  },
6299
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6307
6300
  { providers: ["kimi-for-coding"], model: "k2p5" },
6308
6301
  {
6309
6302
  providers: [
@@ -6349,22 +6342,22 @@ var init_model_requirements = __esm(() => {
6349
6342
  providers: ["anthropic", "github-copilot", "opencode"],
6350
6343
  model: "claude-opus-4-6",
6351
6344
  variant: "max"
6352
- }
6345
+ },
6346
+ { providers: ["opencode-go"], model: "glm-5" }
6353
6347
  ]
6354
6348
  },
6355
6349
  librarian: {
6356
6350
  fallbackChain: [
6357
- {
6358
- providers: ["google", "github-copilot", "opencode"],
6359
- model: "gemini-3-flash"
6360
- },
6351
+ { providers: ["opencode-go"], model: "minimax-m2.5" },
6361
6352
  { providers: ["opencode"], model: "minimax-m2.5-free" },
6362
- { providers: ["opencode"], model: "big-pickle" }
6353
+ { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
6354
+ { providers: ["opencode"], model: "gpt-5-nano" }
6363
6355
  ]
6364
6356
  },
6365
6357
  explore: {
6366
6358
  fallbackChain: [
6367
6359
  { providers: ["github-copilot"], model: "grok-code-fast-1" },
6360
+ { providers: ["opencode-go"], model: "minimax-m2.5" },
6368
6361
  { providers: ["opencode"], model: "minimax-m2.5-free" },
6369
6362
  { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
6370
6363
  { providers: ["opencode"], model: "gpt-5-nano" }
@@ -6372,21 +6365,10 @@ var init_model_requirements = __esm(() => {
6372
6365
  },
6373
6366
  "multimodal-looker": {
6374
6367
  fallbackChain: [
6375
- {
6376
- providers: ["openai", "opencode"],
6377
- model: "gpt-5.4",
6378
- variant: "medium"
6379
- },
6380
- { providers: ["kimi-for-coding"], model: "k2p5" },
6381
- {
6382
- providers: ["google", "github-copilot", "opencode"],
6383
- model: "gemini-3-flash"
6384
- },
6368
+ { providers: ["openai", "opencode"], model: "gpt-5.4", variant: "medium" },
6369
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6385
6370
  { providers: ["zai-coding-plan"], model: "glm-4.6v" },
6386
- {
6387
- providers: ["openai", "github-copilot", "opencode"],
6388
- model: "gpt-5-nano"
6389
- }
6371
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5-nano" }
6390
6372
  ]
6391
6373
  },
6392
6374
  prometheus: {
@@ -6401,6 +6383,7 @@ var init_model_requirements = __esm(() => {
6401
6383
  model: "gpt-5.4",
6402
6384
  variant: "high"
6403
6385
  },
6386
+ { providers: ["opencode-go"], model: "glm-5" },
6404
6387
  {
6405
6388
  providers: ["google", "github-copilot", "opencode"],
6406
6389
  model: "gemini-3.1-pro"
@@ -6419,11 +6402,8 @@ var init_model_requirements = __esm(() => {
6419
6402
  model: "gpt-5.4",
6420
6403
  variant: "high"
6421
6404
  },
6422
- {
6423
- providers: ["google", "github-copilot", "opencode"],
6424
- model: "gemini-3.1-pro",
6425
- variant: "high"
6426
- }
6405
+ { providers: ["opencode-go"], model: "glm-5" },
6406
+ { providers: ["kimi-for-coding"], model: "k2p5" }
6427
6407
  ]
6428
6408
  },
6429
6409
  momus: {
@@ -6442,16 +6422,31 @@ var init_model_requirements = __esm(() => {
6442
6422
  providers: ["google", "github-copilot", "opencode"],
6443
6423
  model: "gemini-3.1-pro",
6444
6424
  variant: "high"
6445
- }
6425
+ },
6426
+ { providers: ["opencode-go"], model: "glm-5" }
6446
6427
  ]
6447
6428
  },
6448
6429
  atlas: {
6449
6430
  fallbackChain: [
6431
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
6432
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6450
6433
  {
6451
- providers: ["anthropic", "github-copilot", "opencode"],
6452
- model: "claude-sonnet-4-6"
6434
+ providers: ["openai", "github-copilot", "opencode"],
6435
+ model: "gpt-5.4",
6436
+ variant: "medium"
6437
+ }
6438
+ ]
6439
+ },
6440
+ "sisyphus-junior": {
6441
+ fallbackChain: [
6442
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
6443
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6444
+ {
6445
+ providers: ["openai", "github-copilot", "opencode"],
6446
+ model: "gpt-5.4",
6447
+ variant: "medium"
6453
6448
  },
6454
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "medium" }
6449
+ { providers: ["opencode"], model: "big-pickle" }
6455
6450
  ]
6456
6451
  }
6457
6452
  };
@@ -6468,14 +6463,16 @@ var init_model_requirements = __esm(() => {
6468
6463
  providers: ["anthropic", "github-copilot", "opencode"],
6469
6464
  model: "claude-opus-4-6",
6470
6465
  variant: "max"
6471
- }
6466
+ },
6467
+ { providers: ["opencode-go"], model: "glm-5" },
6468
+ { providers: ["kimi-for-coding"], model: "k2p5" }
6472
6469
  ]
6473
6470
  },
6474
6471
  ultrabrain: {
6475
6472
  fallbackChain: [
6476
6473
  {
6477
6474
  providers: ["openai", "opencode"],
6478
- model: "gpt-5.3-codex",
6475
+ model: "gpt-5.4",
6479
6476
  variant: "xhigh"
6480
6477
  },
6481
6478
  {
@@ -6487,7 +6484,8 @@ var init_model_requirements = __esm(() => {
6487
6484
  providers: ["anthropic", "github-copilot", "opencode"],
6488
6485
  model: "claude-opus-4-6",
6489
6486
  variant: "max"
6490
- }
6487
+ },
6488
+ { providers: ["opencode-go"], model: "glm-5" }
6491
6489
  ]
6492
6490
  },
6493
6491
  deep: {
@@ -6536,6 +6534,7 @@ var init_model_requirements = __esm(() => {
6536
6534
  providers: ["google", "github-copilot", "opencode"],
6537
6535
  model: "gemini-3-flash"
6538
6536
  },
6537
+ { providers: ["opencode-go"], model: "minimax-m2.5" },
6539
6538
  { providers: ["opencode"], model: "gpt-5-nano" }
6540
6539
  ]
6541
6540
  },
@@ -6550,6 +6549,7 @@ var init_model_requirements = __esm(() => {
6550
6549
  model: "gpt-5.3-codex",
6551
6550
  variant: "medium"
6552
6551
  },
6552
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6553
6553
  {
6554
6554
  providers: ["google", "github-copilot", "opencode"],
6555
6555
  model: "gemini-3-flash"
@@ -6558,18 +6558,20 @@ var init_model_requirements = __esm(() => {
6558
6558
  },
6559
6559
  "unspecified-high": {
6560
6560
  fallbackChain: [
6561
- {
6562
- providers: ["openai", "github-copilot", "opencode"],
6563
- model: "gpt-5.4",
6564
- variant: "high"
6565
- },
6566
6561
  {
6567
6562
  providers: ["anthropic", "github-copilot", "opencode"],
6568
6563
  model: "claude-opus-4-6",
6569
6564
  variant: "max"
6570
6565
  },
6566
+ {
6567
+ providers: ["openai", "github-copilot", "opencode"],
6568
+ model: "gpt-5.4",
6569
+ variant: "high"
6570
+ },
6571
6571
  { providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
6572
6572
  { providers: ["kimi-for-coding"], model: "k2p5" },
6573
+ { providers: ["opencode-go"], model: "glm-5" },
6574
+ { providers: ["opencode"], model: "kimi-k2.5" },
6573
6575
  {
6574
6576
  providers: [
6575
6577
  "opencode",
@@ -6589,6 +6591,7 @@ var init_model_requirements = __esm(() => {
6589
6591
  providers: ["google", "github-copilot", "opencode"],
6590
6592
  model: "gemini-3-flash"
6591
6593
  },
6594
+ { providers: ["opencode-go"], model: "kimi-k2.5" },
6592
6595
  {
6593
6596
  providers: ["anthropic", "github-copilot", "opencode"],
6594
6597
  model: "claude-sonnet-4-6"
@@ -6940,6 +6943,11 @@ var init_git_worktree = __esm(() => {
6940
6943
  var init_safe_create_hook = __esm(() => {
6941
6944
  init_logger();
6942
6945
  });
6946
+ // src/shared/opencode-command-dirs.ts
6947
+ var init_opencode_command_dirs = __esm(() => {
6948
+ init_opencode_config_dir();
6949
+ });
6950
+
6943
6951
  // src/shared/session-directory-resolver.ts
6944
6952
  var init_session_directory_resolver = () => {};
6945
6953
 
@@ -6975,12 +6983,22 @@ var init_skill_loader = __esm(() => {
6975
6983
  init_skill_path_resolver();
6976
6984
  init_logger();
6977
6985
  });
6986
+ // src/features/claude-code-agent-loader/claude-model-mapper.ts
6987
+ var ANTHROPIC_PREFIX = "anthropic/", CLAUDE_CODE_ALIAS_MAP;
6988
+ var init_claude_model_mapper = __esm(() => {
6989
+ CLAUDE_CODE_ALIAS_MAP = new Map([
6990
+ ["sonnet", `${ANTHROPIC_PREFIX}claude-sonnet-4-6`],
6991
+ ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-6`],
6992
+ ["haiku", `${ANTHROPIC_PREFIX}claude-haiku-4-5`]
6993
+ ]);
6994
+ });
6978
6995
 
6979
6996
  // src/features/claude-code-plugin-loader/agent-loader.ts
6980
6997
  var init_agent_loader = __esm(() => {
6981
6998
  init_frontmatter();
6982
6999
  init_file_utils();
6983
7000
  init_logger();
7001
+ init_claude_model_mapper();
6984
7002
  });
6985
7003
  // src/features/claude-code-mcp-loader/transformer.ts
6986
7004
  var init_transformer = () => {};
@@ -7034,6 +7052,9 @@ var init_session_category_registry = __esm(() => {
7034
7052
  sessionCategoryMap = new Map;
7035
7053
  });
7036
7054
 
7055
+ // src/shared/plugin-identity.ts
7056
+ var PLUGIN_NAME = "oh-my-opencode", LEGACY_PLUGIN_NAME = "oh-my-openagent";
7057
+
7037
7058
  // src/shared/index.ts
7038
7059
  var init_shared = __esm(() => {
7039
7060
  init_model_resolver();
@@ -7068,6 +7089,7 @@ var init_shared = __esm(() => {
7068
7089
  init_model_availability();
7069
7090
  init_fallback_model_availability();
7070
7091
  init_connected_providers_cache();
7092
+ init_context_limit_resolver();
7071
7093
  init_session_utils();
7072
7094
  init_tmux();
7073
7095
  init_model_suggestion_retry();
@@ -7078,6 +7100,7 @@ var init_shared = __esm(() => {
7078
7100
  init_safe_create_hook();
7079
7101
  init_opencode_storage_paths();
7080
7102
  init_opencode_message_dir();
7103
+ init_opencode_command_dirs();
7081
7104
  init_session_directory_resolver();
7082
7105
  init_prompt_tools();
7083
7106
  init_plugin_command_discovery();
@@ -7129,26 +7152,26 @@ async function fetchNpmDistTags(packageName) {
7129
7152
  var NPM_FETCH_TIMEOUT_MS = 5000;
7130
7153
 
7131
7154
  // src/cli/config-manager/plugin-name-with-version.ts
7132
- function getFallbackEntry(version) {
7155
+ function getFallbackEntry(version, packageName) {
7133
7156
  const prereleaseMatch = version.match(/-([a-zA-Z][a-zA-Z0-9-]*)(?:\.|$)/);
7134
7157
  if (prereleaseMatch) {
7135
- return `${PACKAGE_NAME}@${prereleaseMatch[1]}`;
7158
+ return `${packageName}@${prereleaseMatch[1]}`;
7136
7159
  }
7137
- return PACKAGE_NAME;
7160
+ return packageName;
7138
7161
  }
7139
- async function getPluginNameWithVersion(currentVersion) {
7140
- const distTags = await fetchNpmDistTags(PACKAGE_NAME);
7162
+ async function getPluginNameWithVersion(currentVersion, packageName = DEFAULT_PACKAGE_NAME) {
7163
+ const distTags = await fetchNpmDistTags(packageName);
7141
7164
  if (distTags) {
7142
7165
  const allTags = new Set([...PRIORITIZED_TAGS, ...Object.keys(distTags)]);
7143
7166
  for (const tag of allTags) {
7144
7167
  if (distTags[tag] === currentVersion) {
7145
- return `${PACKAGE_NAME}@${tag}`;
7168
+ return `${packageName}@${tag}`;
7146
7169
  }
7147
7170
  }
7148
7171
  }
7149
- return getFallbackEntry(currentVersion);
7172
+ return getFallbackEntry(currentVersion, packageName);
7150
7173
  }
7151
- var PACKAGE_NAME = "oh-my-opencode", PRIORITIZED_TAGS;
7174
+ var DEFAULT_PACKAGE_NAME = "oh-my-opencode", PRIORITIZED_TAGS;
7152
7175
  var init_plugin_name_with_version = __esm(() => {
7153
7176
  PRIORITIZED_TAGS = ["latest", "beta", "next"];
7154
7177
  });
@@ -7258,7 +7281,7 @@ async function addPluginToOpenCodeConfig(currentVersion) {
7258
7281
  };
7259
7282
  }
7260
7283
  const { format: format2, path: path3 } = detectConfigFormat();
7261
- const pluginEntry = await getPluginNameWithVersion(currentVersion);
7284
+ const pluginEntry = await getPluginNameWithVersion(currentVersion, PLUGIN_NAME);
7262
7285
  try {
7263
7286
  if (format2 === "none") {
7264
7287
  const config2 = { plugin: [pluginEntry] };
@@ -7276,12 +7299,15 @@ async function addPluginToOpenCodeConfig(currentVersion) {
7276
7299
  }
7277
7300
  const config = parseResult.config;
7278
7301
  const plugins = config.plugin ?? [];
7279
- const existingIndex = plugins.findIndex((p) => p === PACKAGE_NAME2 || p.startsWith(`${PACKAGE_NAME2}@`));
7280
- if (existingIndex !== -1) {
7281
- if (plugins[existingIndex] === pluginEntry) {
7302
+ const currentNameIndex = plugins.findIndex((plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`));
7303
+ const legacyNameIndex = plugins.findIndex((plugin) => plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`));
7304
+ if (currentNameIndex !== -1) {
7305
+ if (plugins[currentNameIndex] === pluginEntry) {
7282
7306
  return { success: true, configPath: path3 };
7283
7307
  }
7284
- plugins[existingIndex] = pluginEntry;
7308
+ plugins[currentNameIndex] = pluginEntry;
7309
+ } else if (legacyNameIndex !== -1) {
7310
+ plugins[legacyNameIndex] = pluginEntry;
7285
7311
  } else {
7286
7312
  plugins.push(pluginEntry);
7287
7313
  }
@@ -7315,8 +7341,8 @@ async function addPluginToOpenCodeConfig(currentVersion) {
7315
7341
  };
7316
7342
  }
7317
7343
  }
7318
- var PACKAGE_NAME2 = "oh-my-opencode";
7319
7344
  var init_add_plugin_to_opencode_config = __esm(() => {
7345
+ init_shared();
7320
7346
  init_config_context();
7321
7347
  init_ensure_config_directory_exists();
7322
7348
  init_opencode_config_format();
@@ -7327,290 +7353,39 @@ var init_add_plugin_to_opencode_config = __esm(() => {
7327
7353
  // src/cli/model-fallback-requirements.ts
7328
7354
  var CLI_AGENT_MODEL_REQUIREMENTS, CLI_CATEGORY_MODEL_REQUIREMENTS;
7329
7355
  var init_model_fallback_requirements = __esm(() => {
7330
- CLI_AGENT_MODEL_REQUIREMENTS = {
7331
- sisyphus: {
7332
- fallbackChain: [
7333
- {
7334
- providers: ["anthropic", "github-copilot", "opencode"],
7335
- model: "claude-opus-4-6",
7336
- variant: "max"
7337
- },
7338
- { providers: ["kimi-for-coding"], model: "k2p5" },
7339
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "medium" },
7340
- { providers: ["zai-coding-plan", "opencode"], model: "glm-5" }
7341
- ],
7342
- requiresAnyModel: true
7343
- },
7344
- hephaestus: {
7345
- fallbackChain: [
7346
- {
7347
- providers: ["openai", "opencode"],
7348
- model: "gpt-5.3-codex",
7349
- variant: "medium"
7350
- }
7351
- ],
7352
- requiresProvider: ["openai", "opencode"]
7353
- },
7354
- oracle: {
7355
- fallbackChain: [
7356
- {
7357
- providers: ["openai", "github-copilot", "opencode"],
7358
- model: "gpt-5.4",
7359
- variant: "high"
7360
- },
7361
- {
7362
- providers: ["google", "github-copilot", "opencode"],
7363
- model: "gemini-3.1-pro",
7364
- variant: "high"
7365
- },
7366
- {
7367
- providers: ["anthropic", "github-copilot", "opencode"],
7368
- model: "claude-opus-4-6",
7369
- variant: "max"
7370
- }
7371
- ]
7372
- },
7373
- librarian: {
7374
- fallbackChain: [
7375
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
7376
- { providers: ["opencode"], model: "glm-4.7-free" },
7377
- {
7378
- providers: ["anthropic", "github-copilot", "opencode"],
7379
- model: "claude-sonnet-4-5"
7380
- }
7381
- ]
7382
- },
7383
- explore: {
7384
- fallbackChain: [
7385
- { providers: ["github-copilot"], model: "grok-code-fast-1" },
7386
- { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
7387
- { providers: ["opencode"], model: "gpt-5-nano" }
7388
- ]
7389
- },
7390
- "multimodal-looker": {
7391
- fallbackChain: [
7392
- {
7393
- providers: ["openai", "opencode"],
7394
- model: "gpt-5.4",
7395
- variant: "medium"
7396
- },
7397
- { providers: ["kimi-for-coding"], model: "k2p5" },
7398
- {
7399
- providers: ["google", "github-copilot", "opencode"],
7400
- model: "gemini-3-flash"
7401
- },
7402
- { providers: ["zai-coding-plan"], model: "glm-4.6v" },
7403
- { providers: ["opencode"], model: "gpt-5-nano" }
7404
- ]
7405
- },
7406
- prometheus: {
7407
- fallbackChain: [
7408
- {
7409
- providers: ["anthropic", "github-copilot", "opencode"],
7410
- model: "claude-opus-4-6",
7411
- variant: "max"
7412
- },
7413
- { providers: ["kimi-for-coding"], model: "k2p5" },
7414
- {
7415
- providers: ["openai", "github-copilot", "opencode"],
7416
- model: "gpt-5.4",
7417
- variant: "high"
7418
- },
7419
- {
7420
- providers: ["google", "github-copilot", "opencode"],
7421
- model: "gemini-3.1-pro"
7422
- }
7423
- ]
7424
- },
7425
- metis: {
7426
- fallbackChain: [
7427
- {
7428
- providers: ["anthropic", "github-copilot", "opencode"],
7429
- model: "claude-opus-4-6",
7430
- variant: "max"
7431
- },
7432
- { providers: ["kimi-for-coding"], model: "k2p5" },
7433
- {
7434
- providers: ["openai", "github-copilot", "opencode"],
7435
- model: "gpt-5.4",
7436
- variant: "high"
7437
- },
7438
- {
7439
- providers: ["google", "github-copilot", "opencode"],
7440
- model: "gemini-3.1-pro",
7441
- variant: "high"
7442
- }
7443
- ]
7444
- },
7445
- momus: {
7446
- fallbackChain: [
7447
- {
7448
- providers: ["openai", "github-copilot", "opencode"],
7449
- model: "gpt-5.4",
7450
- variant: "xhigh"
7451
- },
7452
- {
7453
- providers: ["anthropic", "github-copilot", "opencode"],
7454
- model: "claude-opus-4-6",
7455
- variant: "max"
7456
- },
7457
- {
7458
- providers: ["google", "github-copilot", "opencode"],
7459
- model: "gemini-3.1-pro",
7460
- variant: "high"
7461
- }
7462
- ]
7356
+ init_model_requirements();
7357
+ CLI_AGENT_MODEL_REQUIREMENTS = AGENT_MODEL_REQUIREMENTS;
7358
+ CLI_CATEGORY_MODEL_REQUIREMENTS = CATEGORY_MODEL_REQUIREMENTS;
7359
+ });
7360
+
7361
+ // src/cli/openai-only-model-catalog.ts
7362
+ function isOpenAiOnlyAvailability(availability) {
7363
+ return availability.native.openai && !availability.native.claude && !availability.native.gemini && !availability.opencodeGo && !availability.opencodeZen && !availability.copilot && !availability.zai && !availability.kimiForCoding;
7364
+ }
7365
+ function applyOpenAiOnlyModelCatalog(config) {
7366
+ return {
7367
+ ...config,
7368
+ agents: {
7369
+ ...config.agents,
7370
+ ...OPENAI_ONLY_AGENT_OVERRIDES
7463
7371
  },
7464
- atlas: {
7465
- fallbackChain: [
7466
- { providers: ["kimi-for-coding"], model: "k2p5" },
7467
- {
7468
- providers: ["anthropic", "github-copilot", "opencode"],
7469
- model: "claude-sonnet-4-5"
7470
- },
7471
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4", variant: "medium" },
7472
- {
7473
- providers: ["google", "github-copilot", "opencode"],
7474
- model: "gemini-3.1-pro"
7475
- }
7476
- ]
7372
+ categories: {
7373
+ ...config.categories,
7374
+ ...OPENAI_ONLY_CATEGORY_OVERRIDES
7477
7375
  }
7478
7376
  };
7479
- CLI_CATEGORY_MODEL_REQUIREMENTS = {
7480
- "visual-engineering": {
7481
- fallbackChain: [
7482
- {
7483
- providers: ["google", "github-copilot", "opencode"],
7484
- model: "gemini-3.1-pro",
7485
- variant: "high"
7486
- },
7487
- { providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
7488
- {
7489
- providers: ["anthropic", "github-copilot", "opencode"],
7490
- model: "claude-opus-4-6",
7491
- variant: "max"
7492
- },
7493
- { providers: ["kimi-for-coding"], model: "k2p5" }
7494
- ]
7495
- },
7496
- ultrabrain: {
7497
- fallbackChain: [
7498
- {
7499
- providers: ["openai", "opencode"],
7500
- model: "gpt-5.3-codex",
7501
- variant: "xhigh"
7502
- },
7503
- {
7504
- providers: ["google", "github-copilot", "opencode"],
7505
- model: "gemini-3.1-pro",
7506
- variant: "high"
7507
- },
7508
- {
7509
- providers: ["anthropic", "github-copilot", "opencode"],
7510
- model: "claude-opus-4-6",
7511
- variant: "max"
7512
- }
7513
- ]
7514
- },
7515
- deep: {
7516
- fallbackChain: [
7517
- {
7518
- providers: ["openai", "opencode"],
7519
- model: "gpt-5.3-codex",
7520
- variant: "medium"
7521
- },
7522
- {
7523
- providers: ["anthropic", "github-copilot", "opencode"],
7524
- model: "claude-opus-4-6",
7525
- variant: "max"
7526
- },
7527
- {
7528
- providers: ["google", "github-copilot", "opencode"],
7529
- model: "gemini-3.1-pro",
7530
- variant: "high"
7531
- }
7532
- ],
7533
- requiresModel: "gpt-5.3-codex"
7534
- },
7535
- artistry: {
7536
- fallbackChain: [
7537
- {
7538
- providers: ["google", "github-copilot", "opencode"],
7539
- model: "gemini-3.1-pro",
7540
- variant: "high"
7541
- },
7542
- {
7543
- providers: ["anthropic", "github-copilot", "opencode"],
7544
- model: "claude-opus-4-6",
7545
- variant: "max"
7546
- },
7547
- {
7548
- providers: ["openai", "github-copilot", "opencode"],
7549
- model: "gpt-5.4"
7550
- }
7551
- ],
7552
- requiresModel: "gemini-3.1-pro"
7553
- },
7554
- quick: {
7555
- fallbackChain: [
7556
- {
7557
- providers: ["anthropic", "github-copilot", "opencode"],
7558
- model: "claude-haiku-4-5"
7559
- },
7560
- {
7561
- providers: ["google", "github-copilot", "opencode"],
7562
- model: "gemini-3-flash"
7563
- },
7564
- { providers: ["opencode"], model: "gpt-5-nano" }
7565
- ]
7566
- },
7567
- "unspecified-low": {
7568
- fallbackChain: [
7569
- {
7570
- providers: ["anthropic", "github-copilot", "opencode"],
7571
- model: "claude-sonnet-4-5"
7572
- },
7573
- {
7574
- providers: ["openai", "opencode"],
7575
- model: "gpt-5.3-codex",
7576
- variant: "medium"
7577
- },
7578
- {
7579
- providers: ["google", "github-copilot", "opencode"],
7580
- model: "gemini-3-flash"
7581
- }
7582
- ]
7583
- },
7584
- "unspecified-high": {
7585
- fallbackChain: [
7586
- {
7587
- providers: ["openai", "github-copilot", "opencode"],
7588
- model: "gpt-5.4",
7589
- variant: "high"
7590
- },
7591
- {
7592
- providers: ["anthropic", "github-copilot", "opencode"],
7593
- model: "claude-opus-4-6",
7594
- variant: "max"
7595
- },
7596
- { providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
7597
- { providers: ["kimi-for-coding"], model: "k2p5" },
7598
- { providers: ["opencode"], model: "kimi-k2.5" }
7599
- ]
7600
- },
7601
- writing: {
7602
- fallbackChain: [
7603
- { providers: ["kimi-for-coding"], model: "k2p5" },
7604
- {
7605
- providers: ["google", "github-copilot", "opencode"],
7606
- model: "gemini-3-flash"
7607
- },
7608
- {
7609
- providers: ["anthropic", "github-copilot", "opencode"],
7610
- model: "claude-sonnet-4-5"
7611
- }
7612
- ]
7613
- }
7377
+ }
7378
+ var OPENAI_ONLY_AGENT_OVERRIDES, OPENAI_ONLY_CATEGORY_OVERRIDES;
7379
+ var init_openai_only_model_catalog = __esm(() => {
7380
+ OPENAI_ONLY_AGENT_OVERRIDES = {
7381
+ explore: { model: "openai/gpt-5.4", variant: "medium" },
7382
+ librarian: { model: "openai/gpt-5.4", variant: "medium" }
7383
+ };
7384
+ OPENAI_ONLY_CATEGORY_OVERRIDES = {
7385
+ artistry: { model: "openai/gpt-5.4", variant: "xhigh" },
7386
+ quick: { model: "openai/gpt-5.3-codex", variant: "low" },
7387
+ "visual-engineering": { model: "openai/gpt-5.4", variant: "high" },
7388
+ writing: { model: "openai/gpt-5.4", variant: "medium" }
7614
7389
  };
7615
7390
  });
7616
7391
 
@@ -7626,6 +7401,7 @@ function toProviderAvailability(config) {
7626
7401
  copilot: config.hasCopilot,
7627
7402
  zai: config.hasZaiCodingPlan,
7628
7403
  kimiForCoding: config.hasKimiForCoding,
7404
+ opencodeGo: config.hasOpencodeGo,
7629
7405
  isMaxPlan: config.isMax20
7630
7406
  };
7631
7407
  }
@@ -7637,7 +7413,8 @@ function isProviderAvailable(provider, availability) {
7637
7413
  "github-copilot": availability.copilot,
7638
7414
  opencode: availability.opencodeZen,
7639
7415
  "zai-coding-plan": availability.zai,
7640
- "kimi-for-coding": availability.kimiForCoding
7416
+ "kimi-for-coding": availability.kimiForCoding,
7417
+ "opencode-go": availability.opencodeGo
7641
7418
  };
7642
7419
  return mapping[provider] ?? false;
7643
7420
  }
@@ -7683,7 +7460,7 @@ var init_fallback_chain_resolution = __esm(() => {
7683
7460
  // src/cli/model-fallback.ts
7684
7461
  function generateModelConfig(config) {
7685
7462
  const avail = toProviderAvailability(config);
7686
- const hasAnyProvider = avail.native.claude || avail.native.openai || avail.native.gemini || avail.opencodeZen || avail.copilot || avail.zai || avail.kimiForCoding;
7463
+ const hasAnyProvider = avail.native.claude || avail.native.openai || avail.native.gemini || avail.opencodeZen || avail.copilot || avail.zai || avail.kimiForCoding || avail.opencodeGo;
7687
7464
  if (!hasAnyProvider) {
7688
7465
  return {
7689
7466
  $schema: SCHEMA_URL,
@@ -7694,8 +7471,12 @@ function generateModelConfig(config) {
7694
7471
  const agents = {};
7695
7472
  const categories = {};
7696
7473
  for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) {
7697
- if (role === "librarian" && avail.zai) {
7698
- agents[role] = { model: ZAI_MODEL };
7474
+ if (role === "librarian") {
7475
+ if (avail.opencodeGo) {
7476
+ agents[role] = { model: "opencode-go/minimax-m2.5" };
7477
+ } else if (avail.zai) {
7478
+ agents[role] = { model: ZAI_MODEL };
7479
+ }
7699
7480
  continue;
7700
7481
  }
7701
7482
  if (role === "explore") {
@@ -7703,6 +7484,8 @@ function generateModelConfig(config) {
7703
7484
  agents[role] = { model: "anthropic/claude-haiku-4-5" };
7704
7485
  } else if (avail.opencodeZen) {
7705
7486
  agents[role] = { model: "opencode/claude-haiku-4-5" };
7487
+ } else if (avail.opencodeGo) {
7488
+ agents[role] = { model: "opencode-go/minimax-m2.5" };
7706
7489
  } else if (avail.copilot) {
7707
7490
  agents[role] = { model: "github-copilot/gpt-5-mini" };
7708
7491
  } else {
@@ -7752,15 +7535,17 @@ function generateModelConfig(config) {
7752
7535
  categories[cat] = { model: ULTIMATE_FALLBACK };
7753
7536
  }
7754
7537
  }
7755
- return {
7538
+ const generatedConfig = {
7756
7539
  $schema: SCHEMA_URL,
7757
7540
  agents,
7758
7541
  categories
7759
7542
  };
7543
+ return isOpenAiOnlyAvailability(avail) ? applyOpenAiOnlyModelCatalog(generatedConfig) : generatedConfig;
7760
7544
  }
7761
- var ZAI_MODEL = "zai-coding-plan/glm-4.7", ULTIMATE_FALLBACK = "opencode/glm-4.7-free", SCHEMA_URL = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json";
7545
+ var ZAI_MODEL = "zai-coding-plan/glm-4.7", ULTIMATE_FALLBACK = "opencode/gpt-5-nano", SCHEMA_URL = "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/oh-my-opencode.schema.json";
7762
7546
  var init_model_fallback = __esm(() => {
7763
7547
  init_model_fallback_requirements();
7548
+ init_openai_only_model_catalog();
7764
7549
  init_fallback_chain_resolution();
7765
7550
  });
7766
7551
 
@@ -7954,24 +7739,46 @@ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
7954
7739
  function detectProvidersFromOmoConfig() {
7955
7740
  const omoConfigPath = getOmoConfigPath();
7956
7741
  if (!existsSync8(omoConfigPath)) {
7957
- return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false, hasKimiForCoding: false };
7742
+ return {
7743
+ hasOpenAI: true,
7744
+ hasOpencodeZen: true,
7745
+ hasZaiCodingPlan: false,
7746
+ hasKimiForCoding: false,
7747
+ hasOpencodeGo: false
7748
+ };
7958
7749
  }
7959
7750
  try {
7960
7751
  const content = readFileSync7(omoConfigPath, "utf-8");
7961
7752
  const omoConfig = parseJsonc(content);
7962
7753
  if (!omoConfig || typeof omoConfig !== "object") {
7963
- return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false, hasKimiForCoding: false };
7754
+ return {
7755
+ hasOpenAI: true,
7756
+ hasOpencodeZen: true,
7757
+ hasZaiCodingPlan: false,
7758
+ hasKimiForCoding: false,
7759
+ hasOpencodeGo: false
7760
+ };
7964
7761
  }
7965
7762
  const configStr = JSON.stringify(omoConfig);
7966
7763
  const hasOpenAI = configStr.includes('"openai/');
7967
7764
  const hasOpencodeZen = configStr.includes('"opencode/');
7968
7765
  const hasZaiCodingPlan = configStr.includes('"zai-coding-plan/');
7969
7766
  const hasKimiForCoding = configStr.includes('"kimi-for-coding/');
7970
- return { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan, hasKimiForCoding };
7767
+ const hasOpencodeGo = configStr.includes('"opencode-go/');
7768
+ return { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan, hasKimiForCoding, hasOpencodeGo };
7971
7769
  } catch {
7972
- return { hasOpenAI: true, hasOpencodeZen: true, hasZaiCodingPlan: false, hasKimiForCoding: false };
7770
+ return {
7771
+ hasOpenAI: true,
7772
+ hasOpencodeZen: true,
7773
+ hasZaiCodingPlan: false,
7774
+ hasKimiForCoding: false,
7775
+ hasOpencodeGo: false
7776
+ };
7973
7777
  }
7974
7778
  }
7779
+ function isOurPlugin(plugin) {
7780
+ return plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) || plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`);
7781
+ }
7975
7782
  function detectCurrentConfig() {
7976
7783
  const result = {
7977
7784
  isInstalled: false,
@@ -7982,7 +7789,8 @@ function detectCurrentConfig() {
7982
7789
  hasCopilot: false,
7983
7790
  hasOpencodeZen: true,
7984
7791
  hasZaiCodingPlan: false,
7985
- hasKimiForCoding: false
7792
+ hasKimiForCoding: false,
7793
+ hasOpencodeGo: false
7986
7794
  };
7987
7795
  const { format: format2, path: path3 } = detectConfigFormat();
7988
7796
  if (format2 === "none") {
@@ -7994,17 +7802,18 @@ function detectCurrentConfig() {
7994
7802
  }
7995
7803
  const openCodeConfig = parseResult.config;
7996
7804
  const plugins = openCodeConfig.plugin ?? [];
7997
- result.isInstalled = plugins.some((p) => p.startsWith("oh-my-opencode"));
7805
+ result.isInstalled = plugins.some(isOurPlugin);
7998
7806
  if (!result.isInstalled) {
7999
7807
  return result;
8000
7808
  }
8001
7809
  const providers = openCodeConfig.provider;
8002
7810
  result.hasGemini = providers ? "google" in providers : false;
8003
- const { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan, hasKimiForCoding } = detectProvidersFromOmoConfig();
7811
+ const { hasOpenAI, hasOpencodeZen, hasZaiCodingPlan, hasKimiForCoding, hasOpencodeGo } = detectProvidersFromOmoConfig();
8004
7812
  result.hasOpenAI = hasOpenAI;
8005
7813
  result.hasOpencodeZen = hasOpencodeZen;
8006
7814
  result.hasZaiCodingPlan = hasZaiCodingPlan;
8007
7815
  result.hasKimiForCoding = hasKimiForCoding;
7816
+ result.hasOpencodeGo = hasOpencodeGo;
8008
7817
  return result;
8009
7818
  }
8010
7819
  var init_detect_current_config = __esm(() => {
@@ -8015,35 +7824,75 @@ var init_detect_current_config = __esm(() => {
8015
7824
  });
8016
7825
 
8017
7826
  // src/cli/config-manager/bun-install.ts
8018
- async function runBunInstall() {
8019
- const result = await runBunInstallWithDetails();
8020
- return result.success;
7827
+ import { existsSync as existsSync9 } from "fs";
7828
+ function readProcessOutput(stream) {
7829
+ if (!stream) {
7830
+ return Promise.resolve("");
7831
+ }
7832
+ return Bun.readableStreamToText(stream);
8021
7833
  }
8022
- async function runBunInstallWithDetails() {
7834
+ function logCapturedOutputOnFailure(outputMode, output) {
7835
+ if (outputMode !== "pipe") {
7836
+ return;
7837
+ }
7838
+ const stdout = output.stdout.trim();
7839
+ const stderr = output.stderr.trim();
7840
+ if (!stdout && !stderr) {
7841
+ return;
7842
+ }
7843
+ log("[bun-install] Captured output from failed bun install", {
7844
+ stdout,
7845
+ stderr
7846
+ });
7847
+ }
7848
+ async function runBunInstallWithDetails(options) {
7849
+ const outputMode = options?.outputMode ?? "pipe";
7850
+ const cacheDir = options?.workspaceDir ?? getOpenCodeCacheDir();
7851
+ const packageJsonPath = `${cacheDir}/package.json`;
7852
+ if (!existsSync9(packageJsonPath)) {
7853
+ return {
7854
+ success: false,
7855
+ error: `Workspace not initialized: ${packageJsonPath} not found. OpenCode should create this on first run.`
7856
+ };
7857
+ }
8023
7858
  try {
8024
7859
  const proc = spawnWithWindowsHide(["bun", "install"], {
8025
- cwd: getConfigDir(),
8026
- stdout: "inherit",
8027
- stderr: "inherit"
7860
+ cwd: cacheDir,
7861
+ stdout: outputMode,
7862
+ stderr: outputMode
8028
7863
  });
7864
+ const outputPromise = Promise.all([readProcessOutput(proc.stdout), readProcessOutput(proc.stderr)]).then(([stdout, stderr]) => ({ stdout, stderr }));
8029
7865
  let timeoutId;
8030
7866
  const timeoutPromise = new Promise((resolve2) => {
8031
7867
  timeoutId = setTimeout(() => resolve2("timeout"), BUN_INSTALL_TIMEOUT_MS);
8032
7868
  });
8033
7869
  const exitPromise = proc.exited.then(() => "completed");
8034
7870
  const result = await Promise.race([exitPromise, timeoutPromise]);
8035
- clearTimeout(timeoutId);
7871
+ if (timeoutId) {
7872
+ clearTimeout(timeoutId);
7873
+ }
8036
7874
  if (result === "timeout") {
8037
7875
  try {
8038
7876
  proc.kill();
8039
- } catch {}
7877
+ } catch (err) {
7878
+ log("[cli/install] Failed to kill timed out bun install process:", err);
7879
+ }
7880
+ if (outputMode === "pipe") {
7881
+ outputPromise.then((output2) => {
7882
+ logCapturedOutputOnFailure(outputMode, output2);
7883
+ }).catch((err) => {
7884
+ log("[bun-install] Failed to read captured output after timeout:", err);
7885
+ });
7886
+ }
8040
7887
  return {
8041
7888
  success: false,
8042
7889
  timedOut: true,
8043
- error: `bun install timed out after ${BUN_INSTALL_TIMEOUT_SECONDS} seconds. Try running manually: cd ${getConfigDir()} && bun i`
7890
+ error: `bun install timed out after ${BUN_INSTALL_TIMEOUT_SECONDS} seconds. Try running manually: cd "${cacheDir}" && bun i`
8044
7891
  };
8045
7892
  }
7893
+ const output = await outputPromise;
8046
7894
  if (proc.exitCode !== 0) {
7895
+ logCapturedOutputOnFailure(outputMode, output);
8047
7896
  return {
8048
7897
  success: false,
8049
7898
  error: `bun install failed with exit code ${proc.exitCode}`
@@ -8060,7 +7909,8 @@ async function runBunInstallWithDetails() {
8060
7909
  }
8061
7910
  var BUN_INSTALL_TIMEOUT_SECONDS = 60, BUN_INSTALL_TIMEOUT_MS;
8062
7911
  var init_bun_install = __esm(() => {
8063
- init_config_context();
7912
+ init_data_path();
7913
+ init_logger();
8064
7914
  init_spawn_with_windows_hide();
8065
7915
  BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
8066
7916
  });
@@ -8138,27 +7988,22 @@ var require_src = __commonJS((exports, module) => {
8138
7988
  // src/hooks/auto-update-checker/constants.ts
8139
7989
  import * as path4 from "path";
8140
7990
  import * as os3 from "os";
8141
- function getCacheDir2() {
8142
- if (process.platform === "win32") {
8143
- return path4.join(process.env.LOCALAPPDATA ?? os3.homedir(), "opencode");
8144
- }
8145
- return path4.join(os3.homedir(), ".cache", "opencode");
8146
- }
8147
7991
  function getWindowsAppdataDir() {
8148
7992
  if (process.platform !== "win32")
8149
7993
  return null;
8150
7994
  return process.env.APPDATA ?? path4.join(os3.homedir(), "AppData", "Roaming");
8151
7995
  }
8152
- var PACKAGE_NAME3 = "oh-my-opencode", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_DIR, VERSION_FILE, USER_CONFIG_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC, INSTALLED_PACKAGE_JSON;
7996
+ var PACKAGE_NAME = "oh-my-opencode", NPM_REGISTRY_URL, NPM_FETCH_TIMEOUT = 5000, CACHE_DIR, VERSION_FILE, USER_CONFIG_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC, INSTALLED_PACKAGE_JSON;
8153
7997
  var init_constants3 = __esm(() => {
8154
- init_shared();
8155
- NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME3}/dist-tags`;
8156
- CACHE_DIR = getCacheDir2();
7998
+ init_data_path();
7999
+ init_opencode_config_dir();
8000
+ NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
8001
+ CACHE_DIR = getOpenCodeCacheDir();
8157
8002
  VERSION_FILE = path4.join(CACHE_DIR, "version");
8158
8003
  USER_CONFIG_DIR = getOpenCodeConfigDir({ binary: "opencode" });
8159
8004
  USER_OPENCODE_CONFIG = path4.join(USER_CONFIG_DIR, "opencode.json");
8160
8005
  USER_OPENCODE_CONFIG_JSONC = path4.join(USER_CONFIG_DIR, "opencode.jsonc");
8161
- INSTALLED_PACKAGE_JSON = path4.join(USER_CONFIG_DIR, "node_modules", PACKAGE_NAME3, "package.json");
8006
+ INSTALLED_PACKAGE_JSON = path4.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
8162
8007
  });
8163
8008
 
8164
8009
  // src/hooks/auto-update-checker/checker/config-paths.ts
@@ -8212,7 +8057,7 @@ function getLocalDevPath(directory) {
8212
8057
  const config2 = JSON.parse(stripJsonComments(content));
8213
8058
  const plugins = config2.plugin ?? [];
8214
8059
  for (const entry of plugins) {
8215
- if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME3)) {
8060
+ if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
8216
8061
  try {
8217
8062
  return fileURLToPath(entry);
8218
8063
  } catch {
@@ -8244,7 +8089,7 @@ function findPackageJsonUp(startPath) {
8244
8089
  try {
8245
8090
  const content = fs5.readFileSync(pkgPath, "utf-8");
8246
8091
  const pkg = JSON.parse(content);
8247
- if (pkg.name === PACKAGE_NAME3)
8092
+ if (pkg.name === PACKAGE_NAME)
8248
8093
  return pkgPath;
8249
8094
  } catch {}
8250
8095
  }
@@ -8284,9 +8129,6 @@ var init_local_dev_version = __esm(() => {
8284
8129
 
8285
8130
  // src/hooks/auto-update-checker/checker/plugin-entry.ts
8286
8131
  import * as fs7 from "fs";
8287
- function isExplicitVersionPin(pinnedVersion) {
8288
- return /^\d+\.\d+\.\d+/.test(pinnedVersion);
8289
- }
8290
8132
  function findPluginEntry(directory) {
8291
8133
  for (const configPath of getConfigPaths(directory)) {
8292
8134
  try {
@@ -8296,12 +8138,12 @@ function findPluginEntry(directory) {
8296
8138
  const config2 = JSON.parse(stripJsonComments(content));
8297
8139
  const plugins = config2.plugin ?? [];
8298
8140
  for (const entry of plugins) {
8299
- if (entry === PACKAGE_NAME3) {
8141
+ if (entry === PACKAGE_NAME) {
8300
8142
  return { entry, isPinned: false, pinnedVersion: null, configPath };
8301
8143
  }
8302
- if (entry.startsWith(`${PACKAGE_NAME3}@`)) {
8303
- const pinnedVersion = entry.slice(PACKAGE_NAME3.length + 1);
8304
- const isPinned = isExplicitVersionPin(pinnedVersion);
8144
+ if (entry.startsWith(`${PACKAGE_NAME}@`)) {
8145
+ const pinnedVersion = entry.slice(PACKAGE_NAME.length + 1);
8146
+ const isPinned = EXACT_SEMVER_REGEX.test(pinnedVersion.trim());
8305
8147
  return { entry, isPinned, pinnedVersion, configPath };
8306
8148
  }
8307
8149
  }
@@ -8311,9 +8153,11 @@ function findPluginEntry(directory) {
8311
8153
  }
8312
8154
  return null;
8313
8155
  }
8156
+ var EXACT_SEMVER_REGEX;
8314
8157
  var init_plugin_entry = __esm(() => {
8315
8158
  init_constants3();
8316
8159
  init_config_paths();
8160
+ EXACT_SEMVER_REGEX = /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/;
8317
8161
  });
8318
8162
 
8319
8163
  // src/hooks/auto-update-checker/checker/cached-version.ts
@@ -8362,52 +8206,6 @@ var init_cached_version = __esm(() => {
8362
8206
  });
8363
8207
 
8364
8208
  // src/hooks/auto-update-checker/checker/pinned-version-updater.ts
8365
- import * as fs9 from "fs";
8366
- function replacePluginEntry(configPath, oldEntry, newEntry) {
8367
- try {
8368
- const content = fs9.readFileSync(configPath, "utf-8");
8369
- const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
8370
- if (!pluginMatch || pluginMatch.index === undefined) {
8371
- log(`[auto-update-checker] No "plugin" array found in ${configPath}`);
8372
- return false;
8373
- }
8374
- const startIndex = pluginMatch.index + pluginMatch[0].length;
8375
- let bracketCount = 1;
8376
- let endIndex = startIndex;
8377
- for (let i2 = startIndex;i2 < content.length && bracketCount > 0; i2++) {
8378
- if (content[i2] === "[")
8379
- bracketCount++;
8380
- else if (content[i2] === "]")
8381
- bracketCount--;
8382
- endIndex = i2;
8383
- }
8384
- const before = content.slice(0, startIndex);
8385
- const pluginArrayContent = content.slice(startIndex, endIndex);
8386
- const after = content.slice(endIndex);
8387
- const escapedOldEntry = oldEntry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8388
- const regex = new RegExp(`["']${escapedOldEntry}["']`);
8389
- if (!regex.test(pluginArrayContent)) {
8390
- log(`[auto-update-checker] Entry "${oldEntry}" not found in plugin array of ${configPath}`);
8391
- return false;
8392
- }
8393
- const updatedPluginArray = pluginArrayContent.replace(regex, `"${newEntry}"`);
8394
- const updatedContent = before + updatedPluginArray + after;
8395
- if (updatedContent === content) {
8396
- log(`[auto-update-checker] No changes made to ${configPath}`);
8397
- return false;
8398
- }
8399
- fs9.writeFileSync(configPath, updatedContent, "utf-8");
8400
- log(`[auto-update-checker] Updated ${configPath}: ${oldEntry} \u2192 ${newEntry}`);
8401
- return true;
8402
- } catch (err) {
8403
- log(`[auto-update-checker] Failed to update config file ${configPath}:`, err);
8404
- return false;
8405
- }
8406
- }
8407
- function revertPinnedVersion(configPath, failedVersion, originalEntry) {
8408
- const failedEntry = `${PACKAGE_NAME3}@${failedVersion}`;
8409
- return replacePluginEntry(configPath, failedEntry, originalEntry);
8410
- }
8411
8209
  var init_pinned_version_updater = __esm(() => {
8412
8210
  init_logger();
8413
8211
  init_constants3();
@@ -8531,6 +8329,79 @@ var init_check_for_update = __esm(() => {
8531
8329
  init_latest_version();
8532
8330
  });
8533
8331
 
8332
+ // src/hooks/auto-update-checker/checker/sync-package-json.ts
8333
+ import * as crypto from "crypto";
8334
+ import * as fs9 from "fs";
8335
+ import * as path8 from "path";
8336
+ function safeUnlink(filePath) {
8337
+ try {
8338
+ fs9.unlinkSync(filePath);
8339
+ } catch (err) {
8340
+ log(`[auto-update-checker] Failed to cleanup temp file: ${filePath}`, err);
8341
+ }
8342
+ }
8343
+ function getIntentVersion(pluginInfo) {
8344
+ if (!pluginInfo.pinnedVersion) {
8345
+ return "latest";
8346
+ }
8347
+ return pluginInfo.pinnedVersion;
8348
+ }
8349
+ function syncCachePackageJsonToIntent(pluginInfo) {
8350
+ const cachePackageJsonPath = path8.join(CACHE_DIR, "package.json");
8351
+ if (!fs9.existsSync(cachePackageJsonPath)) {
8352
+ log("[auto-update-checker] Cache package.json not found, nothing to sync");
8353
+ return { synced: false, error: "file_not_found", message: "Cache package.json not found" };
8354
+ }
8355
+ let content;
8356
+ let pkgJson;
8357
+ try {
8358
+ content = fs9.readFileSync(cachePackageJsonPath, "utf-8");
8359
+ } catch (err) {
8360
+ log("[auto-update-checker] Failed to read cache package.json:", err);
8361
+ return { synced: false, error: "parse_error", message: "Failed to read cache package.json" };
8362
+ }
8363
+ try {
8364
+ pkgJson = JSON.parse(content);
8365
+ } catch (err) {
8366
+ log("[auto-update-checker] Failed to parse cache package.json:", err);
8367
+ return { synced: false, error: "parse_error", message: "Failed to parse cache package.json (malformed JSON)" };
8368
+ }
8369
+ if (!pkgJson || !pkgJson.dependencies?.[PACKAGE_NAME]) {
8370
+ log("[auto-update-checker] Plugin not in cache package.json dependencies, nothing to sync");
8371
+ return { synced: false, error: "plugin_not_in_deps", message: "Plugin not in cache package.json dependencies" };
8372
+ }
8373
+ const currentVersion = pkgJson.dependencies[PACKAGE_NAME];
8374
+ const intentVersion = getIntentVersion(pluginInfo);
8375
+ if (currentVersion === intentVersion) {
8376
+ log("[auto-update-checker] Cache package.json already matches intent:", intentVersion);
8377
+ return { synced: false, error: null, message: `Already matches intent: ${intentVersion}` };
8378
+ }
8379
+ const intentIsTag = !EXACT_SEMVER_REGEX2.test(intentVersion.trim());
8380
+ const currentIsSemver = EXACT_SEMVER_REGEX2.test(String(currentVersion).trim());
8381
+ if (intentIsTag && currentIsSemver) {
8382
+ log(`[auto-update-checker] Syncing cache package.json: "${currentVersion}" \u2192 "${intentVersion}" (opencode.json intent)`);
8383
+ } else {
8384
+ log(`[auto-update-checker] Updating cache package.json: "${currentVersion}" \u2192 "${intentVersion}"`);
8385
+ }
8386
+ pkgJson.dependencies[PACKAGE_NAME] = intentVersion;
8387
+ const tmpPath = `${cachePackageJsonPath}.${crypto.randomUUID()}`;
8388
+ try {
8389
+ fs9.writeFileSync(tmpPath, JSON.stringify(pkgJson, null, 2));
8390
+ fs9.renameSync(tmpPath, cachePackageJsonPath);
8391
+ return { synced: true, error: null, message: `Updated: "${currentVersion}" \u2192 "${intentVersion}"` };
8392
+ } catch (err) {
8393
+ log("[auto-update-checker] Failed to write cache package.json:", err);
8394
+ safeUnlink(tmpPath);
8395
+ return { synced: false, error: "write_error", message: "Failed to write cache package.json" };
8396
+ }
8397
+ }
8398
+ var EXACT_SEMVER_REGEX2;
8399
+ var init_sync_package_json = __esm(() => {
8400
+ init_constants3();
8401
+ init_logger();
8402
+ EXACT_SEMVER_REGEX2 = /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/;
8403
+ });
8404
+
8534
8405
  // src/hooks/auto-update-checker/checker.ts
8535
8406
  var init_checker = __esm(() => {
8536
8407
  init_local_dev_path();
@@ -8540,48 +8411,57 @@ var init_checker = __esm(() => {
8540
8411
  init_pinned_version_updater();
8541
8412
  init_latest_version();
8542
8413
  init_check_for_update();
8414
+ init_sync_package_json();
8543
8415
  });
8544
8416
 
8545
8417
  // src/hooks/auto-update-checker/cache.ts
8546
8418
  import * as fs10 from "fs";
8547
- import * as path8 from "path";
8419
+ import * as path9 from "path";
8548
8420
  function stripTrailingCommas(json3) {
8549
8421
  return json3.replace(/,(\s*[}\]])/g, "$1");
8550
8422
  }
8551
- function removeFromBunLock(packageName) {
8552
- const lockPath = path8.join(USER_CONFIG_DIR, "bun.lock");
8553
- if (!fs10.existsSync(lockPath))
8554
- return false;
8423
+ function removeFromTextBunLock(lockPath, packageName) {
8555
8424
  try {
8556
8425
  const content = fs10.readFileSync(lockPath, "utf-8");
8557
8426
  const lock = JSON.parse(stripTrailingCommas(content));
8558
- let modified = false;
8559
- if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
8560
- delete lock.workspaces[""].dependencies[packageName];
8561
- modified = true;
8562
- }
8563
8427
  if (lock.packages?.[packageName]) {
8564
8428
  delete lock.packages[packageName];
8565
- modified = true;
8566
- }
8567
- if (modified) {
8568
8429
  fs10.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
8569
8430
  log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
8431
+ return true;
8570
8432
  }
8571
- return modified;
8433
+ return false;
8434
+ } catch {
8435
+ return false;
8436
+ }
8437
+ }
8438
+ function deleteBinaryBunLock(lockPath) {
8439
+ try {
8440
+ fs10.unlinkSync(lockPath);
8441
+ log(`[auto-update-checker] Removed bun.lockb to force re-resolution`);
8442
+ return true;
8572
8443
  } catch {
8573
8444
  return false;
8574
8445
  }
8575
8446
  }
8576
- function invalidatePackage(packageName = PACKAGE_NAME3) {
8447
+ function removeFromBunLock(packageName) {
8448
+ const textLockPath = path9.join(CACHE_DIR, "bun.lock");
8449
+ const binaryLockPath = path9.join(CACHE_DIR, "bun.lockb");
8450
+ if (fs10.existsSync(textLockPath)) {
8451
+ return removeFromTextBunLock(textLockPath, packageName);
8452
+ }
8453
+ if (fs10.existsSync(binaryLockPath)) {
8454
+ return deleteBinaryBunLock(binaryLockPath);
8455
+ }
8456
+ return false;
8457
+ }
8458
+ function invalidatePackage(packageName = PACKAGE_NAME) {
8577
8459
  try {
8578
8460
  const pkgDirs = [
8579
- path8.join(USER_CONFIG_DIR, "node_modules", packageName),
8580
- path8.join(CACHE_DIR, "node_modules", packageName)
8461
+ path9.join(USER_CONFIG_DIR, "node_modules", packageName),
8462
+ path9.join(CACHE_DIR, "node_modules", packageName)
8581
8463
  ];
8582
- const pkgJsonPath = path8.join(USER_CONFIG_DIR, "package.json");
8583
8464
  let packageRemoved = false;
8584
- let dependencyRemoved = false;
8585
8465
  let lockRemoved = false;
8586
8466
  for (const pkgDir of pkgDirs) {
8587
8467
  if (fs10.existsSync(pkgDir)) {
@@ -8590,18 +8470,8 @@ function invalidatePackage(packageName = PACKAGE_NAME3) {
8590
8470
  packageRemoved = true;
8591
8471
  }
8592
8472
  }
8593
- if (fs10.existsSync(pkgJsonPath)) {
8594
- const content = fs10.readFileSync(pkgJsonPath, "utf-8");
8595
- const pkgJson = JSON.parse(content);
8596
- if (pkgJson.dependencies?.[packageName]) {
8597
- delete pkgJson.dependencies[packageName];
8598
- fs10.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
8599
- log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
8600
- dependencyRemoved = true;
8601
- }
8602
- }
8603
8473
  lockRemoved = removeFromBunLock(packageName);
8604
- if (!packageRemoved && !dependencyRemoved && !lockRemoved) {
8474
+ if (!packageRemoved && !lockRemoved) {
8605
8475
  log(`[auto-update-checker] Package not found, nothing to invalidate: ${packageName}`);
8606
8476
  return false;
8607
8477
  }
@@ -8649,12 +8519,34 @@ var init_update_toasts = __esm(() => {
8649
8519
  });
8650
8520
 
8651
8521
  // src/hooks/auto-update-checker/hook/background-update-check.ts
8522
+ import { existsSync as existsSync20 } from "fs";
8523
+ import { join as join17 } from "path";
8652
8524
  function getPinnedVersionToastMessage(latestVersion) {
8653
8525
  return `Update available: ${latestVersion} (version pinned, update manually)`;
8654
8526
  }
8655
- async function runBunInstallSafe() {
8527
+ function resolveActiveInstallWorkspace() {
8528
+ const configPaths = getOpenCodeConfigPaths({ binary: "opencode" });
8529
+ const cacheDir = getOpenCodeCacheDir();
8530
+ const configInstallPath = join17(configPaths.configDir, "node_modules", PACKAGE_NAME, "package.json");
8531
+ const cacheInstallPath = join17(cacheDir, "node_modules", PACKAGE_NAME, "package.json");
8532
+ if (existsSync20(configInstallPath)) {
8533
+ log(`[auto-update-checker] Active workspace: config-dir (${configPaths.configDir})`);
8534
+ return configPaths.configDir;
8535
+ }
8536
+ if (existsSync20(cacheInstallPath)) {
8537
+ log(`[auto-update-checker] Active workspace: cache-dir (${cacheDir})`);
8538
+ return cacheDir;
8539
+ }
8540
+ log(`[auto-update-checker] Active workspace: config-dir (default, no install detected)`);
8541
+ return configPaths.configDir;
8542
+ }
8543
+ async function runBunInstallSafe(workspaceDir) {
8656
8544
  try {
8657
- return await runBunInstall();
8545
+ const result = await runBunInstallWithDetails({ outputMode: "pipe", workspaceDir });
8546
+ if (!result.success && result.error) {
8547
+ log("[auto-update-checker] bun install error:", result.error);
8548
+ }
8549
+ return result.success;
8658
8550
  } catch (err) {
8659
8551
  const errorMessage = err instanceof Error ? err.message : String(err);
8660
8552
  log("[auto-update-checker] bun install error:", errorMessage);
@@ -8694,23 +8586,27 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
8694
8586
  log(`[auto-update-checker] User-pinned version detected (${pluginInfo.entry}), skipping auto-update. Notification only.`);
8695
8587
  return;
8696
8588
  }
8697
- invalidatePackage(PACKAGE_NAME3);
8698
- const installSuccess = await runBunInstallSafe();
8589
+ const syncResult = syncCachePackageJsonToIntent(pluginInfo);
8590
+ if (syncResult.error) {
8591
+ log(`[auto-update-checker] Sync failed with error: ${syncResult.error}`, syncResult.message);
8592
+ await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
8593
+ return;
8594
+ }
8595
+ invalidatePackage(PACKAGE_NAME);
8596
+ const activeWorkspace = resolveActiveInstallWorkspace();
8597
+ const installSuccess = await runBunInstallSafe(activeWorkspace);
8699
8598
  if (installSuccess) {
8700
8599
  await showAutoUpdatedToast(ctx, currentVersion, latestVersion);
8701
8600
  log(`[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`);
8702
8601
  return;
8703
8602
  }
8704
- if (pluginInfo.isPinned) {
8705
- revertPinnedVersion(pluginInfo.configPath, latestVersion, pluginInfo.entry);
8706
- log("[auto-update-checker] Config reverted due to install failure");
8707
- }
8708
8603
  await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
8709
8604
  log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
8710
8605
  }
8711
8606
  var init_background_update_check = __esm(() => {
8712
8607
  init_config_manager();
8713
8608
  init_logger();
8609
+ init_shared();
8714
8610
  init_cache();
8715
8611
  init_constants3();
8716
8612
  init_checker();
@@ -8940,7 +8836,7 @@ var {
8940
8836
  // package.json
8941
8837
  var package_default = {
8942
8838
  name: "oh-my-opencode",
8943
- version: "3.11.2",
8839
+ version: "3.12.0",
8944
8840
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
8945
8841
  main: "dist/index.js",
8946
8842
  types: "dist/index.d.ts",
@@ -8992,13 +8888,13 @@ var package_default = {
8992
8888
  },
8993
8889
  homepage: "https://github.com/code-yeongyu/oh-my-openagent#readme",
8994
8890
  dependencies: {
8995
- "@ast-grep/cli": "^0.40.0",
8996
- "@ast-grep/napi": "^0.40.0",
8891
+ "@ast-grep/cli": "^0.41.1",
8892
+ "@ast-grep/napi": "^0.41.1",
8997
8893
  "@clack/prompts": "^0.11.0",
8998
8894
  "@code-yeongyu/comment-checker": "^0.7.0",
8999
8895
  "@modelcontextprotocol/sdk": "^1.25.2",
9000
- "@opencode-ai/plugin": "^1.2.16",
9001
- "@opencode-ai/sdk": "^1.2.17",
8896
+ "@opencode-ai/plugin": "^1.2.24",
8897
+ "@opencode-ai/sdk": "^1.2.24",
9002
8898
  commander: "^14.0.2",
9003
8899
  "detect-libc": "^2.0.0",
9004
8900
  diff: "^8.0.3",
@@ -9012,24 +8908,24 @@ var package_default = {
9012
8908
  devDependencies: {
9013
8909
  "@types/js-yaml": "^4.0.9",
9014
8910
  "@types/picomatch": "^3.0.2",
9015
- "bun-types": "1.3.6",
8911
+ "bun-types": "1.3.10",
9016
8912
  typescript: "^5.7.3"
9017
8913
  },
9018
8914
  optionalDependencies: {
9019
- "oh-my-opencode-darwin-arm64": "3.11.2",
9020
- "oh-my-opencode-darwin-x64": "3.11.2",
9021
- "oh-my-opencode-darwin-x64-baseline": "3.11.2",
9022
- "oh-my-opencode-linux-arm64": "3.11.2",
9023
- "oh-my-opencode-linux-arm64-musl": "3.11.2",
9024
- "oh-my-opencode-linux-x64": "3.11.2",
9025
- "oh-my-opencode-linux-x64-baseline": "3.11.2",
9026
- "oh-my-opencode-linux-x64-musl": "3.11.2",
9027
- "oh-my-opencode-linux-x64-musl-baseline": "3.11.2",
9028
- "oh-my-opencode-windows-x64": "3.11.2",
9029
- "oh-my-opencode-windows-x64-baseline": "3.11.2"
8915
+ "oh-my-opencode-darwin-arm64": "3.12.0",
8916
+ "oh-my-opencode-darwin-x64": "3.12.0",
8917
+ "oh-my-opencode-darwin-x64-baseline": "3.12.0",
8918
+ "oh-my-opencode-linux-arm64": "3.12.0",
8919
+ "oh-my-opencode-linux-arm64-musl": "3.12.0",
8920
+ "oh-my-opencode-linux-x64": "3.12.0",
8921
+ "oh-my-opencode-linux-x64-baseline": "3.12.0",
8922
+ "oh-my-opencode-linux-x64-musl": "3.12.0",
8923
+ "oh-my-opencode-linux-x64-musl-baseline": "3.12.0",
8924
+ "oh-my-opencode-windows-x64": "3.12.0",
8925
+ "oh-my-opencode-windows-x64-baseline": "3.12.0"
9030
8926
  },
9031
8927
  overrides: {
9032
- "@opencode-ai/sdk": "^1.2.17"
8928
+ "@opencode-ai/sdk": "^1.2.24"
9033
8929
  },
9034
8930
  trustedDependencies: [
9035
8931
  "@ast-grep/cli",
@@ -9053,6 +8949,7 @@ var SYMBOLS = {
9053
8949
  warn: import_picocolors.default.yellow("[!]"),
9054
8950
  star: import_picocolors.default.yellow("*")
9055
8951
  };
8952
+ var ANSI_COLOR_PATTERN = new RegExp("\x1B\\[[0-9;]*m", "g");
9056
8953
  function formatProvider(name, enabled, detail) {
9057
8954
  const status = enabled ? SYMBOLS.check : import_picocolors.default.dim("\u25CB");
9058
8955
  const label = enabled ? import_picocolors.default.white(name) : import_picocolors.default.dim(name);
@@ -9106,7 +9003,7 @@ function printWarning(message) {
9106
9003
  function printBox(content, title) {
9107
9004
  const lines = content.split(`
9108
9005
  `);
9109
- const maxWidth = Math.max(...lines.map((line) => line.replace(/\x1b\[[0-9;]*m/g, "").length), title?.length ?? 0) + 4;
9006
+ const maxWidth = Math.max(...lines.map((line) => line.replace(ANSI_COLOR_PATTERN, "").length), title?.length ?? 0) + 4;
9110
9007
  const border = import_picocolors.default.dim("\u2500".repeat(maxWidth));
9111
9008
  console.log();
9112
9009
  if (title) {
@@ -9115,7 +9012,7 @@ function printBox(content, title) {
9115
9012
  console.log(import_picocolors.default.dim("\u250C") + border + import_picocolors.default.dim("\u2510"));
9116
9013
  }
9117
9014
  for (const line of lines) {
9118
- const stripped = line.replace(/\x1b\[[0-9;]*m/g, "");
9015
+ const stripped = line.replace(ANSI_COLOR_PATTERN, "");
9119
9016
  const padding = maxWidth - stripped.length;
9120
9017
  console.log(import_picocolors.default.dim("\u2502") + ` ${line}${" ".repeat(padding - 1)}` + import_picocolors.default.dim("\u2502"));
9121
9018
  }
@@ -9142,6 +9039,9 @@ function validateNonTuiArgs(args) {
9142
9039
  if (args.openai !== undefined && !["no", "yes"].includes(args.openai)) {
9143
9040
  errors.push(`Invalid --openai value: ${args.openai} (expected: no, yes)`);
9144
9041
  }
9042
+ if (args.opencodeGo !== undefined && !["no", "yes"].includes(args.opencodeGo)) {
9043
+ errors.push(`Invalid --opencode-go value: ${args.opencodeGo} (expected: no, yes)`);
9044
+ }
9145
9045
  if (args.opencodeZen !== undefined && !["no", "yes"].includes(args.opencodeZen)) {
9146
9046
  errors.push(`Invalid --opencode-zen value: ${args.opencodeZen} (expected: no, yes)`);
9147
9047
  }
@@ -9162,7 +9062,8 @@ function argsToConfig(args) {
9162
9062
  hasCopilot: args.copilot === "yes",
9163
9063
  hasOpencodeZen: args.opencodeZen === "yes",
9164
9064
  hasZaiCodingPlan: args.zaiCodingPlan === "yes",
9165
- hasKimiForCoding: args.kimiForCoding === "yes"
9065
+ hasKimiForCoding: args.kimiForCoding === "yes",
9066
+ hasOpencodeGo: args.opencodeGo === "yes"
9166
9067
  };
9167
9068
  }
9168
9069
  function detectedToInitialValues(detected) {
@@ -9177,7 +9078,8 @@ function detectedToInitialValues(detected) {
9177
9078
  copilot: detected.hasCopilot ? "yes" : "no",
9178
9079
  opencodeZen: detected.hasOpencodeZen ? "yes" : "no",
9179
9080
  zaiCodingPlan: detected.hasZaiCodingPlan ? "yes" : "no",
9180
- kimiForCoding: detected.hasKimiForCoding ? "yes" : "no"
9081
+ kimiForCoding: detected.hasKimiForCoding ? "yes" : "no",
9082
+ opencodeGo: detected.hasOpencodeGo ? "yes" : "no"
9181
9083
  };
9182
9084
  }
9183
9085
 
@@ -9252,7 +9154,7 @@ async function runCliInstaller(args, version) {
9252
9154
  ` + `All features work like magic\u2014parallel agents, background tasks,
9253
9155
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
9254
9156
  console.log(`${SYMBOLS.star} ${import_picocolors2.default.yellow("If you found this helpful, consider starring the repo!")}`);
9255
- console.log(` ${import_picocolors2.default.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-opencode >/dev/null 2>&1 || true")}`);
9157
+ console.log(` ${import_picocolors2.default.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/null 2>&1 || true")}`);
9256
9158
  console.log();
9257
9159
  console.log(import_picocolors2.default.dim("oMoMoMoMo... Enjoy!"));
9258
9160
  console.log();
@@ -9937,6 +9839,16 @@ async function promptInstallConfig(detected) {
9937
9839
  });
9938
9840
  if (!kimiForCoding)
9939
9841
  return null;
9842
+ const opencodeGo = await selectOrCancel({
9843
+ message: "Do you have an OpenCode Go subscription?",
9844
+ options: [
9845
+ { value: "no", label: "No", hint: "Will use other configured providers" },
9846
+ { value: "yes", label: "Yes", hint: "OpenCode Go for quick tasks" }
9847
+ ],
9848
+ initialValue: initial.opencodeGo
9849
+ });
9850
+ if (!opencodeGo)
9851
+ return null;
9940
9852
  return {
9941
9853
  hasClaude: claude !== "no",
9942
9854
  isMax20: claude === "max20",
@@ -9945,7 +9857,8 @@ async function promptInstallConfig(detected) {
9945
9857
  hasCopilot: copilot === "yes",
9946
9858
  hasOpencodeZen: opencodeZen === "yes",
9947
9859
  hasZaiCodingPlan: zaiCodingPlan === "yes",
9948
- hasKimiForCoding: kimiForCoding === "yes"
9860
+ hasKimiForCoding: kimiForCoding === "yes",
9861
+ hasOpencodeGo: opencodeGo === "yes"
9949
9862
  };
9950
9863
  }
9951
9864
 
@@ -10015,7 +9928,7 @@ async function runTuiInstaller(args, version) {
10015
9928
  ` + `All features work like magic\u2014parallel agents, background tasks,
10016
9929
  ` + `deep exploration, and relentless execution until completion.`, "The Magic Word");
10017
9930
  M2.message(`${import_picocolors4.default.yellow("\u2605")} If you found this helpful, consider starring the repo!`);
10018
- M2.message(` ${import_picocolors4.default.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-opencode >/dev/null 2>&1 || true")}`);
9931
+ M2.message(` ${import_picocolors4.default.dim("gh api --silent --method PUT /user/starred/code-yeongyu/oh-my-openagent >/dev/null 2>&1 || true")}`);
10019
9932
  Se(import_picocolors4.default.green("oMoMoMoMo... Enjoy!"));
10020
9933
  if ((config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
10021
9934
  const providers = [];
@@ -10044,7 +9957,7 @@ async function install(args) {
10044
9957
  }
10045
9958
 
10046
9959
  // src/cli/run/runner.ts
10047
- var import_picocolors15 = __toESM(require_picocolors(), 1);
9960
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
10048
9961
 
10049
9962
  // src/cli/run/event-state.ts
10050
9963
  function createEventState() {
@@ -24286,7 +24199,8 @@ var BuiltinAgentNameSchema = exports_external.enum([
24286
24199
  "multimodal-looker",
24287
24200
  "metis",
24288
24201
  "momus",
24289
- "atlas"
24202
+ "atlas",
24203
+ "sisyphus-junior"
24290
24204
  ]);
24291
24205
  var BuiltinSkillNameSchema = exports_external.enum([
24292
24206
  "playwright",
@@ -24386,13 +24300,22 @@ var BabysittingConfigSchema = exports_external.object({
24386
24300
  timeout_ms: exports_external.number().default(120000)
24387
24301
  });
24388
24302
  // src/config/schema/background-task.ts
24303
+ var CircuitBreakerConfigSchema = exports_external.object({
24304
+ maxToolCalls: exports_external.number().int().min(10).optional(),
24305
+ windowSize: exports_external.number().int().min(5).optional(),
24306
+ repetitionThresholdPercent: exports_external.number().gt(0).max(100).optional()
24307
+ });
24389
24308
  var BackgroundTaskConfigSchema = exports_external.object({
24390
24309
  defaultConcurrency: exports_external.number().min(1).optional(),
24391
24310
  providerConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(0)).optional(),
24392
24311
  modelConcurrency: exports_external.record(exports_external.string(), exports_external.number().min(0)).optional(),
24312
+ maxDepth: exports_external.number().int().min(1).optional(),
24313
+ maxDescendants: exports_external.number().int().min(1).optional(),
24393
24314
  staleTimeoutMs: exports_external.number().min(60000).optional(),
24394
24315
  messageStalenessTimeoutMs: exports_external.number().min(60000).optional(),
24395
- syncPollTimeoutMs: exports_external.number().min(60000).optional()
24316
+ syncPollTimeoutMs: exports_external.number().min(60000).optional(),
24317
+ maxToolCalls: exports_external.number().int().min(10).optional(),
24318
+ circuitBreaker: CircuitBreakerConfigSchema.optional()
24396
24319
  });
24397
24320
  // src/config/schema/browser-automation.ts
24398
24321
  var BrowserAutomationProviderSchema = exports_external.enum([
@@ -24505,13 +24428,25 @@ var ExperimentalConfigSchema = exports_external.object({
24505
24428
  hashline_edit: exports_external.boolean().optional(),
24506
24429
  model_fallback_title: exports_external.boolean().optional()
24507
24430
  });
24431
+ // src/config/schema/git-env-prefix.ts
24432
+ var GIT_ENV_ASSIGNMENT_PATTERN = /^(?:[A-Za-z_][A-Za-z0-9_]*=[A-Za-z0-9_-]*)(?: [A-Za-z_][A-Za-z0-9_]*=[A-Za-z0-9_-]*)*$/;
24433
+ var GIT_ENV_PREFIX_VALIDATION_MESSAGE = 'git_env_prefix must be empty or use shell-safe env assignments like "GIT_MASTER=1"';
24434
+ function isValidGitEnvPrefix(value) {
24435
+ if (value === "") {
24436
+ return true;
24437
+ }
24438
+ return GIT_ENV_ASSIGNMENT_PATTERN.test(value);
24439
+ }
24440
+ var GitEnvPrefixSchema = exports_external.string().refine(isValidGitEnvPrefix, { message: GIT_ENV_PREFIX_VALIDATION_MESSAGE }).default("GIT_MASTER=1");
24508
24441
  // src/config/schema/git-master.ts
24509
24442
  var GitMasterConfigSchema = exports_external.object({
24510
24443
  commit_footer: exports_external.union([exports_external.boolean(), exports_external.string()]).default(true),
24511
- include_co_authored_by: exports_external.boolean().default(true)
24444
+ include_co_authored_by: exports_external.boolean().default(true),
24445
+ git_env_prefix: GitEnvPrefixSchema
24512
24446
  });
24513
24447
  // src/config/schema/hooks.ts
24514
24448
  var HookNameSchema = exports_external.enum([
24449
+ "gpt-permission-continuation",
24515
24450
  "todo-continuation-enforcer",
24516
24451
  "context-window-monitor",
24517
24452
  "session-recovery",
@@ -24700,6 +24635,14 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
24700
24635
  });
24701
24636
  // src/plugin-config.ts
24702
24637
  init_shared();
24638
+ var PARTIAL_STRING_ARRAY_KEYS = new Set([
24639
+ "disabled_mcps",
24640
+ "disabled_agents",
24641
+ "disabled_skills",
24642
+ "disabled_hooks",
24643
+ "disabled_commands",
24644
+ "disabled_tools"
24645
+ ]);
24703
24646
  function parseConfigPartially(rawConfig) {
24704
24647
  const fullResult = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
24705
24648
  if (fullResult.success) {
@@ -24708,6 +24651,13 @@ function parseConfigPartially(rawConfig) {
24708
24651
  const partialConfig = {};
24709
24652
  const invalidSections = [];
24710
24653
  for (const key of Object.keys(rawConfig)) {
24654
+ if (PARTIAL_STRING_ARRAY_KEYS.has(key)) {
24655
+ const sectionValue = rawConfig[key];
24656
+ if (Array.isArray(sectionValue) && sectionValue.every((value) => typeof value === "string")) {
24657
+ partialConfig[key] = sectionValue;
24658
+ }
24659
+ continue;
24660
+ }
24711
24661
  const sectionResult = OhMyOpenCodeConfigSchema.safeParse({ [key]: rawConfig[key] });
24712
24662
  if (sectionResult.success) {
24713
24663
  const parsed = sectionResult.data;
@@ -24793,6 +24743,12 @@ function mergeConfigs(base, override) {
24793
24743
  ...override.disabled_skills ?? []
24794
24744
  ])
24795
24745
  ],
24746
+ disabled_tools: [
24747
+ ...new Set([
24748
+ ...base.disabled_tools ?? [],
24749
+ ...override.disabled_tools ?? []
24750
+ ])
24751
+ ],
24796
24752
  claude_code: deepMerge(base.claude_code, override.claude_code)
24797
24753
  };
24798
24754
  }
@@ -26506,14 +26462,28 @@ function createJsonOutputManager(options = {}) {
26506
26462
 
26507
26463
  // src/cli/run/on-complete-hook.ts
26508
26464
  init_spawn_with_windows_hide();
26509
- var import_picocolors11 = __toESM(require_picocolors(), 1);
26465
+ init_shared();
26466
+ async function readOutput(stream, streamName) {
26467
+ if (!stream) {
26468
+ return "";
26469
+ }
26470
+ try {
26471
+ return await new Response(stream).text();
26472
+ } catch (error48) {
26473
+ log("Failed to read on-complete hook output", {
26474
+ stream: streamName,
26475
+ error: error48 instanceof Error ? error48.message : String(error48)
26476
+ });
26477
+ return "";
26478
+ }
26479
+ }
26510
26480
  async function executeOnCompleteHook(options) {
26511
26481
  const { command, sessionId, exitCode, durationMs, messageCount } = options;
26512
26482
  const trimmedCommand = command.trim();
26513
26483
  if (!trimmedCommand) {
26514
26484
  return;
26515
26485
  }
26516
- console.error(import_picocolors11.default.dim(`Running on-complete hook: ${trimmedCommand}`));
26486
+ log("Running on-complete hook", { command: trimmedCommand });
26517
26487
  try {
26518
26488
  const proc = spawnWithWindowsHide(["sh", "-c", trimmedCommand], {
26519
26489
  env: {
@@ -26523,21 +26493,37 @@ async function executeOnCompleteHook(options) {
26523
26493
  DURATION_MS: String(durationMs),
26524
26494
  MESSAGE_COUNT: String(messageCount)
26525
26495
  },
26526
- stdout: "inherit",
26527
- stderr: "inherit"
26496
+ stdout: "pipe",
26497
+ stderr: "pipe"
26528
26498
  });
26529
- const hookExitCode = await proc.exited;
26499
+ const [hookExitCode, stdout, stderr] = await Promise.all([
26500
+ proc.exited,
26501
+ readOutput(proc.stdout, "stdout"),
26502
+ readOutput(proc.stderr, "stderr")
26503
+ ]);
26504
+ if (stdout.trim()) {
26505
+ log("On-complete hook stdout", { command: trimmedCommand, stdout: stdout.trim() });
26506
+ }
26507
+ if (stderr.trim()) {
26508
+ log("On-complete hook stderr", { command: trimmedCommand, stderr: stderr.trim() });
26509
+ }
26530
26510
  if (hookExitCode !== 0) {
26531
- console.error(import_picocolors11.default.yellow(`Warning: on-complete hook exited with code ${hookExitCode}`));
26511
+ log("On-complete hook exited with non-zero code", {
26512
+ command: trimmedCommand,
26513
+ exitCode: hookExitCode
26514
+ });
26532
26515
  }
26533
26516
  } catch (error48) {
26534
- console.error(import_picocolors11.default.yellow(`Warning: Failed to execute on-complete hook: ${error48 instanceof Error ? error48.message : String(error48)}`));
26517
+ log("Failed to execute on-complete hook", {
26518
+ command: trimmedCommand,
26519
+ error: error48 instanceof Error ? error48.message : String(error48)
26520
+ });
26535
26521
  }
26536
26522
  }
26537
26523
 
26538
26524
  // src/cli/run/agent-resolver.ts
26539
26525
  init_agent_display_names();
26540
- var import_picocolors12 = __toESM(require_picocolors(), 1);
26526
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
26541
26527
  var CORE_AGENT_ORDER = ["sisyphus", "hephaestus", "prometheus", "atlas"];
26542
26528
  var DEFAULT_AGENT = "sisyphus";
26543
26529
  var normalizeAgentName = (agent) => {
@@ -26582,21 +26568,45 @@ var resolveRunAgent = (options, pluginConfig, env = process.env) => {
26582
26568
  const fallbackName = getAgentDisplayName(fallback);
26583
26569
  const fallbackDisabled = isAgentDisabled(fallback, pluginConfig);
26584
26570
  if (fallbackDisabled) {
26585
- console.log(import_picocolors12.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled and no enabled core agent was found. Proceeding with "${fallbackName}".`));
26571
+ console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled and no enabled core agent was found. Proceeding with "${fallbackName}".`));
26586
26572
  return fallbackName;
26587
26573
  }
26588
- console.log(import_picocolors12.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled. Falling back to "${fallbackName}".`));
26574
+ console.log(import_picocolors11.default.yellow(`Requested agent "${resolved.resolvedName}" is disabled. Falling back to "${fallbackName}".`));
26589
26575
  return fallbackName;
26590
26576
  }
26591
26577
  return resolved.resolvedName;
26592
26578
  };
26593
26579
 
26580
+ // src/cli/run/model-resolver.ts
26581
+ function resolveRunModel(modelString) {
26582
+ if (modelString === undefined) {
26583
+ return;
26584
+ }
26585
+ const trimmed = modelString.trim();
26586
+ if (trimmed.length === 0) {
26587
+ throw new Error("Model string cannot be empty");
26588
+ }
26589
+ const parts = trimmed.split("/");
26590
+ if (parts.length < 2) {
26591
+ throw new Error("Model string must be in 'provider/model' format");
26592
+ }
26593
+ const providerID = parts[0];
26594
+ if (providerID.length === 0) {
26595
+ throw new Error("Provider cannot be empty");
26596
+ }
26597
+ const modelID = parts.slice(1).join("/");
26598
+ if (modelID.length === 0) {
26599
+ throw new Error("Model ID cannot be empty");
26600
+ }
26601
+ return { providerID, modelID };
26602
+ }
26603
+
26594
26604
  // src/cli/run/poll-for-completion.ts
26595
- var import_picocolors14 = __toESM(require_picocolors(), 1);
26605
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
26596
26606
 
26597
26607
  // src/cli/run/completion.ts
26598
26608
  init_shared();
26599
- var import_picocolors13 = __toESM(require_picocolors(), 1);
26609
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
26600
26610
  // src/features/boulder-state/constants.ts
26601
26611
  var BOULDER_DIR = ".sisyphus";
26602
26612
  var BOULDER_FILE = "boulder.json";
@@ -26604,14 +26614,14 @@ var BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}`;
26604
26614
  var NOTEPAD_DIR = "notepads";
26605
26615
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
26606
26616
  // src/features/boulder-state/storage.ts
26607
- import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, readdirSync } from "fs";
26617
+ import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, readdirSync } from "fs";
26608
26618
  import { dirname as dirname2, join as join9, basename } from "path";
26609
26619
  function getBoulderFilePath(directory) {
26610
26620
  return join9(directory, BOULDER_DIR, BOULDER_FILE);
26611
26621
  }
26612
26622
  function readBoulderState(directory) {
26613
26623
  const filePath = getBoulderFilePath(directory);
26614
- if (!existsSync10(filePath)) {
26624
+ if (!existsSync11(filePath)) {
26615
26625
  return null;
26616
26626
  }
26617
26627
  try {
@@ -26629,7 +26639,7 @@ function readBoulderState(directory) {
26629
26639
  }
26630
26640
  }
26631
26641
  function getPlanProgress(planPath) {
26632
- if (!existsSync10(planPath)) {
26642
+ if (!existsSync11(planPath)) {
26633
26643
  return { total: 0, completed: 0, isComplete: true };
26634
26644
  }
26635
26645
  try {
@@ -26650,14 +26660,14 @@ function getPlanProgress(planPath) {
26650
26660
  // src/features/run-continuation-state/constants.ts
26651
26661
  var CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation";
26652
26662
  // src/features/run-continuation-state/storage.ts
26653
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync6 } from "fs";
26663
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync10, rmSync, writeFileSync as writeFileSync6 } from "fs";
26654
26664
  import { join as join10 } from "path";
26655
26665
  function getMarkerPath(directory, sessionID) {
26656
26666
  return join10(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
26657
26667
  }
26658
26668
  function readContinuationMarker(directory, sessionID) {
26659
26669
  const markerPath = getMarkerPath(directory, sessionID);
26660
- if (!existsSync11(markerPath))
26670
+ if (!existsSync12(markerPath))
26661
26671
  return null;
26662
26672
  try {
26663
26673
  const raw = readFileSync10(markerPath, "utf-8");
@@ -26685,7 +26695,7 @@ function getActiveContinuationMarkerReason(marker) {
26685
26695
  }
26686
26696
  // src/hooks/ralph-loop/storage.ts
26687
26697
  init_frontmatter();
26688
- import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync, mkdirSync as mkdirSync5 } from "fs";
26698
+ import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync, mkdirSync as mkdirSync5 } from "fs";
26689
26699
  import { dirname as dirname3, join as join11 } from "path";
26690
26700
 
26691
26701
  // src/hooks/ralph-loop/constants.ts
@@ -26699,7 +26709,7 @@ function getStateFilePath(directory, customPath) {
26699
26709
  }
26700
26710
  function readState(directory, customPath) {
26701
26711
  const filePath = getStateFilePath(directory, customPath);
26702
- if (!existsSync12(filePath)) {
26712
+ if (!existsSync13(filePath)) {
26703
26713
  return null;
26704
26714
  }
26705
26715
  try {
@@ -26793,7 +26803,7 @@ async function checkCompletionConditions(ctx) {
26793
26803
  }
26794
26804
  return true;
26795
26805
  } catch (err) {
26796
- console.error(import_picocolors13.default.red(`[completion] API error: ${err}`));
26806
+ console.error(import_picocolors12.default.red(`[completion] API error: ${err}`));
26797
26807
  return false;
26798
26808
  }
26799
26809
  }
@@ -26854,7 +26864,7 @@ function logWaiting(ctx, message) {
26854
26864
  if (!ctx.verbose) {
26855
26865
  return;
26856
26866
  }
26857
- console.log(import_picocolors13.default.dim(` Waiting: ${message}`));
26867
+ console.log(import_picocolors12.default.dim(` Waiting: ${message}`));
26858
26868
  }
26859
26869
 
26860
26870
  // src/cli/run/poll-for-completion.ts
@@ -26885,10 +26895,10 @@ async function pollForCompletion(ctx, eventState, abortController, options = {})
26885
26895
  if (eventState.mainSessionError) {
26886
26896
  errorCycleCount++;
26887
26897
  if (errorCycleCount >= ERROR_GRACE_CYCLES) {
26888
- console.error(import_picocolors14.default.red(`
26898
+ console.error(import_picocolors13.default.red(`
26889
26899
 
26890
26900
  Session ended with error: ${eventState.lastError}`));
26891
- console.error(import_picocolors14.default.yellow("Check if todos were completed before the error."));
26901
+ console.error(import_picocolors13.default.yellow("Check if todos were completed before the error."));
26892
26902
  return 1;
26893
26903
  }
26894
26904
  continue;
@@ -26899,7 +26909,7 @@ Session ended with error: ${eventState.lastError}`));
26899
26909
  if (eventState.lastEventTimestamp !== null) {
26900
26910
  const timeSinceLastEvent = Date.now() - eventState.lastEventTimestamp;
26901
26911
  if (timeSinceLastEvent > eventWatchdogMs) {
26902
- console.log(import_picocolors14.default.yellow(`
26912
+ console.log(import_picocolors13.default.yellow(`
26903
26913
  No events for ${Math.round(timeSinceLastEvent / 1000)}s, verifying session status...`));
26904
26914
  mainSessionStatus = await getMainSessionStatus(ctx);
26905
26915
  if (mainSessionStatus === "idle") {
@@ -26948,7 +26958,7 @@ Session ended with error: ${eventState.lastError}`));
26948
26958
  const hasActiveWork = hasActiveChildren || hasActiveTodos;
26949
26959
  if (hasActiveWork) {
26950
26960
  eventState.hasReceivedMeaningfulWork = true;
26951
- console.log(import_picocolors14.default.yellow(`
26961
+ console.log(import_picocolors13.default.yellow(`
26952
26962
  No meaningful work events for ${Math.round(secondaryMeaningfulWorkTimeoutMs / 1000)}s but session has active work - assuming in progress`));
26953
26963
  }
26954
26964
  }
@@ -26968,7 +26978,7 @@ Session ended with error: ${eventState.lastError}`));
26968
26978
  }
26969
26979
  consecutiveCompleteChecks++;
26970
26980
  if (consecutiveCompleteChecks >= requiredConsecutive) {
26971
- console.log(import_picocolors14.default.green(`
26981
+ console.log(import_picocolors13.default.green(`
26972
26982
 
26973
26983
  All tasks completed.`));
26974
26984
  return 0;
@@ -27125,6 +27135,7 @@ async function run(options) {
27125
27135
  const resolvedAgent = resolveRunAgent(options, pluginConfig);
27126
27136
  const abortController = new AbortController;
27127
27137
  try {
27138
+ const resolvedModel = resolveRunModel(options.model);
27128
27139
  const { client: client3, cleanup: serverCleanup } = await createServerConnection({
27129
27140
  port: options.port,
27130
27141
  attach: options.attach,
@@ -27135,7 +27146,7 @@ async function run(options) {
27135
27146
  };
27136
27147
  const restoreInput = suppressRunInput();
27137
27148
  const handleSigint = () => {
27138
- console.log(import_picocolors15.default.yellow(`
27149
+ console.log(import_picocolors14.default.yellow(`
27139
27150
  Interrupted. Shutting down...`));
27140
27151
  restoreInput();
27141
27152
  cleanup();
@@ -27148,7 +27159,10 @@ Interrupted. Shutting down...`));
27148
27159
  sessionId: options.sessionId,
27149
27160
  directory
27150
27161
  });
27151
- console.log(import_picocolors15.default.dim(`Session: ${sessionID}`));
27162
+ console.log(import_picocolors14.default.dim(`Session: ${sessionID}`));
27163
+ if (resolvedModel) {
27164
+ console.log(import_picocolors14.default.dim(`Model: ${resolvedModel.providerID}/${resolvedModel.modelID}`));
27165
+ }
27152
27166
  const ctx = {
27153
27167
  client: client3,
27154
27168
  sessionID,
@@ -27164,6 +27178,7 @@ Interrupted. Shutting down...`));
27164
27178
  path: { id: sessionID },
27165
27179
  body: {
27166
27180
  agent: resolvedAgent,
27181
+ ...resolvedModel ? { model: resolvedModel } : {},
27167
27182
  tools: {
27168
27183
  question: false
27169
27184
  },
@@ -27209,7 +27224,7 @@ Interrupted. Shutting down...`));
27209
27224
  if (err instanceof Error && err.name === "AbortError") {
27210
27225
  return 130;
27211
27226
  }
27212
- console.error(import_picocolors15.default.red(`Error: ${serializeError(err)}`));
27227
+ console.error(import_picocolors14.default.red(`Error: ${serializeError(err)}`));
27213
27228
  return 1;
27214
27229
  } finally {
27215
27230
  timestampOutput?.restore();
@@ -27219,53 +27234,53 @@ Interrupted. Shutting down...`));
27219
27234
  init_checker();
27220
27235
 
27221
27236
  // src/cli/get-local-version/formatter.ts
27222
- var import_picocolors16 = __toESM(require_picocolors(), 1);
27237
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
27223
27238
  var SYMBOLS2 = {
27224
- check: import_picocolors16.default.green("[OK]"),
27225
- cross: import_picocolors16.default.red("[X]"),
27226
- arrow: import_picocolors16.default.cyan("->"),
27227
- info: import_picocolors16.default.blue("[i]"),
27228
- warn: import_picocolors16.default.yellow("[!]"),
27229
- pin: import_picocolors16.default.magenta("[PINNED]"),
27230
- dev: import_picocolors16.default.cyan("[DEV]")
27239
+ check: import_picocolors15.default.green("[OK]"),
27240
+ cross: import_picocolors15.default.red("[X]"),
27241
+ arrow: import_picocolors15.default.cyan("->"),
27242
+ info: import_picocolors15.default.blue("[i]"),
27243
+ warn: import_picocolors15.default.yellow("[!]"),
27244
+ pin: import_picocolors15.default.magenta("[PINNED]"),
27245
+ dev: import_picocolors15.default.cyan("[DEV]")
27231
27246
  };
27232
27247
  function formatVersionOutput(info) {
27233
27248
  const lines = [];
27234
27249
  lines.push("");
27235
- lines.push(import_picocolors16.default.bold(import_picocolors16.default.white("oh-my-opencode Version Information")));
27236
- lines.push(import_picocolors16.default.dim("\u2500".repeat(50)));
27250
+ lines.push(import_picocolors15.default.bold(import_picocolors15.default.white("oh-my-opencode Version Information")));
27251
+ lines.push(import_picocolors15.default.dim("\u2500".repeat(50)));
27237
27252
  lines.push("");
27238
27253
  if (info.currentVersion) {
27239
- lines.push(` Current Version: ${import_picocolors16.default.cyan(info.currentVersion)}`);
27254
+ lines.push(` Current Version: ${import_picocolors15.default.cyan(info.currentVersion)}`);
27240
27255
  } else {
27241
- lines.push(` Current Version: ${import_picocolors16.default.dim("unknown")}`);
27256
+ lines.push(` Current Version: ${import_picocolors15.default.dim("unknown")}`);
27242
27257
  }
27243
27258
  if (!info.isLocalDev && info.latestVersion) {
27244
- lines.push(` Latest Version: ${import_picocolors16.default.cyan(info.latestVersion)}`);
27259
+ lines.push(` Latest Version: ${import_picocolors15.default.cyan(info.latestVersion)}`);
27245
27260
  }
27246
27261
  lines.push("");
27247
27262
  switch (info.status) {
27248
27263
  case "up-to-date":
27249
- lines.push(` ${SYMBOLS2.check} ${import_picocolors16.default.green("You're up to date!")}`);
27264
+ lines.push(` ${SYMBOLS2.check} ${import_picocolors15.default.green("You're up to date!")}`);
27250
27265
  break;
27251
27266
  case "outdated":
27252
- lines.push(` ${SYMBOLS2.warn} ${import_picocolors16.default.yellow("Update available")}`);
27253
- lines.push(` ${import_picocolors16.default.dim("Run:")} ${import_picocolors16.default.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`);
27267
+ lines.push(` ${SYMBOLS2.warn} ${import_picocolors15.default.yellow("Update available")}`);
27268
+ lines.push(` ${import_picocolors15.default.dim("Run:")} ${import_picocolors15.default.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`);
27254
27269
  break;
27255
27270
  case "local-dev":
27256
- lines.push(` ${SYMBOLS2.dev} ${import_picocolors16.default.cyan("Running in local development mode")}`);
27257
- lines.push(` ${import_picocolors16.default.dim("Using file:// protocol from config")}`);
27271
+ lines.push(` ${SYMBOLS2.dev} ${import_picocolors15.default.cyan("Running in local development mode")}`);
27272
+ lines.push(` ${import_picocolors15.default.dim("Using file:// protocol from config")}`);
27258
27273
  break;
27259
27274
  case "pinned":
27260
- lines.push(` ${SYMBOLS2.pin} ${import_picocolors16.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
27261
- lines.push(` ${import_picocolors16.default.dim("Update check skipped for pinned versions")}`);
27275
+ lines.push(` ${SYMBOLS2.pin} ${import_picocolors15.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
27276
+ lines.push(` ${import_picocolors15.default.dim("Update check skipped for pinned versions")}`);
27262
27277
  break;
27263
27278
  case "error":
27264
- lines.push(` ${SYMBOLS2.cross} ${import_picocolors16.default.red("Unable to check for updates")}`);
27265
- lines.push(` ${import_picocolors16.default.dim("Network error or npm registry unavailable")}`);
27279
+ lines.push(` ${SYMBOLS2.cross} ${import_picocolors15.default.red("Unable to check for updates")}`);
27280
+ lines.push(` ${import_picocolors15.default.dim("Network error or npm registry unavailable")}`);
27266
27281
  break;
27267
27282
  case "unknown":
27268
- lines.push(` ${SYMBOLS2.info} ${import_picocolors16.default.yellow("Version information unavailable")}`);
27283
+ lines.push(` ${SYMBOLS2.info} ${import_picocolors15.default.yellow("Version information unavailable")}`);
27269
27284
  break;
27270
27285
  }
27271
27286
  lines.push("");
@@ -27365,21 +27380,21 @@ async function getLocalVersion(options = {}) {
27365
27380
  }
27366
27381
  }
27367
27382
  // src/cli/doctor/constants.ts
27368
- var import_picocolors17 = __toESM(require_picocolors(), 1);
27383
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
27369
27384
  var SYMBOLS3 = {
27370
- check: import_picocolors17.default.green("\u2713"),
27371
- cross: import_picocolors17.default.red("\u2717"),
27372
- warn: import_picocolors17.default.yellow("\u26A0"),
27373
- info: import_picocolors17.default.blue("\u2139"),
27374
- arrow: import_picocolors17.default.cyan("\u2192"),
27375
- bullet: import_picocolors17.default.dim("\u2022"),
27376
- skip: import_picocolors17.default.dim("\u25CB")
27385
+ check: import_picocolors16.default.green("\u2713"),
27386
+ cross: import_picocolors16.default.red("\u2717"),
27387
+ warn: import_picocolors16.default.yellow("\u26A0"),
27388
+ info: import_picocolors16.default.blue("\u2139"),
27389
+ arrow: import_picocolors16.default.cyan("\u2192"),
27390
+ bullet: import_picocolors16.default.dim("\u2022"),
27391
+ skip: import_picocolors16.default.dim("\u25CB")
27377
27392
  };
27378
27393
  var STATUS_COLORS = {
27379
- pass: import_picocolors17.default.green,
27380
- fail: import_picocolors17.default.red,
27381
- warn: import_picocolors17.default.yellow,
27382
- skip: import_picocolors17.default.dim
27394
+ pass: import_picocolors16.default.green,
27395
+ fail: import_picocolors16.default.red,
27396
+ warn: import_picocolors16.default.yellow,
27397
+ skip: import_picocolors16.default.dim
27383
27398
  };
27384
27399
  var CHECK_IDS = {
27385
27400
  SYSTEM: "system",
@@ -27398,34 +27413,34 @@ var EXIT_CODES = {
27398
27413
  FAILURE: 1
27399
27414
  };
27400
27415
  var MIN_OPENCODE_VERSION = "1.0.150";
27401
- var PACKAGE_NAME4 = "oh-my-opencode";
27416
+ var PACKAGE_NAME2 = "oh-my-opencode";
27402
27417
  var OPENCODE_BINARIES2 = ["opencode", "opencode-desktop"];
27403
27418
 
27404
27419
  // src/cli/doctor/checks/system.ts
27405
- import { existsSync as existsSync21, readFileSync as readFileSync21 } from "fs";
27420
+ import { existsSync as existsSync24, readFileSync as readFileSync21 } from "fs";
27406
27421
 
27407
27422
  // src/cli/doctor/checks/system-binary.ts
27408
27423
  init_spawn_with_windows_hide();
27409
- import { existsSync as existsSync18 } from "fs";
27424
+ import { existsSync as existsSync21 } from "fs";
27410
27425
  import { homedir as homedir5 } from "os";
27411
- import { join as join16 } from "path";
27426
+ import { join as join18 } from "path";
27412
27427
  function getDesktopAppPaths(platform) {
27413
27428
  const home = homedir5();
27414
27429
  switch (platform) {
27415
27430
  case "darwin":
27416
27431
  return [
27417
27432
  "/Applications/OpenCode.app/Contents/MacOS/OpenCode",
27418
- join16(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
27433
+ join18(home, "Applications", "OpenCode.app", "Contents", "MacOS", "OpenCode")
27419
27434
  ];
27420
27435
  case "win32": {
27421
27436
  const programFiles = process.env.ProgramFiles;
27422
27437
  const localAppData = process.env.LOCALAPPDATA;
27423
27438
  const paths = [];
27424
27439
  if (programFiles) {
27425
- paths.push(join16(programFiles, "OpenCode", "OpenCode.exe"));
27440
+ paths.push(join18(programFiles, "OpenCode", "OpenCode.exe"));
27426
27441
  }
27427
27442
  if (localAppData) {
27428
- paths.push(join16(localAppData, "OpenCode", "OpenCode.exe"));
27443
+ paths.push(join18(localAppData, "OpenCode", "OpenCode.exe"));
27429
27444
  }
27430
27445
  return paths;
27431
27446
  }
@@ -27433,8 +27448,8 @@ function getDesktopAppPaths(platform) {
27433
27448
  return [
27434
27449
  "/usr/bin/opencode",
27435
27450
  "/usr/lib/opencode/opencode",
27436
- join16(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
27437
- join16(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
27451
+ join18(home, "Applications", "opencode-desktop-linux-x86_64.AppImage"),
27452
+ join18(home, "Applications", "opencode-desktop-linux-aarch64.AppImage")
27438
27453
  ];
27439
27454
  default:
27440
27455
  return [];
@@ -27446,7 +27461,7 @@ function buildVersionCommand(binaryPath, platform) {
27446
27461
  }
27447
27462
  return [binaryPath, "--version"];
27448
27463
  }
27449
- function findDesktopBinary(platform = process.platform, checkExists = existsSync18) {
27464
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync21) {
27450
27465
  for (const desktopPath of getDesktopAppPaths(platform)) {
27451
27466
  if (checkExists(desktopPath)) {
27452
27467
  return { binary: "opencode", path: desktopPath };
@@ -27456,9 +27471,9 @@ function findDesktopBinary(platform = process.platform, checkExists = existsSync
27456
27471
  }
27457
27472
  async function findOpenCodeBinary() {
27458
27473
  for (const binary2 of OPENCODE_BINARIES2) {
27459
- const path9 = Bun.which(binary2);
27460
- if (path9) {
27461
- return { binary: binary2, path: path9 };
27474
+ const path10 = Bun.which(binary2);
27475
+ if (path10) {
27476
+ return { binary: binary2, path: path10 };
27462
27477
  }
27463
27478
  }
27464
27479
  return findDesktopBinary();
@@ -27493,30 +27508,40 @@ function compareVersions(current, minimum) {
27493
27508
  }
27494
27509
 
27495
27510
  // src/cli/doctor/checks/system-plugin.ts
27496
- import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
27497
27511
  init_shared();
27512
+ import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
27498
27513
  function detectConfigPath() {
27499
27514
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
27500
- if (existsSync19(paths.configJsonc))
27515
+ if (existsSync22(paths.configJsonc))
27501
27516
  return paths.configJsonc;
27502
- if (existsSync19(paths.configJson))
27517
+ if (existsSync22(paths.configJson))
27503
27518
  return paths.configJson;
27504
27519
  return null;
27505
27520
  }
27506
27521
  function parsePluginVersion(entry) {
27507
- if (!entry.startsWith(`${PACKAGE_NAME4}@`))
27508
- return null;
27509
- const value = entry.slice(PACKAGE_NAME4.length + 1);
27510
- if (!value || value === "latest")
27511
- return null;
27512
- return value;
27522
+ if (entry.startsWith(`${PLUGIN_NAME}@`)) {
27523
+ const value = entry.slice(PLUGIN_NAME.length + 1);
27524
+ if (!value || value === "latest")
27525
+ return null;
27526
+ return value;
27527
+ }
27528
+ if (entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) {
27529
+ const value = entry.slice(LEGACY_PLUGIN_NAME.length + 1);
27530
+ if (!value || value === "latest")
27531
+ return null;
27532
+ return value;
27533
+ }
27534
+ return null;
27513
27535
  }
27514
27536
  function findPluginEntry2(entries) {
27515
27537
  for (const entry of entries) {
27516
- if (entry === PACKAGE_NAME4 || entry.startsWith(`${PACKAGE_NAME4}@`)) {
27538
+ if (entry === PLUGIN_NAME || entry.startsWith(`${PLUGIN_NAME}@`)) {
27539
+ return { entry, isLocalDev: false };
27540
+ }
27541
+ if (entry === LEGACY_PLUGIN_NAME || entry.startsWith(`${LEGACY_PLUGIN_NAME}@`)) {
27517
27542
  return { entry, isLocalDev: false };
27518
27543
  }
27519
- if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME4)) {
27544
+ if (entry.startsWith("file://") && (entry.includes(PLUGIN_NAME) || entry.includes(LEGACY_PLUGIN_NAME))) {
27520
27545
  return { entry, isLocalDev: true };
27521
27546
  }
27522
27547
  }
@@ -27553,7 +27578,7 @@ function getPluginInfo() {
27553
27578
  registered: true,
27554
27579
  configPath,
27555
27580
  entry: pluginEntry.entry,
27556
- isPinned: pinnedVersion !== null && /^\d+\.\d+\.\d+/.test(pinnedVersion),
27581
+ isPinned: pinnedVersion !== null && /^\d+\.\d+\.\d+/.test(pinnedVersion ?? ""),
27557
27582
  pinnedVersion,
27558
27583
  isLocalDev: pluginEntry.isLocalDev
27559
27584
  };
@@ -27572,29 +27597,29 @@ function getPluginInfo() {
27572
27597
  // src/cli/doctor/checks/system-loaded-version.ts
27573
27598
  init_checker();
27574
27599
  init_auto_update_checker();
27575
- import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
27600
+ import { existsSync as existsSync23, readFileSync as readFileSync20 } from "fs";
27576
27601
  import { homedir as homedir6 } from "os";
27577
- import { join as join17 } from "path";
27602
+ import { join as join19 } from "path";
27578
27603
  init_shared();
27579
27604
  function getPlatformDefaultCacheDir(platform = process.platform) {
27580
27605
  if (platform === "darwin")
27581
- return join17(homedir6(), "Library", "Caches");
27606
+ return join19(homedir6(), "Library", "Caches");
27582
27607
  if (platform === "win32")
27583
- return process.env.LOCALAPPDATA ?? join17(homedir6(), "AppData", "Local");
27584
- return join17(homedir6(), ".cache");
27608
+ return process.env.LOCALAPPDATA ?? join19(homedir6(), "AppData", "Local");
27609
+ return join19(homedir6(), ".cache");
27585
27610
  }
27586
27611
  function resolveOpenCodeCacheDir() {
27587
27612
  const xdgCacheHome = process.env.XDG_CACHE_HOME;
27588
27613
  if (xdgCacheHome)
27589
- return join17(xdgCacheHome, "opencode");
27614
+ return join19(xdgCacheHome, "opencode");
27590
27615
  const fromShared = getOpenCodeCacheDir();
27591
- const platformDefault = join17(getPlatformDefaultCacheDir(), "opencode");
27592
- if (existsSync20(fromShared) || !existsSync20(platformDefault))
27616
+ const platformDefault = join19(getPlatformDefaultCacheDir(), "opencode");
27617
+ if (existsSync23(fromShared) || !existsSync23(platformDefault))
27593
27618
  return fromShared;
27594
27619
  return platformDefault;
27595
27620
  }
27596
27621
  function readPackageJson(filePath) {
27597
- if (!existsSync20(filePath))
27622
+ if (!existsSync23(filePath))
27598
27623
  return null;
27599
27624
  try {
27600
27625
  const content = readFileSync20(filePath, "utf-8");
@@ -27610,15 +27635,28 @@ function normalizeVersion(value) {
27610
27635
  return match?.[0] ?? null;
27611
27636
  }
27612
27637
  function getLoadedPluginVersion() {
27638
+ const configPaths = getOpenCodeConfigPaths({ binary: "opencode" });
27613
27639
  const cacheDir = resolveOpenCodeCacheDir();
27614
- const cachePackagePath = join17(cacheDir, "package.json");
27615
- const installedPackagePath = join17(cacheDir, "node_modules", PACKAGE_NAME4, "package.json");
27640
+ const candidates = [
27641
+ {
27642
+ cacheDir: configPaths.configDir,
27643
+ cachePackagePath: configPaths.packageJson,
27644
+ installedPackagePath: join19(configPaths.configDir, "node_modules", PACKAGE_NAME2, "package.json")
27645
+ },
27646
+ {
27647
+ cacheDir,
27648
+ cachePackagePath: join19(cacheDir, "package.json"),
27649
+ installedPackagePath: join19(cacheDir, "node_modules", PACKAGE_NAME2, "package.json")
27650
+ }
27651
+ ];
27652
+ const selectedCandidate = candidates.find((candidate) => existsSync23(candidate.installedPackagePath)) ?? candidates[0];
27653
+ const { cacheDir: selectedDir, cachePackagePath, installedPackagePath } = selectedCandidate;
27616
27654
  const cachePackage = readPackageJson(cachePackagePath);
27617
27655
  const installedPackage = readPackageJson(installedPackagePath);
27618
- const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME4]);
27656
+ const expectedVersion = normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME2]);
27619
27657
  const loadedVersion = normalizeVersion(installedPackage?.version);
27620
27658
  return {
27621
- cacheDir,
27659
+ cacheDir: selectedDir,
27622
27660
  cachePackagePath,
27623
27661
  installedPackagePath,
27624
27662
  expectedVersion,
@@ -27638,7 +27676,7 @@ init_shared();
27638
27676
  function isConfigValid(configPath) {
27639
27677
  if (!configPath)
27640
27678
  return true;
27641
- if (!existsSync21(configPath))
27679
+ if (!existsSync24(configPath))
27642
27680
  return false;
27643
27681
  try {
27644
27682
  parseJsonc(readFileSync21(configPath, "utf-8"));
@@ -27665,7 +27703,7 @@ async function gatherSystemInfo() {
27665
27703
  const [binaryInfo, pluginInfo] = await Promise.all([findOpenCodeBinary(), Promise.resolve(getPluginInfo())]);
27666
27704
  const loadedInfo = getLoadedPluginVersion();
27667
27705
  const opencodeVersion = binaryInfo ? await getOpenCodeVersion2(binaryInfo.path) : null;
27668
- const pluginVersion = pluginInfo.pinnedVersion ?? loadedInfo.expectedVersion;
27706
+ const pluginVersion = pluginInfo.pinnedVersion ?? loadedInfo.expectedVersion ?? loadedInfo.loadedVersion;
27669
27707
  return {
27670
27708
  opencodeVersion,
27671
27709
  opencodePath: binaryInfo?.path ?? null,
@@ -27745,23 +27783,23 @@ async function checkSystem() {
27745
27783
 
27746
27784
  // src/cli/doctor/checks/config.ts
27747
27785
  import { readFileSync as readFileSync24 } from "fs";
27748
- import { join as join21 } from "path";
27786
+ import { join as join23 } from "path";
27749
27787
  init_shared();
27750
27788
 
27751
27789
  // src/cli/doctor/checks/model-resolution-cache.ts
27752
27790
  init_shared();
27753
- import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
27791
+ import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
27754
27792
  import { homedir as homedir7 } from "os";
27755
- import { join as join18 } from "path";
27793
+ import { join as join20 } from "path";
27756
27794
  function getOpenCodeCacheDir2() {
27757
27795
  const xdgCache = process.env.XDG_CACHE_HOME;
27758
27796
  if (xdgCache)
27759
- return join18(xdgCache, "opencode");
27760
- return join18(homedir7(), ".cache", "opencode");
27797
+ return join20(xdgCache, "opencode");
27798
+ return join20(homedir7(), ".cache", "opencode");
27761
27799
  }
27762
27800
  function loadAvailableModelsFromCache() {
27763
- const cacheFile = join18(getOpenCodeCacheDir2(), "models.json");
27764
- if (!existsSync22(cacheFile)) {
27801
+ const cacheFile = join20(getOpenCodeCacheDir2(), "models.json");
27802
+ if (!existsSync25(cacheFile)) {
27765
27803
  return { providers: [], modelCount: 0, cacheExists: false };
27766
27804
  }
27767
27805
  try {
@@ -27787,10 +27825,10 @@ init_model_requirements();
27787
27825
  // src/cli/doctor/checks/model-resolution-config.ts
27788
27826
  init_shared();
27789
27827
  import { readFileSync as readFileSync23 } from "fs";
27790
- import { join as join19 } from "path";
27791
- var PACKAGE_NAME5 = "oh-my-opencode";
27792
- var USER_CONFIG_BASE = join19(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, PACKAGE_NAME5);
27793
- var PROJECT_CONFIG_BASE = join19(process.cwd(), ".opencode", PACKAGE_NAME5);
27828
+ import { join as join21 } from "path";
27829
+ var PACKAGE_NAME3 = "oh-my-opencode";
27830
+ var USER_CONFIG_BASE = join21(getOpenCodeConfigPaths({ binary: "opencode", version: null }).configDir, PACKAGE_NAME3);
27831
+ var PROJECT_CONFIG_BASE = join21(process.cwd(), ".opencode", PACKAGE_NAME3);
27794
27832
  function loadOmoConfig() {
27795
27833
  const projectDetected = detectConfigFile(PROJECT_CONFIG_BASE);
27796
27834
  if (projectDetected.format !== "none") {
@@ -27815,7 +27853,7 @@ function loadOmoConfig() {
27815
27853
 
27816
27854
  // src/cli/doctor/checks/model-resolution-details.ts
27817
27855
  init_shared();
27818
- import { join as join20 } from "path";
27856
+ import { join as join22 } from "path";
27819
27857
 
27820
27858
  // src/cli/doctor/checks/model-resolution-variant.ts
27821
27859
  function formatModelWithVariant(model, variant) {
@@ -27854,7 +27892,7 @@ function getCategoryEffectiveVariant(categoryName, requirement, config2) {
27854
27892
  // src/cli/doctor/checks/model-resolution-details.ts
27855
27893
  function buildModelResolutionDetails(options) {
27856
27894
  const details = [];
27857
- const cacheFile = join20(getOpenCodeCacheDir(), "models.json");
27895
+ const cacheFile = join22(getOpenCodeCacheDir(), "models.json");
27858
27896
  details.push("\u2550\u2550\u2550 Available Models (from cache) \u2550\u2550\u2550");
27859
27897
  details.push("");
27860
27898
  if (options.available.cacheExists) {
@@ -27966,8 +28004,8 @@ async function checkModels() {
27966
28004
  }
27967
28005
 
27968
28006
  // src/cli/doctor/checks/config.ts
27969
- var USER_CONFIG_BASE2 = join21(getOpenCodeConfigDir({ binary: "opencode" }), PACKAGE_NAME4);
27970
- var PROJECT_CONFIG_BASE2 = join21(process.cwd(), ".opencode", PACKAGE_NAME4);
28007
+ var USER_CONFIG_BASE2 = join23(getOpenCodeConfigDir({ binary: "opencode" }), PACKAGE_NAME2);
28008
+ var PROJECT_CONFIG_BASE2 = join23(process.cwd(), ".opencode", PACKAGE_NAME2);
27971
28009
  function findConfigPath() {
27972
28010
  const projectConfig = detectConfigFile(PROJECT_CONFIG_BASE2);
27973
28011
  if (projectConfig.format !== "none")
@@ -28087,14 +28125,14 @@ async function checkConfig() {
28087
28125
 
28088
28126
  // src/cli/doctor/checks/dependencies.ts
28089
28127
  init_spawn_with_windows_hide();
28090
- import { existsSync as existsSync23 } from "fs";
28128
+ import { existsSync as existsSync26 } from "fs";
28091
28129
  import { createRequire } from "module";
28092
- import { dirname as dirname6, join as join22 } from "path";
28130
+ import { dirname as dirname6, join as join24 } from "path";
28093
28131
  async function checkBinaryExists(binary2) {
28094
28132
  try {
28095
- const path9 = Bun.which(binary2);
28096
- if (path9) {
28097
- return { exists: true, path: path9 };
28133
+ const path10 = Bun.which(binary2);
28134
+ if (path10) {
28135
+ return { exists: true, path: path10 };
28098
28136
  }
28099
28137
  } catch {}
28100
28138
  return { exists: false, path: null };
@@ -28145,15 +28183,15 @@ async function checkAstGrepNapi() {
28145
28183
  path: null
28146
28184
  };
28147
28185
  } catch {
28148
- const { existsSync: existsSync24 } = await import("fs");
28149
- const { join: join23 } = await import("path");
28186
+ const { existsSync: existsSync27 } = await import("fs");
28187
+ const { join: join25 } = await import("path");
28150
28188
  const { homedir: homedir8 } = await import("os");
28151
28189
  const pathsToCheck = [
28152
- join23(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
28153
- join23(process.cwd(), "node_modules", "@ast-grep", "napi")
28190
+ join25(homedir8(), ".config", "opencode", "node_modules", "@ast-grep", "napi"),
28191
+ join25(process.cwd(), "node_modules", "@ast-grep", "napi")
28154
28192
  ];
28155
28193
  for (const napiPath of pathsToCheck) {
28156
- if (existsSync24(napiPath)) {
28194
+ if (existsSync27(napiPath)) {
28157
28195
  return {
28158
28196
  name: "AST-Grep NAPI",
28159
28197
  required: false,
@@ -28178,8 +28216,8 @@ function findCommentCheckerPackageBinary() {
28178
28216
  try {
28179
28217
  const require2 = createRequire(import.meta.url);
28180
28218
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
28181
- const binaryPath = join22(dirname6(pkgPath), "bin", binaryName);
28182
- if (existsSync23(binaryPath))
28219
+ const binaryPath = join24(dirname6(pkgPath), "bin", binaryName);
28220
+ if (existsSync26(binaryPath))
28183
28221
  return binaryPath;
28184
28222
  } catch {}
28185
28223
  return null;
@@ -28292,20 +28330,163 @@ async function getGhCliInfo() {
28292
28330
  error: authStatus.error
28293
28331
  };
28294
28332
  }
28333
+ // src/tools/lsp/server-definitions.ts
28334
+ var BUILTIN_SERVERS = {
28335
+ typescript: { command: ["typescript-language-server", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"] },
28336
+ deno: { command: ["deno", "lsp"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"] },
28337
+ vue: { command: ["vue-language-server", "--stdio"], extensions: [".vue"] },
28338
+ eslint: { command: ["vscode-eslint-language-server", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"] },
28339
+ oxlint: { command: ["oxlint", "--lsp"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".astro", ".svelte"] },
28340
+ biome: { command: ["biome", "lsp-proxy", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".vue", ".astro", ".svelte", ".css", ".graphql", ".gql", ".html"] },
28341
+ gopls: { command: ["gopls"], extensions: [".go"] },
28342
+ "ruby-lsp": { command: ["rubocop", "--lsp"], extensions: [".rb", ".rake", ".gemspec", ".ru"] },
28343
+ basedpyright: { command: ["basedpyright-langserver", "--stdio"], extensions: [".py", ".pyi"] },
28344
+ pyright: { command: ["pyright-langserver", "--stdio"], extensions: [".py", ".pyi"] },
28345
+ ty: { command: ["ty", "server"], extensions: [".py", ".pyi"] },
28346
+ ruff: { command: ["ruff", "server"], extensions: [".py", ".pyi"] },
28347
+ "elixir-ls": { command: ["elixir-ls"], extensions: [".ex", ".exs"] },
28348
+ zls: { command: ["zls"], extensions: [".zig", ".zon"] },
28349
+ csharp: { command: ["csharp-ls"], extensions: [".cs"] },
28350
+ fsharp: { command: ["fsautocomplete"], extensions: [".fs", ".fsi", ".fsx", ".fsscript"] },
28351
+ "sourcekit-lsp": { command: ["sourcekit-lsp"], extensions: [".swift", ".objc", ".objcpp"] },
28352
+ rust: { command: ["rust-analyzer"], extensions: [".rs"] },
28353
+ clangd: { command: ["clangd", "--background-index", "--clang-tidy"], extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"] },
28354
+ svelte: { command: ["svelteserver", "--stdio"], extensions: [".svelte"] },
28355
+ astro: { command: ["astro-ls", "--stdio"], extensions: [".astro"] },
28356
+ bash: { command: ["bash-language-server", "start"], extensions: [".sh", ".bash", ".zsh", ".ksh"] },
28357
+ "bash-ls": { command: ["bash-language-server", "start"], extensions: [".sh", ".bash", ".zsh", ".ksh"] },
28358
+ jdtls: { command: ["jdtls"], extensions: [".java"] },
28359
+ "yaml-ls": { command: ["yaml-language-server", "--stdio"], extensions: [".yaml", ".yml"] },
28360
+ "lua-ls": { command: ["lua-language-server"], extensions: [".lua"] },
28361
+ php: { command: ["intelephense", "--stdio"], extensions: [".php"] },
28362
+ dart: { command: ["dart", "language-server", "--lsp"], extensions: [".dart"] },
28363
+ terraform: { command: ["terraform-ls", "serve"], extensions: [".tf", ".tfvars"] },
28364
+ "terraform-ls": { command: ["terraform-ls", "serve"], extensions: [".tf", ".tfvars"] },
28365
+ prisma: { command: ["prisma", "language-server"], extensions: [".prisma"] },
28366
+ "ocaml-lsp": { command: ["ocamllsp"], extensions: [".ml", ".mli"] },
28367
+ texlab: { command: ["texlab"], extensions: [".tex", ".bib"] },
28368
+ dockerfile: { command: ["docker-langserver", "--stdio"], extensions: [".dockerfile"] },
28369
+ gleam: { command: ["gleam", "lsp"], extensions: [".gleam"] },
28370
+ "clojure-lsp": { command: ["clojure-lsp", "listen"], extensions: [".clj", ".cljs", ".cljc", ".edn"] },
28371
+ nixd: { command: ["nixd"], extensions: [".nix"] },
28372
+ tinymist: { command: ["tinymist"], extensions: [".typ", ".typc"] },
28373
+ "haskell-language-server": { command: ["haskell-language-server-wrapper", "--lsp"], extensions: [".hs", ".lhs"] },
28374
+ "kotlin-ls": { command: ["kotlin-lsp"], extensions: [".kt", ".kts"] }
28375
+ };
28295
28376
  // src/tools/lsp/server-config-loader.ts
28377
+ import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
28378
+ import { join as join25 } from "path";
28296
28379
  init_shared();
28297
28380
  init_jsonc_parser();
28381
+ function loadJsonFile(path10) {
28382
+ if (!existsSync27(path10))
28383
+ return null;
28384
+ try {
28385
+ return parseJsonc(readFileSync25(path10, "utf-8"));
28386
+ } catch {
28387
+ return null;
28388
+ }
28389
+ }
28390
+ function getConfigPaths2() {
28391
+ const cwd = process.cwd();
28392
+ const configDir = getOpenCodeConfigDir({ binary: "opencode" });
28393
+ return {
28394
+ project: detectConfigFile(join25(cwd, ".opencode", "oh-my-opencode")).path,
28395
+ user: detectConfigFile(join25(configDir, "oh-my-opencode")).path,
28396
+ opencode: detectConfigFile(join25(configDir, "opencode")).path
28397
+ };
28398
+ }
28399
+ function loadAllConfigs() {
28400
+ const paths = getConfigPaths2();
28401
+ const configs = new Map;
28402
+ const project = loadJsonFile(paths.project);
28403
+ if (project)
28404
+ configs.set("project", project);
28405
+ const user = loadJsonFile(paths.user);
28406
+ if (user)
28407
+ configs.set("user", user);
28408
+ const opencode = loadJsonFile(paths.opencode);
28409
+ if (opencode)
28410
+ configs.set("opencode", opencode);
28411
+ return configs;
28412
+ }
28413
+ function getMergedServers() {
28414
+ const configs = loadAllConfigs();
28415
+ const servers = [];
28416
+ const disabled = new Set;
28417
+ const seen = new Set;
28418
+ const sources = ["project", "user", "opencode"];
28419
+ for (const source of sources) {
28420
+ const config2 = configs.get(source);
28421
+ if (!config2?.lsp)
28422
+ continue;
28423
+ for (const [id, entry] of Object.entries(config2.lsp)) {
28424
+ if (entry.disabled) {
28425
+ disabled.add(id);
28426
+ continue;
28427
+ }
28428
+ if (seen.has(id))
28429
+ continue;
28430
+ if (!entry.command || !entry.extensions)
28431
+ continue;
28432
+ servers.push({
28433
+ id,
28434
+ command: entry.command,
28435
+ extensions: entry.extensions,
28436
+ priority: entry.priority ?? 0,
28437
+ env: entry.env,
28438
+ initialization: entry.initialization,
28439
+ source
28440
+ });
28441
+ seen.add(id);
28442
+ }
28443
+ }
28444
+ for (const [id, config2] of Object.entries(BUILTIN_SERVERS)) {
28445
+ if (disabled.has(id) || seen.has(id))
28446
+ continue;
28447
+ servers.push({
28448
+ id,
28449
+ command: config2.command,
28450
+ extensions: config2.extensions,
28451
+ priority: -100,
28452
+ source: "opencode"
28453
+ });
28454
+ }
28455
+ return servers.sort((a, b3) => {
28456
+ if (a.source !== b3.source) {
28457
+ const order = { project: 0, user: 1, opencode: 2 };
28458
+ return order[a.source] - order[b3.source];
28459
+ }
28460
+ return b3.priority - a.priority;
28461
+ });
28462
+ }
28298
28463
 
28299
28464
  // src/tools/lsp/server-installation.ts
28465
+ import { existsSync as existsSync28 } from "fs";
28466
+ import { delimiter as delimiter2, join as join27 } from "path";
28467
+
28468
+ // src/tools/lsp/server-path-bases.ts
28300
28469
  init_shared();
28301
- import { existsSync as existsSync24 } from "fs";
28302
- import { join as join23 } from "path";
28470
+ import { join as join26 } from "path";
28471
+ function getLspServerAdditionalPathBases(workingDirectory) {
28472
+ const configDir = getOpenCodeConfigDir({ binary: "opencode" });
28473
+ const dataDir = join26(getDataDir(), "opencode");
28474
+ return [
28475
+ join26(workingDirectory, "node_modules", ".bin"),
28476
+ join26(configDir, "bin"),
28477
+ join26(configDir, "node_modules", ".bin"),
28478
+ join26(dataDir, "bin"),
28479
+ join26(dataDir, "bin", "node_modules", ".bin")
28480
+ ];
28481
+ }
28482
+
28483
+ // src/tools/lsp/server-installation.ts
28303
28484
  function isServerInstalled(command) {
28304
28485
  if (command.length === 0)
28305
28486
  return false;
28306
28487
  const cmd = command[0];
28307
28488
  if (cmd.includes("/") || cmd.includes("\\")) {
28308
- if (existsSync24(cmd))
28489
+ if (existsSync28(cmd))
28309
28490
  return true;
28310
28491
  }
28311
28492
  const isWindows = process.platform === "win32";
@@ -28323,27 +28504,17 @@ function isServerInstalled(command) {
28323
28504
  if (isWindows && !pathEnv) {
28324
28505
  pathEnv = process.env.Path || "";
28325
28506
  }
28326
- const pathSeparator = isWindows ? ";" : ":";
28327
- const paths = pathEnv.split(pathSeparator);
28507
+ const paths = pathEnv.split(delimiter2);
28328
28508
  for (const p2 of paths) {
28329
28509
  for (const suffix of exts) {
28330
- if (existsSync24(join23(p2, cmd + suffix))) {
28510
+ if (existsSync28(join27(p2, cmd + suffix))) {
28331
28511
  return true;
28332
28512
  }
28333
28513
  }
28334
28514
  }
28335
- const cwd = process.cwd();
28336
- const configDir = getOpenCodeConfigDir({ binary: "opencode" });
28337
- const dataDir = join23(getDataDir(), "opencode");
28338
- const additionalBases = [
28339
- join23(cwd, "node_modules", ".bin"),
28340
- join23(configDir, "bin"),
28341
- join23(configDir, "node_modules", ".bin"),
28342
- join23(dataDir, "bin")
28343
- ];
28344
- for (const base of additionalBases) {
28515
+ for (const base of getLspServerAdditionalPathBases(process.cwd())) {
28345
28516
  for (const suffix of exts) {
28346
- if (existsSync24(join23(base, cmd + suffix))) {
28517
+ if (existsSync28(join27(base, cmd + suffix))) {
28347
28518
  return true;
28348
28519
  }
28349
28520
  }
@@ -28353,48 +28524,76 @@ function isServerInstalled(command) {
28353
28524
  }
28354
28525
  return false;
28355
28526
  }
28356
- // src/cli/doctor/checks/tools-lsp.ts
28357
- var DEFAULT_LSP_SERVERS = [
28358
- { id: "typescript-language-server", binary: "typescript-language-server", extensions: [".ts", ".tsx", ".js", ".jsx"] },
28359
- { id: "pyright", binary: "pyright-langserver", extensions: [".py"] },
28360
- { id: "rust-analyzer", binary: "rust-analyzer", extensions: [".rs"] },
28361
- { id: "gopls", binary: "gopls", extensions: [".go"] }
28362
- ];
28363
- function getLspServersInfo() {
28364
- return DEFAULT_LSP_SERVERS.map((server2) => ({
28365
- id: server2.id,
28366
- installed: isServerInstalled([server2.binary]),
28367
- extensions: server2.extensions,
28368
- source: "builtin"
28369
- }));
28527
+
28528
+ // src/tools/lsp/server-resolution.ts
28529
+ function getAllServers() {
28530
+ const configs = loadAllConfigs();
28531
+ const servers = getMergedServers();
28532
+ const disabled = new Set;
28533
+ for (const config2 of configs.values()) {
28534
+ if (!config2.lsp)
28535
+ continue;
28536
+ for (const [id, entry] of Object.entries(config2.lsp)) {
28537
+ if (entry.disabled)
28538
+ disabled.add(id);
28539
+ }
28540
+ }
28541
+ const result = [];
28542
+ const seen = new Set;
28543
+ for (const server2 of servers) {
28544
+ if (seen.has(server2.id))
28545
+ continue;
28546
+ result.push({
28547
+ id: server2.id,
28548
+ installed: isServerInstalled(server2.command),
28549
+ extensions: server2.extensions,
28550
+ disabled: false,
28551
+ source: server2.source,
28552
+ priority: server2.priority
28553
+ });
28554
+ seen.add(server2.id);
28555
+ }
28556
+ for (const id of disabled) {
28557
+ if (seen.has(id))
28558
+ continue;
28559
+ const builtin = BUILTIN_SERVERS[id];
28560
+ result.push({
28561
+ id,
28562
+ installed: builtin ? isServerInstalled(builtin.command) : false,
28563
+ extensions: builtin?.extensions || [],
28564
+ disabled: true,
28565
+ source: "disabled",
28566
+ priority: 0
28567
+ });
28568
+ }
28569
+ return result;
28370
28570
  }
28371
- function getLspServerStats(servers) {
28372
- return {
28373
- installed: servers.filter((server2) => server2.installed).length,
28374
- total: servers.length
28375
- };
28571
+ // src/cli/doctor/checks/tools-lsp.ts
28572
+ function getInstalledLspServers() {
28573
+ const servers = getAllServers();
28574
+ return servers.filter((s) => s.installed && !s.disabled).map((s) => ({ id: s.id, extensions: s.extensions }));
28376
28575
  }
28377
28576
 
28378
28577
  // src/cli/doctor/checks/tools-mcp.ts
28379
28578
  init_shared();
28380
- import { existsSync as existsSync25, readFileSync as readFileSync25 } from "fs";
28579
+ import { existsSync as existsSync29, readFileSync as readFileSync26 } from "fs";
28381
28580
  import { homedir as homedir8 } from "os";
28382
- import { join as join24 } from "path";
28581
+ import { join as join28 } from "path";
28383
28582
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
28384
28583
  function getMcpConfigPaths() {
28385
28584
  return [
28386
- join24(homedir8(), ".claude", ".mcp.json"),
28387
- join24(process.cwd(), ".mcp.json"),
28388
- join24(process.cwd(), ".claude", ".mcp.json")
28585
+ join28(homedir8(), ".claude", ".mcp.json"),
28586
+ join28(process.cwd(), ".mcp.json"),
28587
+ join28(process.cwd(), ".claude", ".mcp.json")
28389
28588
  ];
28390
28589
  }
28391
28590
  function loadUserMcpConfig() {
28392
28591
  const servers = {};
28393
28592
  for (const configPath of getMcpConfigPaths()) {
28394
- if (!existsSync25(configPath))
28593
+ if (!existsSync29(configPath))
28395
28594
  continue;
28396
28595
  try {
28397
- const content = readFileSync25(configPath, "utf-8");
28596
+ const content = readFileSync26(configPath, "utf-8");
28398
28597
  const config2 = parseJsonc(content);
28399
28598
  if (config2.mcpServers) {
28400
28599
  Object.assign(servers, config2.mcpServers);
@@ -28434,13 +28633,11 @@ async function gatherToolsSummary() {
28434
28633
  checkCommentChecker(),
28435
28634
  getGhCliInfo()
28436
28635
  ]);
28437
- const lspServers = getLspServersInfo();
28438
- const lspStats = getLspServerStats(lspServers);
28636
+ const lspServers = getInstalledLspServers();
28439
28637
  const builtinMcp = getBuiltinMcpInfo();
28440
28638
  const userMcp = getUserMcpInfo();
28441
28639
  return {
28442
- lspInstalled: lspStats.installed,
28443
- lspTotal: lspStats.total,
28640
+ lspServers,
28444
28641
  astGrepCli: astGrepCliInfo.installed,
28445
28642
  astGrepNapi: astGrepNapiInfo.installed,
28446
28643
  commentChecker: commentCheckerInfo.installed,
@@ -28473,7 +28670,7 @@ function buildToolIssues(summary) {
28473
28670
  affects: ["comment-checker hook"]
28474
28671
  });
28475
28672
  }
28476
- if (summary.lspInstalled === 0) {
28673
+ if (summary.lspServers.length === 0) {
28477
28674
  issues.push({
28478
28675
  title: "No LSP servers detected",
28479
28676
  description: "LSP-dependent tools will be limited until at least one server is installed.",
@@ -28520,7 +28717,7 @@ async function checkTools() {
28520
28717
  details: [
28521
28718
  `AST-Grep: cli=${summary.astGrepCli ? "yes" : "no"}, napi=${summary.astGrepNapi ? "yes" : "no"}`,
28522
28719
  `Comment checker: ${summary.commentChecker ? "yes" : "no"}`,
28523
- `LSP: ${summary.lspInstalled}/${summary.lspTotal}`,
28720
+ `LSP: ${summary.lspServers.length > 0 ? `${summary.lspServers.length} server(s)` : "none"}`,
28524
28721
  `GH CLI: ${summary.ghCli.installed ? "installed" : "missing"}${summary.ghCli.authenticated ? " (authenticated)" : ""}`,
28525
28722
  `MCP: builtin=${summary.mcpBuiltin.length}, user=${summary.mcpUser.length}`
28526
28723
  ],
@@ -28555,10 +28752,10 @@ function getAllCheckDefinitions() {
28555
28752
  }
28556
28753
 
28557
28754
  // src/cli/doctor/format-default.ts
28558
- var import_picocolors19 = __toESM(require_picocolors(), 1);
28755
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
28559
28756
 
28560
28757
  // src/cli/doctor/format-shared.ts
28561
- var import_picocolors18 = __toESM(require_picocolors(), 1);
28758
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
28562
28759
  function formatStatusSymbol(status) {
28563
28760
  const colorFn = STATUS_COLORS[status];
28564
28761
  switch (status) {
@@ -28573,23 +28770,23 @@ function formatStatusSymbol(status) {
28573
28770
  }
28574
28771
  }
28575
28772
  function formatStatusMark(available) {
28576
- return available ? import_picocolors18.default.green(SYMBOLS3.check) : import_picocolors18.default.red(SYMBOLS3.cross);
28773
+ return available ? import_picocolors17.default.green(SYMBOLS3.check) : import_picocolors17.default.red(SYMBOLS3.cross);
28577
28774
  }
28578
28775
  function formatHeader() {
28579
28776
  return `
28580
- ${import_picocolors18.default.bgMagenta(import_picocolors18.default.white(" oMoMoMoMo Doctor "))}
28777
+ ${import_picocolors17.default.bgMagenta(import_picocolors17.default.white(" oMoMoMoMo Doctor "))}
28581
28778
  `;
28582
28779
  }
28583
28780
  function formatIssue(issue2, index) {
28584
28781
  const lines = [];
28585
- const severityColor = issue2.severity === "error" ? import_picocolors18.default.red : import_picocolors18.default.yellow;
28782
+ const severityColor = issue2.severity === "error" ? import_picocolors17.default.red : import_picocolors17.default.yellow;
28586
28783
  lines.push(`${index}. ${severityColor(issue2.title)}`);
28587
- lines.push(` ${import_picocolors18.default.dim(issue2.description)}`);
28784
+ lines.push(` ${import_picocolors17.default.dim(issue2.description)}`);
28588
28785
  if (issue2.fix) {
28589
- lines.push(` ${import_picocolors18.default.cyan("Fix:")} ${import_picocolors18.default.dim(issue2.fix)}`);
28786
+ lines.push(` ${import_picocolors17.default.cyan("Fix:")} ${import_picocolors17.default.dim(issue2.fix)}`);
28590
28787
  }
28591
28788
  if (issue2.affects && issue2.affects.length > 0) {
28592
- lines.push(` ${import_picocolors18.default.cyan("Affects:")} ${import_picocolors18.default.dim(issue2.affects.join(", "))}`);
28789
+ lines.push(` ${import_picocolors17.default.cyan("Affects:")} ${import_picocolors17.default.dim(issue2.affects.join(", "))}`);
28593
28790
  }
28594
28791
  return lines.join(`
28595
28792
  `);
@@ -28603,12 +28800,12 @@ function formatDefault(result) {
28603
28800
  if (allIssues.length === 0) {
28604
28801
  const opencodeVer = result.systemInfo.opencodeVersion ?? "unknown";
28605
28802
  const pluginVer = result.systemInfo.pluginVersion ?? "unknown";
28606
- lines.push(` ${import_picocolors19.default.green(SYMBOLS3.check)} ${import_picocolors19.default.green(`System OK (opencode ${opencodeVer} \xB7 oh-my-opencode ${pluginVer})`)}`);
28803
+ lines.push(` ${import_picocolors18.default.green(SYMBOLS3.check)} ${import_picocolors18.default.green(`System OK (opencode ${opencodeVer} \xB7 oh-my-opencode ${pluginVer})`)}`);
28607
28804
  } else {
28608
28805
  const issueCount = allIssues.filter((i2) => i2.severity === "error").length;
28609
28806
  const warnCount = allIssues.filter((i2) => i2.severity === "warning").length;
28610
28807
  const totalStr = `${issueCount + warnCount} ${issueCount + warnCount === 1 ? "issue" : "issues"}`;
28611
- lines.push(` ${import_picocolors19.default.yellow(SYMBOLS3.warn)} ${totalStr} found:
28808
+ lines.push(` ${import_picocolors18.default.yellow(SYMBOLS3.warn)} ${totalStr} found:
28612
28809
  `);
28613
28810
  allIssues.forEach((issue2, index) => {
28614
28811
  lines.push(formatIssue(issue2, index + 1));
@@ -28620,7 +28817,7 @@ function formatDefault(result) {
28620
28817
  }
28621
28818
 
28622
28819
  // src/cli/doctor/format-status.ts
28623
- var import_picocolors20 = __toESM(require_picocolors(), 1);
28820
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
28624
28821
  function formatStatus(result) {
28625
28822
  const lines = [];
28626
28823
  lines.push(formatHeader());
@@ -28631,13 +28828,15 @@ function formatStatus(result) {
28631
28828
  const bunVer = systemInfo.bunVersion ?? "unknown";
28632
28829
  lines.push(` ${padding}System ${opencodeVer} \xB7 ${pluginVer} \xB7 Bun ${bunVer}`);
28633
28830
  const configPath = systemInfo.configPath ?? "unknown";
28634
- const configStatus = systemInfo.configValid ? import_picocolors20.default.green("(valid)") : import_picocolors20.default.red("(invalid)");
28831
+ const configStatus = systemInfo.configValid ? import_picocolors19.default.green("(valid)") : import_picocolors19.default.red("(invalid)");
28635
28832
  lines.push(` ${padding}Config ${configPath} ${configStatus}`);
28636
- const lspText = `LSP ${tools.lspInstalled}/${tools.lspTotal}`;
28833
+ const serverCount = tools.lspServers.length;
28834
+ const lspMark = formatStatusMark(serverCount > 0);
28835
+ const lspText = serverCount > 0 ? `${serverCount} server${serverCount === 1 ? "" : "s"}` : "none";
28637
28836
  const astGrepMark = formatStatusMark(tools.astGrepCli);
28638
28837
  const ghMark = formatStatusMark(tools.ghCli.installed && tools.ghCli.authenticated);
28639
28838
  const ghUser = tools.ghCli.username ?? "";
28640
- lines.push(` ${padding}Tools ${lspText} \xB7 AST-Grep ${astGrepMark} \xB7 gh ${ghMark}${ghUser ? ` (${ghUser})` : ""}`);
28839
+ lines.push(` ${padding}Tools LSP ${lspMark} ${lspText} \xB7 AST-Grep ${astGrepMark} \xB7 gh ${ghMark}${ghUser ? ` (${ghUser})` : ""}`);
28641
28840
  const builtinCount = tools.mcpBuiltin.length;
28642
28841
  const userCount = tools.mcpUser.length;
28643
28842
  const builtinText = builtinCount > 0 ? tools.mcpBuiltin.join(" \xB7 ") : "none";
@@ -28648,13 +28847,13 @@ function formatStatus(result) {
28648
28847
  }
28649
28848
 
28650
28849
  // src/cli/doctor/format-verbose.ts
28651
- var import_picocolors21 = __toESM(require_picocolors(), 1);
28850
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
28652
28851
  function formatVerbose(result) {
28653
28852
  const lines = [];
28654
28853
  lines.push(formatHeader());
28655
28854
  const { systemInfo, tools, results, summary } = result;
28656
- lines.push(`${import_picocolors21.default.bold("System Information")}`);
28657
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28855
+ lines.push(`${import_picocolors20.default.bold("System Information")}`);
28856
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28658
28857
  lines.push(` ${formatStatusSymbol("pass")} opencode ${systemInfo.opencodeVersion ?? "unknown"}`);
28659
28858
  lines.push(` ${formatStatusSymbol("pass")} oh-my-opencode ${systemInfo.pluginVersion ?? "unknown"}`);
28660
28859
  if (systemInfo.loadedVersion) {
@@ -28665,54 +28864,73 @@ function formatVerbose(result) {
28665
28864
  }
28666
28865
  lines.push(` ${formatStatusSymbol("pass")} path ${systemInfo.opencodePath ?? "unknown"}`);
28667
28866
  if (systemInfo.isLocalDev) {
28668
- lines.push(` ${import_picocolors21.default.yellow("*")} ${import_picocolors21.default.dim("(local development mode)")}`);
28867
+ lines.push(` ${import_picocolors20.default.yellow("*")} ${import_picocolors20.default.dim("(local development mode)")}`);
28669
28868
  }
28670
28869
  lines.push("");
28671
- lines.push(`${import_picocolors21.default.bold("Configuration")}`);
28672
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28673
- const configStatus = systemInfo.configValid ? import_picocolors21.default.green("valid") : import_picocolors21.default.red("invalid");
28870
+ lines.push(`${import_picocolors20.default.bold("Configuration")}`);
28871
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28872
+ const configStatus = systemInfo.configValid ? import_picocolors20.default.green("valid") : import_picocolors20.default.red("invalid");
28674
28873
  lines.push(` ${formatStatusSymbol(systemInfo.configValid ? "pass" : "fail")} ${systemInfo.configPath ?? "unknown"} (${configStatus})`);
28675
28874
  lines.push("");
28676
- lines.push(`${import_picocolors21.default.bold("Tools")}`);
28677
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28678
- lines.push(` ${formatStatusSymbol("pass")} LSP ${tools.lspInstalled}/${tools.lspTotal} installed`);
28875
+ lines.push(`${import_picocolors20.default.bold("Tools")}`);
28876
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28877
+ if (tools.lspServers.length === 0) {
28878
+ lines.push(` ${formatStatusSymbol("warn")} LSP none detected`);
28879
+ } else {
28880
+ const count = tools.lspServers.length;
28881
+ lines.push(` ${formatStatusSymbol("pass")} LSP ${count} server${count === 1 ? "" : "s"}`);
28882
+ for (const server2 of tools.lspServers) {
28883
+ lines.push(`${" ".repeat(20)}${server2.id} (${server2.extensions.join(", ")})`);
28884
+ }
28885
+ }
28679
28886
  lines.push(` ${formatStatusSymbol(tools.astGrepCli ? "pass" : "fail")} ast-grep CLI ${tools.astGrepCli ? "installed" : "not found"}`);
28680
28887
  lines.push(` ${formatStatusSymbol(tools.astGrepNapi ? "pass" : "fail")} ast-grep napi ${tools.astGrepNapi ? "installed" : "not found"}`);
28681
28888
  lines.push(` ${formatStatusSymbol(tools.commentChecker ? "pass" : "fail")} comment-checker ${tools.commentChecker ? "installed" : "not found"}`);
28682
28889
  lines.push(` ${formatStatusSymbol(tools.ghCli.installed && tools.ghCli.authenticated ? "pass" : "fail")} gh CLI ${tools.ghCli.installed ? "installed" : "not found"}${tools.ghCli.authenticated && tools.ghCli.username ? ` (${tools.ghCli.username})` : ""}`);
28683
28890
  lines.push("");
28684
- lines.push(`${import_picocolors21.default.bold("MCPs")}`);
28685
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28891
+ lines.push(`${import_picocolors20.default.bold("MCPs")}`);
28892
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28686
28893
  if (tools.mcpBuiltin.length === 0) {
28687
- lines.push(` ${import_picocolors21.default.dim("No built-in MCPs")}`);
28894
+ lines.push(` ${import_picocolors20.default.dim("No built-in MCPs")}`);
28688
28895
  } else {
28689
28896
  for (const mcp of tools.mcpBuiltin) {
28690
28897
  lines.push(` ${formatStatusSymbol("pass")} ${mcp}`);
28691
28898
  }
28692
28899
  }
28693
28900
  if (tools.mcpUser.length > 0) {
28694
- lines.push(` ${import_picocolors21.default.cyan("+")} ${tools.mcpUser.length} user MCP(s):`);
28901
+ lines.push(` ${import_picocolors20.default.cyan("+")} ${tools.mcpUser.length} user MCP(s):`);
28695
28902
  for (const mcp of tools.mcpUser) {
28696
28903
  lines.push(` ${formatStatusSymbol("pass")} ${mcp}`);
28697
28904
  }
28698
28905
  }
28699
28906
  lines.push("");
28907
+ for (const check2 of results) {
28908
+ if (!check2.details || check2.details.length === 0) {
28909
+ continue;
28910
+ }
28911
+ lines.push(`${import_picocolors20.default.bold(check2.name)}`);
28912
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28913
+ for (const detail of check2.details) {
28914
+ lines.push(detail);
28915
+ }
28916
+ lines.push("");
28917
+ }
28700
28918
  const allIssues = results.flatMap((r2) => r2.issues);
28701
28919
  if (allIssues.length > 0) {
28702
- lines.push(`${import_picocolors21.default.bold("Issues")}`);
28703
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28920
+ lines.push(`${import_picocolors20.default.bold("Issues")}`);
28921
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28704
28922
  allIssues.forEach((issue2, index) => {
28705
28923
  lines.push(formatIssue(issue2, index + 1));
28706
28924
  lines.push("");
28707
28925
  });
28708
28926
  }
28709
- lines.push(`${import_picocolors21.default.bold("Summary")}`);
28710
- lines.push(`${import_picocolors21.default.dim("\u2500".repeat(40))}`);
28711
- const passText = summary.passed > 0 ? import_picocolors21.default.green(`${summary.passed} passed`) : `${summary.passed} passed`;
28712
- const failText = summary.failed > 0 ? import_picocolors21.default.red(`${summary.failed} failed`) : `${summary.failed} failed`;
28713
- const warnText = summary.warnings > 0 ? import_picocolors21.default.yellow(`${summary.warnings} warnings`) : `${summary.warnings} warnings`;
28927
+ lines.push(`${import_picocolors20.default.bold("Summary")}`);
28928
+ lines.push(`${import_picocolors20.default.dim("\u2500".repeat(40))}`);
28929
+ const passText = summary.passed > 0 ? import_picocolors20.default.green(`${summary.passed} passed`) : `${summary.passed} passed`;
28930
+ const failText = summary.failed > 0 ? import_picocolors20.default.red(`${summary.failed} failed`) : `${summary.failed} failed`;
28931
+ const warnText = summary.warnings > 0 ? import_picocolors20.default.yellow(`${summary.warnings} warnings`) : `${summary.warnings} warnings`;
28714
28932
  lines.push(` ${passText}, ${failText}, ${warnText}`);
28715
- lines.push(` ${import_picocolors21.default.dim(`Total: ${summary.total} checks in ${summary.duration}ms`)}`);
28933
+ lines.push(` ${import_picocolors20.default.dim(`Total: ${summary.total} checks in ${summary.duration}ms`)}`);
28716
28934
  return lines.join(`
28717
28935
  `);
28718
28936
  }
@@ -28796,11 +29014,11 @@ async function doctor(options = { mode: "default" }) {
28796
29014
 
28797
29015
  // src/features/mcp-oauth/storage.ts
28798
29016
  init_shared();
28799
- import { chmodSync, existsSync as existsSync26, mkdirSync as mkdirSync6, readFileSync as readFileSync26, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "fs";
28800
- import { dirname as dirname7, join as join25 } from "path";
29017
+ import { chmodSync, existsSync as existsSync30, mkdirSync as mkdirSync6, readFileSync as readFileSync27, unlinkSync as unlinkSync4, writeFileSync as writeFileSync10 } from "fs";
29018
+ import { dirname as dirname7, join as join29 } from "path";
28801
29019
  var STORAGE_FILE_NAME = "mcp-oauth.json";
28802
29020
  function getMcpOauthStoragePath() {
28803
- return join25(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
29021
+ return join29(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
28804
29022
  }
28805
29023
  function normalizeHost(serverHost) {
28806
29024
  let host = serverHost.trim();
@@ -28837,11 +29055,11 @@ function buildKey(serverHost, resource) {
28837
29055
  }
28838
29056
  function readStore() {
28839
29057
  const filePath = getMcpOauthStoragePath();
28840
- if (!existsSync26(filePath)) {
29058
+ if (!existsSync30(filePath)) {
28841
29059
  return null;
28842
29060
  }
28843
29061
  try {
28844
- const content = readFileSync26(filePath, "utf-8");
29062
+ const content = readFileSync27(filePath, "utf-8");
28845
29063
  return JSON.parse(content);
28846
29064
  } catch {
28847
29065
  return null;
@@ -28851,7 +29069,7 @@ function writeStore(store2) {
28851
29069
  const filePath = getMcpOauthStoragePath();
28852
29070
  try {
28853
29071
  const dir = dirname7(filePath);
28854
- if (!existsSync26(dir)) {
29072
+ if (!existsSync30(dir)) {
28855
29073
  mkdirSync6(dir, { recursive: true });
28856
29074
  }
28857
29075
  writeFileSync10(filePath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
@@ -28886,8 +29104,8 @@ function deleteToken(serverHost, resource) {
28886
29104
  if (Object.keys(store2).length === 0) {
28887
29105
  try {
28888
29106
  const filePath = getMcpOauthStoragePath();
28889
- if (existsSync26(filePath)) {
28890
- unlinkSync2(filePath);
29107
+ if (existsSync30(filePath)) {
29108
+ unlinkSync4(filePath);
28891
29109
  }
28892
29110
  return true;
28893
29111
  } catch {
@@ -29420,7 +29638,7 @@ function createMcpOAuthCommand() {
29420
29638
  var VERSION2 = package_default.version;
29421
29639
  var program2 = new Command;
29422
29640
  program2.name("oh-my-opencode").description("The ultimate OpenCode plugin - multi-model orchestration, LSP tools, and more").version(VERSION2, "-v, --version", "Show version number").enablePositionalOptions();
29423
- program2.command("install").description("Install and configure oh-my-opencode with interactive setup").option("--no-tui", "Run in non-interactive mode (requires all options)").option("--claude <value>", "Claude subscription: no, yes, max20").option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)").option("--gemini <value>", "Gemini integration: no, yes").option("--copilot <value>", "GitHub Copilot subscription: no, yes").option("--opencode-zen <value>", "OpenCode Zen access: no, yes (default: no)").option("--zai-coding-plan <value>", "Z.ai Coding Plan subscription: no, yes (default: no)").option("--kimi-for-coding <value>", "Kimi For Coding subscription: no, yes (default: no)").option("--skip-auth", "Skip authentication setup hints").addHelpText("after", `
29641
+ program2.command("install").description("Install and configure oh-my-opencode with interactive setup").option("--no-tui", "Run in non-interactive mode (requires all options)").option("--claude <value>", "Claude subscription: no, yes, max20").option("--openai <value>", "OpenAI/ChatGPT subscription: no, yes (default: no)").option("--gemini <value>", "Gemini integration: no, yes").option("--copilot <value>", "GitHub Copilot subscription: no, yes").option("--opencode-zen <value>", "OpenCode Zen access: no, yes (default: no)").option("--zai-coding-plan <value>", "Z.ai Coding Plan subscription: no, yes (default: no)").option("--kimi-for-coding <value>", "Kimi For Coding subscription: no, yes (default: no)").option("--opencode-go <value>", "OpenCode Go subscription: no, yes (default: no)").option("--skip-auth", "Skip authentication setup hints").addHelpText("after", `
29424
29642
  Examples:
29425
29643
  $ bunx oh-my-opencode install
29426
29644
  $ bunx oh-my-opencode install --no-tui --claude=max20 --openai=yes --gemini=yes --copilot=no
@@ -29444,12 +29662,13 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
29444
29662
  opencodeZen: options.opencodeZen,
29445
29663
  zaiCodingPlan: options.zaiCodingPlan,
29446
29664
  kimiForCoding: options.kimiForCoding,
29665
+ opencodeGo: options.opencodeGo,
29447
29666
  skipAuth: options.skipAuth ?? false
29448
29667
  };
29449
29668
  const exitCode = await install(args);
29450
29669
  process.exit(exitCode);
29451
29670
  });
29452
- program2.command("run <message>").allowUnknownOption().passThroughOptions().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("-p, --port <port>", "Server port (attaches if port already in use)", parseInt).option("--attach <url>", "Attach to existing opencode server URL").option("--on-complete <command>", "Shell command to run after completion").option("--json", "Output structured JSON result to stdout").option("--no-timestamp", "Disable timestamp prefix in run output").option("--verbose", "Show full event stream (default: messages/tools only)").option("--session-id <id>", "Resume existing session instead of creating new one").addHelpText("after", `
29671
+ program2.command("run <message>").allowUnknownOption().passThroughOptions().description("Run opencode with todo/background task completion enforcement").option("-a, --agent <name>", "Agent to use (default: from CLI/env/config, fallback: Sisyphus)").option("-m, --model <provider/model>", "Model override (e.g., anthropic/claude-sonnet-4)").option("-d, --directory <path>", "Working directory").option("-p, --port <port>", "Server port (attaches if port already in use)", parseInt).option("--attach <url>", "Attach to existing opencode server URL").option("--on-complete <command>", "Shell command to run after completion").option("--json", "Output structured JSON result to stdout").option("--no-timestamp", "Disable timestamp prefix in run output").option("--verbose", "Show full event stream (default: messages/tools only)").option("--session-id <id>", "Resume existing session instead of creating new one").addHelpText("after", `
29453
29672
  Examples:
29454
29673
  $ bunx oh-my-opencode run "Fix the bug in index.ts"
29455
29674
  $ bunx oh-my-opencode run --agent Sisyphus "Implement feature X"
@@ -29458,6 +29677,8 @@ Examples:
29458
29677
  $ bunx oh-my-opencode run --json "Fix the bug" | jq .sessionId
29459
29678
  $ bunx oh-my-opencode run --on-complete "notify-send Done" "Fix the bug"
29460
29679
  $ bunx oh-my-opencode run --session-id ses_abc123 "Continue the work"
29680
+ $ bunx oh-my-opencode run --model anthropic/claude-sonnet-4 "Fix the bug"
29681
+ $ bunx oh-my-opencode run --agent Sisyphus --model openai/gpt-5.4 "Implement feature X"
29461
29682
 
29462
29683
  Agent resolution order:
29463
29684
  1) --agent flag
@@ -29479,6 +29700,7 @@ Unlike 'opencode run', this command waits until:
29479
29700
  const runOptions = {
29480
29701
  message,
29481
29702
  agent: options.agent,
29703
+ model: options.model,
29482
29704
  directory: options.directory,
29483
29705
  port: options.port,
29484
29706
  attach: options.attach,