oh-my-opencode 4.18.0 → 4.18.1

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 (192) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
  3. package/.agents/skills/work-with-pr/SKILL.md +16 -37
  4. package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
  5. package/.opencode/skills/work-with-pr/SKILL.md +16 -37
  6. package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
  7. package/dist/cli/index.js +457 -154
  8. package/dist/cli-node/index.js +457 -154
  9. package/dist/index.js +415 -388
  10. package/package.json +16 -16
  11. package/packages/lsp-core/package.json +4 -0
  12. package/packages/lsp-core/src/index.ts +1 -0
  13. package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
  14. package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
  15. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
  16. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
  17. package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
  18. package/packages/lsp-core/src/lsp/client.ts +262 -80
  19. package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
  20. package/packages/lsp-core/src/lsp/connection.ts +12 -6
  21. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
  22. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
  23. package/packages/lsp-core/src/lsp/errors.ts +11 -0
  24. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
  25. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
  26. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
  27. package/packages/lsp-core/src/lsp/formatters.ts +3 -0
  28. package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
  29. package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
  30. package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
  31. package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
  32. package/packages/lsp-core/src/lsp/transport.ts +96 -70
  33. package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
  34. package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
  35. package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
  36. package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
  37. package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
  38. package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
  39. package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
  40. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
  41. package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
  42. package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
  43. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
  44. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
  45. package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
  46. package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
  47. package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
  48. package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
  49. package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
  50. package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
  51. package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
  52. package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
  53. package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
  54. package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
  55. package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
  56. package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
  57. package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
  58. package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
  59. package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
  60. package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
  61. package/packages/lsp-core/src/mcp.ts +18 -7
  62. package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
  63. package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
  64. package/packages/lsp-core/src/post-edit/index.ts +1 -0
  65. package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
  66. package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
  67. package/packages/lsp-core/src/request-context.test.ts +171 -0
  68. package/packages/lsp-core/src/request-context.ts +222 -9
  69. package/packages/lsp-core/src/tool-surface.test.ts +4 -1
  70. package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
  71. package/packages/lsp-core/src/tools/navigation.ts +12 -12
  72. package/packages/lsp-core/src/tools/rename.ts +10 -15
  73. package/packages/lsp-core/src/tools/symbols.ts +11 -11
  74. package/packages/lsp-core/src/tools/types.ts +2 -1
  75. package/packages/lsp-daemon/dist/cli.js +3114 -747
  76. package/packages/lsp-daemon/dist/client.d.ts +105 -0
  77. package/packages/lsp-daemon/dist/client.js +5851 -0
  78. package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
  79. package/packages/lsp-daemon/dist/daemon-client.js +113 -30
  80. package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
  81. package/packages/lsp-daemon/dist/daemon-server.js +40 -15
  82. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
  83. package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
  84. package/packages/lsp-daemon/dist/index.d.ts +2 -2
  85. package/packages/lsp-daemon/dist/index.js +2862 -754
  86. package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
  87. package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
  88. package/packages/lsp-daemon/dist/lock.js +14 -4
  89. package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
  90. package/packages/lsp-daemon/dist/ownership.js +168 -0
  91. package/packages/lsp-daemon/dist/paths.d.ts +33 -9
  92. package/packages/lsp-daemon/dist/paths.js +72 -33
  93. package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
  94. package/packages/lsp-daemon/dist/proxy.js +54 -3
  95. package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
  96. package/packages/lsp-daemon/dist/request-routing.js +71 -22
  97. package/packages/lsp-daemon/dist/run-daemon.js +9 -2
  98. package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
  99. package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
  100. package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
  101. package/packages/lsp-daemon/package.json +12 -3
  102. package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
  103. package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
  104. package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
  105. package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
  106. package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
  107. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  108. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  109. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  110. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  111. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  112. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  114. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  115. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  116. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  117. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +55 -0
  118. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
  119. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
  120. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
  121. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
  122. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
  123. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
  124. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
  125. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
  126. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  127. package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
  128. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
  129. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
  130. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
  131. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
  132. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
  133. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
  134. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
  135. package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
  136. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
  137. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
  138. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
  139. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  140. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  141. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  142. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  143. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
  144. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  145. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  146. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  147. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  148. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  149. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  151. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  152. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  153. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  154. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
  155. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +6 -5
  156. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  179. package/packages/omo-codex/plugin/package-lock.json +26 -14
  180. package/packages/omo-codex/plugin/package.json +1 -1
  181. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
  182. package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
  183. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
  184. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
  185. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
  186. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +6 -5
  187. package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
  188. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
  189. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
  190. package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
  191. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  192. package/packages/omo-codex/scripts/install-dist/install-local.mjs +328 -63
