oh-my-opencode 4.18.1 → 4.19.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 (217) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
  3. package/README.ja.md +2 -2
  4. package/README.ko.md +2 -2
  5. package/README.md +4 -4
  6. package/README.ru.md +2 -2
  7. package/README.zh-cn.md +2 -2
  8. package/bin/AGENTS.md +33 -0
  9. package/dist/agents/atlas/agent.d.ts +6 -5
  10. package/dist/agents/sisyphus/index.d.ts +5 -0
  11. package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
  12. package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
  13. package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
  14. package/dist/agents/sisyphus-junior/index.d.ts +2 -0
  15. package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
  16. package/dist/agents/types.d.ts +2 -2
  17. package/dist/cli/index.js +690 -139
  18. package/dist/cli-node/index.js +690 -139
  19. package/dist/config/index.d.ts +1 -1
  20. package/dist/config/schema/browser-automation.d.ts +1 -0
  21. package/dist/config/schema/commands.d.ts +1 -3
  22. package/dist/config/schema/default-mode.d.ts +1 -1
  23. package/dist/config/schema/goal.d.ts +7 -0
  24. package/dist/config/schema/hooks.d.ts +1 -1
  25. package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
  26. package/dist/config/schema/ralph-loop.d.ts +1 -1
  27. package/dist/config/schema.d.ts +1 -1
  28. package/dist/create-hooks.d.ts +1 -1
  29. package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
  30. package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
  31. package/dist/features/builtin-commands/types.d.ts +1 -1
  32. package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
  33. package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
  34. package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
  35. package/dist/hooks/comment-checker/hook.d.ts +8 -1
  36. package/dist/hooks/goal/command-arguments.d.ts +13 -0
  37. package/dist/hooks/goal/controller.d.ts +26 -0
  38. package/dist/hooks/goal/index.d.ts +23 -0
  39. package/dist/hooks/goal/prompt.d.ts +3 -0
  40. package/dist/hooks/goal/store.d.ts +8 -0
  41. package/dist/hooks/goal/tools.d.ts +10 -0
  42. package/dist/hooks/goal/types.d.ts +93 -0
  43. package/dist/hooks/goal/validation.d.ts +4 -0
  44. package/dist/hooks/index.d.ts +1 -0
  45. package/dist/hooks/keyword-detector/hook.d.ts +1 -2
  46. package/dist/hooks/ralph-loop/types.d.ts +1 -1
  47. package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
  48. package/dist/index.js +3706 -4329
  49. package/dist/oh-my-opencode.schema.json +23 -19
  50. package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
  51. package/dist/plugin/chat-message/types.d.ts +23 -10
  52. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
  53. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
  54. package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
  55. package/dist/plugin/messages-transform.d.ts +1 -0
  56. package/dist/plugin/stop-continuation.d.ts +2 -2
  57. package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
  58. package/dist/shared/system-directive.d.ts +0 -1
  59. package/dist/skills/ulw-plan/SKILL.md +11 -7
  60. package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
  61. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  62. package/dist/skills/ulw-research/SKILL.md +3 -3
  63. package/dist/tools/delegate-task/types.d.ts +0 -1
  64. package/dist/tui.js +115 -28
  65. package/package.json +14 -14
  66. package/packages/git-bash-mcp/dist/cli.js +81 -19
  67. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
  68. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
  69. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
  70. package/packages/lsp-daemon/dist/cli.js +262 -63
  71. package/packages/lsp-daemon/dist/client.js +194 -50
  72. package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
  73. package/packages/lsp-daemon/dist/daemon-client.js +26 -2
  74. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
  75. package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
  76. package/packages/lsp-daemon/dist/index.js +262 -63
  77. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  78. package/packages/lsp-daemon/dist/proxy.js +79 -23
  79. package/packages/lsp-tools-mcp/dist/cli.js +82 -20
  80. package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
  81. package/packages/lsp-tools-mcp/dist/tools.js +1 -1
  82. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  83. package/packages/omo-codex/plugin/.mcp.json +2 -1
  84. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
  85. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  86. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +7 -6
  88. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
  89. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
  90. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
  92. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
  93. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
  94. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
  95. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
  96. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  97. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  98. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  99. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  101. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  102. package/packages/omo-codex/plugin/components/lsp/.mcp.json +2 -1
  103. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
  104. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  105. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
  106. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  107. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  108. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +1 -0
  109. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  110. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
  111. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  112. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
  114. package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
  115. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
  116. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
  117. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  118. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  119. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +4 -72
  120. package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
  121. package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
  122. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
  123. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
  124. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
  125. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
  126. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  127. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  128. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  129. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  130. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -10
  131. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
  132. package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
  133. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  134. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  135. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
  136. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
  137. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
  138. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  139. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
  140. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
  141. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
  142. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  143. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
  145. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
  146. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
  147. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  148. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  149. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  150. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  151. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  152. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  153. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  154. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  155. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  156. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  170. package/packages/omo-codex/plugin/package-lock.json +13 -13
  171. package/packages/omo-codex/plugin/package.json +1 -1
  172. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
  173. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
  174. package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
  175. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
  176. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
  177. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
  178. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
  179. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
  180. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
  181. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
  182. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  183. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
  184. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
  185. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
  186. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
  187. package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
  188. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
  189. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
  190. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
  191. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
  192. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
  193. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
  194. package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
  195. package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
  196. package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
  197. package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
  198. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
  199. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  200. package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
  201. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
  202. package/dist/skills/ultraresearch/SKILL.md +0 -10
  203. package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
  204. package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
  205. package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
  206. package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
  207. package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
  208. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
  209. package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
  210. package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
  211. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
  212. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
  213. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
  214. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
  215. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
  216. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
  217. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
