oh-my-opencode 4.17.1 → 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 (213) hide show
  1. package/.agents/skills/codex-qa/SKILL.md +2 -0
  2. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
  3. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
  4. package/.agents/skills/work-with-pr/SKILL.md +16 -37
  5. package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
  6. package/.opencode/skills/work-with-pr/SKILL.md +16 -37
  7. package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
  8. package/dist/cli/get-local-version/types.d.ts +1 -1
  9. package/dist/cli/index.js +498 -165
  10. package/dist/cli-node/index.js +498 -165
  11. package/dist/index.js +425 -392
  12. package/dist/skills/frontend/SKILL.md +1 -1
  13. package/dist/skills/frontend/references/design/README.md +9 -0
  14. package/dist/skills/frontend/references/design/design-system-architecture.md +4 -2
  15. package/dist/skills/frontend/references/design/layout-skill.md +107 -0
  16. package/dist/skills/programming/SKILL.md +12 -2
  17. package/package.json +17 -16
  18. package/packages/lsp-core/package.json +4 -0
  19. package/packages/lsp-core/src/index.ts +1 -0
  20. package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
  21. package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
  22. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
  23. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
  24. package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
  25. package/packages/lsp-core/src/lsp/client.ts +262 -80
  26. package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
  27. package/packages/lsp-core/src/lsp/connection.ts +12 -6
  28. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
  29. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
  30. package/packages/lsp-core/src/lsp/errors.ts +11 -0
  31. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
  32. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
  33. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
  34. package/packages/lsp-core/src/lsp/formatters.ts +3 -0
  35. package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
  36. package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
  37. package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
  38. package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
  39. package/packages/lsp-core/src/lsp/transport.ts +96 -70
  40. package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
  41. package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
  42. package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
  43. package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
  44. package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
  45. package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
  46. package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
  47. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
  48. package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
  49. package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
  50. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
  51. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
  52. package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
  53. package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
  54. package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
  55. package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
  56. package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
  57. package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
  58. package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
  59. package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
  60. package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
  61. package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
  62. package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
  63. package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
  64. package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
  65. package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
  66. package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
  67. package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
  68. package/packages/lsp-core/src/mcp.ts +18 -7
  69. package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
  70. package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
  71. package/packages/lsp-core/src/post-edit/index.ts +1 -0
  72. package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
  73. package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
  74. package/packages/lsp-core/src/request-context.test.ts +171 -0
  75. package/packages/lsp-core/src/request-context.ts +222 -9
  76. package/packages/lsp-core/src/tool-surface.test.ts +4 -1
  77. package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
  78. package/packages/lsp-core/src/tools/navigation.ts +12 -12
  79. package/packages/lsp-core/src/tools/rename.ts +10 -15
  80. package/packages/lsp-core/src/tools/symbols.ts +11 -11
  81. package/packages/lsp-core/src/tools/types.ts +2 -1
  82. package/packages/lsp-daemon/dist/cli.js +3114 -747
  83. package/packages/lsp-daemon/dist/client.d.ts +105 -0
  84. package/packages/lsp-daemon/dist/client.js +5851 -0
  85. package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
  86. package/packages/lsp-daemon/dist/daemon-client.js +113 -30
  87. package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
  88. package/packages/lsp-daemon/dist/daemon-server.js +40 -15
  89. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
  90. package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
  91. package/packages/lsp-daemon/dist/index.d.ts +2 -2
  92. package/packages/lsp-daemon/dist/index.js +2862 -754
  93. package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
  94. package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
  95. package/packages/lsp-daemon/dist/lock.js +14 -4
  96. package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
  97. package/packages/lsp-daemon/dist/ownership.js +168 -0
  98. package/packages/lsp-daemon/dist/paths.d.ts +33 -9
  99. package/packages/lsp-daemon/dist/paths.js +72 -33
  100. package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
  101. package/packages/lsp-daemon/dist/proxy.js +54 -3
  102. package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
  103. package/packages/lsp-daemon/dist/request-routing.js +71 -22
  104. package/packages/lsp-daemon/dist/run-daemon.js +9 -2
  105. package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
  106. package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
  107. package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
  108. package/packages/lsp-daemon/package.json +12 -3
  109. package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
  110. package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
  111. package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
  112. package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
  113. package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
  114. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  115. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  116. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  117. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  118. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  119. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  120. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  121. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  122. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  123. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  124. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +55 -0
  125. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
  126. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
  127. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
  128. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
  129. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
  130. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
  131. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
  132. package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
  133. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  134. package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
  135. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
  136. package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
  137. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
  138. package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
  139. package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
  140. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
  141. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
  142. package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
  143. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
  144. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
  145. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
  146. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  147. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +8 -6
  148. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  149. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  150. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
  151. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  152. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  153. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  154. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  155. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  156. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  157. package/packages/omo-codex/plugin/components/ultrawork/directive.md +37 -10
  158. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  159. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  160. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +37 -10
  161. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +37 -10
  162. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  163. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  164. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -2
  165. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -9
  166. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  184. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  185. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  186. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  187. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  188. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  189. package/packages/omo-codex/plugin/package-lock.json +26 -14
  190. package/packages/omo-codex/plugin/package.json +1 -1
  191. package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
  192. package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
  193. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
  194. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
  195. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +9 -0
  196. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +4 -2
  197. package/packages/omo-codex/plugin/skills/frontend/references/design/layout-skill.md +107 -0
  198. package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -2
  199. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
  200. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +37 -10
  201. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -2
  202. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -9
  203. package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
  204. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
  205. package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
  206. package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
  207. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  208. package/packages/omo-codex/scripts/install-dist/install-local.mjs +351 -74
  209. package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
  210. package/packages/shared-skills/skills/frontend/references/design/README.md +9 -0
  211. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +4 -2
  212. package/packages/shared-skills/skills/frontend/references/design/layout-skill.md +107 -0
  213. package/packages/shared-skills/skills/programming/SKILL.md +12 -2