@@ -96,14 +96,14 @@ var init_atomic_write = __esm(() => {
96
96
 
97
97
  // packages/telemetry-core/src/activity-state.ts
98
98
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "node:fs";
99
- import { basename as basename6, join as join33 } from "node:path";
99
+ import { basename as basename7, join as join33 } from "node:path";
100
100
  function resolveTelemetryStateDir(product, options = {}) {
101
101
  const dataDir = resolveXdgDataDir(product.cacheDirName, {
102
102
  env: options.env,
103
103
  osProvider: options.osProvider
104
104
  });
105
105
  const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join33(options.env.XDG_DATA_HOME, product.cacheDirName);
106
- if (dataDir === xdgStateDir || xdgStateDir === undefined && basename6(dataDir) === product.cacheDirName) {
106
+ if (dataDir === xdgStateDir || xdgStateDir === undefined && basename7(dataDir) === product.cacheDirName) {
107
107
  return dataDir;
108
108
  }
109
109
  return join33(dataDir, product.cacheDirName);
@@ -337,18 +337,18 @@ var init_env = __esm(() => {
337
337
  });
338
338
 
339
339
  // packages/telemetry-core/src/machine-id.ts
340
- import { createHash as createHash2 } from "node:crypto";
340
+ import { createHash as createHash3 } from "node:crypto";
341
341
  import os2 from "node:os";
342
342
  function getDefaultTelemetryOsProvider() {
343
343
  return os2;
344
344
  }
345
345
  function getTelemetryDistinctId(machineIdPrefix, osProvider = getDefaultTelemetryOsProvider()) {
346
- return createHash2("sha256").update(`${machineIdPrefix}${osProvider.hostname()}`).digest("hex");
346
+ return createHash3("sha256").update(`${machineIdPrefix}${osProvider.hostname()}`).digest("hex");
347
347
  }
348
348
  var init_machine_id = () => {};
349
349
 
350
350
  // node_modules/.bun/posthog-node@5.35.12/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
351
- import { dirname as dirname10, posix, sep as sep7 } from "node:path";
351
+ import { dirname as dirname10, posix as posix2, sep as sep7 } from "node:path";
352
352
  function createModulerModifier() {
353
353
  const getModuleFromFileName = createGetModuleFromFilename();
354
354
  return async (frames) => {
@@ -363,7 +363,7 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname10(proc
363
363
  if (!filename)
364
364
  return;
365
365
  const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename;
366
- let { dir, base: file, ext } = posix.parse(normalizedFilename);
366
+ let { dir, base: file, ext } = posix2.parse(normalizedFilename);
367
367
  if (ext === ".js" || ext === ".mjs" || ext === ".cjs")
368
368
  file = file.slice(0, -1 * ext.length);
369
369
  const decodedFile = decodeURIComponent(file);
@@ -5903,7 +5903,7 @@ var package_default;
5903
5903
  var init_package = __esm(() => {
5904
5904
  package_default = {
5905
5905
  name: "@oh-my-opencode/omo-codex",
5906
- version: "4.18.0",
5906
+ version: "4.18.1",
5907
5907
  type: "module",
5908
5908
  private: true,
5909
5909
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -6122,7 +6122,7 @@ var init_telemetry = __esm(() => {
6122
6122
  });
6123
6123
 
6124
6124
  // packages/omo-codex/src/install/install-local-cli.ts
6125
- import { readFile as readFile21 } from "node:fs/promises";
6125
+ import { readFile as readFile22 } from "node:fs/promises";
6126
6126
  import { dirname as dirname12, join as join39, resolve as resolve10 } from "node:path";
6127
6127
  import { fileURLToPath as fileURLToPath2 } from "node:url";
6128
6128
 
@@ -9951,65 +9951,297 @@ function formatUnknownError(error) {
9951
9951
  }
9952
9952
 
9953
9953
  // packages/omo-codex/src/install/lsp-daemon-reaper.ts
9954
- import { readFile as readFile18, readdir as readdir9, rm as rm10 } from "node:fs/promises";
9954
+ import { createHash as createHash2 } from "node:crypto";
9955
+ import { lstat as lstat11, readFile as readFile19, readdir as readdir10, rm as rm10 } from "node:fs/promises";
9956
+ import { tmpdir } from "node:os";
9957
+ import { join as join27, posix } from "node:path";
9958
+
9959
+ // packages/omo-codex/src/install/lsp-daemon-reaper-attestation.ts
9960
+ import { execFile } from "node:child_process";
9961
+ import { readFile as readFile18, readdir as readdir9, readlink as readlink5 } from "node:fs/promises";
9955
9962
  import { connect } from "node:net";
9956
- import { join as join27 } from "node:path";
9957
- async function reapLspDaemons(codexHome, deps = {}) {
9958
- const killProcess = deps.killProcess ?? sendSigterm;
9959
- const isDaemonLive = deps.isDaemonLive ?? probeSocketLive;
9960
- const daemonRoot = join27(codexHome, "codex-lsp", "daemon");
9961
- const reaped = [];
9962
- let entries;
9963
+ import { basename as basename6 } from "node:path";
9964
+ var PROBE_TIMEOUT_MS = 500;
9965
+ async function probeLegacyJsonRpcEndpoint(endpoint, timeoutMs = PROBE_TIMEOUT_MS) {
9966
+ return await new Promise((resolve8) => {
9967
+ const socket = connect(endpoint);
9968
+ let settled = false;
9969
+ let buffer = "";
9970
+ const finish = (value) => {
9971
+ if (settled)
9972
+ return;
9973
+ settled = true;
9974
+ clearTimeout(timer);
9975
+ socket.destroy();
9976
+ resolve8(value);
9977
+ };
9978
+ const timer = setTimeout(() => finish(false), timeoutMs);
9979
+ timer.unref?.();
9980
+ socket.once("connect", () => {
9981
+ socket.write(`${JSON.stringify(legacyStatusRequest())}
9982
+ `);
9983
+ });
9984
+ socket.on("data", (chunk) => {
9985
+ buffer += chunk.toString("utf8");
9986
+ const newlineIndex = buffer.indexOf(`
9987
+ `);
9988
+ if (newlineIndex < 0)
9989
+ return;
9990
+ finish(isJsonRpcResponse(buffer.slice(0, newlineIndex).trim()));
9991
+ });
9992
+ socket.once("error", () => finish(false));
9993
+ });
9994
+ }
9995
+ async function attestLegacyDaemonOwnership(input, deps = {}) {
9996
+ if (input.platform === "linux")
9997
+ return await attestLinuxOwnership(input, deps);
9998
+ if (input.platform === "darwin")
9999
+ return await attestMacOwnership(input, deps);
10000
+ return false;
10001
+ }
10002
+ async function attestLinuxOwnership(input, deps) {
10003
+ const readFileImpl = deps.readFile ?? readFile18;
10004
+ const readDirImpl = deps.readDir ?? readdir9;
10005
+ const readLinkImpl = deps.readLink ?? readlink5;
10006
+ const procNetUnix = await readText(readFileImpl, "/proc/net/unix");
10007
+ if (procNetUnix === null)
10008
+ return false;
10009
+ const inode = inodeForEndpoint(procNetUnix, input.endpoint);
10010
+ if (inode === null)
10011
+ return false;
10012
+ const fdEntries = await readDirImpl(`/proc/${input.pid}/fd`).catch(() => null);
10013
+ if (fdEntries === null)
10014
+ return false;
10015
+ let ownsEndpoint = false;
10016
+ for (const fdEntry of fdEntries) {
10017
+ const target = await readLinkImpl(`/proc/${input.pid}/fd/${fdEntry}`).catch(() => null);
10018
+ if (target !== `socket:[${inode}]`)
10019
+ continue;
10020
+ ownsEndpoint = true;
10021
+ break;
10022
+ }
10023
+ if (!ownsEndpoint)
10024
+ return false;
10025
+ const cmdline = await readBinary(readFileImpl, `/proc/${input.pid}/cmdline`);
10026
+ if (cmdline === null)
10027
+ return false;
10028
+ return isNodeCliDaemonArgv(splitCmdline(cmdline));
10029
+ }
10030
+ async function attestMacOwnership(input, deps) {
10031
+ const executeFileImpl = deps.executeFile ?? execFile;
10032
+ const filteredLsofOutput = await executeForStdout(executeFileImpl, "/usr/sbin/lsof", [
10033
+ "-a",
10034
+ "-n",
10035
+ "-P",
10036
+ "-p",
10037
+ String(input.pid),
10038
+ "-U",
10039
+ "-Fn",
10040
+ "--",
10041
+ input.endpoint
10042
+ ]);
10043
+ const lsofOutput = filteredLsofOutput ?? await executeForStdout(executeFileImpl, "/usr/sbin/lsof", [
10044
+ "-a",
10045
+ "-n",
10046
+ "-P",
10047
+ "-p",
10048
+ String(input.pid),
10049
+ "-U",
10050
+ "-Fn"
10051
+ ]);
10052
+ if (lsofOutput === null || !lsofShowsUnixEndpoint(lsofOutput, input.pid, input.endpoint))
10053
+ return false;
10054
+ const commandOutput = await executeForStdout(executeFileImpl, "/bin/ps", ["-p", String(input.pid), "-o", "command="]);
10055
+ if (commandOutput === null)
10056
+ return false;
10057
+ return isNodeCliDaemonCommand(commandOutput.trim());
10058
+ }
10059
+ function legacyStatusRequest() {
10060
+ return {
10061
+ jsonrpc: "2.0",
10062
+ id: 1,
10063
+ method: "tools/call",
10064
+ params: { name: "status", arguments: {} }
10065
+ };
10066
+ }
10067
+ function isJsonRpcResponse(line) {
10068
+ if (line.length === 0)
10069
+ return false;
9963
10070
  try {
9964
- entries = await readdir9(daemonRoot);
10071
+ const parsed = JSON.parse(line);
10072
+ return parsed.jsonrpc === "2.0" && parsed.id === 1 && (Object.hasOwn(parsed, "result") || Object.hasOwn(parsed, "error"));
9965
10073
  } catch {
9966
- return reaped;
10074
+ return false;
9967
10075
  }
9968
- for (const entry of entries) {
9969
- const versionDir = join27(daemonRoot, entry);
9970
- const pid = await readPidFile(join27(versionDir, "daemon.pid"));
9971
- const socketPath = await readEndpointFile(join27(versionDir, "daemon.endpoint"));
9972
- if (pid !== null && socketPath !== null && await isDaemonLive(socketPath) && killProcess(pid)) {
9973
- reaped.push(pid);
10076
+ }
10077
+ function inodeForEndpoint(procNetUnix, endpoint) {
10078
+ for (const line of procNetUnix.split(/\r?\n/)) {
10079
+ const trimmed = line.trim();
10080
+ if (trimmed.length === 0 || trimmed.startsWith("Num"))
10081
+ continue;
10082
+ const fields = trimmed.split(/\s+/);
10083
+ if (fields.length < 8 || fields[7] !== endpoint)
10084
+ continue;
10085
+ return fields[6] ?? null;
10086
+ }
10087
+ return null;
10088
+ }
10089
+ function splitCmdline(buffer) {
10090
+ return buffer.toString("utf8").split("\x00").filter((value) => value.length > 0);
10091
+ }
10092
+ function isNodeCliDaemonArgv(argv) {
10093
+ if (argv.length < 2 || !argv.includes("daemon"))
10094
+ return false;
10095
+ const executable = basename6(argv[0] ?? "");
10096
+ if (!/^node(?:\.exe)?$/i.test(executable))
10097
+ return false;
10098
+ return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
10099
+ }
10100
+ function lsofShowsUnixEndpoint(output, pid, endpoint) {
10101
+ const lines = output.split(/\r?\n/).filter((line) => line.length > 0);
10102
+ const endpointName = basename6(endpoint);
10103
+ return lines.includes(`p${pid}`) && lines.some((line) => line === `n${endpoint}` || line === `n${endpointName}`);
10104
+ }
10105
+ function isNodeCliDaemonCommand(command) {
10106
+ return /\bnode(?:\.exe)?\b/i.test(command) && /\bcli\.js\b/.test(command) && /\bdaemon\b/.test(command);
10107
+ }
10108
+ async function executeForStdout(executeFileImpl, file, args) {
10109
+ return await new Promise((resolve8) => {
10110
+ executeFileImpl(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
10111
+ if (error !== null) {
10112
+ resolve8(null);
10113
+ return;
10114
+ }
10115
+ resolve8(stdout);
10116
+ });
10117
+ });
10118
+ }
10119
+ async function readText(readFileImpl, path) {
10120
+ return await readFileImpl(path, "utf8").catch(() => null);
10121
+ }
10122
+ async function readBinary(readFileImpl, path) {
10123
+ return await readFileImpl(path).catch(() => null);
10124
+ }
10125
+
10126
+ // packages/omo-codex/src/install/lsp-daemon-reaper.ts
10127
+ var LEGACY_EXIT_WAIT_TIMEOUT_MS = 5000;
10128
+ var LEGACY_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
10129
+ async function reapLspDaemons(codexHome, deps = {}) {
10130
+ const daemonRoot = join27(codexHome, "codex-lsp", "daemon");
10131
+ const platform = deps.platform ?? process.platform;
10132
+ const tmpDir = deps.tmpDir ?? tmpdir();
10133
+ const probe = deps.probeLegacyJsonRpc ?? probeLegacyJsonRpcEndpoint;
10134
+ const attest = deps.attestLegacyDaemonOwnership ?? ((input) => attestLegacyDaemonOwnership(input));
10135
+ const killProcess = deps.killProcess ?? sendSigterm;
10136
+ const waitForProcessExit = deps.waitForProcessExit ?? defaultWaitForProcessExit;
10137
+ const entries = await readdir10(daemonRoot, { withFileTypes: true }).catch(() => []);
10138
+ const results = [];
10139
+ for (const entry of [...entries].sort((left, right) => left.name.localeCompare(right.name))) {
10140
+ const versionPath = join27(daemonRoot, entry.name);
10141
+ const parsedVersion = parseVersionEntry(entry.name);
10142
+ if (parsedVersion === null || !entry.isDirectory()) {
10143
+ await removeVersionDir(versionPath);
10144
+ results.push(removed(entry.name, "removed invalid legacy version entry"));
10145
+ continue;
10146
+ }
10147
+ const metadata = await readLegacyMetadata({ versionPath, version: parsedVersion, codexHome, platform, tmpDir });
10148
+ if (metadata.kind === "remove") {
10149
+ await removeVersionDir(versionPath);
10150
+ results.push(removed(parsedVersion, metadata.reason));
10151
+ continue;
10152
+ }
10153
+ if (!await probe(metadata.endpoint)) {
10154
+ await removeVersionDir(versionPath);
10155
+ results.push(removed(parsedVersion, "removed stale legacy daemon state"));
10156
+ continue;
10157
+ }
10158
+ if (platform === "win32") {
10159
+ results.push(deferred(parsedVersion, "legacy named pipe responded but Windows cannot prove pid ownership safely"));
10160
+ continue;
9974
10161
  }
9975
- await rm10(versionDir, { recursive: true, force: true });
10162
+ const owned = await attest({ pid: metadata.pid, endpoint: metadata.endpoint, platform });
10163
+ if (!owned) {
10164
+ results.push(deferred(parsedVersion, "legacy endpoint responded but pid ownership was not proven"));
10165
+ continue;
10166
+ }
10167
+ if (!killProcess(metadata.pid)) {
10168
+ await removeVersionDir(versionPath);
10169
+ results.push(removed(parsedVersion, "removed stale legacy daemon state"));
10170
+ continue;
10171
+ }
10172
+ if (!await waitForProcessExit(metadata.pid, LEGACY_EXIT_WAIT_TIMEOUT_MS)) {
10173
+ results.push(deferred(parsedVersion, `timed out waiting ${LEGACY_EXIT_WAIT_TIMEOUT_MS}ms for the proven legacy daemon to exit`));
10174
+ continue;
10175
+ }
10176
+ await removeVersionDir(versionPath);
10177
+ results.push(terminated(parsedVersion, "terminated proven owned legacy daemon"));
9976
10178
  }
9977
- return reaped;
10179
+ return results;
9978
10180
  }
9979
- async function readEndpointFile(path) {
9980
- try {
9981
- const content = (await readFile18(path, "utf8")).trim();
9982
- return content.length > 0 ? content : null;
9983
- } catch {
10181
+ function parseVersionEntry(entryName) {
10182
+ if (!entryName.startsWith("v"))
9984
10183
  return null;
10184
+ const version = entryName.slice(1);
10185
+ return LEGACY_VERSION_PATTERN.test(version) ? version : null;
10186
+ }
10187
+ async function readLegacyMetadata(input) {
10188
+ const pidText = await readRegularTrimmedFile(join27(input.versionPath, "daemon.pid"));
10189
+ if (pidText === "non_regular")
10190
+ return { kind: "remove", reason: "removed non-regular legacy daemon metadata" };
10191
+ if (pidText === null)
10192
+ return { kind: "remove", reason: "removed malformed legacy daemon metadata" };
10193
+ const pid = Number.parseInt(pidText, 10);
10194
+ if (!Number.isInteger(pid) || pid <= 0)
10195
+ return { kind: "remove", reason: "removed malformed legacy daemon metadata" };
10196
+ const endpointText = await readRegularTrimmedFile(join27(input.versionPath, "daemon.endpoint"));
10197
+ if (endpointText === "non_regular")
10198
+ return { kind: "remove", reason: "removed non-regular legacy daemon metadata" };
10199
+ if (endpointText === null)
10200
+ return { kind: "remove", reason: "removed malformed legacy daemon metadata" };
10201
+ const allowedEndpoints = legacyEndpointCandidates({
10202
+ version: input.version,
10203
+ versionPath: input.versionPath,
10204
+ platform: input.platform,
10205
+ tmpDir: input.tmpDir
10206
+ });
10207
+ if (!allowedEndpoints.includes(endpointText)) {
10208
+ return { kind: "remove", reason: "removed legacy daemon state with an endpoint outside the frozen vectors" };
9985
10209
  }
10210
+ return { kind: "valid", pid, endpoint: endpointText };
9986
10211
  }
9987
- async function readPidFile(path) {
9988
- try {
9989
- const pid = Number.parseInt((await readFile18(path, "utf8")).trim(), 10);
9990
- return Number.isInteger(pid) && pid > 0 ? pid : null;
9991
- } catch {
9992
- return null;
10212
+ function legacyEndpointCandidates(input) {
10213
+ if (input.platform === "win32") {
10214
+ const normalizedVersionPath = input.versionPath.replaceAll("/", "\\");
10215
+ const digest = shortDigest(normalizedVersionPath);
10216
+ return [`\\\\.\\pipe\\omo-lsp-${input.version}-${digest}`];
9993
10217
  }
10218
+ const natural = posix.join(input.versionPath, "daemon.sock");
10219
+ const hashed = posix.join(input.tmpDir, `omo-lsp-${input.version}-${shortDigest(input.versionPath)}.sock`);
10220
+ return [natural, hashed];
9994
10221
  }
9995
- function probeSocketLive(socketPath, timeoutMs = 500) {
9996
- return new Promise((resolve8) => {
9997
- const socket = connect(socketPath);
9998
- const done = (ok) => {
9999
- socket.destroy();
10000
- resolve8(ok);
10001
- };
10002
- const timer = setTimeout(() => done(false), timeoutMs);
10003
- timer.unref();
10004
- socket.once("connect", () => {
10005
- clearTimeout(timer);
10006
- done(true);
10007
- });
10008
- socket.once("error", () => {
10009
- clearTimeout(timer);
10010
- done(false);
10011
- });
10012
- });
10222
+ async function readRegularTrimmedFile(path) {
10223
+ const stats = await lstat11(path).catch(() => null);
10224
+ if (stats === null)
10225
+ return null;
10226
+ if (!stats.isFile())
10227
+ return "non_regular";
10228
+ const content = (await readFile19(path, "utf8")).trim();
10229
+ return content.length > 0 ? content : null;
10230
+ }
10231
+ function shortDigest(value) {
10232
+ return createHash2("sha256").update(value).digest("hex").slice(0, 16);
10233
+ }
10234
+ async function removeVersionDir(path) {
10235
+ await rm10(path, { recursive: true, force: true });
10236
+ }
10237
+ function removed(version, reason) {
10238
+ return { version, status: "removed", reason };
10239
+ }
10240
+ function terminated(version, reason) {
10241
+ return { version, status: "terminated", reason };
10242
+ }
10243
+ function deferred(version, reason) {
10244
+ return { version, status: "deferred", reason };
10013
10245
  }
10014
10246
  function sendSigterm(pid) {
10015
10247
  try {
@@ -10019,6 +10251,24 @@ function sendSigterm(pid) {
10019
10251
  return false;
10020
10252
  }
10021
10253
  }
10254
+ async function defaultWaitForProcessExit(pid, timeoutMs) {
10255
+ const deadline = Date.now() + timeoutMs;
10256
+ for (;; ) {
10257
+ if (!processIsRunning(pid))
10258
+ return true;
10259
+ if (Date.now() >= deadline)
10260
+ return false;
10261
+ await new Promise((resolve8) => setTimeout(resolve8, 100));
10262
+ }
10263
+ }
10264
+ function processIsRunning(pid) {
10265
+ try {
10266
+ process.kill(pid, 0);
10267
+ return true;
10268
+ } catch {
10269
+ return false;
10270
+ }
10271
+ }
10022
10272
 
10023
10273
  // packages/omo-codex/src/install/codex-installer-bin-dir.ts
10024
10274
  import { homedir } from "node:os";
@@ -10036,7 +10286,7 @@ function resolveCodexInstallerBinDir(input) {
10036
10286
  }
10037
10287
 
10038
10288
  // packages/omo-codex/src/install/codex-git-bash-hooks.ts
10039
- import { readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
10289
+ import { readFile as readFile20, writeFile as writeFile11 } from "node:fs/promises";
10040
10290
  import { join as join29 } from "node:path";
10041
10291
  var WINDOWS_ONLY_GIT_BASH_HOOKS = new Set([
10042
10292
  "./hooks/pre-tool-use-recommending-git-bash-mcp.json",
@@ -10046,7 +10296,7 @@ async function removeGitBashHooksOffWindows(input) {
10046
10296
  if (input.platform === "win32")
10047
10297
  return;
10048
10298
  const manifestPath = join29(input.pluginRoot, ".codex-plugin", "plugin.json");
10049
- const parsed = JSON.parse(await readFile19(manifestPath, "utf8"));
10299
+ const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
10050
10300
  if (!isPlainRecord(parsed) || !Array.isArray(parsed.hooks))
10051
10301
  return;
10052
10302
  const hooks = parsed.hooks.filter((hook) => typeof hook !== "string" || !WINDOWS_ONLY_GIT_BASH_HOOKS.has(hook));
@@ -10358,7 +10608,16 @@ async function runCodexInstaller(options = {}) {
10358
10608
  pluginNames: marketplace.plugins.map((plugin) => plugin.name)
10359
10609
  });
10360
10610
  }
10361
- await reapLspDaemons(codexHome).catch(() => []);
10611
+ const legacyDaemonCleanup = await reapLspDaemons(codexHome).catch((error) => {
10612
+ const message = error instanceof Error ? error.message : String(error);
10613
+ log(`Warning: skipped legacy Codex LSP daemon cleanup: ${message}`);
10614
+ return [];
10615
+ });
10616
+ for (const cleanup of legacyDaemonCleanup) {
10617
+ if (cleanup.status !== "deferred")
10618
+ continue;
10619
+ log(`Warning: deferred legacy Codex LSP daemon cleanup for v${cleanup.version}: ${cleanup.reason}`);
10620
+ }
10362
10621
  const marketplaceRoot = join35(codexHome, "plugins", "cache", marketplace.name);
10363
10622
  await writeCachedMarketplaceManifest({
10364
10623
  marketplaceName: marketplace.name,
@@ -10998,7 +11257,7 @@ function readVersionManifest(path2) {
10998
11257
  }
10999
11258
  }
11000
11259
  // packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
11001
- import { readFile as readFile20, writeFile as writeFile12 } from "node:fs/promises";
11260
+ import { readFile as readFile21, writeFile as writeFile12 } from "node:fs/promises";
11002
11261
  import { join as join38 } from "node:path";
11003
11262
  var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
11004
11263
  var CODEGRAPH_RELATIVE_ARGS2 = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
@@ -11006,7 +11265,7 @@ async function stampGitBashMcpEnv(input) {
11006
11265
  const manifestPath = join38(input.pluginRoot, ".mcp.json");
11007
11266
  if (!await fileExistsStrict(manifestPath))
11008
11267
  return false;
11009
- const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
11268
+ const parsed = JSON.parse(await readFile21(manifestPath, "utf8"));
11010
11269
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
11011
11270
  return false;
11012
11271
  let changed = stampCodegraphMcpPath(parsed["mcpServers"], input.pluginRoot);
@@ -11051,13 +11310,17 @@ function resolveDefaultRepoRoot() {
11051
11310
  return resolveDefaultRepoRootForEntrypoint(fileURLToPath2(import.meta.url));
11052
11311
  }
11053
11312
  async function runLazyCodexInstallLocalCli(input) {
11313
+ const logWarning = (message) => {
11314
+ if (message.startsWith("Warning:"))
11315
+ input.log(message);
11316
+ };
11054
11317
  const parsed = parseLazyCodexInstallCliArgs(input.argv);
11055
11318
  if (parsed.kind === "help") {
11056
11319
  input.log(formatLazyCodexInstallHelp());
11057
11320
  return 0;
11058
11321
  }
11059
11322
  if (parsed.kind === "version") {
11060
- const packageJson = JSON.parse(await readFile21(join39(input.defaultRepoRoot, "package.json"), "utf8"));
11323
+ const packageJson = JSON.parse(await readFile22(join39(input.defaultRepoRoot, "package.json"), "utf8"));
11061
11324
  const version2 = typeof packageJson.version === "string" ? packageJson.version : "unknown";
11062
11325
  input.log(`lazycodex-ai ${version2}`);
11063
11326
  return 0;
@@ -11075,7 +11338,8 @@ async function runLazyCodexInstallLocalCli(input) {
11075
11338
  const result2 = await installMarketplaceLocally({
11076
11339
  repoRoot: resolve10(parsed.repoRoot),
11077
11340
  autonomousPermissions: true,
11078
- env: input.env
11341
+ env: input.env,
11342
+ log: logWarning
11079
11343
  });
11080
11344
  input.log(`Installed ${result2.installed.length} plugin(s) from ${result2.marketplaceName}.`);
11081
11345
  return 0;
@@ -11086,7 +11350,8 @@ async function runLazyCodexInstallLocalCli(input) {
11086
11350
  const result = await installMarketplaceLocally({
11087
11351
  repoRoot,
11088
11352
  autonomousPermissions: parsed.autonomousPermissions,
11089
- env: input.env
11353
+ env: input.env,
11354
+ log: logWarning
11090
11355
  });
11091
11356
  input.log(`Installed ${result.installed.length} plugin(s) from ${result.marketplaceName}.`);
11092
11357
  return 0;