@@ -3006,7 +3006,7 @@ async function disposeDefaultLspManager() {
3006
3006
  }
3007
3007
  }
3008
3008
  // src/daemon-client.ts
3009
- import { connect as connect2 } from "node:net";
3009
+ import { connect } from "node:net";
3010
3010
  import { homedir as homedir3 } from "node:os";
3011
3011
  import { join as join7 } from "node:path";
3012
3012
 
@@ -3187,7 +3187,7 @@ function isPlainRecord(value) {
3187
3187
  // src/ensure-daemon.ts
3188
3188
  import { spawn as spawn2 } from "node:child_process";
3189
3189
  import { closeSync as closeSync2, mkdirSync as mkdirSync2, openSync as openSync2 } from "node:fs";
3190
- import { connect } from "node:net";
3190
+ import { Socket } from "node:net";
3191
3191
  import { dirname as dirname6 } from "node:path";
3192
3192
  import { execPath } from "node:process";
3193
3193
 
@@ -3594,42 +3594,48 @@ class DaemonUnreachableError extends Error {
3594
3594
  async function ensureDaemonRunning(paths, deps = defaultEnsureDaemonDeps(), options = {}) {
3595
3595
  const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
3596
3596
  const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
3597
- if (await deps.probe(paths))
3597
+ const signal = options.signal;
3598
+ throwIfAborted(signal);
3599
+ if (await awaitWithSignal2(deps.probe(paths, signal), signal))
3598
3600
  return;
3601
+ throwIfAborted(signal);
3599
3602
  deps.spawnDaemon(paths);
3600
- await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs);
3603
+ await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal);
3601
3604
  }
3602
- async function waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs) {
3605
+ async function waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal) {
3603
3606
  const deadline = deps.now() + readyTimeoutMs;
3604
3607
  for (;; ) {
3605
- if (await deps.probe(paths))
3608
+ throwIfAborted(signal);
3609
+ if (await awaitWithSignal2(deps.probe(paths, signal), signal))
3606
3610
  return;
3607
3611
  if (deps.now() >= deadline)
3608
3612
  throw new DaemonUnreachableError(paths.socket);
3609
- await deps.sleep(pollIntervalMs);
3613
+ await awaitWithSignal2(deps.sleep(pollIntervalMs, signal), signal);
3610
3614
  }
3611
3615
  }
3612
- async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS) {
3616
+ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
3613
3617
  const token = readAuthToken(paths);
3614
3618
  if (!token)
3615
3619
  return false;
3616
- return await pingDaemon(paths, token, timeoutMs) !== null;
3620
+ return await pingDaemon(paths, token, timeoutMs, signal) !== null;
3617
3621
  }
