oh-my-opencode 3.7.3 → 3.8.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 (146) hide show
  1. package/README.ja.md +206 -243
  2. package/README.ko.md +205 -244
  3. package/README.md +176 -174
  4. package/README.zh-cn.md +211 -255
  5. package/dist/agents/atlas/default.d.ts +1 -1
  6. package/dist/agents/atlas/gpt.d.ts +1 -1
  7. package/dist/agents/atlas/prompt-section-builder.d.ts +1 -1
  8. package/dist/agents/builtin-agents/environment-context.d.ts +5 -1
  9. package/dist/agents/builtin-agents/general-agents.d.ts +1 -0
  10. package/dist/agents/builtin-agents/hephaestus-agent.d.ts +1 -0
  11. package/dist/agents/builtin-agents/sisyphus-agent.d.ts +1 -0
  12. package/dist/agents/builtin-agents.d.ts +1 -1
  13. package/dist/agents/dynamic-agent-prompt-builder.d.ts +0 -5
  14. package/dist/agents/index.d.ts +2 -1
  15. package/dist/agents/metis.d.ts +1 -1
  16. package/dist/agents/prometheus/behavioral-summary.d.ts +1 -1
  17. package/dist/agents/prometheus/gpt.d.ts +24 -0
  18. package/dist/agents/prometheus/identity-constraints.d.ts +1 -1
  19. package/dist/agents/prometheus/index.d.ts +3 -1
  20. package/dist/agents/prometheus/interview-mode.d.ts +1 -1
  21. package/dist/agents/prometheus/plan-generation.d.ts +1 -1
  22. package/dist/agents/prometheus/plan-template.d.ts +1 -1
  23. package/dist/agents/prometheus/system-prompt.d.ts +13 -2
  24. package/dist/agents/sisyphus-junior/agent.d.ts +1 -1
  25. package/dist/agents/types.d.ts +1 -0
  26. package/dist/cli/config-manager/antigravity-provider-configuration.d.ts +2 -2
  27. package/dist/cli/fallback-chain-resolution.d.ts +1 -1
  28. package/dist/cli/index.js +527 -175
  29. package/dist/cli/model-fallback-requirements.d.ts +3 -0
  30. package/dist/cli/provider-model-id-transform.d.ts +1 -1
  31. package/dist/cli/run/event-state.d.ts +4 -0
  32. package/dist/cli/run/stdin-suppression.d.ts +12 -0
  33. package/dist/cli/run/timestamp-output.d.ts +5 -0
  34. package/dist/cli/run/types.d.ts +1 -0
  35. package/dist/config/index.d.ts +2 -2
  36. package/dist/config/schema/agent-overrides.d.ts +75 -0
  37. package/dist/config/schema/categories.d.ts +2 -0
  38. package/dist/config/schema/experimental.d.ts +2 -0
  39. package/dist/config/schema/fallback-models.d.ts +3 -0
  40. package/dist/config/schema/hooks.d.ts +4 -3
  41. package/dist/config/schema/oh-my-opencode-config.d.ts +87 -47
  42. package/dist/config/schema/ralph-loop.d.ts +4 -0
  43. package/dist/config/schema/runtime-fallback.d.ts +10 -0
  44. package/dist/config/schema.d.ts +2 -0
  45. package/dist/create-hooks.d.ts +8 -5
  46. package/dist/features/background-agent/manager.d.ts +3 -0
  47. package/dist/features/background-agent/parent-session-context-resolver.d.ts +1 -0
  48. package/dist/features/background-agent/types.d.ts +7 -0
  49. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +1 -1
  50. package/dist/features/claude-code-session-state/state.d.ts +1 -0
  51. package/dist/features/task-toast-manager/manager.d.ts +5 -0
  52. package/dist/features/task-toast-manager/types.d.ts +2 -1
  53. package/dist/features/tmux-subagent/action-executor.d.ts +10 -3
  54. package/dist/features/tmux-subagent/grid-planning.d.ts +5 -3
  55. package/dist/features/tmux-subagent/manager.d.ts +12 -0
  56. package/dist/features/tmux-subagent/pane-split-availability.d.ts +0 -1
  57. package/dist/features/tmux-subagent/spawn-target-finder.d.ts +2 -2
  58. package/dist/features/tmux-subagent/tmux-grid-constants.d.ts +4 -0
  59. package/dist/features/tmux-subagent/types.d.ts +2 -0
  60. package/dist/hooks/atlas/recent-model-resolver.d.ts +6 -0
  61. package/dist/hooks/atlas/system-reminder-templates.d.ts +1 -1
  62. package/dist/hooks/hashline-edit-diff-enhancer/hook.d.ts +28 -0
  63. package/dist/hooks/hashline-edit-diff-enhancer/index.d.ts +1 -0
  64. package/dist/hooks/index.d.ts +5 -2
  65. package/dist/hooks/model-fallback/hook.d.ts +60 -0
  66. package/dist/hooks/no-hephaestus-non-gpt/hook.d.ts +16 -0
  67. package/dist/hooks/no-hephaestus-non-gpt/index.d.ts +1 -0
  68. package/dist/hooks/{sisyphus-gpt-hephaestus-reminder → no-sisyphus-gpt}/hook.d.ts +6 -1
  69. package/dist/hooks/no-sisyphus-gpt/index.d.ts +1 -0
  70. package/dist/hooks/ralph-loop/command-arguments.d.ts +8 -0
  71. package/dist/hooks/ralph-loop/continuation-prompt-injector.d.ts +1 -0
  72. package/dist/hooks/ralph-loop/iteration-continuation.d.ts +12 -0
  73. package/dist/hooks/ralph-loop/loop-state-controller.d.ts +2 -0
  74. package/dist/hooks/ralph-loop/ralph-loop-event-handler.d.ts +1 -0
  75. package/dist/hooks/ralph-loop/ralph-loop-hook.d.ts +1 -0
  76. package/dist/hooks/ralph-loop/session-reset-strategy.d.ts +3 -0
  77. package/dist/hooks/ralph-loop/types.d.ts +1 -0
  78. package/dist/hooks/runtime-fallback/agent-resolver.d.ts +5 -0
  79. package/dist/hooks/runtime-fallback/auto-retry.d.ts +10 -0
  80. package/dist/hooks/runtime-fallback/chat-message-handler.d.ts +20 -0
  81. package/dist/hooks/runtime-fallback/constants.d.ts +19 -0
  82. package/dist/hooks/runtime-fallback/error-classifier.d.ts +17 -0
  83. package/dist/hooks/runtime-fallback/event-handler.d.ts +8 -0
  84. package/dist/hooks/runtime-fallback/fallback-models.d.ts +2 -0
  85. package/dist/hooks/runtime-fallback/fallback-state.d.ts +6 -0
  86. package/dist/hooks/runtime-fallback/hook.d.ts +3 -0
  87. package/dist/hooks/runtime-fallback/index.d.ts +2 -0
  88. package/dist/hooks/runtime-fallback/message-update-handler.d.ts +5 -0
  89. package/dist/hooks/runtime-fallback/types.d.ts +59 -0
  90. package/dist/hooks/session-recovery/detect-error-type.d.ts +2 -1
  91. package/dist/hooks/session-recovery/recover-unavailable-tool.d.ts +5 -0
  92. package/dist/hooks/session-recovery/types.d.ts +1 -0
  93. package/dist/hooks/todo-continuation-enforcer/continuation-injection.d.ts +1 -0
  94. package/dist/hooks/todo-continuation-enforcer/countdown.d.ts +1 -0
  95. package/dist/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
  96. package/dist/hooks/unstable-agent-babysitter/unstable-agent-babysitter-hook.d.ts +2 -0
  97. package/dist/hooks/write-existing-file-guard/hook.d.ts +1 -0
  98. package/dist/index.js +6614 -3149
  99. package/dist/oh-my-opencode.schema.json +3681 -0
  100. package/dist/plugin/chat-headers.d.ts +4 -0
  101. package/dist/plugin/chat-message.d.ts +9 -8
  102. package/dist/plugin/chat-params.d.ts +2 -3
  103. package/dist/plugin/event.d.ts +2 -6
  104. package/dist/plugin/hooks/create-core-hooks.d.ts +8 -5
  105. package/dist/plugin/hooks/create-session-hooks.d.ts +7 -5
  106. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
  107. package/dist/plugin/hooks/create-transform-hooks.d.ts +1 -1
  108. package/dist/plugin/system-transform.d.ts +5 -0
  109. package/dist/plugin/types.d.ts +7 -1
  110. package/dist/plugin/ultrawork-db-model-override.d.ts +11 -0
  111. package/dist/plugin/ultrawork-model-override.d.ts +37 -0
  112. package/dist/shared/index.d.ts +4 -0
  113. package/dist/shared/internal-initiator-marker.d.ts +5 -0
  114. package/dist/shared/model-error-classifier.d.ts +31 -0
  115. package/dist/shared/model-resolution-pipeline.d.ts +1 -0
  116. package/dist/shared/model-resolver.d.ts +6 -0
  117. package/dist/shared/prompt-tools.d.ts +3 -0
  118. package/dist/shared/provider-model-id-transform.d.ts +1 -0
  119. package/dist/shared/session-category-registry.d.ts +32 -0
  120. package/dist/shared/session-model-state.d.ts +7 -0
  121. package/dist/shared/tmux/tmux-utils/layout.d.ts +17 -2
  122. package/dist/tools/delegate-task/background-task.d.ts +2 -1
  123. package/dist/tools/delegate-task/category-resolver.d.ts +2 -0
  124. package/dist/tools/delegate-task/constants.d.ts +1 -1
  125. package/dist/tools/delegate-task/skill-resolver.d.ts +1 -0
  126. package/dist/tools/delegate-task/subagent-resolver.d.ts +2 -0
  127. package/dist/tools/delegate-task/sync-task.d.ts +1 -1
  128. package/dist/tools/hashline-edit/constants.d.ts +5 -2
  129. package/dist/tools/hashline-edit/diff-utils.d.ts +6 -0
  130. package/dist/tools/hashline-edit/edit-operations.d.ts +4 -4
  131. package/dist/tools/hashline-edit/hash-computation.d.ts +1 -1
  132. package/dist/tools/hashline-edit/index.d.ts +1 -1
  133. package/dist/tools/hashline-edit/types.d.ts +4 -4
  134. package/dist/tools/hashline-edit/validation.d.ts +1 -0
  135. package/dist/tools/index.d.ts +2 -2
  136. package/dist/tools/skill/constants.d.ts +2 -2
  137. package/dist/tools/skill/types.d.ts +4 -0
  138. package/dist/tools/slashcommand/index.d.ts +1 -1
  139. package/dist/tools/slashcommand/types.d.ts +1 -7
  140. package/package.json +10 -10
  141. package/dist/cli/run/opencode-bin-path.d.ts +0 -3
  142. package/dist/hooks/sisyphus-gpt-hephaestus-reminder/index.d.ts +0 -1
  143. package/dist/tools/slashcommand/skill-command-converter.d.ts +0 -3
  144. package/dist/tools/slashcommand/slashcommand-description.d.ts +0 -3
  145. package/dist/tools/slashcommand/slashcommand-tool.d.ts +0 -4
  146. package/dist/tools/slashcommand/tools.d.ts +0 -2
