oh-my-opencode 4.1.2 → 4.2.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 (255) hide show
  1. package/README.ja.md +1 -0
  2. package/README.ko.md +1 -0
  3. package/README.md +1 -0
  4. package/README.ru.md +1 -0
  5. package/README.zh-cn.md +1 -0
  6. package/dist/agents/atlas/default-prompt-sections.d.ts +3 -3
  7. package/dist/agents/atlas/gemini-prompt-sections.d.ts +2 -2
  8. package/dist/agents/atlas/gpt-prompt-sections.d.ts +2 -2
  9. package/dist/agents/atlas/kimi-prompt-sections.d.ts +3 -3
  10. package/dist/agents/atlas/opus-4-7-prompt-sections.d.ts +3 -3
  11. package/dist/agents/momus.d.ts +1 -1
  12. package/dist/agents/prometheus/behavioral-summary.d.ts +1 -1
  13. package/dist/agents/prometheus/high-accuracy-mode.d.ts +1 -1
  14. package/dist/agents/prometheus/identity-constraints.d.ts +1 -1
  15. package/dist/agents/prometheus/plan-generation.d.ts +1 -1
  16. package/dist/agents/prometheus/plan-template.d.ts +1 -1
  17. package/dist/cli/index.js +720 -430
  18. package/dist/cli/run/server-connection.d.ts +32 -2
  19. package/dist/config/schema/team-mode.d.ts +1 -1
  20. package/dist/features/background-agent/error-classifier.d.ts +1 -0
  21. package/dist/features/background-agent/fallback-retry-handler.d.ts +15 -0
  22. package/dist/features/background-agent/manager.d.ts +11 -8
  23. package/dist/features/background-agent/parent-wake-notifier.d.ts +74 -0
  24. package/dist/features/background-agent/process-cleanup.d.ts +2 -0
  25. package/dist/features/background-agent/session-route.d.ts +12 -0
  26. package/dist/features/background-agent/spawner.d.ts +2 -2
  27. package/dist/features/background-agent/task-registry.d.ts +6 -0
  28. package/dist/features/background-agent/types.d.ts +2 -0
  29. package/dist/features/boulder-state/constants.d.ts +4 -4
  30. package/dist/features/boulder-state/storage.d.ts +1 -1
  31. package/dist/features/builtin-commands/templates/init-deep.d.ts +1 -1
  32. package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
  33. package/dist/features/context-injector/injector.d.ts +1 -1
  34. package/dist/features/opencode-skill-loader/git-master-template-injection.d.ts +18 -0
  35. package/dist/features/run-continuation-state/constants.d.ts +1 -1
  36. package/dist/features/team-mode/team-layout-tmux/resolve-caller-tmux-session.d.ts +3 -1
  37. package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +3 -3
  38. package/dist/features/team-mode/tools/messaging.d.ts +1 -0
  39. package/dist/features/team-mode/types.d.ts +2 -2
  40. package/dist/features/tmux-subagent/attachable-session-status.d.ts +1 -1
  41. package/dist/features/tmux-subagent/manager.d.ts +6 -0
  42. package/dist/features/tmux-subagent/pane-state-parser.d.ts +2 -0
  43. package/dist/features/tmux-subagent/polling-manager.d.ts +6 -2
  44. package/dist/features/tmux-subagent/types.d.ts +4 -0
  45. package/dist/hooks/atlas/boulder-continuation-injector.d.ts +1 -0
  46. package/dist/hooks/atlas/omo-path.d.ts +6 -0
  47. package/dist/hooks/atlas/tool-execute-after.d.ts +3 -0
  48. package/dist/hooks/atlas/tool-progress.d.ts +14 -0
  49. package/dist/hooks/atlas/types.d.ts +7 -0
  50. package/dist/hooks/auto-slash-command/detector.d.ts +2 -0
  51. package/dist/hooks/auto-update-checker/cache.d.ts +8 -1
  52. package/dist/hooks/auto-update-checker/checker/cached-version.d.ts +8 -1
  53. package/dist/hooks/background-notification/hook.d.ts +0 -6
  54. package/dist/hooks/compaction-context-injector/types.d.ts +1 -0
  55. package/dist/hooks/interactive-bash-session/state-manager.d.ts +1 -1
  56. package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
  57. package/dist/hooks/keyword-detector/detector.d.ts +1 -0
  58. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +1 -1
  59. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +1 -1
  60. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -1
  61. package/dist/hooks/prometheus-md-only/constants.d.ts +1 -1
  62. package/dist/hooks/prometheus-md-only/path-policy.d.ts +3 -3
  63. package/dist/hooks/ralph-loop/completion-promise-detector-test-input.d.ts +11 -0
  64. package/dist/hooks/ralph-loop/constants.d.ts +1 -1
  65. package/dist/hooks/ralph-loop/continuation-prompt-injector.d.ts +4 -0
  66. package/dist/hooks/ralph-loop/iteration-continuation.d.ts +4 -0
  67. package/dist/hooks/rules-injector/injector.d.ts +9 -2
  68. package/dist/hooks/rules-injector/matcher.d.ts +5 -0
  69. package/dist/hooks/rules-injector/project-root-finder.d.ts +4 -0
  70. package/dist/hooks/rules-injector/rule-scan-cache.d.ts +9 -2
  71. package/dist/hooks/runtime-fallback/constants.d.ts +10 -0
  72. package/dist/hooks/runtime-fallback/first-prompt-watchdog.d.ts +25 -0
  73. package/dist/hooks/runtime-fallback/hook.d.ts +14 -1
  74. package/dist/hooks/runtime-fallback/last-user-retry-parts.d.ts +10 -2
  75. package/dist/hooks/runtime-fallback/types.d.ts +10 -0
  76. package/dist/hooks/session-recovery/detect-error-type.d.ts +1 -1
  77. package/dist/hooks/session-recovery/hook.d.ts +1 -0
  78. package/dist/hooks/session-recovery/interrupted-idle-message-fetch-timeout.d.ts +7 -0
  79. package/dist/hooks/session-recovery/recover-tool-result-missing.d.ts +6 -1
  80. package/dist/hooks/session-recovery/types.d.ts +12 -0
  81. package/dist/hooks/shared/prompt-async-gate.d.ts +1 -0
  82. package/dist/hooks/shared/session-idle-settle.d.ts +1 -11
  83. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  84. package/dist/hooks/team-mode-status-injector/hook.d.ts +2 -1
  85. package/dist/hooks/todo-continuation-enforcer/pending-question-detection.d.ts +2 -0
  86. package/dist/hooks/todo-continuation-enforcer/session-state.d.ts +3 -4
  87. package/dist/hooks/todo-continuation-enforcer/types.d.ts +2 -3
  88. package/dist/hooks/tool-pair-validator/hook.d.ts +7 -2
  89. package/dist/hooks/unstable-agent-babysitter/task-message-analyzer.d.ts +1 -0
  90. package/dist/hooks/write-existing-file-guard/tool-execute-before-handler.d.ts +1 -0
  91. package/dist/index.d.ts +1 -1
  92. package/dist/index.js +8035 -9848
  93. package/dist/mcp/index.d.ts +3 -1
  94. package/dist/mcp/lsp.d.ts +13 -0
  95. package/dist/mcp/types.d.ts +1 -0
  96. package/dist/plugin/build-team-idle-wake-hint-client.d.ts +12 -0
  97. package/dist/plugin/chat-message.d.ts +1 -1
  98. package/dist/plugin/tool-registry.d.ts +1 -2
  99. package/dist/plugin-dispose.d.ts +0 -3
  100. package/dist/shared/agent-sort-shim.d.ts +1 -0
  101. package/dist/shared/delegated-child-session-bootstrap.d.ts +25 -0
  102. package/dist/shared/dynamic-truncator.d.ts +2 -0
  103. package/dist/shared/host-skill-config.d.ts +2 -0
  104. package/dist/shared/index.d.ts +2 -0
  105. package/dist/shared/internal-initiator-marker.d.ts +25 -0
  106. package/dist/shared/legacy-workspace-migration.d.ts +5 -0
  107. package/dist/shared/logger.d.ts +12 -0
  108. package/dist/shared/model-error-classifier.d.ts +2 -0
  109. package/dist/shared/model-resolution-pipeline.d.ts +4 -0
  110. package/dist/shared/opencode-http-api.d.ts +9 -0
  111. package/dist/shared/prompt-async-gate.d.ts +82 -0
  112. package/dist/shared/replace-tool-args.d.ts +13 -0
  113. package/dist/shared/session-idle-settle.d.ts +11 -0
  114. package/dist/shared/tmux/tmux-utils/pane-activate.d.ts +1 -0
  115. package/dist/shared/tmux/tmux-utils/pane-close.d.ts +10 -0
  116. package/dist/shared/tmux/tmux-utils/pane-command.d.ts +2 -0
  117. package/dist/shared/tmux/tmux-utils/pane-replace.d.ts +11 -1
  118. package/dist/shared/tmux/tmux-utils/pane-spawn.d.ts +1 -1
  119. package/dist/shared/tmux/tmux-utils/server-health.d.ts +12 -1
  120. package/dist/shared/tmux/tmux-utils/session-spawn.d.ts +2 -2
  121. package/dist/shared/tmux/tmux-utils/window-spawn.d.ts +1 -1
  122. package/dist/shared/tmux/tmux-utils.d.ts +2 -0
  123. package/dist/testing/create-plugin-module.d.ts +41 -0
  124. package/dist/tools/background-task/constants.d.ts +1 -1
  125. package/dist/tools/background-task/with-sdk-call-timeout.d.ts +7 -0
  126. package/dist/tools/call-omo-agent/session-creator.d.ts +2 -1
  127. package/dist/tools/call-omo-agent/sync-executor.d.ts +2 -2
  128. package/dist/tools/delegate-task/subagent-discovery.d.ts +1 -0
  129. package/dist/tools/delegate-task/sync-prompt-sender.d.ts +2 -1
  130. package/dist/tools/delegate-task/sync-session-creator.d.ts +2 -0
  131. package/dist/tools/delegate-task/sync-task.d.ts +1 -1
  132. package/dist/tools/index.d.ts +0 -3
  133. package/dist/tools/interactive-bash/tools.d.ts +5 -0
  134. package/package.json +18 -16
  135. package/packages/lsp-tools-mcp/dist/cli.d.ts +3 -0
  136. package/packages/lsp-tools-mcp/dist/cli.d.ts.map +1 -0
  137. package/packages/lsp-tools-mcp/dist/cli.js +24 -0
  138. package/packages/lsp-tools-mcp/dist/cli.js.map +1 -0
  139. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +2 -0
  140. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts.map +1 -0
  141. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.js +7 -0
  142. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.js.map +1 -0
  143. package/packages/lsp-tools-mcp/dist/lsp/client-wrapper.d.ts +14 -0
  144. package/packages/lsp-tools-mcp/dist/lsp/client-wrapper.d.ts.map +1 -0
  145. package/packages/lsp-tools-mcp/dist/lsp/client-wrapper.js +110 -0
  146. package/packages/lsp-tools-mcp/dist/lsp/client-wrapper.js.map +1 -0
  147. package/packages/lsp-tools-mcp/dist/lsp/client.d.ts +21 -0
  148. package/packages/lsp-tools-mcp/dist/lsp/client.d.ts.map +1 -0
  149. package/packages/lsp-tools-mcp/dist/lsp/client.js +130 -0
  150. package/packages/lsp-tools-mcp/dist/lsp/client.js.map +1 -0
  151. package/{dist/tools/lsp/server-config-loader.d.ts → packages/lsp-tools-mcp/dist/lsp/config-loader.d.ts} +6 -6
  152. package/packages/lsp-tools-mcp/dist/lsp/config-loader.d.ts.map +1 -0
  153. package/packages/lsp-tools-mcp/dist/lsp/config-loader.js +110 -0
  154. package/packages/lsp-tools-mcp/dist/lsp/config-loader.js.map +1 -0
  155. package/packages/lsp-tools-mcp/dist/lsp/connection.d.ts +5 -0
  156. package/packages/lsp-tools-mcp/dist/lsp/connection.d.ts.map +1 -0
  157. package/packages/lsp-tools-mcp/dist/lsp/connection.js +67 -0
  158. package/packages/lsp-tools-mcp/dist/lsp/connection.js.map +1 -0
  159. package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +11 -0
  160. package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts.map +1 -0
  161. package/packages/lsp-tools-mcp/dist/lsp/constants.js +11 -0
  162. package/packages/lsp-tools-mcp/dist/lsp/constants.js.map +1 -0
  163. package/packages/lsp-tools-mcp/dist/lsp/directory-diagnostics.d.ts +4 -0
  164. package/packages/lsp-tools-mcp/dist/lsp/directory-diagnostics.d.ts.map +1 -0
  165. package/packages/lsp-tools-mcp/dist/lsp/directory-diagnostics.js +124 -0
  166. package/packages/lsp-tools-mcp/dist/lsp/directory-diagnostics.js.map +1 -0
  167. package/packages/lsp-tools-mcp/dist/lsp/errors.d.ts +36 -0
  168. package/packages/lsp-tools-mcp/dist/lsp/errors.d.ts.map +1 -0
  169. package/packages/lsp-tools-mcp/dist/lsp/errors.js +57 -0
  170. package/packages/lsp-tools-mcp/dist/lsp/errors.js.map +1 -0
  171. package/{dist/tools/lsp/lsp-formatters.d.ts → packages/lsp-tools-mcp/dist/lsp/formatters.d.ts} +5 -5
  172. package/packages/lsp-tools-mcp/dist/lsp/formatters.d.ts.map +1 -0
  173. package/packages/lsp-tools-mcp/dist/lsp/formatters.js +109 -0
  174. package/packages/lsp-tools-mcp/dist/lsp/formatters.js.map +1 -0
  175. package/{dist/tools → packages/lsp-tools-mcp/dist}/lsp/infer-extension.d.ts +1 -0
  176. package/packages/lsp-tools-mcp/dist/lsp/infer-extension.d.ts.map +1 -0
  177. package/packages/lsp-tools-mcp/dist/lsp/infer-extension.js +59 -0
  178. package/packages/lsp-tools-mcp/dist/lsp/infer-extension.js.map +1 -0
  179. package/packages/lsp-tools-mcp/dist/lsp/json-rpc-connection.d.ts +37 -0
  180. package/packages/lsp-tools-mcp/dist/lsp/json-rpc-connection.d.ts.map +1 -0
  181. package/packages/lsp-tools-mcp/dist/lsp/json-rpc-connection.js +248 -0
  182. package/packages/lsp-tools-mcp/dist/lsp/json-rpc-connection.js.map +1 -0
  183. package/{dist/tools → packages/lsp-tools-mcp/dist}/lsp/language-mappings.d.ts +2 -0
  184. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts.map +1 -0
  185. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.js +170 -0
  186. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.js.map +1 -0
  187. package/packages/lsp-tools-mcp/dist/lsp/manager.d.ts +48 -0
  188. package/packages/lsp-tools-mcp/dist/lsp/manager.d.ts.map +1 -0
  189. package/packages/lsp-tools-mcp/dist/lsp/manager.js +308 -0
  190. package/packages/lsp-tools-mcp/dist/lsp/manager.js.map +1 -0
  191. package/packages/lsp-tools-mcp/dist/lsp/process.d.ts +26 -0
  192. package/packages/lsp-tools-mcp/dist/lsp/process.d.ts.map +1 -0
  193. package/packages/lsp-tools-mcp/dist/lsp/process.js +124 -0
  194. package/packages/lsp-tools-mcp/dist/lsp/process.js.map +1 -0
  195. package/packages/lsp-tools-mcp/dist/lsp/server-definitions.d.ts +5 -0
  196. package/packages/lsp-tools-mcp/dist/lsp/server-definitions.d.ts.map +1 -0
  197. package/packages/lsp-tools-mcp/dist/lsp/server-definitions.js +159 -0
  198. package/packages/lsp-tools-mcp/dist/lsp/server-definitions.js.map +1 -0
  199. package/packages/lsp-tools-mcp/dist/lsp/server-installation.d.ts +3 -0
  200. package/packages/lsp-tools-mcp/dist/lsp/server-installation.d.ts.map +1 -0
  201. package/packages/lsp-tools-mcp/dist/lsp/server-installation.js +51 -0
  202. package/packages/lsp-tools-mcp/dist/lsp/server-installation.js.map +1 -0
  203. package/packages/lsp-tools-mcp/dist/lsp/server-resolution.d.ts +12 -0
  204. package/packages/lsp-tools-mcp/dist/lsp/server-resolution.d.ts.map +1 -0
  205. package/packages/lsp-tools-mcp/dist/lsp/server-resolution.js +75 -0
  206. package/packages/lsp-tools-mcp/dist/lsp/server-resolution.js.map +1 -0
  207. package/packages/lsp-tools-mcp/dist/lsp/transport.d.ts +26 -0
  208. package/packages/lsp-tools-mcp/dist/lsp/transport.d.ts.map +1 -0
  209. package/packages/lsp-tools-mcp/dist/lsp/transport.js +234 -0
  210. package/packages/lsp-tools-mcp/dist/lsp/transport.js.map +1 -0
  211. package/{dist/tools → packages/lsp-tools-mcp/dist}/lsp/types.d.ts +28 -26
  212. package/packages/lsp-tools-mcp/dist/lsp/types.d.ts.map +1 -0
  213. package/packages/lsp-tools-mcp/dist/lsp/types.js +2 -0
  214. package/packages/lsp-tools-mcp/dist/lsp/types.js.map +1 -0
  215. package/packages/lsp-tools-mcp/dist/lsp/utils.d.ts +5 -0
  216. package/packages/lsp-tools-mcp/dist/lsp/utils.d.ts.map +1 -0
  217. package/packages/lsp-tools-mcp/dist/lsp/utils.js +43 -0
  218. package/packages/lsp-tools-mcp/dist/lsp/utils.js.map +1 -0
  219. package/{dist/tools → packages/lsp-tools-mcp/dist}/lsp/workspace-edit.d.ts +2 -1
  220. package/packages/lsp-tools-mcp/dist/lsp/workspace-edit.d.ts.map +1 -0
  221. package/packages/lsp-tools-mcp/dist/lsp/workspace-edit.js +114 -0
  222. package/packages/lsp-tools-mcp/dist/lsp/workspace-edit.js.map +1 -0
  223. package/packages/lsp-tools-mcp/dist/mcp.d.ts +31 -0
  224. package/packages/lsp-tools-mcp/dist/mcp.d.ts.map +1 -0
  225. package/packages/lsp-tools-mcp/dist/mcp.js +95 -0
  226. package/packages/lsp-tools-mcp/dist/mcp.js.map +1 -0
  227. package/packages/lsp-tools-mcp/dist/tools.d.ts +91 -0
  228. package/packages/lsp-tools-mcp/dist/tools.d.ts.map +1 -0
  229. package/packages/lsp-tools-mcp/dist/tools.js +453 -0
  230. package/packages/lsp-tools-mcp/dist/tools.js.map +1 -0
  231. package/dist/hooks/atlas/sisyphus-path.d.ts +0 -6
  232. package/dist/tools/lsp/client.d.ts +0 -3
  233. package/dist/tools/lsp/config.d.ts +0 -3
  234. package/dist/tools/lsp/constants.d.ts +0 -6
  235. package/dist/tools/lsp/diagnostics-tool.d.ts +0 -2
  236. package/dist/tools/lsp/directory-diagnostics.d.ts +0 -1
  237. package/dist/tools/lsp/find-references-tool.d.ts +0 -2
  238. package/dist/tools/lsp/goto-definition-tool.d.ts +0 -2
  239. package/dist/tools/lsp/index.d.ts +0 -8
  240. package/dist/tools/lsp/language-config.d.ts +0 -1
  241. package/dist/tools/lsp/lsp-client-connection.d.ts +0 -4
  242. package/dist/tools/lsp/lsp-client-transport.d.ts +0 -22
  243. package/dist/tools/lsp/lsp-client-wrapper.d.ts +0 -9
  244. package/dist/tools/lsp/lsp-client.d.ts +0 -17
  245. package/dist/tools/lsp/lsp-manager-process-cleanup.d.ts +0 -15
  246. package/dist/tools/lsp/lsp-manager-temp-directory-cleanup.d.ts +0 -8
  247. package/dist/tools/lsp/lsp-process.d.ts +0 -29
  248. package/dist/tools/lsp/lsp-server.d.ts +0 -24
  249. package/dist/tools/lsp/rename-tools.d.ts +0 -3
  250. package/dist/tools/lsp/server-definitions.d.ts +0 -3
  251. package/dist/tools/lsp/server-installation.d.ts +0 -1
  252. package/dist/tools/lsp/server-path-bases.d.ts +0 -1
  253. package/dist/tools/lsp/server-resolution.d.ts +0 -15
  254. package/dist/tools/lsp/symbols-tool.d.ts +0 -2
  255. package/dist/tools/lsp/tools.d.ts +0 -5