3618
- function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS) {
3622
+ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
3619
3623
  return new Promise((resolve7) => {
3620
- const socket = connect(paths.socket);
3624
+ const socket = new Socket;
3621
3625
  let settled = false;
3626
+ let timer;
3622
3627
  const finish = (value) => {
3623
3628
  if (settled)
3624
3629
  return;
3625
3630
  settled = true;
3631
+ if (timer !== undefined)
3632
+ clearTimeout(timer);
3633
+ signal?.removeEventListener("abort", onAbort);
3626
3634
  socket.destroy();
3627
3635
  resolve7(value);
3628
3636
  };
3629
- const timer = setTimeout(() => finish(null), timeoutMs);
3630
- timer.unref?.();
3637
+ const onAbort = () => finish(null);
3631
3638
  const decoder = createLineDecoder((message) => {
3632
- clearTimeout(timer);
3633
3639
  finish(parsePingResponse(message));
3634
3640
  });
3635
3641
  socket.once("connect", () => {
@@ -3637,9 +3643,16 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS) {
3637
3643
  });
3638
3644
  socket.on("data", (chunk) => decoder.push(chunk));
3639
3645
  socket.once("error", () => {
3640
- clearTimeout(timer);
3641
3646
  finish(null);
3642
3647
  });
3648
+ timer = setTimeout(() => finish(null), timeoutMs);
3649
+ timer.unref?.();
3650
+ if (signal?.aborted) {
3651
+ onAbort();
3652
+ return;
3653
+ }
3654
+ signal?.addEventListener("abort", onAbort, { once: true });
3655
+ socket.connect(paths.socket);
3643
3656
  });
3644
3657
  }