@@ -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.17.1",
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
 
@@ -7519,9 +7519,11 @@ function collectCommands(value, commands) {
7519
7519
 
7520
7520
  // packages/omo-codex/src/install/codex-cache-install.ts
7521
7521
  async function installCachedPlugin(input) {
7522
+ const env = input.env ?? process.env;
7523
+ const npmInstallEnv = sanitizeNpmInstallEnv(env);
7522
7524
  if (input.buildSource !== false) {
7523
- await maybeRunNpmInstall(input.sourcePath, input.runCommand);
7524
- await maybeRunNpmBuild(input.sourcePath, input.runCommand);
7525
+ await maybeRunNpmInstall(input.sourcePath, input.runCommand, npmInstallEnv);
7526
+ await maybeRunNpmBuild(input.sourcePath, input.runCommand, env);
7525
7527
  }
7526
7528
  const targetPath = join12(input.codexHome, "plugins", "cache", input.marketplaceName, input.name, input.version);
7527
7529
  const tempPath = createTempSiblingPath(targetPath);
@@ -7531,10 +7533,10 @@ async function installCachedPlugin(input) {
7531
7533
  await rewriteCachedPackageLocalFileDependencies(tempPath, input.sourcePath);
7532
7534
  await copyBundledMcpRuntimeDists({ pluginRoot: tempPath, sourceRoot: input.sourcePath });
7533
7535
  await copyRootRuntimeDists({ pluginRoot: tempPath, sourcePath: input.sourcePath });
7534
- await maybeRunNpmInstall(tempPath, input.runCommand, ["ci", "--omit=dev"]);
7536
+ await maybeRunNpmInstall(tempPath, input.runCommand, npmInstallEnv, ["ci", "--omit=dev"]);
7535
7537
  await removeCachedManagedNpmBinShims(tempPath);
7536
7538
  if (input.buildSource === false)
7537
- await maybeRunNpmSyncSkills(tempPath, input.runCommand);
7539
+ await maybeRunNpmSyncSkills(tempPath, input.runCommand, env);
7538
7540
  await assertNoRemovedSparkshellPromptReferences(tempPath);
7539
7541
  await rewriteCachedMcpManifest(tempPath, input.sourcePath);
7540
7542
  await rewriteCachedManifestRoot(tempPath, tempPath, targetPath);
@@ -7546,12 +7548,12 @@ async function installCachedPlugin(input) {
7546
7548
  }
7547
7549
  return { name: input.name, version: input.version, path: targetPath };
7548
7550
  }
7549
- async function maybeRunNpmInstall(cwd, runCommand, args = ["install"]) {
7551
+ async function maybeRunNpmInstall(cwd, runCommand, env, args = ["install"]) {
7550
7552
  if (!await fileExistsStrict(join12(cwd, "package.json")))
7551
7553
  return;
7552
- await runCommand("npm", args, { cwd });
7554
+ await runCommand("npm", args, { cwd, env });
7553
7555
  }
7554
- async function maybeRunNpmBuild(cwd, runCommand) {
7556
+ async function maybeRunNpmBuild(cwd, runCommand, env) {
7555
7557
  if (!await fileExistsStrict(join12(cwd, "package.json")))
7556
7558
  return;
7557
7559
  const packageJson = JSON.parse(await readFile8(join12(cwd, "package.json"), "utf8"));
@@ -7560,9 +7562,9 @@ async function maybeRunNpmBuild(cwd, runCommand) {
7560
7562
  const scripts = packageJson.scripts;
7561
7563
  if (!isPlainRecord(scripts) || typeof scripts.build !== "string")
7562
7564
  return;
7563
- await runCommand("npm", ["run", "build"], { cwd });
7565
+ await runCommand("npm", ["run", "build"], { cwd, env });
7564
7566
  }
7565
- async function maybeRunNpmSyncSkills(cwd, runCommand) {
7567
+ async function maybeRunNpmSyncSkills(cwd, runCommand, env) {
7566
7568
  if (!await fileExistsStrict(join12(cwd, "package.json")))
7567
7569
  return;
7568
7570
  const packageJson = JSON.parse(await readFile8(join12(cwd, "package.json"), "utf8"));
@@ -7571,7 +7573,10 @@ async function maybeRunNpmSyncSkills(cwd, runCommand) {
7571
7573
  const scripts = packageJson.scripts;
7572
7574
  if (!isPlainRecord(scripts) || typeof scripts["sync:skills"] !== "string")
7573
7575
  return;
7574
- await runCommand("npm", ["run", "sync:skills"], { cwd });
7576
+ await runCommand("npm", ["run", "sync:skills"], { cwd, env });
7577
+ }
7578
+ function sanitizeNpmInstallEnv(env) {
7579
+ return Object.fromEntries(Object.entries(env).filter(([key]) => key.toLowerCase() !== "npm_config_allow_scripts"));
7575
7580
  }
7576
7581
  function createTempSiblingPath(targetPath) {
7577
7582
  return join12(dirname5(targetPath), `.tmp-${basename3(targetPath)}-${process.pid}-${Date.now()}`);
@@ -9600,6 +9605,10 @@ async function readDistributionManifest(repoRoot) {
9600
9605
  }
9601
9606
  }
9602
9607
  function resolveLazyCodexPluginVersion(input) {
9608
+ const override = input.versionOverride?.trim();
9609
+ if (override !== undefined && override.length > 0) {
9610
+ return override;
9611
+ }
9603
9612
  if (input.marketplaceName === "sisyphuslabs" && input.pluginName === "omo" && input.distributionManifest !== undefined) {
9604
9613
  return input.distributionManifest.version;
9605
9614
  }
@@ -9942,65 +9951,297 @@ function formatUnknownError(error) {
9942
9951
  }
9943
9952
 
9944
9953
  // packages/omo-codex/src/install/lsp-daemon-reaper.ts
9945
- 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";
9946
9962
  import { connect } from "node:net";
9947
- import { join as join27 } from "node:path";
9948
- async function reapLspDaemons(codexHome, deps = {}) {
9949
- const killProcess = deps.killProcess ?? sendSigterm;
9950
- const isDaemonLive = deps.isDaemonLive ?? probeSocketLive;
9951
- const daemonRoot = join27(codexHome, "codex-lsp", "daemon");
9952
- const reaped = [];
9953
- 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;
9954
10070
  try {
9955
- 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"));
9956
10073
  } catch {
9957
- return reaped;
10074
+ return false;
9958
10075
  }
9959
- for (const entry of entries) {
9960
- const versionDir = join27(daemonRoot, entry);
9961
- const pid = await readPidFile(join27(versionDir, "daemon.pid"));
9962
- const socketPath = await readEndpointFile(join27(versionDir, "daemon.endpoint"));
9963
- if (pid !== null && socketPath !== null && await isDaemonLive(socketPath) && killProcess(pid)) {
9964
- 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;
9965
10161
  }
9966
- 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"));
9967
10178
  }
9968
- return reaped;
10179
+ return results;
9969
10180
  }
9970
- async function readEndpointFile(path) {
9971
- try {
9972
- const content = (await readFile18(path, "utf8")).trim();
9973
- return content.length > 0 ? content : null;
9974
- } catch {
10181
+ function parseVersionEntry(entryName) {
10182
+ if (!entryName.startsWith("v"))
9975
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" };
9976
10209
  }
10210
+ return { kind: "valid", pid, endpoint: endpointText };
9977
10211
  }
9978
- async function readPidFile(path) {
9979
- try {
9980
- const pid = Number.parseInt((await readFile18(path, "utf8")).trim(), 10);
9981
- return Number.isInteger(pid) && pid > 0 ? pid : null;
9982
- } catch {
9983
- 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}`];
9984
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];
9985
10221
  }
9986
- function probeSocketLive(socketPath, timeoutMs = 500) {
9987
- return new Promise((resolve8) => {
9988
- const socket = connect(socketPath);
9989
- const done = (ok) => {
9990
- socket.destroy();
9991
- resolve8(ok);
9992
- };
9993
- const timer = setTimeout(() => done(false), timeoutMs);
9994
- timer.unref();
9995
- socket.once("connect", () => {
9996
- clearTimeout(timer);
9997
- done(true);
9998
- });
9999
- socket.once("error", () => {
10000
- clearTimeout(timer);
10001
- done(false);
10002
- });
10003
- });
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 };
10004
10245
  }
10005
10246
  function sendSigterm(pid) {
10006
10247
  try {
@@ -10010,6 +10251,24 @@ function sendSigterm(pid) {
10010
10251
  return false;
10011
10252
  }
10012
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
+ }
10013
10272
 
10014
10273
  // packages/omo-codex/src/install/codex-installer-bin-dir.ts
10015
10274
  import { homedir } from "node:os";
@@ -10027,7 +10286,7 @@ function resolveCodexInstallerBinDir(input) {
10027
10286
  }
10028
10287
 
10029
10288
  // packages/omo-codex/src/install/codex-git-bash-hooks.ts
10030
- import { readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
10289
+ import { readFile as readFile20, writeFile as writeFile11 } from "node:fs/promises";
10031
10290
  import { join as join29 } from "node:path";
10032
10291
  var WINDOWS_ONLY_GIT_BASH_HOOKS = new Set([
10033
10292
  "./hooks/pre-tool-use-recommending-git-bash-mcp.json",
@@ -10037,7 +10296,7 @@ async function removeGitBashHooksOffWindows(input) {
10037
10296
  if (input.platform === "win32")
10038
10297
  return;
10039
10298
  const manifestPath = join29(input.pluginRoot, ".codex-plugin", "plugin.json");
10040
- const parsed = JSON.parse(await readFile19(manifestPath, "utf8"));
10299
+ const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
10041
10300
  if (!isPlainRecord(parsed) || !Array.isArray(parsed.hooks))
10042
10301
  return;
10043
10302
  const hooks = parsed.hooks.filter((hook) => typeof hook !== "string" || !WINDOWS_ONLY_GIT_BASH_HOOKS.has(hook));
@@ -10240,6 +10499,7 @@ async function runCodexInstaller(options = {}) {
10240
10499
  return;
10241
10500
  });
10242
10501
  const buildSource = await shouldBuildSourcePackages(repoRoot);
10502
+ const versionOverride = env2.LAZYCODEX_DEV_VERSION?.trim() || undefined;
10243
10503
  const gitBashResolution = await prepareGitBashForInstall({
10244
10504
  platform,
10245
10505
  env: env2,
@@ -10266,13 +10526,15 @@ async function runCodexInstaller(options = {}) {
10266
10526
  manifestVersion: manifest.version,
10267
10527
  marketplaceName: marketplace.name,
10268
10528
  pluginName: entry.name,
10269
- distributionManifest
10529
+ distributionManifest,
10530
+ versionOverride
10270
10531
  });
10271
10532
  validatePathSegment(version2, "plugin version");
10272
10533
  log(`Building ${entry.name}@${version2}`);
10273
10534
  const plugin = await installCachedPlugin({
10274
10535
  buildSource,
10275
10536
  codexHome,
10537
+ env: env2,
10276
10538
  marketplaceName: marketplace.name,
10277
10539
  name: entry.name,
10278
10540
  runCommand,
@@ -10346,7 +10608,16 @@ async function runCodexInstaller(options = {}) {
10346
10608
  pluginNames: marketplace.plugins.map((plugin) => plugin.name)
10347
10609
  });
10348
10610
  }
10349
- 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
+ }
10350
10621
  const marketplaceRoot = join35(codexHome, "plugins", "cache", marketplace.name);
10351
10622
  await writeCachedMarketplaceManifest({
10352
10623
  marketplaceName: marketplace.name,
@@ -10986,7 +11257,7 @@ function readVersionManifest(path2) {
10986
11257
  }
10987
11258
  }
10988
11259
  // packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
10989
- import { readFile as readFile20, writeFile as writeFile12 } from "node:fs/promises";
11260
+ import { readFile as readFile21, writeFile as writeFile12 } from "node:fs/promises";
10990
11261
  import { join as join38 } from "node:path";
10991
11262
  var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
10992
11263
  var CODEGRAPH_RELATIVE_ARGS2 = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
@@ -10994,7 +11265,7 @@ async function stampGitBashMcpEnv(input) {
10994
11265
  const manifestPath = join38(input.pluginRoot, ".mcp.json");
10995
11266
  if (!await fileExistsStrict(manifestPath))
10996
11267
  return false;
10997
- const parsed = JSON.parse(await readFile20(manifestPath, "utf8"));
11268
+ const parsed = JSON.parse(await readFile21(manifestPath, "utf8"));
10998
11269
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
10999
11270
  return false;
11000
11271
  let changed = stampCodegraphMcpPath(parsed["mcpServers"], input.pluginRoot);
@@ -11039,13 +11310,17 @@ function resolveDefaultRepoRoot() {
11039
11310
  return resolveDefaultRepoRootForEntrypoint(fileURLToPath2(import.meta.url));
11040
11311
  }
11041
11312
  async function runLazyCodexInstallLocalCli(input) {
11313
+ const logWarning = (message) => {
11314
+ if (message.startsWith("Warning:"))
11315
+ input.log(message);
11316
+ };
11042
11317
  const parsed = parseLazyCodexInstallCliArgs(input.argv);
11043
11318
  if (parsed.kind === "help") {
11044
11319
  input.log(formatLazyCodexInstallHelp());
11045
11320
  return 0;
11046
11321
  }
11047
11322
  if (parsed.kind === "version") {
11048
- 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"));
11049
11324
  const version2 = typeof packageJson.version === "string" ? packageJson.version : "unknown";
11050
11325
  input.log(`lazycodex-ai ${version2}`);
11051
11326
  return 0;
@@ -11063,7 +11338,8 @@ async function runLazyCodexInstallLocalCli(input) {
11063
11338
  const result2 = await installMarketplaceLocally({
11064
11339
  repoRoot: resolve10(parsed.repoRoot),
11065
11340
  autonomousPermissions: true,
11066
- env: input.env
11341
+ env: input.env,
11342
+ log: logWarning
11067
11343
  });
11068
11344
  input.log(`Installed ${result2.installed.length} plugin(s) from ${result2.marketplaceName}.`);
11069
11345
  return 0;
@@ -11074,7 +11350,8 @@ async function runLazyCodexInstallLocalCli(input) {
11074
11350
  const result = await installMarketplaceLocally({
11075
11351
  repoRoot,
11076
11352
  autonomousPermissions: parsed.autonomousPermissions,
11077
- env: input.env
11353
+ env: input.env,
11354
+ log: logWarning
11078
11355
  });
11079
11356
  input.log(`Installed ${result.installed.length} plugin(s) from ${result.marketplaceName}.`);
11080
11357
  return 0;
@@ -32,7 +32,7 @@ Every implementation must choose one of these branches before UI code changes:
32
32
  - **Embedded references:** use `references/design/_INDEX.md` to shortlist 2-3 plausible Layer B references, then read exactly one Layer A style skill and one Layer B reference in full — every line, no partial reads (they are 200-500 lines; a sliced read produces the flattened token set this gate exists to prevent). Log the shortlist, the pick, and why. Use `open-design` only when the curated set has no fit; add `ui-ux-db` lookups for palette/type/domain questions.
33
33
  - **Lazyweb real-product screens:** READ `references/design/lazyweb.md` FIRST and run its recipe verbatim — do not improvise curl calls against lazyweb.com; the recipe mints its own anonymous token. Log the queries run, how many screens you actually VIEWED, and the layout grammar harvested — never pixel copies.
34
34
  - **Imagen concept drafts:** generate 2-3 imagen concept drafts, each seeded with the loaded Layer A + Layer B tokens (palette, type, material); pick the strongest and treat the chosen draft as the reference-fidelity contract. Log the draft paths and the pick.
35
- Synthesize every lane into `DESIGN.md`. Treat sources as source material, not mood labels: extract tokens, layout grammar, component anatomy, interaction states, motion, and taste decisions, then recombine them into project-specific primitives. Never freestyle past the selected references, never copy logos or brand-specific copy. Then run the Primitive Showcase Gate (`references/design/README.md` Phase 0) before any product screen.
35
+ Synthesize every lane into `DESIGN.md`. Treat sources as source material, not mood labels: extract tokens, layout grammar, component anatomy, interaction states, motion, and taste decisions, then recombine them into project-specific primitives. Before laying out sections, inventory the content blocks and assign each a job — hook, explain, prove, compare, convert, navigate, retain — then order sections by the visitor's decision path, not by visual symmetry. Never freestyle past the selected references, never copy logos or brand-specific copy. Then run the Primitive Showcase Gate (`references/design/README.md` Phase 0) before any product screen.
36
36
  3. **Existing project with `DESIGN.md` or a component system:** read it, follow it, and update it before implementation only when the requested work needs a new token, primitive, state, motion rule, accessibility constraint, accepted debt, or reference-fidelity requirement.
37
37
  4. **Existing project with UI but no `DESIGN.md` and no reusable component layer:** STOP and ask the user one focused question: should you preserve the current look with copy-nearby styling, or extract a real `DESIGN.md` plus reusable components before continuing? Do not silently choose.
38
38