package/dist/cli/index.js CHANGED
@@ -4964,6 +4964,27 @@ var init_plugin_identity = __esm(() => {
4964
4964
  import * as fs from "fs";
4965
4965
  import * as os from "os";
4966
4966
  import * as path from "path";
4967
+ function rotateLogFileIfNeeded() {
4968
+ try {
4969
+ if (!fs.existsSync(logFile))
4970
+ return;
4971
+ const stats = fs.statSync(logFile);
4972
+ if (stats.size <= maxLogFileSizeBytes)
4973
+ return;
4974
+ const oldest = `${logFile}.${maxLogFileBackups}`;
4975
+ if (fs.existsSync(oldest)) {
4976
+ fs.unlinkSync(oldest);
4977
+ }
4978
+ for (let i2 = maxLogFileBackups - 1;i2 >= 1; i2 -= 1) {
4979
+ const src = `${logFile}.${i2}`;
4980
+ const dst = `${logFile}.${i2 + 1}`;
4981
+ if (fs.existsSync(src)) {
4982
+ fs.renameSync(src, dst);
4983
+ }
4984
+ }
4985
+ fs.renameSync(logFile, `${logFile}.1`);
4986
+ } catch {}
4987
+ }
4967
4988
  function flush() {
4968
4989
  if (buffer.length === 0)
4969
4990
  return;
@@ -4971,6 +4992,7 @@ function flush() {
4971
4992
  buffer = [];
4972
4993
  try {
4973
4994
  fs.appendFileSync(logFile, data);
4995
+ rotateLogFileIfNeeded();
4974
4996
  } catch {}
4975
4997
  }
4976
4998
  function scheduleFlush() {
@@ -4994,10 +5016,13 @@ function log(message, data) {
4994
5016
  }
4995
5017
  } catch {}
4996
5018
  }
4997
- var logFile, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
5019
+ var DEFAULT_MAX_LOG_FILE_SIZE_BYTES, DEFAULT_MAX_LOG_FILE_BACKUPS = 2, logFile, maxLogFileSizeBytes, maxLogFileBackups, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
4998
5020
  var init_logger = __esm(() => {
4999
5021
  init_plugin_identity();
5022
+ DEFAULT_MAX_LOG_FILE_SIZE_BYTES = 50 * 1024 * 1024;
5000
5023
  logFile = path.join(os.tmpdir(), LOG_FILENAME);
5024
+ maxLogFileSizeBytes = DEFAULT_MAX_LOG_FILE_SIZE_BYTES;
5025
+ maxLogFileBackups = DEFAULT_MAX_LOG_FILE_BACKUPS;
5001
5026
  buffer = [];
5002
5027
  });
5003
5028
 
@@ -5098,6 +5123,7 @@ function normalizeSDKResponse(response, fallback, options) {
5098
5123
  var usageCacheByClient;
5099
5124
  var init_dynamic_truncator = __esm(() => {
5100
5125
  init_context_limit_resolver();
5126
+ init_logger();
5101
5127
  usageCacheByClient = new WeakMap;
5102
5128
  });
5103
5129
 
@@ -6020,7 +6046,7 @@ var init_main = __esm(() => {
6020
6046
  });
6021
6047
 
6022
6048
  // src/shared/jsonc-parser.ts
6023
- import { existsSync as existsSync2, readFileSync } from "fs";
6049
+ import { existsSync as existsSync3, readFileSync } from "fs";
6024
6050
  import { join as join4 } from "path";
6025
6051
  function stripBom(content) {
6026
6052
  return content.charCodeAt(0) === 65279 ? content.slice(1) : content;
@@ -6041,10 +6067,10 @@ function parseJsonc(content) {
6041
6067
  function detectConfigFile(basePath) {
6042
6068
  const jsoncPath = `${basePath}.jsonc`;
6043
6069
  const jsonPath = `${basePath}.json`;
6044
- if (existsSync2(jsoncPath)) {
6070
+ if (existsSync3(jsoncPath)) {
6045
6071
  return { format: "jsonc", path: jsoncPath };
6046
6072
  }
6047
- if (existsSync2(jsonPath)) {
6073
+ if (existsSync3(jsonPath)) {
6048
6074
  return { format: "json", path: jsonPath };
6049
6075
  }
6050
6076
  return { format: "none", path: jsonPath };
@@ -6317,8 +6343,8 @@ var init_tolerant_fsync = __esm(() => {
6317
6343
  import {
6318
6344
  closeSync,
6319
6345
  openSync,
6320
- renameSync,
6321
- unlinkSync,
6346
+ renameSync as renameSync2,
6347
+ unlinkSync as unlinkSync2,
6322
6348
  writeFileSync
6323
6349
  } from "fs";
6324
6350
  function writeFileAtomically(filePath, content, deps = {}) {
@@ -6331,13 +6357,13 @@ function writeFileAtomically(filePath, content, deps = {}) {
6331
6357
  closeSync(tempFileDescriptor);
6332
6358
  }
6333
6359
  try {
6334
- renameSync(tempPath, filePath);
6360
+ renameSync2(tempPath, filePath);
6335
6361
  } catch (error) {
6336
6362
  const isWindows = process.platform === "win32";
6337
6363
  const isPermissionError = error instanceof Error && (error.message.includes("EPERM") || error.message.includes("EACCES"));
6338
6364
  if (isWindows && isPermissionError) {
6339
- unlinkSync(filePath);
6340
- renameSync(tempPath, filePath);
6365
+ unlinkSync2(filePath);
6366
+ renameSync2(tempPath, filePath);
6341
6367
  } else {
6342
6368
  throw error;
6343
6369
  }
@@ -6573,7 +6599,7 @@ var init_migration = __esm(() => {
6573
6599
  });
6574
6600
 
6575
6601
  // src/shared/opencode-config-dir.ts
6576
- import { existsSync as existsSync4, realpathSync as realpathSync3 } from "fs";
6602
+ import { existsSync as existsSync5, realpathSync as realpathSync3 } from "fs";
6577
6603
  import { homedir as homedir3 } from "os";
6578
6604
  import { join as join5, resolve as resolve2, win32 } from "path";
6579
6605
  function isDevBuild(version) {
@@ -6599,7 +6625,7 @@ function getTauriConfigDir(identifier) {
6599
6625
  }
6600
6626
  function resolveConfigPath(pathValue) {
6601
6627
  const resolvedPath = resolve2(pathValue);
6602
- if (!existsSync4(resolvedPath))
6628
+ if (!existsSync5(resolvedPath))
6603
6629
  return resolvedPath;
6604
6630
  try {
6605
6631
  return realpathSync3(resolvedPath);
@@ -6627,7 +6653,7 @@ function getOpenCodeConfigDir(options) {
6627
6653
  const legacyDir = getCliConfigDir();
6628
6654
  const legacyConfig = join5(legacyDir, "opencode.json");
6629
6655
  const legacyConfigC = join5(legacyDir, "opencode.jsonc");
6630
- if (existsSync4(legacyConfig) || existsSync4(legacyConfigC)) {
6656
+ if (existsSync5(legacyConfig) || existsSync5(legacyConfigC)) {
6631
6657
  return legacyDir;
6632
6658
  }
6633
6659
  }
@@ -6669,7 +6695,7 @@ var init_resolve_agent_definition_paths = __esm(() => {
6669
6695
 
6670
6696
  // src/shared/opencode-version.ts
6671
6697
  import { execSync } from "child_process";
6672
- import { existsSync as existsSync5, readFileSync as readFileSync4, realpathSync as realpathSync4 } from "fs";
6698
+ import { existsSync as existsSync6, readFileSync as readFileSync4, realpathSync as realpathSync4 } from "fs";
6673
6699
  import { dirname as dirname3, join as join6 } from "path";
6674
6700
  function parseVersion(version) {
6675
6701
  const cleaned = version.replace(/^v/, "").split("-")[0];
@@ -6764,14 +6790,14 @@ var init_opencode_version = __esm(() => {
6764
6790
  return envPath;
6765
6791
  return globalThis.Bun?.which("opencode") ?? null;
6766
6792
  },
6767
- exists: existsSync5,
6793
+ exists: existsSync6,
6768
6794
  realpath: realpathSync4,
6769
6795
  readText: (filePath) => readFileSync4(filePath, "utf-8")
6770
6796
  };
6771
6797
  });
6772
6798
 
6773
6799
  // src/shared/opencode-storage-detection.ts
6774
- import { existsSync as existsSync6 } from "fs";
6800
+ import { existsSync as existsSync7 } from "fs";
6775
6801
  import { join as join7 } from "path";
6776
6802
  function isSqliteBackend() {
6777
6803
  if (cachedResult === true)
@@ -6781,7 +6807,7 @@ function isSqliteBackend() {
6781
6807
  const check = () => {
6782
6808
  const versionOk = isOpenCodeVersionAtLeast(OPENCODE_SQLITE_VERSION);
6783
6809
  const dbPath = join7(getDataDir(), "opencode", "opencode.db");
6784
- return versionOk && existsSync6(dbPath);
6810
+ return versionOk && existsSync7(dbPath);
6785
6811
  };
6786
6812
  if (cachedResult === FALSE_PENDING_RETRY) {
6787
6813
  const result2 = check();
@@ -6967,11 +6993,11 @@ var init_bun_file_shim = __esm(() => {
6967
6993
  });
6968
6994
 
6969
6995
  // src/shared/binary-downloader.ts
6970
- import { chmodSync, existsSync as existsSync7, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
6996
+ import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3 } from "fs";
6971
6997
  import * as path5 from "path";
6972
6998
  function getCachedBinaryPath(cacheDir, binaryName) {
6973
6999
  const binaryPath = path5.join(cacheDir, binaryName);
6974
- return existsSync7(binaryPath) ? binaryPath : null;
7000
+ return existsSync8(binaryPath) ? binaryPath : null;
6975
7001
  }
6976
7002
  var init_binary_downloader = __esm(() => {
6977
7003
  init_bun_spawn_shim();
@@ -7426,7 +7452,7 @@ function normalizeModelID(modelID) {
7426
7452
  }
7427
7453
 
7428
7454
  // src/shared/json-file-cache-store.ts
7429
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
7455
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
7430
7456
  import { join as join9 } from "path";
7431
7457
  function toLogLabel(cacheLabel) {
7432
7458
  return cacheLabel.toLowerCase();
@@ -7439,7 +7465,7 @@ function createJsonFileCacheStore(options) {
7439
7465
  }
7440
7466
  function ensureCacheDir() {
7441
7467
  const cacheDir = options.getCacheDir();
7442
- if (!existsSync8(cacheDir)) {
7468
+ if (!existsSync9(cacheDir)) {
7443
7469
  mkdirSync4(cacheDir, { recursive: true });
7444
7470
  }
7445
7471
  }
@@ -7448,7 +7474,7 @@ function createJsonFileCacheStore(options) {
7448
7474
  return memoryValue;
7449
7475
  }
7450
7476
  const cacheFile = getCacheFilePath();
7451
- if (!existsSync8(cacheFile)) {
7477
+ if (!existsSync9(cacheFile)) {
7452
7478
  memoryValue = null;
7453
7479
  log(`[${options.logPrefix}] ${options.cacheLabel} file not found`, { cacheFile });
7454
7480
  return null;
@@ -7474,7 +7500,7 @@ function createJsonFileCacheStore(options) {
7474
7500
  if (writtenInCurrentProcess) {
7475
7501
  return true;
7476
7502
  }
7477
- return existsSync8(getCacheFilePath());
7503
+ return existsSync9(getCacheFilePath());
7478
7504
  }
7479
7505
  function write(value) {
7480
7506
  ensureCacheDir();
@@ -7650,14 +7676,14 @@ var init_connected_providers_cache = __esm(() => {
7650
7676
  });
7651
7677
 
7652
7678
  // src/shared/model-availability.ts
7653
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
7679
+ import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
7654
7680
  import { join as join10 } from "path";
7655
7681
  function isModelCacheAvailable() {
7656
7682
  if (hasProviderModelsCache()) {
7657
7683
  return true;
7658
7684
  }
7659
7685
  const cacheFile = join10(getOpenCodeCacheDir(), "models.json");
7660
- return existsSync9(cacheFile);
7686
+ return existsSync10(cacheFile);
7661
7687
  }
7662
7688
  var init_model_availability = __esm(() => {
7663
7689
  init_logger();
@@ -50834,7 +50860,7 @@ var init_opencode_storage_paths = __esm(() => {
50834
50860
  });
50835
50861
 
50836
50862
  // src/shared/compaction-marker.ts
50837
- import { existsSync as existsSync10, readdirSync, readFileSync as readFileSync7 } from "fs";
50863
+ import { existsSync as existsSync11, readdirSync, readFileSync as readFileSync7 } from "fs";
50838
50864
  import { join as join12 } from "path";
50839
50865
  function isCompactionPart(part) {
50840
50866
  return typeof part === "object" && part !== null && part.type === "compaction";
@@ -50856,7 +50882,7 @@ function hasCompactionPartInStorage(messageID) {
50856
50882
  return false;
50857
50883
  }
50858
50884
  const partDir = getCompactionPartStorageDir(messageID);
50859
- if (!existsSync10(partDir)) {
50885
+ if (!existsSync11(partDir)) {
50860
50886
  return false;
50861
50887
  }
50862
50888
  try {
@@ -50895,23 +50921,23 @@ var init_hook_message_injector = __esm(() => {
50895
50921
  });
50896
50922
 
50897
50923
  // src/shared/opencode-message-dir.ts
50898
- import { existsSync as existsSync11, readdirSync as readdirSync2 } from "fs";
50924
+ import { existsSync as existsSync12, readdirSync as readdirSync2 } from "fs";
50899
50925
  import { join as join13 } from "path";
50900
50926
  function getMessageDir(sessionID) {
50901
50927
  if (!sessionID.startsWith("ses_"))
50902
50928
  return null;
50903
50929
  if (/[/\\]|\.\./.test(sessionID))
50904
50930
  return null;
50905
- if (!existsSync11(MESSAGE_STORAGE))
50931
+ if (!existsSync12(MESSAGE_STORAGE))
50906
50932
  return null;
50907
50933
  const directPath = join13(MESSAGE_STORAGE, sessionID);
50908
- if (existsSync11(directPath)) {
50934
+ if (existsSync12(directPath)) {
50909
50935
  return directPath;
50910
50936
  }
50911
50937
  try {
50912
50938
  for (const dir of readdirSync2(MESSAGE_STORAGE)) {
50913
50939
  const sessionPath = join13(MESSAGE_STORAGE, dir, sessionID);
50914
- if (existsSync11(sessionPath)) {
50940
+ if (existsSync12(sessionPath)) {
50915
50941
  return sessionPath;
50916
50942
  }
50917
50943
  }
@@ -50963,26 +50989,41 @@ var init_pane_dimensions = __esm(() => {
50963
50989
  init_tmux_path_resolver();
50964
50990
  });
50965
50991
 
50992
+ // src/shared/tmux/tmux-utils/pane-command.ts
50993
+ var init_pane_command = () => {};
50994
+
50966
50995
  // src/shared/tmux/tmux-utils/pane-spawn.ts
50967
50996
  var init_pane_spawn = __esm(() => {
50968
50997
  init_tmux_path_resolver();
50969
50998
  init_server_health();
50999
+ init_pane_command();
50970
51000
  });
50971
51001
  // src/shared/tmux/tmux-utils/pane-replace.ts
50972
51002
  var init_pane_replace = __esm(() => {
50973
51003
  init_tmux_path_resolver();
51004
+ init_pane_command();
51005
+ });
51006
+
51007
+ // src/shared/tmux/tmux-utils/pane-activate.ts
51008
+ var init_pane_activate = __esm(() => {
51009
+ init_tmux_path_resolver();
51010
+ init_logger();
51011
+ init_runner();
51012
+ init_pane_command();
50974
51013
  });
50975
51014
 
50976
51015
  // src/shared/tmux/tmux-utils/window-spawn.ts
50977
51016
  var init_window_spawn = __esm(() => {
50978
51017
  init_tmux_path_resolver();
50979
51018
  init_server_health();
51019
+ init_pane_command();
50980
51020
  });
50981
51021
 
50982
51022
  // src/shared/tmux/tmux-utils/session-spawn.ts
50983
51023
  var init_session_spawn = __esm(() => {
50984
51024
  init_tmux_path_resolver();
50985
51025
  init_server_health();
51026
+ init_pane_command();
50986
51027
  });
50987
51028
  // src/shared/tmux/tmux-utils/stale-session-sweep.ts
50988
51029
  var init_stale_session_sweep = () => {};
@@ -50998,9 +51039,11 @@ var init_tmux_utils = __esm(() => {
50998
51039
  init_pane_dimensions();
50999
51040
  init_pane_spawn();
51000
51041
  init_pane_replace();
51042
+ init_pane_activate();
51001
51043
  init_window_spawn();
51002
51044
  init_session_spawn();
51003
51045
  init_stale_session_sweep();
51046
+ init_pane_command();
51004
51047
  init_layout();
51005
51048
  });
51006
51049
 
@@ -51010,9 +51053,306 @@ var init_tmux = __esm(() => {
51010
51053
  init_runner();
51011
51054
  init_tmux_utils();
51012
51055
  });
51056
+ // src/shared/session-idle-settle.ts
51057
+ function settleAfterSessionIdle(ms = DEFAULT_SESSION_IDLE_SETTLE_MS) {
51058
+ return ms > 0 ? new Promise((resolve4) => setTimeout(resolve4, ms)) : Promise.resolve();
51059
+ }
51060
+ function isRecord6(value) {
51061
+ return typeof value === "object" && value !== null;
51062
+ }
51063
+ function getSessionStatusPayload(response) {
51064
+ if (isRecord6(response) && isRecord6(response.data)) {
51065
+ return response.data;
51066
+ }
51067
+ if (isRecord6(response)) {
51068
+ return response;
51069
+ }
51070
+ return {};
51071
+ }
51072
+ function isActiveSessionStatusType(statusType) {
51073
+ return ACTIVE_SESSION_STATUSES.has(statusType);
51074
+ }
51075
+ async function isSessionActive(client, sessionID) {
51076
+ if (typeof client.session?.status !== "function") {
51077
+ return false;
51078
+ }
51079
+ try {
51080
+ const statusResult = await client.session.status();
51081
+ const status = getSessionStatusPayload(statusResult)[sessionID];
51082
+ if (!isRecord6(status)) {
51083
+ return false;
51084
+ }
51085
+ const statusType = status.type;
51086
+ return typeof statusType === "string" && isActiveSessionStatusType(statusType);
51087
+ } catch {
51088
+ return false;
51089
+ }
51090
+ }
51091
+ var DEFAULT_SESSION_IDLE_SETTLE_MS = 150, ACTIVE_SESSION_STATUSES;
51092
+ var init_session_idle_settle = __esm(() => {
51093
+ ACTIVE_SESSION_STATUSES = new Set(["busy", "retry", "running"]);
51094
+ });
51095
+
51096
+ // src/shared/prompt-async-gate.ts
51097
+ function getPromptGateMessagesFetchTimeoutMs() {
51098
+ return promptGateMessagesFetchTimeoutMsForTesting ?? DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS;
51099
+ }
51100
+ function pruneExpiredReservations(now = Date.now()) {
51101
+ for (const [sessionID, reservation] of promptAsyncReservations) {
51102
+ if (typeof reservation.expiresAt === "number" && reservation.expiresAt <= now) {
51103
+ promptAsyncReservations.delete(sessionID);
51104
+ log("[prompt-async-gate] expired reservation released", {
51105
+ sessionID,
51106
+ source: reservation.source
51107
+ });
51108
+ }
51109
+ }
51110
+ }
51111
+ function getActiveReservation(sessionID) {
51112
+ pruneExpiredReservations();
51113
+ return promptAsyncReservations.get(sessionID);
51114
+ }
51115
+ async function withDispatchTimeout(operation, dispatchTimeoutMs, operationName) {
51116
+ if (dispatchTimeoutMs <= 0) {
51117
+ return operation;
51118
+ }
51119
+ let timeoutID;
51120
+ const timeoutPromise = new Promise((_, reject) => {
51121
+ timeoutID = setTimeout(() => {
51122
+ reject(new Error(`${operationName} timed out after ${dispatchTimeoutMs}ms`));
51123
+ }, dispatchTimeoutMs);
51124
+ });
51125
+ try {
51126
+ return await Promise.race([operation, timeoutPromise]);
51127
+ } finally {
51128
+ if (timeoutID !== undefined) {
51129
+ clearTimeout(timeoutID);
51130
+ }
51131
+ }
51132
+ }
51133
+ function isRecord7(value) {
51134
+ return typeof value === "object" && value !== null;
51135
+ }
51136
+ function getPromptQuery(input) {
51137
+ if (!isRecord7(input)) {
51138
+ return { directory: "" };
51139
+ }
51140
+ const query = input.query;
51141
+ if (!isRecord7(query)) {
51142
+ return { directory: "" };
51143
+ }
51144
+ const promptQuery = { directory: "" };
51145
+ if (typeof query.directory === "string") {
51146
+ promptQuery.directory = query.directory;
51147
+ }
51148
+ if (typeof query.limit === "number") {
51149
+ promptQuery.limit = query.limit;
51150
+ }
51151
+ return promptQuery;
51152
+ }
51153
+ function getMessagesData(response) {
51154
+ if (isRecord7(response) && Array.isArray(response.data)) {
51155
+ return response.data;
51156
+ }
51157
+ return Array.isArray(response) ? response : [];
51158
+ }
51159
+ function messageRole(message) {
51160
+ if (!isRecord7(message)) {
51161
+ return;
51162
+ }
51163
+ const info = message.info;
51164
+ if (isRecord7(info) && typeof info.role === "string") {
51165
+ return info.role;
51166
+ }
51167
+ return typeof message.role === "string" ? message.role : undefined;
51168
+ }
51169
+ function partIsWaitingOnTool(part) {
51170
+ if (!isRecord7(part)) {
51171
+ return false;
51172
+ }
51173
+ if (part.type !== "tool" && part.type !== "tool_use") {
51174
+ return false;
51175
+ }
51176
+ const state = part.state;
51177
+ if (!isRecord7(state)) {
51178
+ return false;
51179
+ }
51180
+ return state.status === "pending" || state.status === "running";
51181
+ }
51182
+ function latestAssistantTurnIsWaitingOnTools(messages) {
51183
+ for (let index = messages.length - 1;index >= 0; index--) {
51184
+ const message = messages[index];
51185
+ const role = messageRole(message);
51186
+ if (role === "assistant") {
51187
+ if (!isRecord7(message) || !Array.isArray(message.parts)) {
51188
+ return false;
51189
+ }
51190
+ return message.parts.some(partIsWaitingOnTool);
51191
+ }
51192
+ if (role === "user") {
51193
+ return false;
51194
+ }
51195
+ }
51196
+ return false;
51197
+ }
51198
+ async function sessionLatestAssistantIsWaitingOnTools(args) {
51199
+ const session = args.client.session;
51200
+ if (typeof session?.messages !== "function") {
51201
+ return false;
51202
+ }
51203
+ const messages = session.messages.bind(session);
51204
+ try {
51205
+ const response = await withDispatchTimeout(messages({
51206
+ path: { id: args.sessionID },
51207
+ query: getPromptQuery(args.input)
51208
+ }), args.timeoutMs, `[prompt-async-gate] ${args.sessionName} session.messages`);
51209
+ return latestAssistantTurnIsWaitingOnTools(getMessagesData(response));
51210
+ } catch (error) {
51211
+ log("[prompt-async-gate] latest assistant tool-state check failed", {
51212
+ sessionID: args.sessionID,
51213
+ source: args.source,
51214
+ error: String(error)
51215
+ });
51216
+ return false;
51217
+ }
51218
+ }
51219
+ async function dispatchAfterSessionIdle(args) {
51220
+ const {
51221
+ sessionName,
51222
+ client,
51223
+ sessionID,
51224
+ input,
51225
+ source,
51226
+ settleMs,
51227
+ postDispatchHoldMs,
51228
+ dispatchTimeoutMs,
51229
+ checkStatus,
51230
+ checkToolState,
51231
+ dispatch
51232
+ } = args;
51233
+ const existing = getActiveReservation(sessionID);
51234
+ if (existing) {
51235
+ log(`[prompt-async-gate] ${sessionName} skipped because session is reserved`, {
51236
+ sessionID,
51237
+ source,
51238
+ reservedBy: existing.source,
51239
+ reservedAgeMs: Date.now() - existing.reservedAt
51240
+ });
51241
+ return { status: "reserved", reservedBy: existing.source };
51242
+ }
51243
+ const reservation = {
51244
+ source,
51245
+ reservedAt: Date.now(),
51246
+ token: Symbol(source)
51247
+ };
51248
+ promptAsyncReservations.set(sessionID, reservation);
51249
+ let dispatchAttempted = false;
51250
+ try {
51251
+ const canReadStatus = checkStatus && typeof client.session?.status === "function";
51252
+ if (settleMs > 0) {
51253
+ await settleAfterSessionIdle(settleMs);
51254
+ }
51255
+ let sessionActive = false;
51256
+ if (canReadStatus) {
51257
+ try {
51258
+ sessionActive = await withDispatchTimeout(isSessionActive(client, sessionID), Math.min(dispatchTimeoutMs, 5000), `[prompt-async-gate] ${sessionName} isSessionActive`);
51259
+ } catch {
51260
+ sessionActive = false;
51261
+ }
51262
+ }
51263
+ if (sessionActive) {
51264
+ log(`[prompt-async-gate] ${sessionName} skipped because session is active`, { sessionID, source });
51265
+ return { status: "active" };
51266
+ }
51267
+ if (checkToolState && typeof client.session?.messages === "function" && await sessionLatestAssistantIsWaitingOnTools({
51268
+ client,
51269
+ sessionID,
51270
+ input,
51271
+ sessionName,
51272
+ source,
51273
+ timeoutMs: Math.min(dispatchTimeoutMs, getPromptGateMessagesFetchTimeoutMs())
51274
+ })) {
51275
+ log(`[prompt-async-gate] ${sessionName} skipped because latest assistant is waiting on tools`, {
51276
+ sessionID,
51277
+ source
51278
+ });
51279
+ return { status: "active" };
51280
+ }
51281
+ log(`[prompt-async-gate] ${sessionName} dispatching`, { sessionID, source });
51282
+ dispatchAttempted = true;
51283
+ const response = await withDispatchTimeout(dispatch(input), dispatchTimeoutMs, `[prompt-async-gate] ${sessionName} dispatch`);
51284
+ log(`[prompt-async-gate] ${sessionName} dispatched`, { sessionID, source });
51285
+ return { status: "dispatched", response };
51286
+ } catch (error) {
51287
+ log(`[prompt-async-gate] ${sessionName} failed`, { sessionID, source, error: String(error) });
51288
+ return { status: "failed", error };
51289
+ } finally {
51290
+ const current = promptAsyncReservations.get(sessionID);
51291
+ if (current?.token === reservation.token) {
51292
+ if (dispatchAttempted && postDispatchHoldMs > 0) {
51293
+ reservation.expiresAt = Date.now() + postDispatchHoldMs;
51294
+ } else {
51295
+ promptAsyncReservations.delete(sessionID);
51296
+ }
51297
+ }
51298
+ }
51299
+ }
51300
+ async function dispatchInternalPrompt(args) {
51301
+ const {
51302
+ client,
51303
+ sessionID,
51304
+ input,
51305
+ source,
51306
+ settleMs = DEFAULT_SESSION_IDLE_SETTLE_MS
51307
+ } = args;
51308
+ const postDispatchHoldMs = args.postDispatchHoldMs ?? DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS;
51309
+ const dispatchTimeoutMs = args.dispatchTimeoutMs ?? DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS;
51310
+ const sessionName = args.mode === "async" ? "promptAsync" : "prompt";
51311
+ const dispatch = (() => {
51312
+ if (args.mode === "async") {
51313
+ const session2 = args.client.session;
51314
+ if (typeof session2?.promptAsync !== "function") {
51315
+ return;
51316
+ }
51317
+ const dispatchPromptAsync = session2.promptAsync.bind(session2);
51318
+ return (dispatchInput) => dispatchPromptAsync(dispatchInput);
51319
+ }
51320
+ const session = args.client.session;
51321
+ if (typeof session?.prompt !== "function") {
51322
+ return;
51323
+ }
51324
+ const dispatchPrompt = session.prompt.bind(session);
51325
+ return (dispatchInput) => dispatchPrompt(dispatchInput);
51326
+ })();
51327
+ if (!dispatch) {
51328
+ log(`[prompt-async-gate] ${sessionName} unavailable`, { sessionID, source });
51329
+ return { status: "unavailable" };
51330
+ }
51331
+ return dispatchAfterSessionIdle({
51332
+ sessionName,
51333
+ client,
51334
+ sessionID,
51335
+ input,
51336
+ source,
51337
+ settleMs,
51338
+ postDispatchHoldMs,
51339
+ dispatchTimeoutMs,
51340
+ checkStatus: args.checkStatus !== false,
51341
+ checkToolState: args.checkToolState !== false,
51342
+ dispatch
51343
+ });
51344
+ }
51345
+ var DEFAULT_PROMPT_ASYNC_POST_DISPATCH_HOLD_MS = 250, DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS = 30000, DEFAULT_PROMPT_GATE_MESSAGES_FETCH_TIMEOUT_MS = 5000, promptGateMessagesFetchTimeoutMsForTesting, promptAsyncReservations;
51346
+ var init_prompt_async_gate = __esm(() => {
51347
+ init_logger();
51348
+ init_session_idle_settle();
51349
+ promptAsyncReservations = new Map;
51350
+ });
51351
+
51013
51352
  // src/shared/model-suggestion-retry.ts
51014
51353
  var init_model_suggestion_retry = __esm(() => {
51015
51354
  init_logger();
51355
+ init_prompt_async_gate();
51016
51356
  });
51017
51357
 
51018
51358
  // src/shared/opencode-server-auth.ts
@@ -51025,7 +51365,7 @@ function getServerBasicAuthHeader() {
51025
51365
  const token = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
51026
51366
  return `Basic ${token}`;
51027
51367
  }
51028
- function isRecord6(value) {
51368
+ function isRecord8(value) {
51029
51369
  return typeof value === "object" && value !== null;
51030
51370
  }
51031
51371
  function isRequestFetch(value) {
@@ -51039,11 +51379,11 @@ function wrapRequestFetch(baseFetch, auth) {
51039
51379
  };
51040
51380
  }
51041
51381
  function getInternalClient(client) {
51042
- if (!isRecord6(client)) {
51382
+ if (!isRecord8(client)) {
51043
51383
  return null;
51044
51384
  }
51045
51385
  const internal = client["_client"];
51046
- return isRecord6(internal) ? internal : null;
51386
+ return isRecord8(internal) ? internal : null;
51047
51387
  }
51048
51388
  function tryInjectViaSetConfigHeaders(internal, auth) {
51049
51389
  const setConfig = internal["setConfig"];
@@ -51059,11 +51399,11 @@ function tryInjectViaSetConfigHeaders(internal, auth) {
51059
51399
  }
51060
51400
  function tryInjectViaInterceptors(internal, auth) {
51061
51401
  const interceptors = internal["interceptors"];
51062
- if (!isRecord6(interceptors)) {
51402
+ if (!isRecord8(interceptors)) {
51063
51403
  return false;
51064
51404
  }
51065
51405
  const requestInterceptors = interceptors["request"];
51066
- if (!isRecord6(requestInterceptors)) {
51406
+ if (!isRecord8(requestInterceptors)) {
51067
51407
  return false;
51068
51408
  }
51069
51409
  const use = requestInterceptors["use"];
@@ -51085,7 +51425,7 @@ function tryInjectViaFetchWrapper(internal, auth) {
51085
51425
  return false;
51086
51426
  }
51087
51427
  const config = getConfig();
51088
- if (!isRecord6(config)) {
51428
+ if (!isRecord8(config)) {
51089
51429
  return false;
51090
51430
  }
51091
51431
  const fetchValue = config["fetch"];
@@ -51099,7 +51439,7 @@ function tryInjectViaFetchWrapper(internal, auth) {
51099
51439
  }
51100
51440
  function tryInjectViaMutableInternalConfig(internal, auth) {
51101
51441
  const configValue = internal["_config"];
51102
- if (!isRecord6(configValue)) {
51442
+ if (!isRecord8(configValue)) {
51103
51443
  return false;
51104
51444
  }
51105
51445
  const fetchValue = configValue["fetch"];
@@ -51110,7 +51450,7 @@ function tryInjectViaMutableInternalConfig(internal, auth) {
51110
51450
  return true;
51111
51451
  }
51112
51452
  function tryInjectViaTopLevelFetch(client, auth) {
51113
- if (!isRecord6(client)) {
51453
+ if (!isRecord8(client)) {
51114
51454
  return false;
51115
51455
  }
51116
51456
  const fetchValue = client["fetch"];
@@ -51247,11 +51587,11 @@ var init_opencode_command_dirs = __esm(() => {
51247
51587
  });
51248
51588
 
51249
51589
  // src/shared/project-discovery-dirs.ts
51250
- import { existsSync as existsSync12, realpathSync as realpathSync5 } from "fs";
51590
+ import { existsSync as existsSync13, realpathSync as realpathSync5 } from "fs";
51251
51591
  import { dirname as dirname4, join as join14, resolve as resolve4 } from "path";
51252
51592
  function normalizePath(path6) {
51253
51593
  const resolvedPath = resolve4(path6);
51254
- if (!existsSync12(resolvedPath)) {
51594
+ if (!existsSync13(resolvedPath)) {
51255
51595
  return resolvedPath;
51256
51596
  }
51257
51597
  try {
@@ -51267,7 +51607,7 @@ function findProjectOpencodePluginConfigFiles(startDirectory, stopDirectory) {
51267
51607
  const resolvedStopDirectory = stopDirectory ? normalizePath(stopDirectory) : undefined;
51268
51608
  while (true) {
51269
51609
  const opencodeDirectory = join14(currentDirectory, ".opencode");
51270
- if (existsSync12(opencodeDirectory)) {
51610
+ if (existsSync13(opencodeDirectory)) {
51271
51611
  const detected = detectPluginConfigFile(opencodeDirectory);
51272
51612
  if (detected.format !== "none" && !seen.has(detected.path)) {
51273
51613
  seen.add(detected.path);
@@ -51296,6 +51636,7 @@ var init_session_directory_resolver = () => {};
51296
51636
  // src/shared/session-route.ts
51297
51637
  var init_session_route = __esm(() => {
51298
51638
  init_model_suggestion_retry();
51639
+ init_prompt_async_gate();
51299
51640
  });
51300
51641
 
51301
51642
  // src/shared/session-tools-store.ts
@@ -51462,6 +51803,11 @@ var init_log_legacy_plugin_startup_warning = __esm(() => {
51462
51803
  init_plugin_entry_migrator();
51463
51804
  init_plugin_identity();
51464
51805
  });
51806
+
51807
+ // src/shared/legacy-workspace-migration.ts
51808
+ var init_legacy_workspace_migration = __esm(() => {
51809
+ init_logger();
51810
+ });
51465
51811
  // src/shared/model-string-parser.ts
51466
51812
  var KNOWN_VARIANTS2;
51467
51813
  var init_model_string_parser = __esm(() => {
@@ -51487,6 +51833,7 @@ var init_excluded_dirs = __esm(() => {
51487
51833
  "dist",
51488
51834
  "build",
51489
51835
  ".next",
51836
+ ".omo",
51490
51837
  ".sisyphus",
51491
51838
  ".omx",
51492
51839
  ".turbo",
@@ -51499,7 +51846,6 @@ var init_excluded_dirs = __esm(() => {
51499
51846
  ];
51500
51847
  EXCLUDED_DIRS = Object.freeze(new Set(EXCLUDED_DIR_NAMES));
51501
51848
  });
51502
-
51503
51849
  // src/shared/index.ts
51504
51850
  var init_shared = __esm(() => {
51505
51851
  init_model_resolver();
@@ -51567,6 +51913,7 @@ var init_shared = __esm(() => {
51567
51913
  init_plugin_command_discovery();
51568
51914
  init_plugin_identity();
51569
51915
  init_log_legacy_plugin_startup_warning();
51916
+ init_legacy_workspace_migration();
51570
51917
  });
51571
51918
 
51572
51919
  // src/cli/config-manager/config-context.ts
@@ -51646,17 +51993,17 @@ var init_plugin_name_with_version = __esm(() => {
51646
51993
  });
51647
51994
 
51648
51995
  // src/cli/config-manager/backup-config.ts
51649
- import { copyFileSync as copyFileSync2, existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
51996
+ import { copyFileSync as copyFileSync2, existsSync as existsSync14, mkdirSync as mkdirSync5 } from "fs";
51650
51997
  import { dirname as dirname5 } from "path";
51651
51998
  function backupConfigFile(configPath) {
51652
- if (!existsSync13(configPath)) {
51999
+ if (!existsSync14(configPath)) {
51653
52000
  return { success: true };
51654
52001
  }
51655
52002
  const timestamp2 = new Date().toISOString().replace(/[:.]/g, "-");
51656
52003
  const backupPath = `${configPath}.backup-${timestamp2}`;
51657
52004
  try {
51658
52005
  const dir = dirname5(backupPath);
51659
- if (!existsSync13(dir)) {
52006
+ if (!existsSync14(dir)) {
51660
52007
  mkdirSync5(dir, { recursive: true });
51661
52008
  }
51662
52009
  copyFileSync2(configPath, backupPath);
@@ -51671,10 +52018,10 @@ function backupConfigFile(configPath) {
51671
52018
  var init_backup_config = () => {};
51672
52019
 
51673
52020
  // src/cli/config-manager/ensure-config-directory-exists.ts
51674
- import { existsSync as existsSync14, mkdirSync as mkdirSync6 } from "fs";
52021
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6 } from "fs";
51675
52022
  function ensureConfigDirectoryExists() {
51676
52023
  const configDir = getConfigDir();
51677
- if (!existsSync14(configDir)) {
52024
+ if (!existsSync15(configDir)) {
51678
52025
  mkdirSync6(configDir, { recursive: true });
51679
52026
  }
51680
52027
  }
@@ -51712,14 +52059,14 @@ function formatErrorWithSuggestion(err, context) {
51712
52059
  }
51713
52060
 
51714
52061
  // src/cli/config-manager/opencode-config-format.ts
51715
- import { existsSync as existsSync15 } from "fs";
52062
+ import { existsSync as existsSync16 } from "fs";
51716
52063
  function detectConfigFormat() {
51717
52064
  const configJsonc = getConfigJsonc();
51718
52065
  const configJson = getConfigJson();
51719
- if (existsSync15(configJsonc)) {
52066
+ if (existsSync16(configJsonc)) {
51720
52067
  return { format: "jsonc", path: configJsonc };
51721
52068
  }
51722
- if (existsSync15(configJson)) {
52069
+ if (existsSync16(configJson)) {
51723
52070
  return { format: "json", path: configJson };
51724
52071
  }
51725
52072
  return { format: "none", path: configJson };
@@ -51729,13 +52076,13 @@ var init_opencode_config_format = __esm(() => {
51729
52076
  });
51730
52077
 
51731
52078
  // src/cli/config-manager/parse-opencode-config-file.ts
51732
- import { readFileSync as readFileSync8, statSync } from "fs";
52079
+ import { readFileSync as readFileSync8, statSync as statSync2 } from "fs";
51733
52080
  function isEmptyOrWhitespace(content) {
51734
52081
  return content.trim().length === 0;
51735
52082
  }
51736
52083
  function parseOpenCodeConfigFileWithError(path6) {
51737
52084
  try {
51738
- const stat = statSync(path6);
52085
+ const stat = statSync2(path6);
51739
52086
  if (stat.size === 0) {
51740
52087
  return { config: null, error: `Config file is empty: ${path6}. Delete it or add valid JSON content.` };
51741
52088
  }
@@ -52262,7 +52609,7 @@ var init_generate_omo_config = __esm(() => {
52262
52609
  });
52263
52610
 
52264
52611
  // src/shared/migrate-legacy-config-file.ts
52265
- import { existsSync as existsSync16, readFileSync as readFileSync10, renameSync as renameSync2, rmSync } from "fs";
52612
+ import { existsSync as existsSync17, readFileSync as readFileSync10, renameSync as renameSync3, rmSync } from "fs";
52266
52613
  import { join as join15, dirname as dirname6, basename as basename2 } from "path";
52267
52614
  function buildCanonicalPath(legacyPath) {
52268
52615
  const dir = dirname6(legacyPath);
@@ -52272,7 +52619,7 @@ function buildCanonicalPath(legacyPath) {
52272
52619
  function archiveLegacyConfigFile(legacyPath) {
52273
52620
  const backupPath = `${legacyPath}.bak`;
52274
52621
  try {
52275
- renameSync2(legacyPath, backupPath);
52622
+ renameSync3(legacyPath, backupPath);
52276
52623
  log("[migrateLegacyConfigFile] Legacy config was migrated and renamed to backup. Update the canonical file only.", {
52277
52624
  legacyPath,
52278
52625
  backupPath
@@ -52300,10 +52647,10 @@ function archiveLegacyConfigFile(legacyPath) {
52300
52647
  }
52301
52648
  function migrateLegacySidecarFile(legacyPath, canonicalPath) {
52302
52649
  const legacySidecarPath = getSidecarPath(legacyPath);
52303
- if (!existsSync16(legacySidecarPath))
52650
+ if (!existsSync17(legacySidecarPath))
52304
52651
  return true;
52305
52652
  const canonicalSidecarPath = getSidecarPath(canonicalPath);
52306
- if (existsSync16(canonicalSidecarPath))
52653
+ if (existsSync17(canonicalSidecarPath))
52307
52654
  return true;
52308
52655
  try {
52309
52656
  const content = readFileSync10(legacySidecarPath, "utf-8");
@@ -52323,12 +52670,12 @@ function migrateLegacySidecarFile(legacyPath, canonicalPath) {
52323
52670
  }
52324
52671
  }
52325
52672
  function migrateLegacyConfigFile(legacyPath) {
52326
- if (!existsSync16(legacyPath))
52673
+ if (!existsSync17(legacyPath))
52327
52674
  return false;
52328
52675
  if (!basename2(legacyPath).startsWith(LEGACY_CONFIG_BASENAME))
52329
52676
  return false;
52330
52677
  const canonicalPath = buildCanonicalPath(legacyPath);
52331
- if (existsSync16(canonicalPath))
52678
+ if (existsSync17(canonicalPath))
52332
52679
  return false;
52333
52680
  try {
52334
52681
  const content = readFileSync10(legacyPath, "utf-8");
@@ -52372,7 +52719,7 @@ function deepMergeRecord(target, source) {
52372
52719
  }
52373
52720
 
52374
52721
  // src/cli/config-manager/write-omo-config.ts
52375
- import { existsSync as existsSync17, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync4 } from "fs";
52722
+ import { existsSync as existsSync18, readFileSync as readFileSync11, statSync as statSync3, writeFileSync as writeFileSync4 } from "fs";
52376
52723
  import { basename as basename3, dirname as dirname7, extname, join as join16 } from "path";
52377
52724
  function isEmptyOrWhitespace2(content) {
52378
52725
  return content.trim().length === 0;
@@ -52390,10 +52737,10 @@ function writeOmoConfig(installConfig) {
52390
52737
  const detectedConfigPath = getOmoConfigPath();
52391
52738
  const canonicalConfigPath = join16(dirname7(detectedConfigPath), `${CONFIG_BASENAME}${extname(detectedConfigPath) || ".json"}`);
52392
52739
  const shouldMigrateLegacyPath = basename3(detectedConfigPath).startsWith(LEGACY_CONFIG_BASENAME);
52393
- const omoConfigPath = shouldMigrateLegacyPath ? migrateLegacyConfigFile(detectedConfigPath) || existsSync17(canonicalConfigPath) ? canonicalConfigPath : detectedConfigPath : detectedConfigPath;
52740
+ const omoConfigPath = shouldMigrateLegacyPath ? migrateLegacyConfigFile(detectedConfigPath) || existsSync18(canonicalConfigPath) ? canonicalConfigPath : detectedConfigPath : detectedConfigPath;
52394
52741
  try {
52395
52742
  const newConfig = generateOmoConfig(installConfig);
52396
- if (existsSync17(omoConfigPath)) {
52743
+ if (existsSync18(omoConfigPath)) {
52397
52744
  const backupResult = backupConfigFile(omoConfigPath);
52398
52745
  if (!backupResult.success) {
52399
52746
  return {
@@ -52403,7 +52750,7 @@ function writeOmoConfig(installConfig) {
52403
52750
  };
52404
52751
  }
52405
52752
  try {
52406
- const stat = statSync2(omoConfigPath);
52753
+ const stat = statSync3(omoConfigPath);
52407
52754
  const content = readFileSync11(omoConfigPath, "utf-8");
52408
52755
  if (stat.size === 0 || isEmptyOrWhitespace2(content)) {
52409
52756
  writeFileSync4(omoConfigPath, JSON.stringify(newConfig, null, 2) + `
@@ -52600,10 +52947,10 @@ var init_opencode_binary = __esm(() => {
52600
52947
  });
52601
52948
 
52602
52949
  // src/cli/config-manager/detect-current-config.ts
52603
- import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
52950
+ import { existsSync as existsSync19, readFileSync as readFileSync12 } from "fs";
52604
52951
  function detectProvidersFromOmoConfig() {
52605
52952
  const omoConfigPath = getOmoConfigPath();
52606
- if (!existsSync18(omoConfigPath)) {
52953
+ if (!existsSync19(omoConfigPath)) {
52607
52954
  return {
52608
52955
  hasOpenAI: true,
52609
52956
  hasOpencodeZen: true,
@@ -52703,7 +53050,7 @@ var init_detect_current_config = __esm(() => {
52703
53050
  });
52704
53051
 
52705
53052
  // src/cli/config-manager/bun-install.ts
52706
- import { existsSync as existsSync19 } from "fs";
53053
+ import { existsSync as existsSync20 } from "fs";
52707
53054
  import { join as join17 } from "path";
52708
53055
  function getDefaultWorkspaceDir() {
52709
53056
  return join17(getOpenCodeCacheDir(), "packages");
@@ -52732,7 +53079,7 @@ async function runBunInstallWithDetails(options) {
52732
53079
  const outputMode = options?.outputMode ?? "pipe";
52733
53080
  const cacheDir = options?.workspaceDir ?? getDefaultWorkspaceDir();
52734
53081
  const packageJsonPath = `${cacheDir}/package.json`;
52735
- if (!existsSync19(packageJsonPath)) {
53082
+ if (!existsSync20(packageJsonPath)) {
52736
53083
  return {
52737
53084
  success: false,
52738
53085
  error: `Workspace not initialized: ${packageJsonPath} not found. OpenCode should create this on first run.`
@@ -53530,17 +53877,21 @@ function readPackageVersion(packageJsonPath) {
53530
53877
  const pkg = JSON.parse(content);
53531
53878
  return pkg.version ?? null;
53532
53879
  }
53533
- function getCachedVersion() {
53880
+ function getCachedVersion(options = {}) {
53881
+ const packageJsonCandidates = options.packageJsonCandidates ?? INSTALLED_PACKAGE_JSON_CANDIDATES;
53882
+ const findPackageJson = options.findPackageJson ?? findPackageJsonUp;
53534
53883
  try {
53535
- const currentDir = path10.dirname(fileURLToPath2(import.meta.url));
53536
- const pkgPath = findPackageJsonUp(currentDir);
53537
- if (pkgPath) {
53538
- return readPackageVersion(pkgPath);
53884
+ const currentDir = options.currentDir === undefined ? path10.dirname(fileURLToPath2(import.meta.url)) : options.currentDir;
53885
+ if (currentDir) {
53886
+ const pkgPath = findPackageJson(currentDir);
53887
+ if (pkgPath) {
53888
+ return readPackageVersion(pkgPath);
53889
+ }
53539
53890
  }
53540
53891
  } catch (err) {
53541
53892
  log("[auto-update-checker] Failed to resolve version from current directory:", err);
53542
53893
  }
53543
- for (const candidate of INSTALLED_PACKAGE_JSON_CANDIDATES) {
53894
+ for (const candidate of packageJsonCandidates) {
53544
53895
  try {
53545
53896
  if (fs9.existsSync(candidate)) {
53546
53897
  return readPackageVersion(candidate);
@@ -53548,10 +53899,12 @@ function getCachedVersion() {
53548
53899
  } catch {}
53549
53900
  }
53550
53901
  try {
53551
- const execDir = path10.dirname(fs9.realpathSync(process.execPath));
53552
- const pkgPath = findPackageJsonUp(execDir);
53553
- if (pkgPath) {
53554
- return readPackageVersion(pkgPath);
53902
+ const execDir = options.execDir === undefined ? path10.dirname(fs9.realpathSync(process.execPath)) : options.execDir;
53903
+ if (execDir) {
53904
+ const pkgPath = findPackageJson(execDir);
53905
+ if (pkgPath) {
53906
+ return readPackageVersion(pkgPath);
53907
+ }
53555
53908
  }
53556
53909
  } catch (err) {
53557
53910
  log("[auto-update-checker] Failed to resolve version from execPath:", err);
@@ -53800,17 +54153,22 @@ import * as path12 from "path";
53800
54153
  function stripTrailingCommas(json3) {
53801
54154
  return json3.replace(/,(\s*[}\]])/g, "$1");
53802
54155
  }
53803
- function removeFromTextBunLock(lockPath, packageName) {
54156
+ function removeFromTextBunLock(lockPath, packageNames) {
53804
54157
  try {
53805
54158
  const content = fs11.readFileSync(lockPath, "utf-8");
53806
54159
  const lock = JSON.parse(stripTrailingCommas(content));
53807
- if (lock.packages?.[packageName]) {
53808
- delete lock.packages[packageName];
54160
+ let removed = false;
54161
+ for (const packageName of packageNames) {
54162
+ if (lock.packages?.[packageName]) {
54163
+ delete lock.packages[packageName];
54164
+ log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
54165
+ removed = true;
54166
+ }
54167
+ }
54168
+ if (removed) {
53809
54169
  fs11.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
53810
- log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
53811
- return true;
53812
54170
  }
53813
- return false;
54171
+ return removed;
53814
54172
  } catch {
53815
54173
  return false;
53816
54174
  }
@@ -53824,26 +54182,57 @@ function deleteBinaryBunLock(lockPath) {
53824
54182
  return false;
53825
54183
  }
53826
54184
  }
53827
- function removeFromBunLock(packageName) {
53828
- const textLockPath = path12.join(CACHE_DIR, "bun.lock");
53829
- const binaryLockPath = path12.join(CACHE_DIR, "bun.lockb");
54185
+ function removeFromBunLock(cacheDir, packageNames) {
54186
+ const textLockPath = path12.join(cacheDir, "bun.lock");
54187
+ const binaryLockPath = path12.join(cacheDir, "bun.lockb");
53830
54188
  if (fs11.existsSync(textLockPath)) {
53831
- return removeFromTextBunLock(textLockPath, packageName);
54189
+ return removeFromTextBunLock(textLockPath, packageNames);
53832
54190
  }
53833
54191
  if (fs11.existsSync(binaryLockPath)) {
53834
54192
  return deleteBinaryBunLock(binaryLockPath);
53835
54193
  }
53836
54194
  return false;
53837
54195
  }
53838
- function invalidatePackage(packageName = PACKAGE_NAME2) {
54196
+ function getInvalidationPackageNames(packageName, defaultPackageName, acceptedPackageNames) {
54197
+ if (packageName === defaultPackageName) {
54198
+ return acceptedPackageNames;
54199
+ }
54200
+ return [packageName];
54201
+ }
54202
+ function removeSpecifierRootDirs(cacheDir, packageNames) {
54203
+ const parentDirs = [cacheDir, path12.join(cacheDir, "packages")];
54204
+ const prefixes = packageNames.map((packageName) => `${packageName}@`);
54205
+ let removed = false;
54206
+ for (const parentDir of parentDirs) {
54207
+ if (!fs11.existsSync(parentDir)) {
54208
+ continue;
54209
+ }
54210
+ for (const entry of fs11.readdirSync(parentDir, { withFileTypes: true })) {
54211
+ if (!entry.isDirectory() || !prefixes.some((prefix) => entry.name.startsWith(prefix))) {
54212
+ continue;
54213
+ }
54214
+ const specifierDir = path12.join(parentDir, entry.name);
54215
+ fs11.rmSync(specifierDir, { recursive: true, force: true });
54216
+ log(`[auto-update-checker] Specifier cache removed: ${specifierDir}`);
54217
+ removed = true;
54218
+ }
54219
+ }
54220
+ return removed;
54221
+ }
54222
+ function invalidatePackage(packageName = PACKAGE_NAME2, options = {}) {
53839
54223
  try {
53840
- const userConfigDir = getUserConfigDir();
53841
- const pkgDirs = [
53842
- path12.join(userConfigDir, "node_modules", packageName),
53843
- path12.join(CACHE_DIR, "node_modules", packageName)
53844
- ];
54224
+ const acceptedPackageNames = options.acceptedPackageNames ?? ACCEPTED_PACKAGE_NAMES2;
54225
+ const cacheDir = options.cacheDir ?? CACHE_DIR;
54226
+ const defaultPackageName = options.defaultPackageName ?? PACKAGE_NAME2;
54227
+ const userConfigDir = options.userConfigDir ?? getUserConfigDir();
54228
+ const packageNames = getInvalidationPackageNames(packageName, defaultPackageName, acceptedPackageNames);
54229
+ const pkgDirs = packageNames.flatMap((name) => [
54230
+ path12.join(userConfigDir, "node_modules", name),
54231
+ path12.join(cacheDir, "node_modules", name)
54232
+ ]);
53845
54233
  let packageRemoved = false;
53846
54234
  let lockRemoved = false;
54235
+ let specifierRemoved = false;
53847
54236
  for (const pkgDir of pkgDirs) {
53848
54237
  if (fs11.existsSync(pkgDir)) {
53849
54238
  fs11.rmSync(pkgDir, { recursive: true, force: true });
@@ -53851,8 +54240,9 @@ function invalidatePackage(packageName = PACKAGE_NAME2) {
53851
54240
  packageRemoved = true;
53852
54241
  }
53853
54242
  }
53854
- lockRemoved = removeFromBunLock(packageName);
53855
- if (!packageRemoved && !lockRemoved) {
54243
+ specifierRemoved = removeSpecifierRootDirs(cacheDir, packageNames);
54244
+ lockRemoved = removeFromBunLock(cacheDir, packageNames);
54245
+ if (!packageRemoved && !specifierRemoved && !lockRemoved) {
53856
54246
  log(`[auto-update-checker] Package not found, nothing to invalidate: ${packageName}`);
53857
54247
  return false;
53858
54248
  }
@@ -53900,7 +54290,7 @@ var init_update_toasts = __esm(() => {
53900
54290
  });
53901
54291
 
53902
54292
  // src/hooks/auto-update-checker/hook/background-update-check.ts
53903
- import { existsSync as existsSync32 } from "fs";
54293
+ import { existsSync as existsSync33 } from "fs";
53904
54294
  import { join as join30 } from "path";
53905
54295
  function getCacheWorkspaceDir(deps) {
53906
54296
  return deps.join(deps.getOpenCodeCacheDir(), "packages");
@@ -53951,7 +54341,7 @@ async function primeCacheWorkspace(activeWorkspace, deps) {
53951
54341
  return runBunInstallSafe(cacheWorkspace, deps);
53952
54342
  }
53953
54343
  function createBackgroundUpdateCheckRunner(overrides = {}) {
53954
- const deps = { ...defaultDeps2, ...overrides };
54344
+ const deps = { ...defaultDeps3, ...overrides };
53955
54345
  return async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
53956
54346
  const pluginInfo = deps.findPluginEntry(ctx.directory);
53957
54347
  if (!pluginInfo) {
@@ -54009,7 +54399,7 @@ function createBackgroundUpdateCheckRunner(overrides = {}) {
54009
54399
  deps.log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
54010
54400
  };
54011
54401
  }
54012
- var defaultDeps2, runBackgroundUpdateCheck;
54402
+ var defaultDeps3, runBackgroundUpdateCheck;
54013
54403
  var init_background_update_check = __esm(() => {
54014
54404
  init_config_manager();
54015
54405
  init_logger();
@@ -54018,8 +54408,8 @@ var init_background_update_check = __esm(() => {
54018
54408
  init_constants3();
54019
54409
  init_checker();
54020
54410
  init_update_toasts();
54021
- defaultDeps2 = {
54022
- existsSync: existsSync32,
54411
+ defaultDeps3 = {
54412
+ existsSync: existsSync33,
54023
54413
  join: join30,
54024
54414
  runBunInstallWithDetails,
54025
54415
  log,
@@ -54205,7 +54595,7 @@ var init_startup_toasts = __esm(() => {
54205
54595
  });
54206
54596
 
54207
54597
  // src/hooks/auto-update-checker/hook.ts
54208
- function createAutoUpdateCheckerHook(ctx, options = {}, deps = defaultDeps3) {
54598
+ function createAutoUpdateCheckerHook(ctx, options = {}, deps = defaultDeps4) {
54209
54599
  const {
54210
54600
  showStartupToast = true,
54211
54601
  isSisyphusEnabled = false,
@@ -54262,13 +54652,13 @@ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on S
54262
54652
  }
54263
54653
  };
54264
54654
  }
54265
- var defaultDeps3, isRecord7 = (value) => {
54655
+ var defaultDeps4, isRecord9 = (value) => {
54266
54656
  return typeof value === "object" && value !== null;
54267
54657
  }, getParentID = (properties) => {
54268
- if (!isRecord7(properties))
54658
+ if (!isRecord9(properties))
54269
54659
  return;
54270
54660
  const { info } = properties;
54271
- if (!isRecord7(info))
54661
+ if (!isRecord9(info))
54272
54662
  return;
54273
54663
  const { parentID } = info;
54274
54664
  return typeof parentID === "string" && parentID.length > 0 ? parentID : undefined;
@@ -54282,7 +54672,7 @@ var init_hook = __esm(() => {
54282
54672
  init_model_capabilities_status();
54283
54673
  init_model_cache_warning();
54284
54674
  init_startup_toasts();
54285
- defaultDeps3 = {
54675
+ defaultDeps4 = {
54286
54676
  getCachedVersion,
54287
54677
  getLocalDevVersion,
54288
54678
  showConfigErrorsIfAny,
@@ -54332,7 +54722,7 @@ var {
54332
54722
  // package.json
54333
54723
  var package_default = {
54334
54724
  name: "oh-my-opencode",
54335
- version: "4.1.2",
54725
+ version: "4.2.0",
54336
54726
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
54337
54727
  main: "./dist/index.js",
54338
54728
  types: "dist/index.d.ts",
@@ -54344,7 +54734,8 @@ var package_default = {
54344
54734
  files: [
54345
54735
  "dist",
54346
54736
  "bin",
54347
- "postinstall.mjs"
54737
+ "postinstall.mjs",
54738
+ "packages/lsp-tools-mcp/dist"
54348
54739
  ],
54349
54740
  exports: {
54350
54741
  ".": {
@@ -54355,6 +54746,7 @@ var package_default = {
54355
54746
  },
54356
54747
  scripts: {
54357
54748
  build: "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi --external zod && bun run build:node-require-shim && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema",
54749
+ "build:lsp-tools-mcp": "npm --prefix packages/lsp-tools-mcp ci && npm --prefix packages/lsp-tools-mcp run build",
54358
54750
  "build:node-require-shim": "bun run script/patch-node-require-shim.ts",
54359
54751
  "build:all": "bun run build && bun run build:binaries",
54360
54752
  "build:binaries": "bun run script/build-binaries.ts",
@@ -54363,11 +54755,11 @@ var package_default = {
54363
54755
  clean: "rm -rf dist",
54364
54756
  prepare: "bun run build",
54365
54757
  postinstall: "node postinstall.mjs",
54366
- prepublishOnly: "bun run clean && bun run build",
54758
+ prepublishOnly: "bun run clean && bun run build:lsp-tools-mcp && bun run build",
54367
54759
  "test:model-capabilities": "bun test src/shared/model-capability-aliases.test.ts src/shared/model-capability-guardrails.test.ts src/shared/model-capabilities.test.ts src/cli/doctor/checks/model-resolution.test.ts --bail",
54368
54760
  typecheck: "tsgo --noEmit",
54369
54761
  "typecheck:script": "tsgo --noEmit -p script/tsconfig.json",
54370
- test: "bun run script/run-ci-tests.ts"
54762
+ test: "bun test"
54371
54763
  },
54372
54764
  keywords: [
54373
54765
  "opencode",
@@ -54392,7 +54784,7 @@ var package_default = {
54392
54784
  "@ast-grep/cli": "^0.41.1",
54393
54785
  "@ast-grep/napi": "^0.41.1",
54394
54786
  "@clack/prompts": "^0.11.0",
54395
- "@code-yeongyu/comment-checker": "^0.7.0",
54787
+ "@code-yeongyu/comment-checker": "^0.7.1",
54396
54788
  "@modelcontextprotocol/sdk": "^1.29.0",
54397
54789
  "@opencode-ai/plugin": "^1.4.0",
54398
54790
  "@opencode-ai/sdk": "^1.4.0",
@@ -54415,17 +54807,17 @@ var package_default = {
54415
54807
  zod: "^4.4.3"
54416
54808
  },
54417
54809
  optionalDependencies: {
54418
- "oh-my-opencode-darwin-arm64": "4.1.2",
54419
- "oh-my-opencode-darwin-x64": "4.1.2",
54420
- "oh-my-opencode-darwin-x64-baseline": "4.1.2",
54421
- "oh-my-opencode-linux-arm64": "4.1.2",
54422
- "oh-my-opencode-linux-arm64-musl": "4.1.2",
54423
- "oh-my-opencode-linux-x64": "4.1.2",
54424
- "oh-my-opencode-linux-x64-baseline": "4.1.2",
54425
- "oh-my-opencode-linux-x64-musl": "4.1.2",
54426
- "oh-my-opencode-linux-x64-musl-baseline": "4.1.2",
54427
- "oh-my-opencode-windows-x64": "4.1.2",
54428
- "oh-my-opencode-windows-x64-baseline": "4.1.2"
54810
+ "oh-my-opencode-darwin-arm64": "4.2.0",
54811
+ "oh-my-opencode-darwin-x64": "4.2.0",
54812
+ "oh-my-opencode-darwin-x64-baseline": "4.2.0",
54813
+ "oh-my-opencode-linux-arm64": "4.2.0",
54814
+ "oh-my-opencode-linux-arm64-musl": "4.2.0",
54815
+ "oh-my-opencode-linux-x64": "4.2.0",
54816
+ "oh-my-opencode-linux-x64-baseline": "4.2.0",
54817
+ "oh-my-opencode-linux-x64-musl": "4.2.0",
54818
+ "oh-my-opencode-linux-x64-musl-baseline": "4.2.0",
54819
+ "oh-my-opencode-windows-x64": "4.2.0",
54820
+ "oh-my-opencode-windows-x64-baseline": "4.2.0"
54429
54821
  },
54430
54822
  overrides: {
54431
54823
  hono: "^4.12.18",
@@ -70868,7 +71260,7 @@ var NotificationConfigSchema = exports_external.object({
70868
71260
  force_enable: exports_external.boolean().optional()
70869
71261
  });
70870
71262
  // src/mcp/types.ts
70871
- var McpNameSchema = exports_external.enum(["websearch", "context7", "grep_app"]);
71263
+ var McpNameSchema = exports_external.enum(["websearch", "context7", "grep_app", "lsp"]);
70872
71264
  var AnyMcpNameSchema = exports_external.string().min(1);
70873
71265
 
70874
71266
  // src/config/schema/agent-definitions.ts
@@ -71235,7 +71627,10 @@ function loadConfigFromPath(configPath, _ctx) {
71235
71627
  const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
71236
71628
  if (result.success) {
71237
71629
  addAgentOrderWarnings(configPath, result.data.agent_order);
71238
- log(`Config loaded from ${configPath}`, { agents: result.data.agents });
71630
+ log(`Config loaded from ${configPath}`, {
71631
+ agents: result.data.agents,
71632
+ team_mode: result.data.team_mode
71633
+ });
71239
71634
  return result.data;
71240
71635
  }
71241
71636
  const errorMsg = result.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join(", ");
@@ -71247,7 +71642,10 @@ function loadConfigFromPath(configPath, _ctx) {
71247
71642
  const partialResult = parseConfigPartially(rawConfig);
71248
71643
  if (partialResult) {
71249
71644
  addAgentOrderWarnings(configPath, partialResult.agent_order);
71250
- log(`Partial config loaded from ${configPath}`, { agents: partialResult.agents });
71645
+ log(`Partial config loaded from ${configPath}`, {
71646
+ agents: partialResult.agents,
71647
+ team_mode: partialResult.team_mode
71648
+ });
71251
71649
  return partialResult;
71252
71650
  }
71253
71651
  return null;
@@ -71393,6 +71791,7 @@ function loadPluginConfig(directory, ctx) {
71393
71791
  };
71394
71792
  log("Final merged config", {
71395
71793
  agents: config2.agents,
71794
+ team_mode: config2.team_mode,
71396
71795
  disabled_agents: config2.disabled_agents,
71397
71796
  disabled_mcps: config2.disabled_mcps,
71398
71797
  disabled_hooks: config2.disabled_hooks,
@@ -72989,6 +73388,14 @@ async function withWorkingOpencodePath(startServer, finder = findWorkingOpencode
72989
73388
 
72990
73389
  // src/cli/run/server-connection.ts
72991
73390
  var LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"]);
73391
+ var defaultDeps2 = {
73392
+ createOpencode,
73393
+ createOpencodeClient,
73394
+ injectServerAuthIntoClient,
73395
+ isPortAvailable,
73396
+ getAvailableServerPort,
73397
+ withWorkingOpencodePath
73398
+ };
72992
73399
  function isLoopbackAttachUrl(url2) {
72993
73400
  try {
72994
73401
  const parsed = new URL(url2);
@@ -73009,19 +73416,19 @@ function isPortRangeExhausted(error51) {
73009
73416
  }
73010
73417
  return error51.message.includes("No available port found in range");
73011
73418
  }
73012
- async function startServer(options) {
73419
+ async function startServer(options, deps) {
73013
73420
  const { signal, port } = options;
73014
- const { client: client3, server: server2 } = await withWorkingOpencodePath(() => createOpencode({ signal, port, hostname: "127.0.0.1" }));
73421
+ const { client: client3, server: server2 } = await deps.withWorkingOpencodePath(() => deps.createOpencode({ signal, port, hostname: "127.0.0.1" }));
73015
73422
  console.log(import_picocolors10.default.dim("Server listening at"), import_picocolors10.default.cyan(server2.url));
73016
73423
  return { client: client3, cleanup: () => server2.close() };
73017
73424
  }
73018
- async function createServerConnection(options) {
73425
+ async function createServerConnectionWithDeps(options, deps) {
73019
73426
  const { port, attach, signal } = options;
73020
73427
  if (attach !== undefined) {
73021
73428
  console.log(import_picocolors10.default.dim("Attaching to existing server at"), import_picocolors10.default.cyan(attach));
73022
- const client3 = createOpencodeClient({ baseUrl: attach });
73429
+ const client3 = deps.createOpencodeClient({ baseUrl: attach });
73023
73430
  if (isLoopbackAttachUrl(attach)) {
73024
- injectServerAuthIntoClient(client3);
73431
+ deps.injectServerAuthIntoClient(client3);
73025
73432
  }
73026
73433
  return { client: client3, cleanup: () => {} };
73027
73434
  }
@@ -73029,47 +73436,47 @@ async function createServerConnection(options) {
73029
73436
  if (port < 1 || port > 65535) {
73030
73437
  throw new Error("Port must be between 1 and 65535");
73031
73438
  }
73032
- const available = await isPortAvailable(port, "127.0.0.1");
73439
+ const available = await deps.isPortAvailable(port, "127.0.0.1");
73033
73440
  if (available) {
73034
73441
  console.log(import_picocolors10.default.dim("Starting server on port"), import_picocolors10.default.cyan(port.toString()));
73035
73442
  try {
73036
- return await startServer({ signal, port });
73443
+ return await startServer({ signal, port }, deps);
73037
73444
  } catch (error51) {
73038
73445
  if (!isPortStartFailure(error51, port)) {
73039
73446
  throw error51;
73040
73447
  }
73041
- const stillAvailable = await isPortAvailable(port, "127.0.0.1");
73448
+ const stillAvailable = await deps.isPortAvailable(port, "127.0.0.1");
73042
73449
  if (stillAvailable) {
73043
73450
  throw error51;
73044
73451
  }
73045
73452
  console.log(import_picocolors10.default.dim("Port"), import_picocolors10.default.cyan(port.toString()), import_picocolors10.default.dim("became occupied, attaching to existing server"));
73046
- const client4 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
73047
- injectServerAuthIntoClient(client4);
73453
+ const client4 = deps.createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
73454
+ deps.injectServerAuthIntoClient(client4);
73048
73455
  return { client: client4, cleanup: () => {} };
73049
73456
  }
73050
73457
  }
73051
73458
  console.log(import_picocolors10.default.dim("Port"), import_picocolors10.default.cyan(port.toString()), import_picocolors10.default.dim("is occupied, attaching to existing server"));
73052
- const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
73053
- injectServerAuthIntoClient(client3);
73459
+ const client3 = deps.createOpencodeClient({ baseUrl: `http://127.0.0.1:${port}` });
73460
+ deps.injectServerAuthIntoClient(client3);
73054
73461
  return { client: client3, cleanup: () => {} };
73055
73462
  }
73056
73463
  let selectedPort;
73057
73464
  let wasAutoSelected;
73058
73465
  try {
73059
- const selected = await getAvailableServerPort(DEFAULT_SERVER_PORT, "127.0.0.1");
73466
+ const selected = await deps.getAvailableServerPort(DEFAULT_SERVER_PORT, "127.0.0.1");
73060
73467
  selectedPort = selected.port;
73061
73468
  wasAutoSelected = selected.wasAutoSelected;
73062
73469
  } catch (error51) {
73063
73470
  if (!isPortRangeExhausted(error51)) {
73064
73471
  throw error51;
73065
73472
  }
73066
- const defaultPortIsAvailable = await isPortAvailable(DEFAULT_SERVER_PORT, "127.0.0.1");
73473
+ const defaultPortIsAvailable = await deps.isPortAvailable(DEFAULT_SERVER_PORT, "127.0.0.1");
73067
73474
  if (defaultPortIsAvailable) {
73068
73475
  throw error51;
73069
73476
  }
73070
73477
  console.log(import_picocolors10.default.dim("Port range exhausted, attaching to existing server on"), import_picocolors10.default.cyan(DEFAULT_SERVER_PORT.toString()));
73071
- const client3 = createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` });
73072
- injectServerAuthIntoClient(client3);
73478
+ const client3 = deps.createOpencodeClient({ baseUrl: `http://127.0.0.1:${DEFAULT_SERVER_PORT}` });
73479
+ deps.injectServerAuthIntoClient(client3);
73073
73480
  return { client: client3, cleanup: () => {} };
73074
73481
  }
73075
73482
  if (wasAutoSelected) {
@@ -73078,16 +73485,19 @@ async function createServerConnection(options) {
73078
73485
  console.log(import_picocolors10.default.dim("Starting server on port"), import_picocolors10.default.cyan(selectedPort.toString()));
73079
73486
  }
73080
73487
  try {
73081
- return await startServer({ signal, port: selectedPort });
73488
+ return await startServer({ signal, port: selectedPort }, deps);
73082
73489
  } catch (error51) {
73083
73490
  if (!isPortStartFailure(error51, selectedPort)) {
73084
73491
  throw error51;
73085
73492
  }
73086
- const { port: retryPort } = await getAvailableServerPort(selectedPort + 1, "127.0.0.1");
73493
+ const { port: retryPort } = await deps.getAvailableServerPort(selectedPort + 1, "127.0.0.1");
73087
73494
  console.log(import_picocolors10.default.dim("Retrying server start on port"), import_picocolors10.default.cyan(retryPort.toString()));
73088
- return await startServer({ signal, port: retryPort });
73495
+ return await startServer({ signal, port: retryPort }, deps);
73089
73496
  }
73090
73497
  }
73498
+ async function createServerConnection(options) {
73499
+ return await createServerConnectionWithDeps(options, defaultDeps2);
73500
+ }
73091
73501
 
73092
73502
  // src/cli/run/session-resolver.ts
73093
73503
  init_shared();
@@ -73338,13 +73748,13 @@ var import_picocolors14 = __toESM(require_picocolors(), 1);
73338
73748
  init_shared();
73339
73749
  var import_picocolors13 = __toESM(require_picocolors(), 1);
73340
73750
  // src/features/boulder-state/constants.ts
73341
- var BOULDER_DIR = ".sisyphus";
73751
+ var BOULDER_DIR = ".omo";
73342
73752
  var BOULDER_FILE = "boulder.json";
73343
73753
  var BOULDER_STATE_PATH = `${BOULDER_DIR}/${BOULDER_FILE}`;
73344
73754
  var NOTEPAD_DIR = "notepads";
73345
73755
  var NOTEPAD_BASE_PATH = `${BOULDER_DIR}/${NOTEPAD_DIR}`;
73346
73756
  // src/features/boulder-state/storage.ts
73347
- import { existsSync as existsSync21, readFileSync as readFileSync14, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7, readdirSync as readdirSync3 } from "fs";
73757
+ import { existsSync as existsSync22, readFileSync as readFileSync14, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7, readdirSync as readdirSync3 } from "fs";
73348
73758
  import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute3, join as join20, relative as relative2, resolve as resolve5 } from "path";
73349
73759
  var RESERVED_KEYS = new Set(["__proto__", "prototype", "constructor"]);
73350
73760
  function parseIsoToMs(value) {
@@ -73424,11 +73834,11 @@ function resolveBoulderPlanPath(directory, state) {
73424
73834
  }
73425
73835
  const absoluteWorktreePath = resolveTrackedPath(directory, worktreePath);
73426
73836
  const worktreePlanPath = resolve5(absoluteWorktreePath, relativePlanPath);
73427
- return existsSync21(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
73837
+ return existsSync22(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
73428
73838
  }
73429
73839
  function readBoulderState(directory) {
73430
73840
  const filePath = getBoulderFilePath(directory);
73431
- if (!existsSync21(filePath)) {
73841
+ if (!existsSync22(filePath)) {
73432
73842
  return null;
73433
73843
  }
73434
73844
  try {
@@ -73471,7 +73881,7 @@ var CHECKED_CHECKBOX_PATTERN = /^(\s*)[-*]\s*\[[xX]\]\s*(.+)$/;
73471
73881
  var TODO_TASK_PATTERN = /^\d+\.\s+/;
73472
73882
  var FINAL_WAVE_TASK_PATTERN = /^F\d+\.\s+/i;
73473
73883
  function getPlanProgress(planPath) {
73474
- if (!existsSync21(planPath)) {
73884
+ if (!existsSync22(planPath)) {
73475
73885
  return { total: 0, completed: 0, isComplete: false };
73476
73886
  }
73477
73887
  try {
@@ -73550,7 +73960,7 @@ function resolveBoulderPlanPathForWork(directory, work) {
73550
73960
  return resolveBoulderPlanPath(directory, work);
73551
73961
  }
73552
73962
  // src/features/boulder-state/top-level-task.ts
73553
- import { existsSync as existsSync22, readFileSync as readFileSync15 } from "fs";
73963
+ import { existsSync as existsSync23, readFileSync as readFileSync15 } from "fs";
73554
73964
  var TODO_HEADING_PATTERN2 = /^##\s+TODOs\b/i;
73555
73965
  var FINAL_VERIFICATION_HEADING_PATTERN2 = /^##\s+Final Verification Wave\b/i;
73556
73966
  var SECOND_LEVEL_HEADING_PATTERN2 = /^##\s+/;
@@ -73573,7 +73983,7 @@ function buildTaskRef(section, taskLabel) {
73573
73983
  };
73574
73984
  }
73575
73985
  function readCurrentTopLevelTask(planPath) {
73576
- if (!existsSync22(planPath)) {
73986
+ if (!existsSync23(planPath)) {
73577
73987
  return null;
73578
73988
  }
73579
73989
  try {
@@ -73615,16 +74025,16 @@ function getSessionAgent(sessionID) {
73615
74025
  return sessionAgentMap.get(sessionID);
73616
74026
  }
73617
74027
  // src/features/run-continuation-state/constants.ts
73618
- var CONTINUATION_MARKER_DIR = ".sisyphus/run-continuation";
74028
+ var CONTINUATION_MARKER_DIR = ".omo/run-continuation";
73619
74029
  // src/features/run-continuation-state/storage.ts
73620
- import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync16, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
74030
+ import { existsSync as existsSync24, mkdirSync as mkdirSync8, readFileSync as readFileSync16, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
73621
74031
  import { join as join21 } from "path";
73622
74032
  function getMarkerPath(directory, sessionID) {
73623
74033
  return join21(directory, CONTINUATION_MARKER_DIR, `${sessionID}.json`);
73624
74034
  }
73625
74035
  function readContinuationMarker(directory, sessionID) {
73626
74036
  const markerPath = getMarkerPath(directory, sessionID);
73627
- if (!existsSync23(markerPath))
74037
+ if (!existsSync24(markerPath))
73628
74038
  return null;
73629
74039
  try {
73630
74040
  const raw = readFileSync16(markerPath, "utf-8");
@@ -73770,11 +74180,11 @@ init_agent_display_names();
73770
74180
 
73771
74181
  // src/hooks/ralph-loop/storage.ts
73772
74182
  init_frontmatter();
73773
- import { existsSync as existsSync24, readFileSync as readFileSync18, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, mkdirSync as mkdirSync9 } from "fs";
74183
+ import { existsSync as existsSync25, readFileSync as readFileSync18, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, mkdirSync as mkdirSync9 } from "fs";
73774
74184
  import { dirname as dirname11, join as join23 } from "path";
73775
74185
 
73776
74186
  // src/hooks/ralph-loop/constants.ts
73777
- var DEFAULT_STATE_FILE = ".sisyphus/ralph-loop.local.md";
74187
+ var DEFAULT_STATE_FILE = ".omo/ralph-loop.local.md";
73778
74188
  var DEFAULT_MAX_ITERATIONS = 100;
73779
74189
  var DEFAULT_COMPLETION_PROMISE = "DONE";
73780
74190
 
@@ -73784,7 +74194,7 @@ function getStateFilePath(directory, customPath) {
73784
74194
  }
73785
74195
  function readState(directory, customPath) {
73786
74196
  const filePath = getStateFilePath(directory, customPath);
73787
- if (!existsSync24(filePath)) {
74197
+ if (!existsSync25(filePath)) {
73788
74198
  return null;
73789
74199
  }
73790
74200
  try {
@@ -73989,6 +74399,13 @@ var ERROR_GRACE_CYCLES = 3;
73989
74399
  var MIN_STABILIZATION_MS = 1000;
73990
74400
  var DEFAULT_EVENT_WATCHDOG_MS = 30000;
73991
74401
  var DEFAULT_SECONDARY_MEANINGFUL_WORK_TIMEOUT_MS = 60000;
74402
+ function isIncompleteTodo(value) {
74403
+ if (!isRecord(value)) {
74404
+ return true;
74405
+ }
74406
+ const status = value.status;
74407
+ return status !== "completed" && status !== "cancelled";
74408
+ }
73992
74409
  async function pollForCompletion(ctx, eventState, abortController, options = {}) {
73993
74410
  const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
73994
74411
  const requiredConsecutive = options.requiredConsecutive ?? DEFAULT_REQUIRED_CONSECUTIVE;
@@ -74068,7 +74485,7 @@ Session ended with error: ${eventState.lastError}`));
74068
74485
  });
74069
74486
  const todos = normalizeSDKResponse(todosRes, []);
74070
74487
  const hasActiveChildren = Array.isArray(children) && children.length > 0;
74071
- const hasActiveTodos = Array.isArray(todos) && todos.some((t) => t?.status !== "completed" && t?.status !== "cancelled");
74488
+ const hasActiveTodos = Array.isArray(todos) && todos.some(isIncompleteTodo);
74072
74489
  const hasActiveWork = hasActiveChildren || hasActiveTodos;
74073
74490
  if (hasActiveWork) {
74074
74491
  eventState.hasReceivedMeaningfulWork = true;
@@ -79328,7 +79745,7 @@ init_data_path();
79328
79745
  init_logger();
79329
79746
  init_plugin_identity();
79330
79747
  init_write_file_atomically();
79331
- import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync19 } from "fs";
79748
+ import { existsSync as existsSync26, mkdirSync as mkdirSync10, readFileSync as readFileSync19 } from "fs";
79332
79749
  import { join as join24 } from "path";
79333
79750
  var POSTHOG_ACTIVITY_STATE_FILE = "posthog-activity.json";
79334
79751
  function getPostHogActivityStateFilePath() {
@@ -79342,7 +79759,7 @@ function isPostHogActivityState(value) {
79342
79759
  }
79343
79760
  function readPostHogActivityState() {
79344
79761
  const stateFilePath = getPostHogActivityStateFilePath();
79345
- if (!existsSync25(stateFilePath)) {
79762
+ if (!existsSync26(stateFilePath)) {
79346
79763
  return {};
79347
79764
  }
79348
79765
  try {
@@ -79508,6 +79925,7 @@ function createCliPostHog() {
79508
79925
  }
79509
79926
 
79510
79927
  // src/cli/run/runner.ts
79928
+ init_prompt_async_gate();
79511
79929
  var EVENT_PROCESSOR_SHUTDOWN_TIMEOUT_MS = 2000;
79512
79930
  async function waitForEventProcessorShutdown(eventProcessor, timeoutMs = EVENT_PROCESSOR_SHUTDOWN_TIMEOUT_MS) {
79513
79931
  const completed = await Promise.race([
@@ -79576,18 +79994,31 @@ Interrupted. Shutting down...`));
79576
79994
  const eventState = createEventState();
79577
79995
  eventState.agentColorsByName = await loadAgentProfileColors(client3);
79578
79996
  const eventProcessor = processEvents(ctx, events.stream, eventState).catch(() => {});
79579
- await client3.session.promptAsync({
79580
- path: { id: sessionID },
79581
- body: {
79582
- agent: resolvedAgent,
79583
- ...resolvedModel ? { model: resolvedModel } : {},
79584
- tools: {
79585
- question: false
79997
+ const promptResult = await dispatchInternalPrompt({
79998
+ mode: "async",
79999
+ client: client3,
80000
+ sessionID,
80001
+ source: "cli-run",
80002
+ settleMs: 0,
80003
+ input: {
80004
+ path: { id: sessionID },
80005
+ body: {
80006
+ agent: resolvedAgent,
80007
+ ...resolvedModel ? { model: resolvedModel } : {},
80008
+ tools: {
80009
+ question: false
80010
+ },
80011
+ parts: [{ type: "text", text: message }]
79586
80012
  },
79587
- parts: [{ type: "text", text: message }]
79588
- },
79589
- query: { directory }
80013
+ query: { directory }
80014
+ }
79590
80015
  });
80016
+ if (promptResult.status === "failed") {
80017
+ throw promptResult.error;
80018
+ }
80019
+ if (promptResult.status !== "dispatched") {
80020
+ throw new Error(`Session ${sessionID} is not idle; promptAsync skipped by gate: ${promptResult.status}`);
80021
+ }
79591
80022
  const exitCode = await pollForCompletion(ctx, eventState, abortController);
79592
80023
  abortController.abort();
79593
80024
  await waitForEventProcessorShutdown(eventProcessor);
@@ -79786,10 +80217,10 @@ async function getLocalVersion(options = {}) {
79786
80217
  }
79787
80218
  }
79788
80219
  // src/cli/doctor/checks/system.ts
79789
- import { existsSync as existsSync36, readFileSync as readFileSync29 } from "fs";
80220
+ import { existsSync as existsSync37, readFileSync as readFileSync29 } from "fs";
79790
80221
 
79791
80222
  // src/cli/doctor/checks/system-binary.ts
79792
- import { existsSync as existsSync33 } from "fs";
80223
+ import { existsSync as existsSync34 } from "fs";
79793
80224
  import { homedir as homedir8 } from "os";
79794
80225
  import { join as join31 } from "path";
79795
80226
 
@@ -79861,7 +80292,7 @@ function buildVersionCommand(binaryPath, platform) {
79861
80292
  }
79862
80293
  return [binaryPath, "--version"];
79863
80294
  }
79864
- function findDesktopBinary(platform = process.platform, checkExists = existsSync33) {
80295
+ function findDesktopBinary(platform = process.platform, checkExists = existsSync34) {
79865
80296
  for (const desktopPath of getDesktopAppPaths(platform)) {
79866
80297
  if (checkExists(desktopPath)) {
79867
80298
  return { binary: "opencode", path: desktopPath };
@@ -79907,12 +80338,12 @@ function compareVersions3(current, minimum) {
79907
80338
 
79908
80339
  // src/cli/doctor/checks/system-plugin.ts
79909
80340
  init_shared();
79910
- import { existsSync as existsSync34, readFileSync as readFileSync27 } from "fs";
80341
+ import { existsSync as existsSync35, readFileSync as readFileSync27 } from "fs";
79911
80342
  function detectConfigPath() {
79912
80343
  const paths = getOpenCodeConfigPaths({ binary: "opencode", version: null });
79913
- if (existsSync34(paths.configJsonc))
80344
+ if (existsSync35(paths.configJsonc))
79914
80345
  return paths.configJsonc;
79915
- if (existsSync34(paths.configJson))
80346
+ if (existsSync35(paths.configJson))
79916
80347
  return paths.configJson;
79917
80348
  return null;
79918
80349
  }
@@ -79996,7 +80427,7 @@ function getPluginInfo() {
79996
80427
  init_file_utils();
79997
80428
  init_checker();
79998
80429
  init_auto_update_checker();
79999
- import { existsSync as existsSync35, readFileSync as readFileSync28 } from "fs";
80430
+ import { existsSync as existsSync36, readFileSync as readFileSync28 } from "fs";
80000
80431
  import { homedir as homedir9 } from "os";
80001
80432
  import { join as join32 } from "path";
80002
80433
  init_shared();
@@ -80013,17 +80444,17 @@ function resolveOpenCodeCacheDir() {
80013
80444
  return join32(xdgCacheHome, "opencode");
80014
80445
  const fromShared = getOpenCodeCacheDir();
80015
80446
  const platformDefault = join32(getPlatformDefaultCacheDir(), "opencode");
80016
- if (existsSync35(fromShared) || !existsSync35(platformDefault))
80447
+ if (existsSync36(fromShared) || !existsSync36(platformDefault))
80017
80448
  return fromShared;
80018
80449
  return platformDefault;
80019
80450
  }
80020
80451
  function resolveExistingDir(dirPath) {
80021
- if (!existsSync35(dirPath))
80452
+ if (!existsSync36(dirPath))
80022
80453
  return dirPath;
80023
80454
  return resolveSymlink(dirPath);
80024
80455
  }
80025
80456
  function readPackageJson(filePath) {
80026
- if (!existsSync35(filePath))
80457
+ if (!existsSync36(filePath))
80027
80458
  return null;
80028
80459
  try {
80029
80460
  const content = readFileSync28(filePath, "utf-8");
@@ -80045,7 +80476,7 @@ function createPackageCandidates(rootDir) {
80045
80476
  }));
80046
80477
  }
80047
80478
  function selectInstalledPackage(candidate) {
80048
- return candidate.packageCandidates.find((packageCandidate) => existsSync35(packageCandidate.installedPackagePath)) ?? candidate.packageCandidates[0];
80479
+ return candidate.packageCandidates.find((packageCandidate) => existsSync36(packageCandidate.installedPackagePath)) ?? candidate.packageCandidates[0];
80049
80480
  }
80050
80481
  function getExpectedVersion(cachePackage, packageName) {
80051
80482
  return normalizeVersion(cachePackage?.dependencies?.[packageName]) ?? normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME]);
@@ -80066,7 +80497,7 @@ function getLoadedPluginVersion() {
80066
80497
  packageCandidates: createPackageCandidates(cacheDir)
80067
80498
  }
80068
80499
  ];
80069
- const selectedCandidate = candidates.find((candidate) => candidate.packageCandidates.some((packageCandidate) => existsSync35(packageCandidate.installedPackagePath))) ?? candidates[0];
80500
+ const selectedCandidate = candidates.find((candidate) => candidate.packageCandidates.some((packageCandidate) => existsSync36(packageCandidate.installedPackagePath))) ?? candidates[0];
80070
80501
  const { cacheDir: selectedDir, cachePackagePath } = selectedCandidate;
80071
80502
  const selectedPackage = selectInstalledPackage(selectedCandidate);
80072
80503
  const installedPackagePath = selectedPackage.installedPackagePath;
@@ -80093,7 +80524,7 @@ function getSuggestedInstallTag(currentVersion) {
80093
80524
  // src/cli/doctor/checks/system.ts
80094
80525
  init_shared();
80095
80526
  init_plugin_identity();
80096
- var defaultDeps4 = {
80527
+ var defaultDeps5 = {
80097
80528
  findOpenCodeBinary,
80098
80529
  getOpenCodeVersion: getOpenCodeVersion3,
80099
80530
  compareVersions: compareVersions3,
@@ -80105,7 +80536,7 @@ var defaultDeps4 = {
80105
80536
  function isConfigValid(configPath) {
80106
80537
  if (!configPath)
80107
80538
  return true;
80108
- if (!existsSync36(configPath))
80539
+ if (!existsSync37(configPath))
80109
80540
  return false;
80110
80541
  try {
80111
80542
  parseJsonc(readFileSync29(configPath, "utf-8"));
@@ -80128,7 +80559,7 @@ function buildMessage(status, issues) {
80128
80559
  return `${issues.length} system issue(s) detected`;
80129
80560
  return `${issues.length} system warning(s) detected`;
80130
80561
  }
80131
- async function gatherSystemInfo(deps = defaultDeps4) {
80562
+ async function gatherSystemInfo(deps = defaultDeps5) {
80132
80563
  const [binaryInfo, pluginInfo] = await Promise.all([
80133
80564
  deps.findOpenCodeBinary(),
80134
80565
  Promise.resolve(deps.getPluginInfo())
@@ -80147,7 +80578,7 @@ async function gatherSystemInfo(deps = defaultDeps4) {
80147
80578
  isLocalDev: pluginInfo.isLocalDev
80148
80579
  };
80149
80580
  }
80150
- async function checkSystem(deps = defaultDeps4) {
80581
+ async function checkSystem(deps = defaultDeps5) {
80151
80582
  const [systemInfo, pluginInfo] = await Promise.all([
80152
80583
  gatherSystemInfo(deps),
80153
80584
  Promise.resolve(deps.getPluginInfo())
@@ -80236,7 +80667,7 @@ init_shared();
80236
80667
 
80237
80668
  // src/cli/doctor/checks/model-resolution-cache.ts
80238
80669
  init_shared();
80239
- import { existsSync as existsSync37, readFileSync as readFileSync30 } from "fs";
80670
+ import { existsSync as existsSync38, readFileSync as readFileSync30 } from "fs";
80240
80671
  import { homedir as homedir10 } from "os";
80241
80672
  import { join as join33 } from "path";
80242
80673
  function getUserConfigDir2() {
@@ -80252,7 +80683,7 @@ function loadCustomProviderNames() {
80252
80683
  join33(configDir, "opencode.jsonc")
80253
80684
  ];
80254
80685
  for (const configPath of candidatePaths) {
80255
- if (!existsSync37(configPath))
80686
+ if (!existsSync38(configPath))
80256
80687
  continue;
80257
80688
  try {
80258
80689
  const content = readFileSync30(configPath, "utf-8");
@@ -80267,7 +80698,7 @@ function loadCustomProviderNames() {
80267
80698
  function loadAvailableModelsFromCache() {
80268
80699
  const cacheFile = join33(getOpenCodeCacheDir(), "models.json");
80269
80700
  const customProviders = loadCustomProviderNames();
80270
- if (!existsSync37(cacheFile)) {
80701
+ if (!existsSync38(cacheFile)) {
80271
80702
  if (customProviders.length > 0) {
80272
80703
  return { providers: customProviders, modelCount: 0, cacheExists: true };
80273
80704
  }
@@ -80642,7 +81073,7 @@ async function checkConfig() {
80642
81073
  }
80643
81074
 
80644
81075
  // src/cli/doctor/checks/dependencies.ts
80645
- import { existsSync as existsSync38 } from "fs";
81076
+ import { existsSync as existsSync39 } from "fs";
80646
81077
  import { createRequire } from "module";
80647
81078
  import { dirname as dirname16, join as join38 } from "path";
80648
81079
 
@@ -80726,7 +81157,7 @@ async function checkAstGrepNapi() {
80726
81157
  path: null
80727
81158
  };
80728
81159
  } catch {
80729
- const { existsSync: existsSync39 } = await import("fs");
81160
+ const { existsSync: existsSync40 } = await import("fs");
80730
81161
  const { join: join39 } = await import("path");
80731
81162
  const { homedir: homedir12 } = await import("os");
80732
81163
  const pathsToCheck = [
@@ -80734,7 +81165,7 @@ async function checkAstGrepNapi() {
80734
81165
  join39(process.cwd(), "node_modules", "@ast-grep", "napi")
80735
81166
  ];
80736
81167
  for (const napiPath of pathsToCheck) {
80737
- if (existsSync39(napiPath)) {
81168
+ if (existsSync40(napiPath)) {
80738
81169
  return {
80739
81170
  name: "AST-Grep NAPI",
80740
81171
  required: false,
@@ -80760,7 +81191,7 @@ function findCommentCheckerPackageBinary() {
80760
81191
  const require2 = createRequire(import.meta.url);
80761
81192
  const pkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
80762
81193
  const binaryPath = join38(dirname16(pkgPath), "bin", binaryName);
80763
- if (existsSync38(binaryPath))
81194
+ if (existsSync39(binaryPath))
80764
81195
  return binaryPath;
80765
81196
  } catch {}
80766
81197
  return null;
@@ -80890,261 +81321,120 @@ async function getGhCliInfo() {
80890
81321
  error: authStatus.error
80891
81322
  };
80892
81323
  }
80893
- // src/tools/lsp/server-definitions.ts
80894
- var BUILTIN_SERVERS = {
80895
- typescript: { command: ["typescript-language-server", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"] },
80896
- deno: { command: ["deno", "lsp"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"] },
80897
- vue: { command: ["vue-language-server", "--stdio"], extensions: [".vue"] },
80898
- eslint: { command: ["vscode-eslint-language-server", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"] },
80899
- oxlint: { command: ["oxlint", "--lsp"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".astro", ".svelte"] },
80900
- biome: { command: ["biome", "lsp-proxy", "--stdio"], extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".vue", ".astro", ".svelte", ".css", ".graphql", ".gql", ".html"] },
80901
- gopls: { command: ["gopls"], extensions: [".go"] },
80902
- "ruby-lsp": { command: ["rubocop", "--lsp"], extensions: [".rb", ".rake", ".gemspec", ".ru"] },
80903
- basedpyright: { command: ["basedpyright-langserver", "--stdio"], extensions: [".py", ".pyi"] },
80904
- pyright: { command: ["pyright-langserver", "--stdio"], extensions: [".py", ".pyi"] },
80905
- ty: { command: ["ty", "server"], extensions: [".py", ".pyi"] },
80906
- ruff: { command: ["ruff", "server"], extensions: [".py", ".pyi"] },
80907
- "elixir-ls": { command: ["elixir-ls"], extensions: [".ex", ".exs"] },
80908
- zls: { command: ["zls"], extensions: [".zig", ".zon"] },
80909
- csharp: { command: ["csharp-ls"], extensions: [".cs"] },
80910
- fsharp: { command: ["fsautocomplete"], extensions: [".fs", ".fsi", ".fsx", ".fsscript"] },
80911
- "sourcekit-lsp": { command: ["sourcekit-lsp"], extensions: [".swift", ".objc", ".objcpp"] },
80912
- rust: { command: ["rust-analyzer"], extensions: [".rs"] },
80913
- clangd: { command: ["clangd", "--background-index", "--clang-tidy"], extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"] },
80914
- svelte: { command: ["svelteserver", "--stdio"], extensions: [".svelte"] },
80915
- astro: { command: ["astro-ls", "--stdio"], extensions: [".astro"] },
80916
- bash: { command: ["bash-language-server", "start"], extensions: [".sh", ".bash", ".zsh", ".ksh"] },
80917
- "bash-ls": { command: ["bash-language-server", "start"], extensions: [".sh", ".bash", ".zsh", ".ksh"] },
80918
- jdtls: { command: ["jdtls"], extensions: [".java"] },
80919
- "yaml-ls": { command: ["yaml-language-server", "--stdio"], extensions: [".yaml", ".yml"] },
80920
- "lua-ls": { command: ["lua-language-server"], extensions: [".lua"] },
80921
- php: { command: ["intelephense", "--stdio"], extensions: [".php"] },
80922
- dart: { command: ["dart", "language-server", "--lsp"], extensions: [".dart"] },
80923
- terraform: { command: ["terraform-ls", "serve"], extensions: [".tf", ".tfvars"] },
80924
- "terraform-ls": { command: ["terraform-ls", "serve"], extensions: [".tf", ".tfvars"] },
80925
- prisma: { command: ["prisma", "language-server"], extensions: [".prisma"] },
80926
- "ocaml-lsp": { command: ["ocamllsp"], extensions: [".ml", ".mli"] },
80927
- texlab: { command: ["texlab"], extensions: [".tex", ".bib"] },
80928
- dockerfile: { command: ["docker-langserver", "--stdio"], extensions: [".dockerfile"] },
80929
- gleam: { command: ["gleam", "lsp"], extensions: [".gleam"] },
80930
- "clojure-lsp": { command: ["clojure-lsp", "listen"], extensions: [".clj", ".cljs", ".cljc", ".edn"] },
80931
- nixd: { command: ["nixd"], extensions: [".nix"] },
80932
- tinymist: { command: ["tinymist"], extensions: [".typ", ".typc"] },
80933
- "haskell-language-server": { command: ["haskell-language-server-wrapper", "--lsp"], extensions: [".hs", ".lhs"] },
80934
- "kotlin-ls": { command: ["kotlin-lsp"], extensions: [".kt", ".kts"] }
80935
- };
80936
- // src/tools/lsp/server-config-loader.ts
80937
- import { existsSync as existsSync39, readFileSync as readFileSync33 } from "fs";
81324
+
81325
+ // src/cli/doctor/checks/tools-lsp.ts
81326
+ import { readFileSync as readFileSync33 } from "fs";
80938
81327
  import { join as join39 } from "path";
80939
- init_shared();
80940
- init_jsonc_parser();
80941
- function loadJsonFile(path13) {
80942
- if (!existsSync39(path13))
80943
- return null;
81328
+
81329
+ // src/mcp/lsp.ts
81330
+ import { existsSync as existsSync40 } from "fs";
81331
+ import { dirname as dirname17, resolve as resolve6 } from "path";
81332
+ import { fileURLToPath as fileURLToPath3 } from "url";
81333
+ var SUBMODULE_REL = "packages/lsp-tools-mcp";
81334
+ var DIST_CLI_REL = "dist/cli.js";
81335
+ var SOURCE_CLI_REL = "src/cli.ts";
81336
+ var PROJECT_LSP_CONFIG = ".opencode/lsp.json";
81337
+ function addAncestorCommandCandidates(startDirectory, target, seenPaths, pathExists) {
81338
+ let currentDirectory = resolve6(startDirectory);
81339
+ while (true) {
81340
+ const distCliPath = resolve6(currentDirectory, SUBMODULE_REL, DIST_CLI_REL);
81341
+ if (!seenPaths.has(distCliPath)) {
81342
+ seenPaths.add(distCliPath);
81343
+ target.push({ command: ["node", distCliPath, "mcp"], path: distCliPath, exists: pathExists(distCliPath) });
81344
+ }
81345
+ const sourceCliPath = resolve6(currentDirectory, SUBMODULE_REL, SOURCE_CLI_REL);
81346
+ if (!seenPaths.has(sourceCliPath)) {
81347
+ seenPaths.add(sourceCliPath);
81348
+ target.push({ command: ["bun", sourceCliPath, "mcp"], path: sourceCliPath, exists: pathExists(sourceCliPath) });
81349
+ }
81350
+ const parentDirectory = resolve6(currentDirectory, "..");
81351
+ if (parentDirectory === currentDirectory) {
81352
+ return;
81353
+ }
81354
+ currentDirectory = parentDirectory;
81355
+ }
81356
+ }
81357
+ function getModuleDirectory(moduleUrl) {
80944
81358
  try {
80945
- return parseJsonc(readFileSync33(path13, "utf-8"));
81359
+ return dirname17(fileURLToPath3(moduleUrl));
80946
81360
  } catch {
80947
81361
  return null;
80948
81362
  }
80949
81363
  }
80950
- function getConfigPaths2() {
80951
- const cwd = process.cwd();
80952
- const configDir = getOpenCodeConfigDir({ binary: "opencode" });
80953
- return {
80954
- project: detectPluginConfigFile(join39(cwd, ".opencode")).path,
80955
- user: detectPluginConfigFile(configDir).path,
80956
- opencode: detectConfigFile(join39(configDir, "opencode")).path
80957
- };
80958
- }
80959
- function loadAllConfigs() {
80960
- const paths = getConfigPaths2();
80961
- const configs = new Map;
80962
- const project = loadJsonFile(paths.project);
80963
- if (project)
80964
- configs.set("project", project);
80965
- const user = loadJsonFile(paths.user);
80966
- if (user)
80967
- configs.set("user", user);
80968
- const opencode = loadJsonFile(paths.opencode);
80969
- if (opencode)
80970
- configs.set("opencode", opencode);
80971
- return configs;
80972
- }
80973
- function getMergedServers() {
80974
- const configs = loadAllConfigs();
80975
- const servers = [];
80976
- const disabled = new Set;
80977
- const seen = new Set;
80978
- const sources = ["project", "user", "opencode"];
80979
- for (const source of sources) {
80980
- const config2 = configs.get(source);
80981
- if (!config2?.lsp)
80982
- continue;
80983
- for (const [id, entry] of Object.entries(config2.lsp)) {
80984
- if (entry.disabled) {
80985
- disabled.add(id);
80986
- continue;
80987
- }
80988
- if (seen.has(id))
80989
- continue;
80990
- if (!entry.command || !entry.extensions)
80991
- continue;
80992
- servers.push({
80993
- id,
80994
- command: entry.command,
80995
- extensions: entry.extensions,
80996
- priority: entry.priority ?? 0,
80997
- env: entry.env,
80998
- initialization: entry.initialization,
80999
- source
81000
- });
81001
- seen.add(id);
81002
- }
81364
+ function resolveLspCommand(options = {}) {
81365
+ const pathExists = options.exists ?? existsSync40;
81366
+ const candidates = [];
81367
+ const seenPaths = new Set;
81368
+ const moduleDirectory = getModuleDirectory(options.moduleUrl ?? import.meta.url);
81369
+ if (moduleDirectory) {
81370
+ addAncestorCommandCandidates(moduleDirectory, candidates, seenPaths, pathExists);
81003
81371
  }
81004
- for (const [id, config2] of Object.entries(BUILTIN_SERVERS)) {
81005
- if (disabled.has(id) || seen.has(id))
81006
- continue;
81007
- servers.push({
81008
- id,
81009
- command: config2.command,
81010
- extensions: config2.extensions,
81011
- priority: -100,
81012
- source: "opencode"
81013
- });
81372
+ addAncestorCommandCandidates(options.cwd ?? process.cwd(), candidates, seenPaths, pathExists);
81373
+ const distCandidate = candidates.find((candidate) => candidate.path.endsWith(DIST_CLI_REL) && candidate.exists);
81374
+ if (distCandidate) {
81375
+ return distCandidate.command;
81014
81376
  }
81015
- return servers.sort((a, b3) => {
81016
- if (a.source !== b3.source) {
81017
- const order = { project: 0, user: 1, opencode: 2 };
81018
- return order[a.source] - order[b3.source];
81377
+ const sourceCandidate = candidates.find((candidate) => candidate.path.endsWith(SOURCE_CLI_REL) && candidate.exists);
81378
+ if (sourceCandidate) {
81379
+ return sourceCandidate.command;
81380
+ }
81381
+ return candidates[0]?.command ?? ["node", resolve6(process.cwd(), SUBMODULE_REL, DIST_CLI_REL), "mcp"];
81382
+ }
81383
+ function createLspMcpConfig(options = {}) {
81384
+ return {
81385
+ type: "local",
81386
+ command: resolveLspCommand(options),
81387
+ enabled: true,
81388
+ environment: {
81389
+ LSP_TOOLS_MCP_PROJECT_CONFIG: PROJECT_LSP_CONFIG
81019
81390
  }
81020
- return b3.priority - a.priority;
81021
- });
81391
+ };
81022
81392
  }
81023
81393
 
81024
- // src/tools/lsp/server-installation.ts
81025
- import { existsSync as existsSync40 } from "fs";
81026
- import { delimiter as delimiter2, join as join41 } from "path";
81027
-
81028
- // src/tools/lsp/server-path-bases.ts
81394
+ // src/cli/doctor/checks/tools-lsp.ts
81029
81395
  init_shared();
81030
- import { join as join40 } from "path";
81031
- function getLspServerAdditionalPathBases(workingDirectory) {
81032
- const configDir = getOpenCodeConfigDir({ binary: "opencode" });
81033
- const dataDir = join40(getDataDir(), "opencode");
81034
- return [
81035
- join40(workingDirectory, "node_modules", ".bin"),
81036
- join40(configDir, "bin"),
81037
- join40(configDir, "node_modules", ".bin"),
81038
- join40(dataDir, "bin"),
81039
- join40(dataDir, "bin", "node_modules", ".bin")
81040
- ];
81041
- }
81042
-
81043
- // src/tools/lsp/server-installation.ts
81044
- function isServerInstalled(command) {
81045
- if (command.length === 0)
81046
- return false;
81047
- const cmd = command[0];
81048
- if (cmd.includes("/") || cmd.includes("\\")) {
81049
- if (existsSync40(cmd))
81050
- return true;
81051
- }
81052
- const isWindows = process.platform === "win32";
81053
- let exts = [""];
81054
- if (isWindows) {
81055
- const pathExt = process.env.PATHEXT || "";
81056
- if (pathExt) {
81057
- const systemExts = pathExt.split(";").filter(Boolean);
81058
- exts = [...new Set([...exts, ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
81059
- } else {
81060
- exts = ["", ".exe", ".cmd", ".bat", ".ps1"];
81061
- }
81062
- }
81063
- let pathEnv = process.env.PATH || "";
81064
- if (isWindows && !pathEnv) {
81065
- pathEnv = process.env.Path || "";
81066
- }
81067
- const paths = pathEnv.split(delimiter2);
81068
- for (const p2 of paths) {
81069
- for (const suffix of exts) {
81070
- if (existsSync40(join41(p2, cmd + suffix))) {
81071
- return true;
81072
- }
81073
- }
81074
- }
81075
- for (const base of getLspServerAdditionalPathBases(process.cwd())) {
81076
- for (const suffix of exts) {
81077
- if (existsSync40(join41(base, cmd + suffix))) {
81078
- return true;
81079
- }
81080
- }
81396
+ var PROJECT_CONFIG_DIR3 = join39(process.cwd(), ".opencode");
81397
+ function readOmoConfig(configDirectory) {
81398
+ const detected = detectPluginConfigFile(configDirectory);
81399
+ if (detected.format === "none") {
81400
+ return null;
81081
81401
  }
81082
- if (cmd === "bun" || cmd === "node") {
81083
- return true;
81402
+ try {
81403
+ const content = readFileSync33(detected.path, "utf-8");
81404
+ return parseJsonc(content);
81405
+ } catch {
81406
+ return null;
81084
81407
  }
81085
- return false;
81086
81408
  }
81087
-
81088
- // src/tools/lsp/server-resolution.ts
81089
- function getAllServers() {
81090
- const configs = loadAllConfigs();
81091
- const servers = getMergedServers();
81092
- const disabled = new Set;
81093
- for (const config2 of configs.values()) {
81094
- if (!config2.lsp)
81095
- continue;
81096
- for (const [id, entry] of Object.entries(config2.lsp)) {
81097
- if (entry.disabled)
81098
- disabled.add(id);
81099
- }
81100
- }
81101
- const result = [];
81102
- const seen = new Set;
81103
- for (const server2 of servers) {
81104
- if (seen.has(server2.id))
81105
- continue;
81106
- result.push({
81107
- id: server2.id,
81108
- installed: isServerInstalled(server2.command),
81109
- extensions: server2.extensions,
81110
- disabled: false,
81111
- source: server2.source,
81112
- priority: server2.priority
81113
- });
81114
- seen.add(server2.id);
81115
- }
81116
- for (const id of disabled) {
81117
- if (seen.has(id))
81118
- continue;
81119
- const builtin = BUILTIN_SERVERS[id];
81120
- result.push({
81121
- id,
81122
- installed: builtin ? isServerInstalled(builtin.command) : false,
81123
- extensions: builtin?.extensions || [],
81124
- disabled: true,
81125
- source: "disabled",
81126
- priority: 0
81127
- });
81128
- }
81129
- return result;
81409
+ function isLspMcpDisabled() {
81410
+ const userConfigDirectory = getOpenCodeConfigDir({ binary: "opencode" });
81411
+ const userConfig = readOmoConfig(userConfigDirectory);
81412
+ const projectConfig = readOmoConfig(PROJECT_CONFIG_DIR3);
81413
+ const disabledMcps = new Set([
81414
+ ...userConfig?.disabled_mcps ?? [],
81415
+ ...projectConfig?.disabled_mcps ?? []
81416
+ ]);
81417
+ return disabledMcps.has("lsp");
81130
81418
  }
81131
- // src/cli/doctor/checks/tools-lsp.ts
81132
81419
  function getInstalledLspServers() {
81133
- const servers = getAllServers();
81134
- return servers.filter((s) => s.installed && !s.disabled).map((s) => ({ id: s.id, extensions: s.extensions }));
81420
+ if (isLspMcpDisabled()) {
81421
+ return [];
81422
+ }
81423
+ const lspMcpConfig = createLspMcpConfig();
81424
+ return lspMcpConfig.enabled ? [{ id: "lsp-tools-mcp", extensions: ["*"] }] : [];
81135
81425
  }
81136
81426
 
81137
81427
  // src/cli/doctor/checks/tools-mcp.ts
81138
81428
  init_shared();
81139
81429
  import { existsSync as existsSync41, readFileSync as readFileSync34 } from "fs";
81140
81430
  import { homedir as homedir12 } from "os";
81141
- import { join as join42 } from "path";
81431
+ import { join as join40 } from "path";
81142
81432
  var BUILTIN_MCP_SERVERS = ["context7", "grep_app"];
81143
81433
  function getMcpConfigPaths() {
81144
81434
  return [
81145
- join42(homedir12(), ".claude", ".mcp.json"),
81146
- join42(process.cwd(), ".mcp.json"),
81147
- join42(process.cwd(), ".claude", ".mcp.json")
81435
+ join40(homedir12(), ".claude", ".mcp.json"),
81436
+ join40(process.cwd(), ".mcp.json"),
81437
+ join40(process.cwd(), ".claude", ".mcp.json")
81148
81438
  ];
81149
81439
  }
81150
81440
  function loadUserMcpConfig() {
@@ -81749,11 +82039,11 @@ async function refreshModelCapabilities(options, deps = {}) {
81749
82039
 
81750
82040
  // src/features/mcp-oauth/storage.ts
81751
82041
  init_shared();
81752
- import { chmodSync as chmodSync2, existsSync as existsSync42, mkdirSync as mkdirSync12, readFileSync as readFileSync36, renameSync as renameSync4, unlinkSync as unlinkSync6, writeFileSync as writeFileSync10 } from "fs";
81753
- import { dirname as dirname17, join as join43 } from "path";
82042
+ import { chmodSync as chmodSync2, existsSync as existsSync42, mkdirSync as mkdirSync12, readFileSync as readFileSync36, renameSync as renameSync5, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "fs";
82043
+ import { dirname as dirname18, join as join41 } from "path";
81754
82044
  var STORAGE_FILE_NAME = "mcp-oauth.json";
81755
82045
  function getMcpOauthStoragePath() {
81756
- return join43(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
82046
+ return join41(getOpenCodeConfigDir({ binary: "opencode" }), STORAGE_FILE_NAME);
81757
82047
  }
81758
82048
  function normalizeHost2(serverHost) {
81759
82049
  let host = serverHost.trim();
@@ -81803,14 +82093,14 @@ function readStore() {
81803
82093
  function writeStore(store2) {
81804
82094
  const filePath = getMcpOauthStoragePath();
81805
82095
  try {
81806
- const dir = dirname17(filePath);
82096
+ const dir = dirname18(filePath);
81807
82097
  if (!existsSync42(dir)) {
81808
82098
  mkdirSync12(dir, { recursive: true });
81809
82099
  }
81810
82100
  const tempPath = `${filePath}.tmp.${Date.now()}`;
81811
82101
  writeFileSync10(tempPath, JSON.stringify(store2, null, 2), { encoding: "utf-8", mode: 384 });
81812
82102
  chmodSync2(tempPath, 384);
81813
- renameSync4(tempPath, filePath);
82103
+ renameSync5(tempPath, filePath);
81814
82104
  return true;
81815
82105
  } catch {
81816
82106
  return false;
@@ -81842,7 +82132,7 @@ function deleteToken(serverHost, resource) {
81842
82132
  try {
81843
82133
  const filePath = getMcpOauthStoragePath();
81844
82134
  if (existsSync42(filePath)) {
81845
- unlinkSync6(filePath);
82135
+ unlinkSync7(filePath);
81846
82136
  }
81847
82137
  return true;
81848
82138
  } catch {
@@ -82010,7 +82300,7 @@ async function getOrRegisterClient(options) {
82010
82300
  }
82011
82301
  }
82012
82302
  function parseRegistrationResponse(data) {
82013
- if (!isRecord8(data))
82303
+ if (!isRecord10(data))
82014
82304
  return null;
82015
82305
  const clientId = data.client_id;
82016
82306
  if (typeof clientId !== "string" || clientId.length === 0)
@@ -82021,7 +82311,7 @@ function parseRegistrationResponse(data) {
82021
82311
  }
82022
82312
  return { clientId };
82023
82313
  }
82024
- function isRecord8(value) {
82314
+ function isRecord10(value) {
82025
82315
  return typeof value === "object" && value !== null;
82026
82316
  }
82027
82317
 
@@ -82061,7 +82351,7 @@ function buildAuthorizationUrl(authorizationEndpoint, options) {
82061
82351
  }
82062
82352
  var CALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
82063
82353
  function startCallbackServer(port) {
82064
- return new Promise((resolve6, reject) => {
82354
+ return new Promise((resolve7, reject) => {
82065
82355
  let timeoutId;
82066
82356
  const server2 = createServer2((request, response) => {
82067
82357
  clearTimeout(timeoutId);
@@ -82087,7 +82377,7 @@ function startCallbackServer(port) {
82087
82377
  response.writeHead(200, { "content-type": "text/html" });
82088
82378
  response.end("<html><body><h1>Authorization successful. You can close this tab.</h1></body></html>");
82089
82379
  server2.close();
82090
- resolve6({ code, state: state2 });
82380
+ resolve7({ code, state: state2 });
82091
82381
  });
82092
82382
  timeoutId = setTimeout(() => {
82093
82383
  server2.close();