3645
3658
  function spawnDaemonProcess(paths) {
@@ -3657,14 +3670,62 @@ function spawnDaemonProcess(paths) {
3657
3670
  }
3658
3671
  function defaultEnsureDaemonDeps() {
3659
3672
  return {
3660
- probe: (paths) => probeDaemon(paths),
3673
+ probe: (paths, signal) => probeDaemon(paths, PROBE_TIMEOUT_MS, signal),
3661
3674
  spawnDaemon: (paths) => spawnDaemonProcess(paths),
3662
- sleep: (ms) => new Promise((resolve7) => {
3663
- setTimeout(resolve7, ms);
3664
- }),
3675
+ sleep: (ms, signal) => sleepWithSignal(ms, signal),
3665
3676
  now: () => Date.now()
3666
3677
  };
3667
3678
  }
3679
+ function sleepWithSignal(ms, signal) {
3680
+ return new Promise((resolve7) => {
3681
+ let settled = false;
3682
+ const finish = () => {
3683
+ if (settled)
3684
+ return;
3685
+ settled = true;
3686
+ clearTimeout(timer);
3687
+ signal?.removeEventListener("abort", finish);
3688
+ resolve7();
3689
+ };
3690
+ const timer = setTimeout(finish, ms);
3691
+ if (signal?.aborted) {
3692
+ finish();
3693
+ return;
3694
+ }
3695
+ signal?.addEventListener("abort", finish, { once: true });
3696
+ });
3697
+ }
3698
+ function awaitWithSignal2(promise, signal) {
3699
+ if (!signal)
3700
+ return promise;
3701
+ if (signal.aborted)
3702
+ return Promise.reject(abortError3(signal));
3703
+ return new Promise((resolve7, reject) => {
3704
+ let settled = false;
3705
+ const finish = (run) => {
3706
+ if (settled)
3707
+ return;
3708
+ settled = true;
3709
+ signal.removeEventListener("abort", onAbort);
3710
+ run();
3711
+ };
3712
+ const onAbort = () => finish(() => reject(abortError3(signal)));
3713
+ signal.addEventListener("abort", onAbort, { once: true });
3714
+ promise.then((value) => finish(() => resolve7(value)), (error) => finish(() => reject(error)));
3715
+ });
3716
+ }
3717
+ function throwIfAborted(signal) {
3718
+ if (signal?.aborted)
3719
+ throw abortError3(signal);
3720
+ }
3721
+ function abortError3(signal) {
3722
+ const reason = signal.reason;
3723
+ if (reason instanceof Error)
3724
+ return reason;
3725
+ const error = new Error(typeof reason === "string" ? reason : "daemon startup cancelled");
3726
+ error.name = "AbortError";
3727
+ return error;
3728
+ }
3668
3729
  function parsePingResponse(message) {
3669
3730
  if (!message || typeof message !== "object" || Array.isArray(message))
3670
3731
  return null;
@@ -3704,6 +3765,9 @@ function errorResponse(id, code, message, data) {
3704
3765
  function jsonRpcId2(value) {
3705
3766
  return typeof value === "string" || typeof value === "number" || value === null ? value : null;
3706
3767
  }
3768
+ function messageFromError(error) {
3769
+ return error instanceof Error ? error.message : String(error);
3770
+ }
3707
3771
  // ../mcp-stdio-core/src/transport.ts
3708
3772
  var HEADER_SEPARATOR2 = Buffer.from(`\r
3709
3773
  \r
@@ -3726,16 +3790,45 @@ async function* readStdioJsonRpcMessages(input) {
3726
3790
  yield parseJsonPayload(trailing, "line");
3727
3791
  }
3728
3792
  }
3729
- function writeStdioJsonRpcResponse(output, response, responseMode) {
3793
+ async function writeStdioJsonRpcResponse(output, response, responseMode) {
3730
3794
  const body = JSON.stringify(response);
3731
- if (responseMode === "framed") {
3732
- output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
3795
+ const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
3733
3796
  \r
3734
- ${body}`);
3735
- return;
3736
- }
3737
- output.write(`${body}
3738
- `);
3797
+ ${body}` : `${body}
3798
+ `;
3799
+ await writeChunk(output, payload);
3800
+ }
3801
+ function writeChunk(output, chunk) {
3802
+ return new Promise((resolve7, reject) => {
3803
+ let settled = false;
3804
+ const onError = (error) => {
3805
+ if (settled)
3806
+ return;
3807
+ settled = true;
3808
+ reject(error);
3809
+ };
3810
+ output.once("error", onError);
3811
+ try {
3812
+ output.write(chunk, (error) => {
3813
+ if (settled)
3814
+ return;
3815
+ settled = true;
3816
+ if (error) {
3817
+ queueMicrotask(() => output.removeListener("error", onError));
3818
+ reject(error);
3819
+ return;
3820
+ }
3821
+ output.removeListener("error", onError);
3822
+ resolve7();
3823
+ });
3824
+ } catch (error) {
3825
+ output.removeListener("error", onError);
3826
+ if (settled)
3827
+ return;
3828
+ settled = true;
3829
+ reject(error);
3830
+ }
3831
+ });
3739
3832
  }
3740
3833
  function readNextMessage(buffer) {
3741
3834
  if (buffer.length === 0)
@@ -3831,40 +3924,70 @@ async function runJsonRpcStdioServer(config) {
3831
3924
  break;
3832
3925
  idleTimer.arm();
3833
3926
  if (message.kind === "parse_error") {
3834
- handleParseError(message, config, log);
3927
+ if (!await handleParseError(message, config, log))
3928
+ break;
3835
3929
  continue;
3836
3930
  }
3837
- await handleRequest(message, config, log);
3931
+ if (!await handleRequest(message, config, log))
3932
+ break;
3838
3933
  }
3839
3934
  } finally {
3840
3935
  idleTimer.clear();
3841
3936
  log("stdio_stopped");
3842
3937
  }
3843
3938
  }
3844
- function handleParseError(message, config, log) {
3939
+ async function handleParseError(message, config, log) {
3845
3940
  log("parse_error", { message: message.message });
3846
3941
  const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
3847
- if (response !== undefined) {
3848
- writeStdioJsonRpcResponse(config.output, response, message.responseMode);
3849
- }
3942
+ if (response === undefined)
3943
+ return true;
3944
+ return writeResponse(response, {
3945
+ output: config.output,
3946
+ responseMode: message.responseMode,
3947
+ log
3948
+ });
3850
3949
  }
3851
3950
  async function handleRequest(message, config, log) {
3852
3951
  const parsed = message.payload;
3853
3952
  const id = isPlainRecord(parsed) ? jsonRpcId2(parsed["id"]) : null;
3854
3953
  const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
3855
3954
  log("request", { id: id === null ? null : String(id), method });
3955
+ let response;
3856
3956
  try {
3857
- const response = await config.handler(parsed, config.handlerOptions);
3858
- if (response === undefined)
3859
- return;
3860
- writeStdioJsonRpcResponse(config.output, response, message.responseMode);
3861
- log("response", { id: String(response.id), method, is_error: response.error !== undefined });
3957
+ response = await config.handler(parsed, config.handlerOptions);
3862
3958
  } catch (error) {
3863
3959
  if (config.onHandlerError === undefined)
3864
3960
  throw error;
3865
3961
  config.onHandlerError(error);
3962
+ return true;
3963
+ }
3964
+ if (response === undefined)
3965
+ return true;
3966
+ if (!await writeResponse(response, {
3967
+ output: config.output,
3968
+ responseMode: message.responseMode,
3969
+ log
3970
+ }))
3971
+ return false;
3972
+ log("response", { id: String(response.id), method, is_error: response.error !== undefined });
3973
+ return true;
3974
+ }
3975
+ async function writeResponse(response, context) {
3976
+ try {
3977
+ await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
3978
+ return true;
3979
+ } catch (error) {
3980
+ if (!isTerminalOutputError(error))
3981
+ throw error;
3982
+ context.log("output_error", { message: messageFromError(error) });
3983
+ return false;
3866
3984
  }
3867
3985
  }
3986
+ function isTerminalOutputError(error) {
3987
+ if (!(error instanceof Error) || !("code" in error))
3988
+ return false;
3989
+ return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
3990
+ }
3868
3991
  function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
3869
3992
  let timer = null;
3870
3993
  let isClosed = false;
@@ -4747,7 +4870,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4747
4870
  const fileErrors = [];
4748
4871
  const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
4749
4872
  options.signal?.throwIfAborted();
4750
- const client = await manager.getClient(root, server2);
4873
+ const client = await manager.getClient(root, server2, options.signal);
4751
4874
  try {
4752
4875
  let nextIndex = 0;
4753
4876
  const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
@@ -5617,14 +5740,14 @@ class DaemonRequestCancelledError extends DaemonRequestError {
5617
5740
  async function callToolViaDaemon(name, args, options) {
5618
5741
  const context = requireContext(options.context);
5619
5742
  const paths = options.paths ?? daemonPaths();
5620
- const ensure = options.ensure ?? ensureDaemonRunning;
5743
+ const ensure = options.ensure ?? ((ensurePaths, signal) => ensureDaemonRunning(ensurePaths, undefined, signal === undefined ? {} : { signal }));
5621
5744
  const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
5622
5745
  const requestArgs = withContext(args, context);
5623
5746
  let lastError;
5624
5747
  let authRefreshUsed = false;
5625
5748
  for (let attempt = 0;attempt < 3; attempt += 1) {
5626
5749
  try {
5627
- await ensure(paths);
5750
+ await ensureDaemonAvailable(paths, ensure, options.signal);
5628
5751
  const token = readAuthToken(paths);
5629
5752
  if (!token)
5630
5753
  throw new DaemonRequestError("daemon auth token missing", false);
@@ -5666,6 +5789,27 @@ function requireContext(context) {
5666
5789
  function withContext(args, context) {
5667
5790
  return { ...args, [CONTEXT_KEY]: context };
5668
5791
  }
5792
+ function ensureDaemonAvailable(paths, ensure, signal) {
5793
+ if (!signal)
5794
+ return ensure(paths);
5795
+ return new Promise((resolve9, reject) => {
5796
+ let settled = false;
5797
+ const finish = (run) => {
5798
+ if (settled)
5799
+ return;
5800
+ settled = true;
5801
+ signal.removeEventListener("abort", onAbort);
5802
+ run();
5803
+ };
5804
+ const onAbort = () => finish(() => reject(new DaemonRequestCancelledError(false)));
5805
+ if (signal.aborted) {
5806
+ onAbort();
5807
+ return;
5808
+ }
5809
+ signal.addEventListener("abort", onAbort, { once: true });
5810
+ Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve9()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
5811
+ });
5812
+ }
5669
5813
  function daemonUnreachableResult(paths, error) {
5670
5814
  const text2 = [
5671
5815
  `LSP daemon unreachable: ${errorText(error)}.`,
@@ -5679,7 +5823,7 @@ function daemonUnreachableResult(paths, error) {
5679
5823
  }
5680
5824
  function sendToolCall(paths, token, name, args, options) {
5681
5825
  return new Promise((resolve9, reject) => {
5682
- const socket = connect2(paths.socket);
5826
+ const socket = connect(paths.socket);
5683
5827
  const requestId = allocateProxyRequestId();
5684
5828
  let settled = false;
5685
5829
  let requestWritten = false;
@@ -5781,38 +5925,93 @@ function errorText(error) {
5781
5925
  // src/proxy.ts
5782
5926
  import { existsSync as existsSync11, realpathSync as realpathSync4 } from "node:fs";
5783
5927
  import { basename as basename3, delimiter as delimiter4, dirname as dirname9, isAbsolute as isAbsolute4 } from "node:path";
5928
+ var DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
5784
5929
  async function runMcpStdioProxy(options = {}) {
5785
5930
  const input = options.input ?? process.stdin;
5786
5931
  const output = options.output ?? process.stdout;
5787
- const paths = options.paths ?? daemonPaths();
5788
- const env = options.env ?? process.env;
5789
- const cwd = options.cwd ?? inferOpenCodeProjectCwd(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]);
5790
- const contextEnv = cwd === undefined ? env : canonicalizeContextEnv(env);
5791
- const contextInput = {
5792
- env: contextEnv,
5793
- ...cwd === undefined ? {} : { cwd },
5794
- ...options.homeDir === undefined ? {} : { homeDir: options.homeDir }
5932
+ const stderr = options.stderr ?? process.stderr;
5933
+ const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
5934
+ const lifecycleController = new AbortController;
5935
+ const abortFromInput = () => lifecycleController.abort();
5936
+ let startupExpired = false;
5937
+ let startupTimer;
5938
+ const clearStartupWatchdog = () => {
5939
+ if (startupTimer === undefined)
5940
+ return;
5941
+ clearTimeout(startupTimer);
5942
+ startupTimer = undefined;
5795
5943
  };
5796
- const context = options.context ?? createStandaloneMcpRequestContext(contextInput);
5797
- const callOptions = { paths, context, ...options.ensure ? { ensure: options.ensure } : {} };
5798
- await runJsonRpcStdioServer({
5799
- input,
5800
- output,
5801
- idleTimeoutMs: 0,
5802
- handler: (request, requestOptions) => runWithRequestContext(context, () => handleProxyRequest(request, requestOptions)),
5803
- handlerOptions: callOptions,
5804
- onHandlerError: (error) => {
5805
- process.stderr.write(`[lsp-daemon] proxy error: ${error instanceof Error ? error.message : String(error)}
5944
+ input.once("end", abortFromInput);
5945
+ input.once("close", abortFromInput);
5946
+ if (startupTimeoutMs > 0) {
5947
+ startupTimer = setTimeout(() => {
5948
+ startupExpired = true;
5949
+ input.destroy();
5950
+ try {
5951
+ stderr.write(`[lsp-daemon] no MCP request received within ${startupTimeoutMs}ms; exiting
5806
5952
  `);
5807
- }
5808
- });
5953
+ } catch (error) {
5954
+ if (stderr !== process.stderr) {
5955
+ process.stderr.write(`[lsp-daemon] startup diagnostic failed: ${error instanceof Error ? error.message : String(error)}
5956
+ `);
5957
+ }
5958
+ }
5959
+ }, startupTimeoutMs);
5960
+ }
5961
+ try {
5962
+ const paths = options.paths ?? daemonPaths();
5963
+ const env = options.env ?? process.env;
5964
+ const cwd = options.cwd ?? inferOpenCodeProjectCwd(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]);
5965
+ const contextEnv = cwd === undefined ? env : canonicalizeContextEnv(env);
5966
+ const contextInput = {
5967
+ env: contextEnv,
5968
+ ...cwd === undefined ? {} : { cwd },
5969
+ ...options.homeDir === undefined ? {} : { homeDir: options.homeDir }
5970
+ };
5971
+ const context = options.context ?? createStandaloneMcpRequestContext(contextInput);
5972
+ const callOptions = {
5973
+ paths,
5974
+ context,
5975
+ ...options.ensure ? { ensure: options.ensure } : {},
5976
+ signal: lifecycleController.signal
5977
+ };
5978
+ await runJsonRpcStdioServer({
5979
+ input,
5980
+ output,
5981
+ idleTimeoutMs: 0,
5982
+ handler: (request, requestOptions) => {
5983
+ clearStartupWatchdog();
5984
+ return runWithRequestContext(context, () => handleProxyRequest(request, requestOptions));
5985
+ },
5986
+ handlerOptions: callOptions,
5987
+ onHandlerError: (error) => {
5988
+ stderr.write(`[lsp-daemon] proxy error: ${error instanceof Error ? error.message : String(error)}
5989
+ `);
5990
+ }
5991
+ });
5992
+ } catch (error) {
5993
+ if (!startupExpired || !isPrematureCloseError(error))
5994
+ throw error;
5995
+ } finally {
5996
+ if (startupTimer !== undefined)
5997
+ clearTimeout(startupTimer);
5998
+ input.removeListener("end", abortFromInput);
5999
+ input.removeListener("close", abortFromInput);
6000
+ }
6001
+ }
6002
+ function isPrematureCloseError(error) {
6003
+ return error instanceof Error && Reflect.get(error, "code") === "ERR_STREAM_PREMATURE_CLOSE";
5809
6004
  }