package/dist/cli/index.js CHANGED
@@ -6513,6 +6513,7 @@ var init_hook_names = __esm(() => {
6513
6513
  HOOK_NAME_MAP = {
6514
6514
  "anthropic-auto-compact": "anthropic-context-window-limit-recovery",
6515
6515
  "sisyphus-orchestrator": "atlas",
6516
+ "sisyphus-gpt-hephaestus-reminder": "no-sisyphus-gpt",
6516
6517
  "empty-message-sanitizer": null
6517
6518
  };
6518
6519
  });
@@ -6549,8 +6550,8 @@ function migrateModelVersions(configs, appliedMigrations) {
6549
6550
  var MODEL_VERSION_MAP;
6550
6551
  var init_model_versions = __esm(() => {
6551
6552
  MODEL_VERSION_MAP = {
6552
- "openai/gpt-5.2-codex": "openai/gpt-5.3-codex",
6553
- "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6"
6553
+ "anthropic/claude-opus-4-5": "anthropic/claude-opus-4-6",
6554
+ "anthropic/claude-sonnet-4-5": "anthropic/claude-sonnet-4-6"
6554
6555
  };
6555
6556
  });
6556
6557
 
@@ -6600,6 +6601,19 @@ function migrateConfigFile(configPath, rawConfig) {
6600
6601
  delete copy.omo_agent;
6601
6602
  needsWrite = true;
6602
6603
  }
6604
+ if (copy.experimental && typeof copy.experimental === "object") {
6605
+ const experimental = copy.experimental;
6606
+ if ("hashline_edit" in experimental) {
6607
+ if (copy.hashline_edit === undefined) {
6608
+ copy.hashline_edit = experimental.hashline_edit;
6609
+ }
6610
+ delete experimental.hashline_edit;
6611
+ if (Object.keys(experimental).length === 0) {
6612
+ delete copy.experimental;
6613
+ }
6614
+ needsWrite = true;
6615
+ }
6616
+ }
6603
6617
  if (copy.disabled_agents && Array.isArray(copy.disabled_agents)) {
6604
6618
  const migrated = [];
6605
6619
  let changed = false;
@@ -6783,10 +6797,9 @@ var init_model_requirements = __esm(() => {
6783
6797
  sisyphus: {
6784
6798
  fallbackChain: [
6785
6799
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
6786
- { providers: ["kimi-for-coding"], model: "k2p5" },
6787
6800
  { providers: ["opencode"], model: "kimi-k2.5-free" },
6788
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
6789
- { providers: ["opencode"], model: "glm-4.7-free" }
6801
+ { providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
6802
+ { providers: ["opencode"], model: "big-pickle" }
6790
6803
  ],
6791
6804
  requiresAnyModel: true
6792
6805
  },
@@ -6805,42 +6818,39 @@ var init_model_requirements = __esm(() => {
6805
6818
  },
6806
6819
  librarian: {
6807
6820
  fallbackChain: [
6808
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
6809
- { providers: ["opencode"], model: "glm-4.7-free" },
6810
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
6821
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
6822
+ { providers: ["opencode"], model: "minimax-m2.5-free" },
6823
+ { providers: ["opencode"], model: "big-pickle" }
6811
6824
  ]
6812
6825
  },
6813
6826
  explore: {
6814
6827
  fallbackChain: [
6815
6828
  { providers: ["github-copilot"], model: "grok-code-fast-1" },
6829
+ { providers: ["opencode"], model: "minimax-m2.5-free" },
6816
6830
  { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
6817
6831
  { providers: ["opencode"], model: "gpt-5-nano" }
6818
6832
  ]
6819
6833
  },
6820
6834
  "multimodal-looker": {
6821
6835
  fallbackChain: [
6836
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
6822
6837
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
6823
6838
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
6824
6839
  { providers: ["zai-coding-plan"], model: "glm-4.6v" },
6825
- { providers: ["kimi-for-coding"], model: "k2p5" },
6826
- { providers: ["opencode"], model: "kimi-k2.5-free" },
6827
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
6828
- { providers: ["opencode"], model: "gpt-5-nano" }
6840
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5-nano" }
6829
6841
  ]
6830
6842
  },
6831
6843
  prometheus: {
6832
6844
  fallbackChain: [
6833
6845
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
6834
- { providers: ["kimi-for-coding"], model: "k2p5" },
6835
- { providers: ["opencode"], model: "kimi-k2.5-free" },
6836
6846
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6847
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
6837
6848
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6838
6849
  ]
6839
6850
  },
6840
6851
  metis: {
6841
6852
  fallbackChain: [
6842
6853
  { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
6843
- { providers: ["kimi-for-coding"], model: "k2p5" },
6844
6854
  { providers: ["opencode"], model: "kimi-k2.5-free" },
6845
6855
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
6846
6856
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
@@ -6855,11 +6865,9 @@ var init_model_requirements = __esm(() => {
6855
6865
  },
6856
6866
  atlas: {
6857
6867
  fallbackChain: [
6858
- { providers: ["kimi-for-coding"], model: "k2p5" },
6859
6868
  { providers: ["opencode"], model: "kimi-k2.5-free" },
6860
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6861
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
6862
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
6869
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
6870
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
6863
6871
  ]
6864
6872
  }
6865
6873
  };
@@ -6867,9 +6875,8 @@ var init_model_requirements = __esm(() => {
6867
6875
  "visual-engineering": {
6868
6876
  fallbackChain: [
6869
6877
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
6870
- { providers: ["zai-coding-plan"], model: "glm-5" },
6871
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
6872
- { providers: ["kimi-for-coding"], model: "k2p5" }
6878
+ { providers: ["zai-coding-plan", "opencode"], model: "glm-5" },
6879
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
6873
6880
  ]
6874
6881
  },
6875
6882
  ultrabrain: {
@@ -6904,7 +6911,7 @@ var init_model_requirements = __esm(() => {
6904
6911
  },
6905
6912
  "unspecified-low": {
6906
6913
  fallbackChain: [
6907
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
6914
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
6908
6915
  { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
6909
6916
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
6910
6917
  ]
@@ -6918,9 +6925,8 @@ var init_model_requirements = __esm(() => {
6918
6925
  },
6919
6926
  writing: {
6920
6927
  fallbackChain: [
6921
- { providers: ["kimi-for-coding"], model: "k2p5" },
6922
6928
  { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
6923
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
6929
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" }
6924
6930
  ]
6925
6931
  }
6926
6932
  };
@@ -6954,10 +6960,6 @@ function ensureCacheDir() {
6954
6960
  mkdirSync(cacheDir, { recursive: true });
6955
6961
  }
6956
6962
  }
6957
- function hasConnectedProvidersCache() {
6958
- const cacheFile = getCacheFilePath(CONNECTED_PROVIDERS_CACHE_FILE);
6959
- return existsSync3(cacheFile);
6960
- }
6961
6963
  function writeConnectedProvidersCache(connected) {
6962
6964
  ensureCacheDir();
6963
6965
  const cacheFile = getCacheFilePath(CONNECTED_PROVIDERS_CACHE_FILE);
@@ -7046,6 +7048,17 @@ var init_model_availability = __esm(() => {
7046
7048
  init_connected_providers_cache();
7047
7049
  });
7048
7050
 
7051
+ // src/shared/provider-model-id-transform.ts
7052
+ function transformModelForProvider(provider, model) {
7053
+ if (provider === "github-copilot") {
7054
+ return model.replace("claude-opus-4-6", "claude-opus-4.6").replace("claude-sonnet-4-6", "claude-sonnet-4.6").replace("claude-sonnet-4-5", "claude-sonnet-4.5").replace("claude-haiku-4-5", "claude-haiku-4.5").replace("claude-sonnet-4", "claude-sonnet-4").replace(/gemini-3-pro(?!-)/g, "gemini-3-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
7055
+ }
7056
+ if (provider === "google") {
7057
+ return model.replace(/gemini-3-pro(?!-)/g, "gemini-3-pro-preview").replace(/gemini-3-flash(?!-)/g, "gemini-3-flash-preview");
7058
+ }
7059
+ return model;
7060
+ }
7061
+
7049
7062
  // src/shared/model-resolution-pipeline.ts
7050
7063
  var init_model_resolution_pipeline = __esm(() => {
7051
7064
  init_logger();
@@ -7268,9 +7281,27 @@ var init_safe_create_hook = __esm(() => {
7268
7281
  // src/shared/session-directory-resolver.ts
7269
7282
  var init_session_directory_resolver = () => {};
7270
7283
 
7284
+ // src/shared/session-tools-store.ts
7285
+ var store;
7286
+ var init_session_tools_store = __esm(() => {
7287
+ store = new Map;
7288
+ });
7289
+
7290
+ // src/shared/prompt-tools.ts
7291
+ var init_prompt_tools = __esm(() => {
7292
+ init_session_tools_store();
7293
+ });
7294
+ // src/shared/session-category-registry.ts
7295
+ var sessionCategoryMap;
7296
+ var init_session_category_registry = __esm(() => {
7297
+ sessionCategoryMap = new Map;
7298
+ });
7299
+
7271
7300
  // src/shared/index.ts
7272
7301
  var init_shared = __esm(() => {
7302
+ init_model_resolver();
7273
7303
  init_model_resolution_pipeline();
7304
+ init_session_category_registry();
7274
7305
  init_frontmatter();
7275
7306
  init_command_executor();
7276
7307
  init_file_reference_resolver();
@@ -7311,6 +7342,7 @@ var init_shared = __esm(() => {
7311
7342
  init_opencode_storage_paths();
7312
7343
  init_opencode_message_dir();
7313
7344
  init_session_directory_resolver();
7345
+ init_prompt_tools();
7314
7346
  });
7315
7347
 
7316
7348
  // src/cli/config-manager/config-context.ts
@@ -7362,6 +7394,13 @@ async function fetchNpmDistTags(packageName) {
7362
7394
  var NPM_FETCH_TIMEOUT_MS = 5000;
7363
7395
 
7364
7396
  // src/cli/config-manager/plugin-name-with-version.ts
7397
+ function getFallbackEntry(version) {
7398
+ const prereleaseMatch = version.match(/-([a-zA-Z][a-zA-Z0-9-]*)(?:\.|$)/);
7399
+ if (prereleaseMatch) {
7400
+ return `${PACKAGE_NAME}@${prereleaseMatch[1]}`;
7401
+ }
7402
+ return PACKAGE_NAME;
7403
+ }
7365
7404
  async function getPluginNameWithVersion(currentVersion) {
7366
7405
  const distTags = await fetchNpmDistTags(PACKAGE_NAME);
7367
7406
  if (distTags) {
@@ -7372,7 +7411,7 @@ async function getPluginNameWithVersion(currentVersion) {
7372
7411
  }
7373
7412
  }
7374
7413
  }
7375
- return `${PACKAGE_NAME}@${currentVersion}`;
7414
+ return getFallbackEntry(currentVersion);
7376
7415
  }
7377
7416
  var PACKAGE_NAME = "oh-my-opencode", PRIORITIZED_TAGS;
7378
7417
  var init_plugin_name_with_version = __esm(() => {
@@ -7550,6 +7589,156 @@ var init_add_plugin_to_opencode_config = __esm(() => {
7550
7589
  init_plugin_name_with_version();
7551
7590
  });
7552
7591
 
7592
+ // src/cli/model-fallback-requirements.ts
7593
+ var CLI_AGENT_MODEL_REQUIREMENTS, CLI_CATEGORY_MODEL_REQUIREMENTS;
7594
+ var init_model_fallback_requirements = __esm(() => {
7595
+ CLI_AGENT_MODEL_REQUIREMENTS = {
7596
+ sisyphus: {
7597
+ fallbackChain: [
7598
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7599
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7600
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
7601
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
7602
+ { providers: ["opencode"], model: "glm-4.7-free" }
7603
+ ],
7604
+ requiresAnyModel: true
7605
+ },
7606
+ hephaestus: {
7607
+ fallbackChain: [
7608
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.3-codex", variant: "medium" }
7609
+ ],
7610
+ requiresProvider: ["openai", "github-copilot", "opencode"]
7611
+ },
7612
+ oracle: {
7613
+ fallbackChain: [
7614
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
7615
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
7616
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
7617
+ ]
7618
+ },
7619
+ librarian: {
7620
+ fallbackChain: [
7621
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
7622
+ { providers: ["opencode"], model: "glm-4.7-free" },
7623
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
7624
+ ]
7625
+ },
7626
+ explore: {
7627
+ fallbackChain: [
7628
+ { providers: ["github-copilot"], model: "grok-code-fast-1" },
7629
+ { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
7630
+ { providers: ["opencode"], model: "gpt-5-nano" }
7631
+ ]
7632
+ },
7633
+ "multimodal-looker": {
7634
+ fallbackChain: [
7635
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
7636
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
7637
+ { providers: ["zai-coding-plan"], model: "glm-4.6v" },
7638
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7639
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
7640
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
7641
+ { providers: ["opencode"], model: "gpt-5-nano" }
7642
+ ]
7643
+ },
7644
+ prometheus: {
7645
+ fallbackChain: [
7646
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7647
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7648
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
7649
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
7650
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
7651
+ ]
7652
+ },
7653
+ metis: {
7654
+ fallbackChain: [
7655
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7656
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7657
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
7658
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
7659
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
7660
+ ]
7661
+ },
7662
+ momus: {
7663
+ fallbackChain: [
7664
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
7665
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7666
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
7667
+ ]
7668
+ },
7669
+ atlas: {
7670
+ fallbackChain: [
7671
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7672
+ { providers: ["opencode"], model: "kimi-k2.5-free" },
7673
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
7674
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
7675
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
7676
+ ]
7677
+ }
7678
+ };
7679
+ CLI_CATEGORY_MODEL_REQUIREMENTS = {
7680
+ "visual-engineering": {
7681
+ fallbackChain: [
7682
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
7683
+ { providers: ["zai-coding-plan"], model: "glm-5" },
7684
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7685
+ { providers: ["kimi-for-coding"], model: "k2p5" }
7686
+ ]
7687
+ },
7688
+ ultrabrain: {
7689
+ fallbackChain: [
7690
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.3-codex", variant: "xhigh" },
7691
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
7692
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" }
7693
+ ]
7694
+ },
7695
+ deep: {
7696
+ fallbackChain: [
7697
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
7698
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7699
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" }
7700
+ ],
7701
+ requiresModel: "gpt-5.3-codex"
7702
+ },
7703
+ artistry: {
7704
+ fallbackChain: [
7705
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "high" },
7706
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7707
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
7708
+ ],
7709
+ requiresModel: "gemini-3-pro"
7710
+ },
7711
+ quick: {
7712
+ fallbackChain: [
7713
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
7714
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
7715
+ { providers: ["opencode"], model: "gpt-5-nano" }
7716
+ ]
7717
+ },
7718
+ "unspecified-low": {
7719
+ fallbackChain: [
7720
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
7721
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.3-codex", variant: "medium" },
7722
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
7723
+ ]
7724
+ },
7725
+ "unspecified-high": {
7726
+ fallbackChain: [
7727
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-6", variant: "max" },
7728
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
7729
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
7730
+ ]
7731
+ },
7732
+ writing: {
7733
+ fallbackChain: [
7734
+ { providers: ["kimi-for-coding"], model: "k2p5" },
7735
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
7736
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
7737
+ ]
7738
+ }
7739
+ };
7740
+ });
7741
+
7553
7742
  // src/cli/provider-availability.ts
7554
7743
  function toProviderAvailability(config) {
7555
7744
  return {
@@ -7579,12 +7768,7 @@ function isProviderAvailable(provider, availability) {
7579
7768
  }
7580
7769
 
7581
7770
  // src/cli/provider-model-id-transform.ts
7582
- function transformModelForProvider(provider, model) {
7583
- if (provider === "github-copilot") {
7584
- return model.replace("claude-opus-4-6", "claude-opus-4.6").replace("claude-sonnet-4-5", "claude-sonnet-4.5").replace("claude-haiku-4-5", "claude-haiku-4.5").replace("claude-sonnet-4", "claude-sonnet-4").replace("gemini-3-pro", "gemini-3-pro-preview").replace("gemini-3-flash", "gemini-3-flash-preview");
7585
- }
7586
- return model;
7587
- }
7771
+ var init_provider_model_id_transform = () => {};
7588
7772
 
7589
7773
  // src/cli/fallback-chain-resolution.ts
7590
7774
  function resolveModelFromChain(fallbackChain, availability) {
@@ -7602,7 +7786,7 @@ function resolveModelFromChain(fallbackChain, availability) {
7602
7786
  return null;
7603
7787
  }
7604
7788
  function getSisyphusFallbackChain() {
7605
- return AGENT_MODEL_REQUIREMENTS.sisyphus.fallbackChain;
7789
+ return CLI_AGENT_MODEL_REQUIREMENTS.sisyphus.fallbackChain;
7606
7790
  }
7607
7791
  function isAnyFallbackEntryAvailable(fallbackChain, availability) {
7608
7792
  return fallbackChain.some((entry) => entry.providers.some((provider) => isProviderAvailable(provider, availability)));
@@ -7617,7 +7801,8 @@ function isRequiredProviderAvailable(requiredProviders, availability) {
7617
7801
  return requiredProviders.some((provider) => isProviderAvailable(provider, availability));
7618
7802
  }
7619
7803
  var init_fallback_chain_resolution = __esm(() => {
7620
- init_model_requirements();
7804
+ init_model_fallback_requirements();
7805
+ init_provider_model_id_transform();
7621
7806
  });
7622
7807
 
7623
7808
  // src/cli/model-fallback.ts
@@ -7627,13 +7812,13 @@ function generateModelConfig(config) {
7627
7812
  if (!hasAnyProvider) {
7628
7813
  return {
7629
7814
  $schema: SCHEMA_URL,
7630
- agents: Object.fromEntries(Object.entries(AGENT_MODEL_REQUIREMENTS).filter(([role, req]) => !(role === "sisyphus" && req.requiresAnyModel)).map(([role]) => [role, { model: ULTIMATE_FALLBACK }])),
7631
- categories: Object.fromEntries(Object.keys(CATEGORY_MODEL_REQUIREMENTS).map((cat) => [cat, { model: ULTIMATE_FALLBACK }]))
7815
+ agents: Object.fromEntries(Object.entries(CLI_AGENT_MODEL_REQUIREMENTS).filter(([role, req]) => !(role === "sisyphus" && req.requiresAnyModel)).map(([role]) => [role, { model: ULTIMATE_FALLBACK }])),
7816
+ categories: Object.fromEntries(Object.keys(CLI_CATEGORY_MODEL_REQUIREMENTS).map((cat) => [cat, { model: ULTIMATE_FALLBACK }]))
7632
7817
  };
7633
7818
  }
7634
7819
  const agents = {};
7635
7820
  const categories = {};
7636
- for (const [role, req] of Object.entries(AGENT_MODEL_REQUIREMENTS)) {
7821
+ for (const [role, req] of Object.entries(CLI_AGENT_MODEL_REQUIREMENTS)) {
7637
7822
  if (role === "librarian" && avail.zai) {
7638
7823
  agents[role] = { model: ZAI_MODEL };
7639
7824
  continue;
@@ -7676,8 +7861,8 @@ function generateModelConfig(config) {
7676
7861
  agents[role] = { model: ULTIMATE_FALLBACK };
7677
7862
  }
7678
7863
  }
7679
- for (const [cat, req] of Object.entries(CATEGORY_MODEL_REQUIREMENTS)) {
7680
- const fallbackChain = cat === "unspecified-high" && !avail.isMaxPlan ? CATEGORY_MODEL_REQUIREMENTS["unspecified-low"].fallbackChain : req.fallbackChain;
7864
+ for (const [cat, req] of Object.entries(CLI_CATEGORY_MODEL_REQUIREMENTS)) {
7865
+ const fallbackChain = cat === "unspecified-high" && !avail.isMaxPlan ? CLI_CATEGORY_MODEL_REQUIREMENTS["unspecified-low"].fallbackChain : req.fallbackChain;
7681
7866
  if (req.requiresModel && !isRequiredModelAvailable(req.requiresModel, req.fallbackChain, avail)) {
7682
7867
  continue;
7683
7868
  }
@@ -7700,7 +7885,7 @@ function generateModelConfig(config) {
7700
7885
  }
7701
7886
  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/master/assets/oh-my-opencode.schema.json";
7702
7887
  var init_model_fallback = __esm(() => {
7703
- init_model_requirements();
7888
+ init_model_fallback_requirements();
7704
7889
  init_fallback_chain_resolution();
7705
7890
  });
7706
7891
 
@@ -7830,17 +8015,6 @@ var init_opencode_binary = __esm(() => {
7830
8015
 
7831
8016
  // src/cli/config-manager/auth-plugins.ts
7832
8017
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, copyFileSync as copyFileSync2, existsSync as existsSync8 } from "fs";
7833
- async function fetchLatestVersion(packageName) {
7834
- try {
7835
- const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`);
7836
- if (!res.ok)
7837
- return null;
7838
- const data = await res.json();
7839
- return data.version;
7840
- } catch {
7841
- return null;
7842
- }
7843
- }
7844
8018
  async function addAuthPlugins(config) {
7845
8019
  try {
7846
8020
  ensureConfigDirectoryExists();
@@ -7868,13 +8042,6 @@ async function addAuthPlugins(config) {
7868
8042
  }
7869
8043
  const rawPlugins = existingConfig?.plugin;
7870
8044
  const plugins = Array.isArray(rawPlugins) ? rawPlugins : [];
7871
- if (config.hasGemini) {
7872
- const version = await fetchLatestVersion("opencode-antigravity-auth");
7873
- const pluginEntry = version ? `opencode-antigravity-auth@${version}` : "opencode-antigravity-auth";
7874
- if (!plugins.some((p) => p.startsWith("opencode-antigravity-auth"))) {
7875
- plugins.push(pluginEntry);
7876
- }
7877
- }
7878
8045
  const newConfig = { ...existingConfig ?? {}, plugin: plugins };
7879
8046
  if (format2 !== "none" && existsSync8(path3)) {
7880
8047
  copyFileSync2(path3, backupPath);
@@ -7983,13 +8150,13 @@ var init_antigravity_provider_configuration = __esm(() => {
7983
8150
  high: { thinkingLevel: "high" }
7984
8151
  }
7985
8152
  },
7986
- "antigravity-claude-sonnet-4-5": {
7987
- name: "Claude Sonnet 4.5 (Antigravity)",
8153
+ "antigravity-claude-sonnet-4-6": {
8154
+ name: "Claude Sonnet 4.6 (Antigravity)",
7988
8155
  limit: { context: 200000, output: 64000 },
7989
8156
  modalities: { input: ["text", "image", "pdf"], output: ["text"] }
7990
8157
  },
7991
- "antigravity-claude-sonnet-4-5-thinking": {
7992
- name: "Claude Sonnet 4.5 Thinking (Antigravity)",
8158
+ "antigravity-claude-sonnet-4-6-thinking": {
8159
+ name: "Claude Sonnet 4.6 Thinking (Antigravity)",
7993
8160
  limit: { context: 200000, output: 64000 },
7994
8161
  modalities: { input: ["text", "image", "pdf"], output: ["text"] },
7995
8162
  variants: {
@@ -8430,6 +8597,9 @@ var init_local_dev_version = __esm(() => {
8430
8597
 
8431
8598
  // src/hooks/auto-update-checker/checker/plugin-entry.ts
8432
8599
  import * as fs7 from "fs";
8600
+ function isExplicitVersionPin(pinnedVersion) {
8601
+ return /^\d+\.\d+\.\d+/.test(pinnedVersion);
8602
+ }
8433
8603
  function findPluginEntry(directory) {
8434
8604
  for (const configPath of getConfigPaths(directory)) {
8435
8605
  try {
@@ -8444,8 +8614,8 @@ function findPluginEntry(directory) {
8444
8614
  }
8445
8615
  if (entry.startsWith(`${PACKAGE_NAME3}@`)) {
8446
8616
  const pinnedVersion = entry.slice(PACKAGE_NAME3.length + 1);
8447
- const isPinned = pinnedVersion !== "latest";
8448
- return { entry, isPinned, pinnedVersion: isPinned ? pinnedVersion : null, configPath };
8617
+ const isPinned = isExplicitVersionPin(pinnedVersion);
8618
+ return { entry, isPinned, pinnedVersion, configPath };
8449
8619
  }
8450
8620
  }
8451
8621
  } catch {
@@ -8787,6 +8957,9 @@ var init_update_toasts = __esm(() => {
8787
8957
  });
8788
8958
 
8789
8959
  // src/hooks/auto-update-checker/hook/background-update-check.ts
8960
+ function getPinnedVersionToastMessage(latestVersion) {
8961
+ return `Update available: ${latestVersion} (version pinned, update manually)`;
8962
+ }
8790
8963
  async function runBunInstallSafe() {
8791
8964
  try {
8792
8965
  return await runBunInstall();
@@ -8825,7 +8998,7 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
8825
8998
  return;
8826
8999
  }
8827
9000
  if (pluginInfo.isPinned) {
8828
- await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
9001
+ await showUpdateAvailableToast(ctx, latestVersion, () => getPinnedVersionToastMessage(latestVersion));
8829
9002
  log(`[auto-update-checker] User-pinned version detected (${pluginInfo.entry}), skipping auto-update. Notification only.`);
8830
9003
  return;
8831
9004
  }
@@ -8878,24 +9051,46 @@ var init_config_errors_toast = __esm(() => {
8878
9051
 
8879
9052
  // src/hooks/auto-update-checker/hook/connected-providers-status.ts
8880
9053
  async function updateAndShowConnectedProvidersCacheStatus(ctx) {
8881
- const hadCache = hasConnectedProvidersCache();
8882
- updateConnectedProvidersCache(ctx.client).catch(() => {});
9054
+ const hadCache = isModelCacheAvailable();
8883
9055
  if (!hadCache) {
8884
- await ctx.client.tui.showToast({
8885
- body: {
8886
- title: "Connected Providers Cache",
8887
- message: "Building provider cache for first time. Restart OpenCode for full model filtering.",
8888
- variant: "info",
8889
- duration: 8000
8890
- }
8891
- }).catch(() => {});
8892
- log("[auto-update-checker] Connected providers cache toast shown (first run)");
9056
+ let timeoutId;
9057
+ try {
9058
+ await Promise.race([
9059
+ updateConnectedProvidersCache(ctx.client),
9060
+ new Promise((_3, reject) => {
9061
+ timeoutId = setTimeout(() => reject(new Error("Cache update timed out")), CACHE_UPDATE_TIMEOUT_MS);
9062
+ })
9063
+ ]);
9064
+ } catch (err) {
9065
+ log("[auto-update-checker] Connected providers cache creation failed", { error: String(err) });
9066
+ } finally {
9067
+ if (timeoutId)
9068
+ clearTimeout(timeoutId);
9069
+ }
9070
+ if (!isModelCacheAvailable()) {
9071
+ await ctx.client.tui.showToast({
9072
+ body: {
9073
+ title: "Connected Providers Cache",
9074
+ message: "Failed to build provider cache. Restart OpenCode to retry.",
9075
+ variant: "warning",
9076
+ duration: 8000
9077
+ }
9078
+ }).catch(() => {});
9079
+ log("[auto-update-checker] Connected providers cache toast shown (creation failed)");
9080
+ } else {
9081
+ log("[auto-update-checker] Connected providers cache created on first run");
9082
+ }
8893
9083
  } else {
9084
+ updateConnectedProvidersCache(ctx.client).catch((err) => {
9085
+ log("[auto-update-checker] Background cache update failed", { error: String(err) });
9086
+ });
8894
9087
  log("[auto-update-checker] Connected providers cache exists, updating in background");
8895
9088
  }
8896
9089
  }
9090
+ var CACHE_UPDATE_TIMEOUT_MS = 1e4;
8897
9091
  var init_connected_providers_status = __esm(() => {
8898
9092
  init_connected_providers_cache();
9093
+ init_model_availability();
8899
9094
  init_logger();
8900
9095
  });
8901
9096
 
@@ -8988,8 +9183,8 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
8988
9183
  const localDevVersion = getLocalDevVersion(ctx.directory);
8989
9184
  const displayVersion = localDevVersion ?? cachedVersion;
8990
9185
  await showConfigErrorsIfAny(ctx);
8991
- await showModelCacheWarningIfNeeded(ctx);
8992
9186
  await updateAndShowConnectedProvidersCacheStatus(ctx);
9187
+ await showModelCacheWarningIfNeeded(ctx);
8993
9188
  if (localDevVersion) {
8994
9189
  if (showStartupToast) {
8995
9190
  showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {});
@@ -9053,13 +9248,13 @@ var {
9053
9248
  // package.json
9054
9249
  var package_default = {
9055
9250
  name: "oh-my-opencode",
9056
- version: "3.7.3",
9251
+ version: "3.8.0",
9057
9252
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
9058
9253
  main: "dist/index.js",
9059
9254
  types: "dist/index.d.ts",
9060
9255
  type: "module",
9061
9256
  bin: {
9062
- "oh-my-opencode": "./bin/oh-my-opencode.js"
9257
+ "oh-my-opencode": "bin/oh-my-opencode.js"
9063
9258
  },
9064
9259
  files: [
9065
9260
  "dist",
@@ -9108,7 +9303,7 @@ var package_default = {
9108
9303
  "@ast-grep/napi": "^0.40.0",
9109
9304
  "@clack/prompts": "^0.11.0",
9110
9305
  "@code-yeongyu/comment-checker": "^0.6.1",
9111
- "@modelcontextprotocol/sdk": "^1.25.1",
9306
+ "@modelcontextprotocol/sdk": "^1.25.2",
9112
9307
  "@opencode-ai/plugin": "^1.1.19",
9113
9308
  "@opencode-ai/sdk": "^1.1.19",
9114
9309
  commander: "^14.0.2",
@@ -9127,13 +9322,13 @@ var package_default = {
9127
9322
  typescript: "^5.7.3"
9128
9323
  },
9129
9324
  optionalDependencies: {
9130
- "oh-my-opencode-darwin-arm64": "3.7.3",
9131
- "oh-my-opencode-darwin-x64": "3.7.3",
9132
- "oh-my-opencode-linux-arm64": "3.7.3",
9133
- "oh-my-opencode-linux-arm64-musl": "3.7.3",
9134
- "oh-my-opencode-linux-x64": "3.7.3",
9135
- "oh-my-opencode-linux-x64-musl": "3.7.3",
9136
- "oh-my-opencode-windows-x64": "3.7.3"
9325
+ "oh-my-opencode-darwin-arm64": "3.8.0",
9326
+ "oh-my-opencode-darwin-x64": "3.8.0",
9327
+ "oh-my-opencode-linux-arm64": "3.8.0",
9328
+ "oh-my-opencode-linux-arm64-musl": "3.8.0",
9329
+ "oh-my-opencode-linux-x64": "3.8.0",
9330
+ "oh-my-opencode-linux-x64-musl": "3.8.0",
9331
+ "oh-my-opencode-windows-x64": "3.8.0"
9137
9332
  },
9138
9333
  trustedDependencies: [
9139
9334
  "@ast-grep/cli",
@@ -9366,7 +9561,7 @@ async function runCliInstaller(args, version) {
9366
9561
  console.log();
9367
9562
  }
9368
9563
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
9369
- printWarning("No model providers configured. Using opencode/glm-4.7-free as fallback.");
9564
+ printWarning("No model providers configured. Using opencode/big-pickle as fallback.");
9370
9565
  }
9371
9566
  console.log(`${SYMBOLS.star} ${import_picocolors2.default.bold(import_picocolors2.default.green(isUpdate ? "Configuration updated!" : "Installation complete!"))}`);
9372
9567
  console.log(` Run ${import_picocolors2.default.cyan("opencode")} to start!`);
@@ -9992,9 +10187,9 @@ async function promptInstallConfig(detected) {
9992
10187
  const claude = await selectOrCancel({
9993
10188
  message: "Do you have a Claude Pro/Max subscription?",
9994
10189
  options: [
9995
- { value: "no", label: "No", hint: "Will use opencode/glm-4.7-free as fallback" },
10190
+ { value: "no", label: "No", hint: "Will use opencode/big-pickle as fallback" },
9996
10191
  { value: "yes", label: "Yes (standard)", hint: "Claude Opus 4.5 for orchestration" },
9997
- { value: "max20", label: "Yes (max20 mode)", hint: "Full power with Claude Sonnet 4.5 for Librarian" }
10192
+ { value: "max20", label: "Yes (max20 mode)", hint: "Full power with Claude Sonnet 4.6 for Librarian" }
9998
10193
  ],
9999
10194
  initialValue: initial.claude
10000
10195
  });
@@ -10147,7 +10342,7 @@ async function runTuiInstaller(args, version) {
10147
10342
  console.log();
10148
10343
  }
10149
10344
  if (!config.hasClaude && !config.hasOpenAI && !config.hasGemini && !config.hasCopilot && !config.hasOpencodeZen) {
10150
- M2.warn("No model providers configured. Using opencode/glm-4.7-free as fallback.");
10345
+ M2.warn("No model providers configured. Using opencode/big-pickle as fallback.");
10151
10346
  }
10152
10347
  Me(formatConfigSummary(config), isUpdate ? "Updated Configuration" : "Installation Complete");
10153
10348
  M2.success(import_picocolors4.default.bold(isUpdate ? "Configuration updated!" : "Installation complete!"));
@@ -10212,7 +10407,9 @@ function createEventState() {
10212
10407
  lastThinkingSummary: "",
10213
10408
  textAtLineStart: true,
10214
10409
  thinkingAtLineStart: false,
10215
- currentMessageId: null
10410
+ currentMessageId: null,
10411
+ messageStartedAtById: {},
10412
+ completionMetaPrintedByMessageId: {}
10216
10413
  };
10217
10414
  }
10218
10415
  // src/cli/run/event-formatting.ts
@@ -10572,6 +10769,19 @@ function getPartMessageId(props) {
10572
10769
  function getDeltaMessageId(props) {
10573
10770
  return props?.messageID;
10574
10771
  }
10772
+ function renderCompletionMetaLine(state, messageID) {
10773
+ if (state.completionMetaPrintedByMessageId[messageID])
10774
+ return;
10775
+ const startedAt = state.messageStartedAtById[messageID];
10776
+ const elapsedSec = startedAt ? ((Date.now() - startedAt) / 1000).toFixed(1) : "0.0";
10777
+ const agent = state.currentAgent ?? "assistant";
10778
+ const model = state.currentModel ?? "unknown-model";
10779
+ const variant = state.currentVariant ? ` (${state.currentVariant})` : "";
10780
+ process.stdout.write(import_picocolors7.default.dim(`
10781
+ ${displayChars.treeEnd} ${agent} \xB7 ${model}${variant} \xB7 ${elapsedSec}s
10782
+ `));
10783
+ state.completionMetaPrintedByMessageId[messageID] = true;
10784
+ }
10575
10785
  function handleSessionIdle(ctx, payload, state) {
10576
10786
  if (payload.type !== "session.idle")
10577
10787
  return;
@@ -10646,6 +10856,12 @@ function handleMessagePartUpdated(ctx, payload, state) {
10646
10856
  state.hasReceivedMeaningfulWork = true;
10647
10857
  }
10648
10858
  state.lastPartText = part.text;
10859
+ if (part.time?.end) {
10860
+ const messageID = part.messageID ?? state.currentMessageId;
10861
+ if (messageID) {
10862
+ renderCompletionMetaLine(state, messageID);
10863
+ }
10864
+ }
10649
10865
  }
10650
10866
  if (part.type === "tool") {
10651
10867
  handleToolPart(ctx, part, state);
@@ -10740,6 +10956,10 @@ function handleMessageUpdated(ctx, payload, state) {
10740
10956
  state.textAtLineStart = true;
10741
10957
  state.thinkingAtLineStart = false;
10742
10958
  closeThinkBlockIfNeeded(state);
10959
+ if (messageID) {
10960
+ state.messageStartedAtById[messageID] = Date.now();
10961
+ state.completionMetaPrintedByMessageId[messageID] = false;
10962
+ }
10743
10963
  }
10744
10964
  const agent = props?.info?.agent ?? null;
10745
10965
  const model = props?.info?.modelID ?? null;
@@ -23208,6 +23428,9 @@ var OverridableAgentNameSchema = exports_external.enum([
23208
23428
  "multimodal-looker",
23209
23429
  "atlas"
23210
23430
  ]);
23431
+ // src/config/schema/fallback-models.ts
23432
+ var FallbackModelsSchema = exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]);
23433
+
23211
23434
  // src/config/schema/internal/permission.ts
23212
23435
  var PermissionValueSchema = exports_external.enum(["ask", "allow", "deny"]);
23213
23436
  var BashPermissionSchema = exports_external.union([
@@ -23226,6 +23449,7 @@ var AgentPermissionSchema = exports_external.object({
23226
23449
  // src/config/schema/agent-overrides.ts
23227
23450
  var AgentOverrideConfigSchema = exports_external.object({
23228
23451
  model: exports_external.string().optional(),
23452
+ fallback_models: FallbackModelsSchema.optional(),
23229
23453
  variant: exports_external.string().optional(),
23230
23454
  category: exports_external.string().optional(),
23231
23455
  skills: exports_external.array(exports_external.string()).optional(),
@@ -23246,7 +23470,11 @@ var AgentOverrideConfigSchema = exports_external.object({
23246
23470
  }).optional(),
23247
23471
  reasoningEffort: exports_external.enum(["low", "medium", "high", "xhigh"]).optional(),
23248
23472
  textVerbosity: exports_external.enum(["low", "medium", "high"]).optional(),
23249
- providerOptions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
23473
+ providerOptions: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
23474
+ ultrawork: exports_external.object({
23475
+ model: exports_external.string().optional(),
23476
+ variant: exports_external.string().optional()
23477
+ }).optional()
23250
23478
  });
23251
23479
  var AgentOverridesSchema = exports_external.object({
23252
23480
  build: AgentOverrideConfigSchema.optional(),
@@ -23290,6 +23518,7 @@ var BrowserAutomationConfigSchema = exports_external.object({
23290
23518
  var CategoryConfigSchema = exports_external.object({
23291
23519
  description: exports_external.string().optional(),
23292
23520
  model: exports_external.string().optional(),
23521
+ fallback_models: FallbackModelsSchema.optional(),
23293
23522
  variant: exports_external.string().optional(),
23294
23523
  temperature: exports_external.number().min(0).max(2).optional(),
23295
23524
  top_p: exports_external.number().min(0).max(1).optional(),
@@ -23381,7 +23610,9 @@ var ExperimentalConfigSchema = exports_external.object({
23381
23610
  task_system: exports_external.boolean().optional(),
23382
23611
  plugin_load_timeout_ms: exports_external.number().min(1000).optional(),
23383
23612
  safe_hook_creation: exports_external.boolean().optional(),
23384
- hashline_edit: exports_external.boolean().optional()
23613
+ disable_omo_env: exports_external.boolean().optional(),
23614
+ hashline_edit: exports_external.boolean().optional(),
23615
+ model_fallback_title: exports_external.boolean().optional()
23385
23616
  });
23386
23617
  // src/config/schema/git-master.ts
23387
23618
  var GitMasterConfigSchema = exports_external.object({
@@ -23395,13 +23626,13 @@ var HookNameSchema = exports_external.enum([
23395
23626
  "session-recovery",
23396
23627
  "session-notification",
23397
23628
  "comment-checker",
23398
- "grep-output-truncator",
23399
23629
  "tool-output-truncator",
23400
23630
  "question-label-truncator",
23401
23631
  "directory-agents-injector",
23402
23632
  "directory-readme-injector",
23403
23633
  "empty-task-response-detector",
23404
23634
  "think-mode",
23635
+ "model-fallback",
23405
23636
  "anthropic-context-window-limit-recovery",
23406
23637
  "preemptive-compaction",
23407
23638
  "rules-injector",
@@ -23424,14 +23655,15 @@ var HookNameSchema = exports_external.enum([
23424
23655
  "delegate-task-retry",
23425
23656
  "prometheus-md-only",
23426
23657
  "sisyphus-junior-notepad",
23427
- "sisyphus-gpt-hephaestus-reminder",
23658
+ "no-sisyphus-gpt",
23659
+ "no-hephaestus-non-gpt",
23428
23660
  "start-work",
23429
23661
  "atlas",
23430
23662
  "unstable-agent-babysitter",
23431
- "task-reminder",
23432
23663
  "task-resume-info",
23433
23664
  "stop-continuation-guard",
23434
23665
  "tasks-todowrite-disabler",
23666
+ "runtime-fallback",
23435
23667
  "write-existing-file-guard",
23436
23668
  "anthropic-effort",
23437
23669
  "hashline-read-enhancer"
@@ -23448,7 +23680,18 @@ var AnyMcpNameSchema = exports_external.string().min(1);
23448
23680
  var RalphLoopConfigSchema = exports_external.object({
23449
23681
  enabled: exports_external.boolean().default(false),
23450
23682
  default_max_iterations: exports_external.number().min(1).max(1000).default(100),
23451
- state_dir: exports_external.string().optional()
23683
+ state_dir: exports_external.string().optional(),
23684
+ default_strategy: exports_external.enum(["reset", "continue"]).default("continue")
23685
+ });
23686
+
23687
+ // src/config/schema/runtime-fallback.ts
23688
+ var RuntimeFallbackConfigSchema = exports_external.object({
23689
+ enabled: exports_external.boolean().optional(),
23690
+ retry_on_errors: exports_external.array(exports_external.number()).optional(),
23691
+ max_fallback_attempts: exports_external.number().min(1).max(20).optional(),
23692
+ cooldown_seconds: exports_external.number().min(0).optional(),
23693
+ timeout_seconds: exports_external.number().min(0).optional(),
23694
+ notify_on_fallback: exports_external.boolean().optional()
23452
23695
  });
23453
23696
 
23454
23697
  // src/config/schema/skills.ts
@@ -23532,9 +23775,10 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
23532
23775
  disabled_mcps: exports_external.array(AnyMcpNameSchema).optional(),
23533
23776
  disabled_agents: exports_external.array(BuiltinAgentNameSchema).optional(),
23534
23777
  disabled_skills: exports_external.array(BuiltinSkillNameSchema).optional(),
23535
- disabled_hooks: exports_external.array(HookNameSchema).optional(),
23778
+ disabled_hooks: exports_external.array(exports_external.string()).optional(),
23536
23779
  disabled_commands: exports_external.array(BuiltinCommandNameSchema).optional(),
23537
23780
  disabled_tools: exports_external.array(exports_external.string()).optional(),
23781
+ hashline_edit: exports_external.boolean().optional(),
23538
23782
  agents: AgentOverridesSchema.optional(),
23539
23783
  categories: CategoriesConfigSchema.optional(),
23540
23784
  claude_code: ClaudeCodeConfigSchema.optional(),
@@ -23544,6 +23788,7 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
23544
23788
  auto_update: exports_external.boolean().optional(),
23545
23789
  skills: SkillsConfigSchema.optional(),
23546
23790
  ralph_loop: RalphLoopConfigSchema.optional(),
23791
+ runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
23547
23792
  background_task: BackgroundTaskConfigSchema.optional(),
23548
23793
  notification: NotificationConfigSchema.optional(),
23549
23794
  babysitting: BabysittingConfigSchema.optional(),
@@ -25192,26 +25437,6 @@ async function withWorkingOpencodePath(startServer, finder = findWorkingOpencode
25192
25437
  }
25193
25438
  }
25194
25439
 
25195
- // src/cli/run/opencode-bin-path.ts
25196
- import { delimiter as delimiter2, dirname as dirname2 } from "path";
25197
- import { createRequire } from "module";
25198
- var resolveFromCurrentModule = createRequire(import.meta.url).resolve;
25199
- function prependResolvedOpencodeBinToPath(env = process.env, resolve2 = resolveFromCurrentModule) {
25200
- let resolvedPath;
25201
- try {
25202
- resolvedPath = resolve2("opencode-ai/bin/opencode");
25203
- } catch {
25204
- return;
25205
- }
25206
- const opencodeBinDir = dirname2(resolvedPath);
25207
- const currentPath = env.PATH ?? "";
25208
- const pathSegments = currentPath ? currentPath.split(delimiter2) : [];
25209
- if (pathSegments.includes(opencodeBinDir)) {
25210
- return;
25211
- }
25212
- env.PATH = currentPath ? `${opencodeBinDir}${delimiter2}${currentPath}` : opencodeBinDir;
25213
- }
25214
-
25215
25440
  // src/cli/run/server-connection.ts
25216
25441
  function isPortStartFailure(error45, port) {
25217
25442
  if (!(error45 instanceof Error)) {
@@ -25219,6 +25444,12 @@ function isPortStartFailure(error45, port) {
25219
25444
  }
25220
25445
  return error45.message.includes(`Failed to start server on port ${port}`);
25221
25446
  }
25447
+ function isPortRangeExhausted(error45) {
25448
+ if (!(error45 instanceof Error)) {
25449
+ return false;
25450
+ }
25451
+ return error45.message.includes("No available port found in range");
25452
+ }
25222
25453
  async function startServer(options) {
25223
25454
  const { signal, port } = options;
25224
25455
  const { client: client3, server: server2 } = await withWorkingOpencodePath(() => createOpencode({ signal, port, hostname: "127.0.0.1" }));
@@ -25226,7 +25457,6 @@ async function startServer(options) {
25226
25457
  return { client: client3, cleanup: () => server2.close() };
25227
25458
  }
25228
25459
  async function createServerConnection(options) {
25229
- prependResolvedOpencodeBinToPath();
25230
25460
  const { port, attach, signal } = options;
25231
25461
  if (attach !== undefined) {
25232
25462
  console.log(import_picocolors9.default.dim("Attaching to existing server at"), import_picocolors9.default.cyan(attach));
@@ -25259,7 +25489,24 @@ async function createServerConnection(options) {
25259
25489
  const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
25260
25490
  return { client: client3, cleanup: () => {} };
25261
25491
  }
25262
- const { port: selectedPort, wasAutoSelected } = await getAvailableServerPort(DEFAULT_SERVER_PORT, "127.0.0.1");
25492
+ let selectedPort;
25493
+ let wasAutoSelected;
25494
+ try {
25495
+ const selected = await getAvailableServerPort(DEFAULT_SERVER_PORT, "127.0.0.1");
25496
+ selectedPort = selected.port;
25497
+ wasAutoSelected = selected.wasAutoSelected;
25498
+ } catch (error45) {
25499
+ if (!isPortRangeExhausted(error45)) {
25500
+ throw error45;
25501
+ }
25502
+ const defaultPortIsAvailable = await isPortAvailable(DEFAULT_SERVER_PORT, "127.0.0.1");
25503
+ if (defaultPortIsAvailable) {
25504
+ throw error45;
25505
+ }
25506
+ console.log(import_picocolors9.default.dim("Port range exhausted, attaching to existing server on"), import_picocolors9.default.cyan(DEFAULT_SERVER_PORT.toString()));
25507
+ const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` });
25508
+ return { client: client3, cleanup: () => {} };
25509
+ }
25263
25510
  if (wasAutoSelected) {
25264
25511
  console.log(import_picocolors9.default.dim("Auto-selected port"), import_picocolors9.default.cyan(selectedPort.toString()));
25265
25512
  } else {
@@ -25457,7 +25704,7 @@ var NOTEPAD_DIR = "notepads";
25457
25704
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
25458
25705
  // src/features/boulder-state/storage.ts
25459
25706
  import { existsSync as existsSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync3, readdirSync } from "fs";
25460
- import { dirname as dirname3, join as join9, basename } from "path";
25707
+ import { dirname as dirname2, join as join9, basename } from "path";
25461
25708
  function getBoulderFilePath(directory) {
25462
25709
  return join9(directory, BOULDER_DIR, BOULDER_FILE);
25463
25710
  }
@@ -25538,7 +25785,7 @@ function getActiveContinuationMarkerReason(marker) {
25538
25785
  // src/hooks/ralph-loop/storage.ts
25539
25786
  init_frontmatter();
25540
25787
  import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync9, unlinkSync, mkdirSync as mkdirSync5 } from "fs";
25541
- import { dirname as dirname4, join as join11 } from "path";
25788
+ import { dirname as dirname3, join as join11 } from "path";
25542
25789
 
25543
25790
  // src/hooks/ralph-loop/constants.ts
25544
25791
  var DEFAULT_STATE_FILE = ".sisyphus/ralph-loop.local.md";
@@ -25579,7 +25826,8 @@ function readState(directory, customPath) {
25579
25826
  started_at: stripQuotes(data.started_at) || new Date().toISOString(),
25580
25827
  prompt: body.trim(),
25581
25828
  session_id: data.session_id ? stripQuotes(data.session_id) : undefined,
25582
- ultrawork: data.ultrawork === true || data.ultrawork === "true" ? true : undefined
25829
+ ultrawork: data.ultrawork === true || data.ultrawork === "true" ? true : undefined,
25830
+ strategy: data.strategy === "reset" || data.strategy === "continue" ? data.strategy : undefined
25583
25831
  };
25584
25832
  } catch {
25585
25833
  return null;
@@ -25623,7 +25871,7 @@ async function checkCompletionConditions(ctx) {
25623
25871
  const continuationState = getContinuationState(ctx.directory, ctx.sessionID);
25624
25872
  if (continuationState.hasActiveHookMarker) {
25625
25873
  const reason = continuationState.activeHookMarkerReason ?? "continuation hook is active";
25626
- console.log(import_picocolors13.default.dim(` Waiting: ${reason}`));
25874
+ logWaiting(ctx, reason);
25627
25875
  return false;
25628
25876
  }
25629
25877
  if (!continuationState.hasTodoHookMarker && !await areAllTodosComplete(ctx)) {
@@ -25632,7 +25880,7 @@ async function checkCompletionConditions(ctx) {
25632
25880
  if (!await areAllChildrenIdle(ctx)) {
25633
25881
  return false;
25634
25882
  }
25635
- if (!areContinuationHooksIdle(continuationState)) {
25883
+ if (!areContinuationHooksIdle(ctx, continuationState)) {
25636
25884
  return false;
25637
25885
  }
25638
25886
  return true;
@@ -25641,13 +25889,13 @@ async function checkCompletionConditions(ctx) {
25641
25889
  return false;
25642
25890
  }
25643
25891
  }
25644
- function areContinuationHooksIdle(continuationState) {
25892
+ function areContinuationHooksIdle(ctx, continuationState) {
25645
25893
  if (continuationState.hasActiveBoulder) {
25646
- console.log(import_picocolors13.default.dim(" Waiting: boulder continuation is active"));
25894
+ logWaiting(ctx, "boulder continuation is active");
25647
25895
  return false;
25648
25896
  }
25649
25897
  if (continuationState.hasActiveRalphLoop) {
25650
- console.log(import_picocolors13.default.dim(" Waiting: ralph-loop continuation is active"));
25898
+ logWaiting(ctx, "ralph-loop continuation is active");
25651
25899
  return false;
25652
25900
  }
25653
25901
  return true;
@@ -25660,7 +25908,7 @@ async function areAllTodosComplete(ctx) {
25660
25908
  const todos = normalizeSDKResponse(todosRes, []);
25661
25909
  const incompleteTodos = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
25662
25910
  if (incompleteTodos.length > 0) {
25663
- console.log(import_picocolors13.default.dim(` Waiting: ${incompleteTodos.length} todos remaining`));
25911
+ logWaiting(ctx, `${incompleteTodos.length} todos remaining`);
25664
25912
  return false;
25665
25913
  }
25666
25914
  return true;
@@ -25684,7 +25932,7 @@ async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
25684
25932
  for (const child of children) {
25685
25933
  const status = allStatuses[child.id];
25686
25934
  if (status && status.type !== "idle") {
25687
- console.log(import_picocolors13.default.dim(` Waiting: session ${child.id.slice(0, 8)}... is ${status.type}`));
25935
+ logWaiting(ctx, `session ${child.id.slice(0, 8)}... is ${status.type}`);
25688
25936
  return false;
25689
25937
  }
25690
25938
  const descendantsIdle = await areAllDescendantsIdle(ctx, child.id, allStatuses);
@@ -25694,17 +25942,24 @@ async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
25694
25942
  }
25695
25943
  return true;
25696
25944
  }
25945
+ function logWaiting(ctx, message) {
25946
+ if (!ctx.verbose) {
25947
+ return;
25948
+ }
25949
+ console.log(import_picocolors13.default.dim(` Waiting: ${message}`));
25950
+ }
25697
25951
 
25698
25952
  // src/cli/run/poll-for-completion.ts
25699
25953
  init_shared();
25700
25954
  var DEFAULT_POLL_INTERVAL_MS = 500;
25701
25955
  var DEFAULT_REQUIRED_CONSECUTIVE = 1;
25702
25956
  var ERROR_GRACE_CYCLES = 3;
25703
- var MIN_STABILIZATION_MS = 0;
25957
+ var MIN_STABILIZATION_MS = 1000;
25704
25958
  async function pollForCompletion(ctx, eventState, abortController, options = {}) {
25705
25959
  const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
25706
25960
  const requiredConsecutive = options.requiredConsecutive ?? DEFAULT_REQUIRED_CONSECUTIVE;
25707
- const minStabilizationMs = options.minStabilizationMs ?? MIN_STABILIZATION_MS;
25961
+ const rawMinStabilizationMs = options.minStabilizationMs ?? MIN_STABILIZATION_MS;
25962
+ const minStabilizationMs = rawMinStabilizationMs > 0 ? rawMinStabilizationMs : MIN_STABILIZATION_MS;
25708
25963
  let consecutiveCompleteChecks = 0;
25709
25964
  let errorCycleCount = 0;
25710
25965
  let firstWorkTimestamp = null;
@@ -25742,22 +25997,18 @@ Session ended with error: ${eventState.lastError}`));
25742
25997
  continue;
25743
25998
  }
25744
25999
  if (!eventState.hasReceivedMeaningfulWork) {
25745
- if (minStabilizationMs <= 0) {
26000
+ if (Date.now() - pollStartTimestamp < minStabilizationMs) {
25746
26001
  consecutiveCompleteChecks = 0;
25747
26002
  continue;
25748
26003
  }
25749
- if (Date.now() - pollStartTimestamp < minStabilizationMs) {
26004
+ } else {
26005
+ if (firstWorkTimestamp === null) {
26006
+ firstWorkTimestamp = Date.now();
26007
+ }
26008
+ if (Date.now() - firstWorkTimestamp < minStabilizationMs) {
25750
26009
  consecutiveCompleteChecks = 0;
25751
26010
  continue;
25752
26011
  }
25753
- consecutiveCompleteChecks = 0;
25754
- }
25755
- if (firstWorkTimestamp === null) {
25756
- firstWorkTimestamp = Date.now();
25757
- }
25758
- if (Date.now() - firstWorkTimestamp < minStabilizationMs) {
25759
- consecutiveCompleteChecks = 0;
25760
- continue;
25761
26012
  }
25762
26013
  const shouldExit = await checkCompletionConditions(ctx);
25763
26014
  if (shouldExit) {
@@ -25813,6 +26064,92 @@ async function loadAgentProfileColors(client3) {
25813
26064
  }
25814
26065
  }
25815
26066
 
26067
+ // src/cli/run/stdin-suppression.ts
26068
+ function includesCtrlC(chunk) {
26069
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
26070
+ return text.includes("\x03");
26071
+ }
26072
+ function suppressRunInput(stdin = process.stdin, onInterrupt = () => {
26073
+ process.kill(process.pid, "SIGINT");
26074
+ }) {
26075
+ if (!stdin.isTTY) {
26076
+ return () => {};
26077
+ }
26078
+ const wasRaw = stdin.isRaw === true;
26079
+ const wasPaused = stdin.isPaused?.() ?? false;
26080
+ const canSetRawMode = typeof stdin.setRawMode === "function";
26081
+ const onData = (chunk) => {
26082
+ if (includesCtrlC(chunk)) {
26083
+ onInterrupt();
26084
+ }
26085
+ };
26086
+ if (canSetRawMode) {
26087
+ stdin.setRawMode(true);
26088
+ }
26089
+ stdin.on("data", onData);
26090
+ stdin.resume();
26091
+ return () => {
26092
+ stdin.removeListener("data", onData);
26093
+ if (canSetRawMode) {
26094
+ stdin.setRawMode(wasRaw);
26095
+ }
26096
+ if (wasPaused) {
26097
+ stdin.pause();
26098
+ }
26099
+ };
26100
+ }
26101
+
26102
+ // src/cli/run/timestamp-output.ts
26103
+ function formatTimestamp(date5) {
26104
+ const hh = String(date5.getHours()).padStart(2, "0");
26105
+ const mm = String(date5.getMinutes()).padStart(2, "0");
26106
+ const ss = String(date5.getSeconds()).padStart(2, "0");
26107
+ return `${hh}:${mm}:${ss}`;
26108
+ }
26109
+ function createTimestampTransformer(now = () => new Date) {
26110
+ let atLineStart = true;
26111
+ return (chunk) => {
26112
+ if (!chunk)
26113
+ return "";
26114
+ let output = "";
26115
+ for (let i2 = 0;i2 < chunk.length; i2++) {
26116
+ const ch = chunk[i2];
26117
+ if (atLineStart) {
26118
+ output += `[${formatTimestamp(now())}] `;
26119
+ atLineStart = false;
26120
+ }
26121
+ output += ch;
26122
+ if (ch === `
26123
+ `) {
26124
+ atLineStart = true;
26125
+ }
26126
+ }
26127
+ return output;
26128
+ };
26129
+ }
26130
+ function createTimestampedStdoutController(stdout = process.stdout) {
26131
+ const originalWrite = stdout.write.bind(stdout);
26132
+ const transform2 = createTimestampTransformer();
26133
+ function enable() {
26134
+ const write = (chunk, encodingOrCallback, callback) => {
26135
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString(typeof encodingOrCallback === "string" ? encodingOrCallback : undefined);
26136
+ const stamped = transform2(text);
26137
+ if (typeof encodingOrCallback === "function") {
26138
+ return originalWrite(stamped, encodingOrCallback);
26139
+ }
26140
+ if (encodingOrCallback !== undefined) {
26141
+ return originalWrite(stamped, encodingOrCallback, callback);
26142
+ }
26143
+ return originalWrite(stamped);
26144
+ };
26145
+ stdout.write = write;
26146
+ }
26147
+ function restore() {
26148
+ stdout.write = originalWrite;
26149
+ }
26150
+ return { enable, restore };
26151
+ }
26152
+
25816
26153
  // src/cli/run/runner.ts
25817
26154
  var EVENT_PROCESSOR_SHUTDOWN_TIMEOUT_MS = 2000;
25818
26155
  async function waitForEventProcessorShutdown(eventProcessor, timeoutMs = EVENT_PROCESSOR_SHUTDOWN_TIMEOUT_MS) {
@@ -25831,6 +26168,8 @@ async function run(options) {
25831
26168
  const jsonManager = options.json ? createJsonOutputManager() : null;
25832
26169
  if (jsonManager)
25833
26170
  jsonManager.redirectToStderr();
26171
+ const timestampOutput = options.json || options.timestamp === false ? null : createTimestampedStdoutController();
26172
+ timestampOutput?.enable();
25834
26173
  const pluginConfig = loadPluginConfig(directory, { command: "run" });
25835
26174
  const resolvedAgent = resolveRunAgent(options, pluginConfig);
25836
26175
  const abortController = new AbortController;
@@ -25843,12 +26182,15 @@ async function run(options) {
25843
26182
  const cleanup = () => {
25844
26183
  serverCleanup();
25845
26184
  };
25846
- process.on("SIGINT", () => {
26185
+ const restoreInput = suppressRunInput();
26186
+ const handleSigint = () => {
25847
26187
  console.log(import_picocolors15.default.yellow(`
25848
26188
  Interrupted. Shutting down...`));
26189
+ restoreInput();
25849
26190
  cleanup();
25850
26191
  process.exit(130);
25851
- });
26192
+ };
26193
+ process.on("SIGINT", handleSigint);
25852
26194
  try {
25853
26195
  const sessionID = await resolveSession({
25854
26196
  client: client3,
@@ -25871,6 +26213,9 @@ Interrupted. Shutting down...`));
25871
26213
  path: { id: sessionID },
25872
26214
  body: {
25873
26215
  agent: resolvedAgent,
26216
+ tools: {
26217
+ question: false
26218
+ },
25874
26219
  parts: [{ type: "text", text: message }]
25875
26220
  },
25876
26221
  query: { directory }
@@ -25902,15 +26247,21 @@ Interrupted. Shutting down...`));
25902
26247
  } catch (err) {
25903
26248
  cleanup();
25904
26249
  throw err;
26250
+ } finally {
26251
+ process.removeListener("SIGINT", handleSigint);
26252
+ restoreInput();
25905
26253
  }
25906
26254
  } catch (err) {
25907
26255
  if (jsonManager)
25908
26256
  jsonManager.restore();
26257
+ timestampOutput?.restore();
25909
26258
  if (err instanceof Error && err.name === "AbortError") {
25910
26259
  return 130;
25911
26260
  }
25912
26261
  console.error(import_picocolors15.default.red(`Error: ${serializeError(err)}`));
25913
26262
  return 1;
26263
+ } finally {
26264
+ timestampOutput?.restore();
25914
26265
  }
25915
26266
  }
25916
26267
  // src/cli/get-local-version/get-local-version.ts
@@ -26250,7 +26601,7 @@ function getPluginInfo() {
26250
26601
  registered: true,
26251
26602
  configPath,
26252
26603
  entry: pluginEntry.entry,
26253
- isPinned: pinnedVersion !== null,
26604
+ isPinned: pinnedVersion !== null && /^\d+\.\d+\.\d+/.test(pinnedVersion),
26254
26605
  pinnedVersion,
26255
26606
  isLocalDev: pluginEntry.isLocalDev
26256
26607
  };
@@ -26780,8 +27131,8 @@ async function checkConfig() {
26780
27131
 
26781
27132
  // src/cli/doctor/checks/dependencies.ts
26782
27133
  import { existsSync as existsSync24 } from "fs";
26783
- import { createRequire as createRequire2 } from "module";
26784
- import { dirname as dirname7, join as join22 } from "path";
27134
+ import { createRequire } from "module";
27135
+ import { dirname as dirname6, join as join22 } from "path";
26785
27136
  async function checkBinaryExists(binary2) {
26786
27137
  try {
26787
27138
  const path9 = Bun.which(binary2);
@@ -26868,9 +27219,9 @@ async function checkAstGrepNapi() {
26868
27219
  function findCommentCheckerPackageBinary() {
26869
27220
  const binaryName = process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
26870
27221
  try {
26871
- const require2 = createRequire2(import.meta.url);
27222
+ const require2 = createRequire(import.meta.url);
26872
27223
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
26873
- const binaryPath = join22(dirname7(pkgPath), "bin", binaryName);
27224
+ const binaryPath = join22(dirname6(pkgPath), "bin", binaryName);
26874
27225
  if (existsSync24(binaryPath))
26875
27226
  return binaryPath;
26876
27227
  } catch {}
@@ -27488,7 +27839,7 @@ async function doctor(options = { mode: "default" }) {
27488
27839
  // src/features/mcp-oauth/storage.ts
27489
27840
  init_shared();
27490
27841
  import { chmodSync, existsSync as existsSync27, mkdirSync as mkdirSync6, readFileSync as readFileSync28, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "fs";
27491
- import { dirname as dirname8, join as join25 } from "path";
27842
+ import { dirname as dirname7, join as join25 } from "path";
27492
27843
  var STORAGE_FILE_NAME = "mcp-oauth.json";
27493
27844
  function getMcpOauthStoragePath() {
27494
27845
  return join25(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
@@ -27538,14 +27889,14 @@ function readStore() {
27538
27889
  return null;
27539
27890
  }
27540
27891
  }
27541
- function writeStore(store) {
27892
+ function writeStore(store2) {
27542
27893
  const filePath = getMcpOauthStoragePath();
27543
27894
  try {
27544
- const dir = dirname8(filePath);
27895
+ const dir = dirname7(filePath);
27545
27896
  if (!existsSync27(dir)) {
27546
27897
  mkdirSync6(dir, { recursive: true });
27547
27898
  }
27548
- writeFileSync12(filePath, JSON.stringify(store, null, 2), { encoding: "utf-8", mode: 384 });
27899
+ writeFileSync12(filePath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
27549
27900
  chmodSync(filePath, 384);
27550
27901
  return true;
27551
27902
  } catch {
@@ -27553,28 +27904,28 @@ function writeStore(store) {
27553
27904
  }
27554
27905
  }
27555
27906
  function loadToken(serverHost, resource) {
27556
- const store = readStore();
27557
- if (!store)
27907
+ const store2 = readStore();
27908
+ if (!store2)
27558
27909
  return null;
27559
27910
  const key = buildKey(serverHost, resource);
27560
- return store[key] ?? null;
27911
+ return store2[key] ?? null;
27561
27912
  }
27562
27913
  function saveToken(serverHost, resource, token) {
27563
- const store = readStore() ?? {};
27914
+ const store2 = readStore() ?? {};
27564
27915
  const key = buildKey(serverHost, resource);
27565
- store[key] = token;
27566
- return writeStore(store);
27916
+ store2[key] = token;
27917
+ return writeStore(store2);
27567
27918
  }
27568
27919
  function deleteToken(serverHost, resource) {
27569
- const store = readStore();
27570
- if (!store)
27920
+ const store2 = readStore();
27921
+ if (!store2)
27571
27922
  return true;
27572
27923
  const key = buildKey(serverHost, resource);
27573
- if (!(key in store)) {
27924
+ if (!(key in store2)) {
27574
27925
  return true;
27575
27926
  }
27576
- delete store[key];
27577
- if (Object.keys(store).length === 0) {
27927
+ delete store2[key];
27928
+ if (Object.keys(store2).length === 0) {
27578
27929
  try {
27579
27930
  const filePath = getMcpOauthStoragePath();
27580
27931
  if (existsSync27(filePath)) {
@@ -27585,16 +27936,16 @@ function deleteToken(serverHost, resource) {
27585
27936
  return false;
27586
27937
  }
27587
27938
  }
27588
- return writeStore(store);
27939
+ return writeStore(store2);
27589
27940
  }
27590
27941
  function listTokensByHost(serverHost) {
27591
- const store = readStore();
27592
- if (!store)
27942
+ const store2 = readStore();
27943
+ if (!store2)
27593
27944
  return {};
27594
27945
  const host = normalizeHost(serverHost);
27595
27946
  const prefix = `${host}/`;
27596
27947
  const result = {};
27597
- for (const [key, value] of Object.entries(store)) {
27948
+ for (const [key, value] of Object.entries(store2)) {
27598
27949
  if (key.startsWith(prefix)) {
27599
27950
  result[key] = value;
27600
27951
  }
@@ -28123,7 +28474,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
28123
28474
  Gemini Native google/ models (Gemini 3 Pro, Flash)
28124
28475
  Copilot github-copilot/ models (fallback)
28125
28476
  OpenCode Zen opencode/ models (opencode/claude-opus-4-6, etc.)
28126
- Z.ai zai-coding-plan/glm-4.7 (Librarian priority)
28477
+ Z.ai zai-coding-plan/glm-5 (visual-engineering fallback)
28127
28478
  Kimi kimi-for-coding/k2p5 (Sisyphus/Prometheus fallback)
28128
28479
  `).action(async (options) => {
28129
28480
  const args = {
@@ -28140,7 +28491,7 @@ Model Providers (Priority: Native > Copilot > OpenCode Zen > Z.ai > Kimi):
28140
28491
  const exitCode = await install(args);
28141
28492
  process.exit(exitCode);
28142
28493
  });
28143
- 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("--verbose", "Show full event stream (default: messages/tools only)").option("--session-id <id>", "Resume existing session instead of creating new one").addHelpText("after", `
28494
+ 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", `
28144
28495
  Examples:
28145
28496
  $ bunx oh-my-opencode run "Fix the bug in index.ts"
28146
28497
  $ bunx oh-my-opencode run --agent Sisyphus "Implement feature X"
@@ -28175,6 +28526,7 @@ Unlike 'opencode run', this command waits until:
28175
28526
  attach: options.attach,
28176
28527
  onComplete: options.onComplete,
28177
28528
  json: options.json ?? false,
28529
+ timestamp: options.timestamp ?? true,
28178
28530
  verbose: options.verbose ?? false,
28179
28531
  sessionId: options.sessionId
28180
28532
  };