5810
6005
  async function handleProxyRequest(parsed, callOptions) {
5811
6006
  const toolCall = asToolCall(parsed);
5812
6007
  if (!toolCall)
5813
6008
  return handleLspMcpRequest(parsed);
5814
6009
  const result = await callToolViaDaemon(toolCall.name, toolCall.args, callOptions);
5815
- return successResponse(toolCall.id, { content: result.content, isError: result.isError ?? false, details: result.details });
6010
+ return successResponse(toolCall.id, {
6011
+ content: result.content,
6012
+ isError: result.isError ?? false,
6013
+ details: result.details
6014
+ });
5816
6015
  }
5817
6016
  function asToolCall(parsed) {
5818
6017
  if (!isPlainRecord(parsed) || parsed["method"] !== "tools/call")
@@ -4,11 +4,13 @@ import { type DaemonPaths } from "./paths.js";
4
4
  export interface ProxyOptions {
5
5
  input?: Readable;
6
6
  output?: Writable;
7
+ stderr?: Writable;
7
8
  paths?: DaemonPaths;
8
9
  context?: DaemonToolContext;
9
10
  cwd?: string;
10
11
  env?: Record<string, string | undefined>;
11
12
  homeDir?: string;
12
13
  ensure?: CallToolOptions["ensure"];
14
+ startupTimeoutMs?: number;
13
15
  }
14
16
  export declare function runMcpStdioProxy(options?: ProxyOptions): Promise<void>;
@@ -1,42 +1,98 @@
1
1
  import { existsSync, realpathSync } from "node:fs";
2
2
  import { basename, delimiter, dirname, isAbsolute } from "node:path";
3
- import { jsonRpcId, runJsonRpcStdioServer, successResponse } from "@oh-my-opencode/mcp-stdio-core";
4
- import { isPlainRecord } from "@oh-my-opencode/mcp-stdio-core/record";
5
3
  import { handleLspMcpRequest } from "@oh-my-opencode/lsp-core/mcp";
6
4
  import { createStandaloneMcpRequestContext, runWithRequestContext } from "@oh-my-opencode/lsp-core/request-context";
5
+ import { jsonRpcId, runJsonRpcStdioServer, successResponse } from "@oh-my-opencode/mcp-stdio-core";
6
+ import { isPlainRecord } from "@oh-my-opencode/mcp-stdio-core/record";
7
7
  import { callToolViaDaemon } from "./daemon-client.js";
8
8
  import { daemonPaths } from "./paths.js";
9
+ const DEFAULT_STARTUP_TIMEOUT_MS = 10_000;
9
10
  export async function runMcpStdioProxy(options = {}) {
10
11
  const input = options.input ?? process.stdin;
11
12
  const output = options.output ?? process.stdout;
12
- const paths = options.paths ?? daemonPaths();
13
- const env = options.env ?? process.env;
14
- const cwd = options.cwd ?? inferOpenCodeProjectCwd(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]);
15
- const contextEnv = cwd === undefined ? env : canonicalizeContextEnv(env);
16
- const contextInput = {
17
- env: contextEnv,
18
- ...(cwd === undefined ? {} : { cwd }),
19
- ...(options.homeDir === undefined ? {} : { homeDir: options.homeDir }),
13
+ const stderr = options.stderr ?? process.stderr;
14
+ const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
15
+ const lifecycleController = new AbortController();
16
+ const abortFromInput = () => lifecycleController.abort();
17
+ let startupExpired = false;
18
+ let startupTimer;
19
+ const clearStartupWatchdog = () => {
20
+ if (startupTimer === undefined)
21
+ return;
22
+ clearTimeout(startupTimer);
23
+ startupTimer = undefined;
20
24
  };
21
- const context = options.context ?? createStandaloneMcpRequestContext(contextInput);
22
- const callOptions = { paths, context, ...(options.ensure ? { ensure: options.ensure } : {}) };
23
- await runJsonRpcStdioServer({
24
- input,
25
- output,
26
- idleTimeoutMs: 0,
27
- handler: (request, requestOptions) => runWithRequestContext(context, () => handleProxyRequest(request, requestOptions)),
28
- handlerOptions: callOptions,
29
- onHandlerError: (error) => {
30
- process.stderr.write(`[lsp-daemon] proxy error: ${error instanceof Error ? error.message : String(error)}\n`);
31
- },
32
- });
25
+ input.once("end", abortFromInput);
26
+ input.once("close", abortFromInput);
27
+ if (startupTimeoutMs > 0) {
28
+ startupTimer = setTimeout(() => {
29
+ startupExpired = true;
30
+ input.destroy();
31
+ try {
32
+ stderr.write(`[lsp-daemon] no MCP request received within ${startupTimeoutMs}ms; exiting\n`);
33
+ }
34
+ catch (error) {
35
+ if (stderr !== process.stderr) {
36
+ process.stderr.write(`[lsp-daemon] startup diagnostic failed: ${error instanceof Error ? error.message : String(error)}\n`);
37
+ }
38
+ }
39
+ }, startupTimeoutMs);
40
+ }
41
+ try {
42
+ const paths = options.paths ?? daemonPaths();
43
+ const env = options.env ?? process.env;
44
+ const cwd = options.cwd ?? inferOpenCodeProjectCwd(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]);
45
+ const contextEnv = cwd === undefined ? env : canonicalizeContextEnv(env);
46
+ const contextInput = {
47
+ env: contextEnv,
48
+ ...(cwd === undefined ? {} : { cwd }),
49
+ ...(options.homeDir === undefined ? {} : { homeDir: options.homeDir }),
50
+ };
51
+ const context = options.context ?? createStandaloneMcpRequestContext(contextInput);
52
+ const callOptions = {
53
+ paths,
54
+ context,
55
+ ...(options.ensure ? { ensure: options.ensure } : {}),
56
+ signal: lifecycleController.signal,
57
+ };
58
+ await runJsonRpcStdioServer({
59
+ input,
60
+ output,
61
+ idleTimeoutMs: 0,
62
+ handler: (request, requestOptions) => {
63
+ clearStartupWatchdog();
64
+ return runWithRequestContext(context, () => handleProxyRequest(request, requestOptions));
65
+ },
66
+ handlerOptions: callOptions,
67
+ onHandlerError: (error) => {
68
+ stderr.write(`[lsp-daemon] proxy error: ${error instanceof Error ? error.message : String(error)}\n`);
69
+ },
70
+ });
71
+ }
72
+ catch (error) {
73
+ if (!startupExpired || !isPrematureCloseError(error))
74
+ throw error;
75
+ }
76
+ finally {
77
+ if (startupTimer !== undefined)
78
+ clearTimeout(startupTimer);
79
+ input.removeListener("end", abortFromInput);
80
+ input.removeListener("close", abortFromInput);
81
+ }
82
+ }
83
+ function isPrematureCloseError(error) {
84
+ return error instanceof Error && Reflect.get(error, "code") === "ERR_STREAM_PREMATURE_CLOSE";
33
85
  }
34
86
  async function handleProxyRequest(parsed, callOptions) {
35
87
  const toolCall = asToolCall(parsed);
36
88
  if (!toolCall)
37
89
  return handleLspMcpRequest(parsed);
38
90
  const result = await callToolViaDaemon(toolCall.name, toolCall.args, callOptions);
39
- return successResponse(toolCall.id, { content: result.content, isError: result.isError ?? false, details: result.details });
91
+ return successResponse(toolCall.id, {
92
+ content: result.content,
93
+ isError: result.isError ?? false,
94
+ details: result.details,
95
+ });
40
96
  }
41
97
  function asToolCall(parsed) {
42
98
  if (!isPlainRecord(parsed) || parsed["method"] !== "tools/call")