oh-my-opencode 4.11.0 → 4.12.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 (177) hide show
  1. package/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
  2. package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
  3. package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
  4. package/.agents/skills/work-with-pr/SKILL.md +19 -5
  5. package/.opencode/skills/work-with-pr/SKILL.md +19 -5
  6. package/dist/agents/atlas/agent.d.ts +3 -2
  7. package/dist/agents/sisyphus/glm-5-2.d.ts +4 -0
  8. package/dist/agents/sisyphus/index.d.ts +1 -0
  9. package/dist/agents/sisyphus-agent-config.d.ts +1 -0
  10. package/dist/agents/sisyphus-junior/agent.d.ts +1 -1
  11. package/dist/agents/sisyphus-junior/glm-5-2.d.ts +1 -0
  12. package/dist/agents/sisyphus-junior/index.d.ts +1 -0
  13. package/dist/agents/types.d.ts +7 -6
  14. package/dist/cli/index.js +449 -318
  15. package/dist/cli-node/index.js +449 -318
  16. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
  17. package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
  18. package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
  19. package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
  20. package/dist/hooks/keyword-detector/ultrawork/glm.d.ts +2 -0
  21. package/dist/hooks/keyword-detector/ultrawork/index.d.ts +4 -2
  22. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +5 -4
  23. package/dist/index.js +1185 -87
  24. package/dist/plugin/tool-execute-before.d.ts +2 -0
  25. package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
  26. package/dist/skills/init-deep/SKILL.md +21 -26
  27. package/dist/skills/programming/SKILL.md +25 -121
  28. package/dist/skills/programming/references/code-smells.md +390 -0
  29. package/dist/skills/ulw-plan/SKILL.md +2 -1
  30. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  31. package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
  32. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
  33. package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
  34. package/dist/tui.js +16 -7
  35. package/package.json +13 -13
  36. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +22 -2
  37. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +51 -21
  38. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +18 -7
  41. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +9 -2
  42. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +8 -7
  44. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +7 -2
  45. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +2 -1
  46. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +20 -19
  47. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
  48. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
  49. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  50. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  51. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
  52. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  53. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  54. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  55. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  56. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  57. package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
  58. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
  59. package/packages/omo-codex/plugin/components/rules/dist/cli.js +2 -2
  60. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  61. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +2 -2
  63. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
  64. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +3 -0
  65. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
  66. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  67. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
  68. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
  69. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
  70. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
  71. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
  72. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
  73. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
  74. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
  75. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  76. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  77. package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
  78. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  79. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
  82. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  83. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
  84. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
  85. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  86. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
  88. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
  89. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
  90. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
  91. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
  92. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
  93. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
  94. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
  95. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
  96. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
  97. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
  98. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
  99. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
  100. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
  101. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
  102. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
  103. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
  104. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
  105. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
  106. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
  107. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
  108. package/packages/omo-codex/plugin/package-lock.json +12 -22
  109. package/packages/omo-codex/plugin/package.json +1 -1
  110. package/packages/omo-codex/plugin/scripts/auto-update.mjs +1 -1
  111. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +14 -11
  112. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
  113. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
  114. package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
  115. package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
  116. package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
  117. package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
  118. package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
  119. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +21 -26
  120. package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
  121. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  122. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  123. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  124. package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
  125. package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
  126. package/packages/omo-codex/plugin/skills/programming/SKILL.md +25 -121
  127. package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
  128. package/packages/omo-codex/plugin/skills/programming/references/code-smells.md +390 -0
  129. package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
  130. package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
  131. package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
  132. package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
  133. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
  134. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
  135. package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
  136. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
  137. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
  138. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
  139. package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
  140. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
  141. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  142. package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
  143. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  144. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
  145. package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
  146. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +34 -33
  147. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +5 -2
  148. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +13 -0
  149. package/packages/omo-codex/plugin/test/auto-update.test.mjs +1 -1
  150. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
  151. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
  152. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
  153. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +31 -0
  154. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +3 -3
  155. package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
  156. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +30 -19
  157. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
  158. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
  159. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  160. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
  161. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
  162. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
  163. package/packages/omo-codex/scripts/install-dist/install-local.mjs +412 -216
  164. package/packages/omo-codex/scripts/install-git-bash-mcp-env.test.mjs +24 -0
  165. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
  166. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
  167. package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
  168. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
  169. package/packages/omo-codex/scripts/install-local.mjs +1 -0
  170. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +36 -0
  171. package/packages/shared-skills/skills/init-deep/SKILL.md +21 -26
  172. package/packages/shared-skills/skills/programming/SKILL.md +25 -121
  173. package/packages/shared-skills/skills/programming/references/code-smells.md +390 -0
  174. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  175. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  176. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
  177. package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
@@ -96,20 +96,20 @@ var init_atomic_write = __esm(() => {
96
96
 
97
97
  // packages/telemetry-core/src/activity-state.ts
98
98
  import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync } from "node:fs";
99
- import { basename as basename5, join as join26 } from "node:path";
99
+ import { basename as basename5, join as join27 } 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
- const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join26(options.env.XDG_DATA_HOME, product.cacheDirName);
105
+ const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join27(options.env.XDG_DATA_HOME, product.cacheDirName);
106
106
  if (dataDir === xdgStateDir || xdgStateDir === undefined && basename5(dataDir) === product.cacheDirName) {
107
107
  return dataDir;
108
108
  }
109
- return join26(dataDir, product.cacheDirName);
109
+ return join27(dataDir, product.cacheDirName);
110
110
  }
111
111
  function getTelemetryActivityStateFilePath(stateDir) {
112
- return join26(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
112
+ return join27(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
113
113
  }
114
114
  function getDailyActiveCaptureState(input) {
115
115
  const state = readPostHogActivityState(input.stateDir, input.diagnostics);
@@ -180,9 +180,9 @@ var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com", DEFAULT_POSTHOG_API_KEY =
180
180
 
181
181
  // packages/telemetry-core/src/diagnostics.ts
182
182
  import { appendFileSync, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync2 } from "node:fs";
183
- import { join as join27 } from "node:path";
183
+ import { join as join28 } from "node:path";
184
184
  function getTelemetryDiagnosticsFilePath(diagnosticsDir) {
185
- return join27(diagnosticsDir, DIAGNOSTICS_FILE_NAME);
185
+ return join28(diagnosticsDir, DIAGNOSTICS_FILE_NAME);
186
186
  }
187
187
  function writeTelemetryDiagnostic(input, options) {
188
188
  const now = options.now ?? new Date;
@@ -348,7 +348,7 @@ function getTelemetryDistinctId(machineIdPrefix, osProvider = getDefaultTelemetr
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 dirname7, posix, sep as sep6 } from "node:path";
351
+ import { dirname as dirname7, posix, sep as sep7 } from "node:path";
352
352
  function createModulerModifier() {
353
353
  const getModuleFromFileName = createGetModuleFromFilename();
354
354
  return async (frames) => {
@@ -357,7 +357,7 @@ function createModulerModifier() {
357
357
  return frames;
358
358
  };
359
359
  }
360
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname7(process.argv[1]) : process.cwd(), isWindows = sep6 === "\\") {
360
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname7(process.argv[1]) : process.cwd(), isWindows = sep7 === "\\") {
361
361
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
362
362
  return (filename) => {
363
363
  if (!filename)
@@ -3378,9 +3378,9 @@ var init_context_lines_node = __esm(() => {
3378
3378
  });
3379
3379
 
3380
3380
  // node_modules/.bun/posthog-node@5.35.12/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs
3381
- import { isAbsolute as isAbsolute5, relative as relative4, sep as sep7 } from "node:path";
3381
+ import { isAbsolute as isAbsolute5, relative as relative4, sep as sep8 } from "node:path";
3382
3382
  function createRelativePathModifier(basePath = process.cwd()) {
3383
- const isWindows = sep7 === "\\";
3383
+ const isWindows = sep8 === "\\";
3384
3384
  const toUnix = (p) => isWindows ? p.replace(/\\/g, "/") : p;
3385
3385
  const normalizedBase = toUnix(basePath);
3386
3386
  return async (frames) => {
@@ -5907,7 +5907,7 @@ var package_default;
5907
5907
  var init_package = __esm(() => {
5908
5908
  package_default = {
5909
5909
  name: "@oh-my-opencode/omo-codex",
5910
- version: "4.11.0",
5910
+ version: "4.12.0",
5911
5911
  type: "module",
5912
5912
  private: true,
5913
5913
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -6127,7 +6127,7 @@ var init_telemetry = __esm(() => {
6127
6127
 
6128
6128
  // packages/omo-codex/src/install/install-local-cli.ts
6129
6129
  import { readFile as readFile19 } from "node:fs/promises";
6130
- import { dirname as dirname9, join as join32, resolve as resolve11 } from "node:path";
6130
+ import { dirname as dirname9, join as join33, resolve as resolve11 } from "node:path";
6131
6131
  import { fileURLToPath as fileURLToPath2 } from "node:url";
6132
6132
 
6133
6133
  // packages/utils/src/runtime/spawn.ts
@@ -6395,7 +6395,7 @@ var defaultRunCommand = async (command, args, options) => {
6395
6395
  };
6396
6396
 
6397
6397
  // packages/omo-codex/src/install/install-codex.ts
6398
- import { join as join28, resolve as resolve10 } from "node:path";
6398
+ import { join as join29, resolve as resolve10 } from "node:path";
6399
6399
  import { existsSync as existsSync6 } from "node:fs";
6400
6400
  import { homedir as homedir2 } from "node:os";
6401
6401
 
@@ -6759,8 +6759,8 @@ async function existingNonSymlink(path) {
6759
6759
  }
6760
6760
  }
6761
6761
  // packages/omo-codex/src/install/codex-cache-install.ts
6762
- import { cp as cp2, mkdir as mkdir3, readFile as readFile6, rename, rm as rm3 } from "node:fs/promises";
6763
- import { basename as basename2, dirname as dirname3, join as join8, sep as sep4 } from "node:path";
6762
+ import { cp as cp2, mkdir as mkdir3, readFile as readFile7, rename, rm as rm3 } from "node:fs/promises";
6763
+ import { basename as basename2, dirname as dirname3, join as join9, sep as sep5 } from "node:path";
6764
6764
 
6765
6765
  // packages/omo-codex/src/install/codex-cache-bundled-mcps.ts
6766
6766
  import { cp, mkdir as mkdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
@@ -6979,6 +6979,7 @@ async function collectPackageJsonPaths(directory, root, paths) {
6979
6979
  // packages/omo-codex/src/install/codex-cache-mcp-manifest.ts
6980
6980
  import { readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
6981
6981
  import { join as join7, sep as sep3 } from "node:path";
6982
+ var CODEGRAPH_RELATIVE_ARGS = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
6982
6983
  async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
6983
6984
  const manifestPath = join7(pluginRoot, ".mcp.json");
6984
6985
  if (!await fileExistsStrict(manifestPath))
@@ -7004,6 +7005,8 @@ async function rewriteCachedMcpManifest(pluginRoot, sourceRoot = pluginRoot) {
7004
7005
  const bundledMcpRuntimeArg = resolveBundledMcpRuntimeArg(pluginRoot, arg);
7005
7006
  if (bundledMcpRuntimeArg !== null)
7006
7007
  return bundledMcpRuntimeArg;
7008
+ if (CODEGRAPH_RELATIVE_ARGS.has(arg))
7009
+ return join7(pluginRoot, "components", "codegraph", "dist", "serve.js");
7007
7010
  if (arg.startsWith("./") || arg.startsWith("../"))
7008
7011
  return resolveCachedRuntimePath(pluginRoot, sourceRoot, arg);
7009
7012
  return arg;
@@ -7052,13 +7055,83 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
7052
7055
  `);
7053
7056
  }
7054
7057
 
7058
+ // packages/omo-codex/src/install/codex-hook-targets.ts
7059
+ import { readFile as readFile6 } from "node:fs/promises";
7060
+ import { join as join8, sep as sep4 } from "node:path";
7061
+ var PLUGIN_ROOT_TARGET_PATTERN = /\$\{PLUGIN_ROOT\}[\\/]+([^"']+)/g;
7062
+ async function findMissingHookCommandTargets(pluginRoot) {
7063
+ const commands = [];
7064
+ for (const manifestPath of await hookManifestPaths(pluginRoot)) {
7065
+ if (!await fileExistsStrict(manifestPath))
7066
+ continue;
7067
+ const parsed = JSON.parse(await readFile6(manifestPath, "utf8"));
7068
+ collectCommands(parsed, commands);
7069
+ }
7070
+ const missing = [];
7071
+ const seen = new Set;
7072
+ for (const command of commands) {
7073
+ for (const match of command.matchAll(PLUGIN_ROOT_TARGET_PATTERN)) {
7074
+ const targetSuffix = match[1];
7075
+ if (targetSuffix === undefined)
7076
+ continue;
7077
+ const target = join8(pluginRoot, ...targetSuffix.split(/[\\/]+/));
7078
+ if (seen.has(target))
7079
+ continue;
7080
+ seen.add(target);
7081
+ if (!await fileExistsStrict(target))
7082
+ missing.push(target);
7083
+ }
7084
+ }
7085
+ return missing;
7086
+ }
7087
+ async function hookManifestPaths(pluginRoot) {
7088
+ const pluginManifestPath = join8(pluginRoot, ".codex-plugin", "plugin.json");
7089
+ if (!await fileExistsStrict(pluginManifestPath))
7090
+ return [join8(pluginRoot, "hooks", "hooks.json")];
7091
+ const parsed = JSON.parse(await readFile6(pluginManifestPath, "utf8"));
7092
+ if (!isPlainRecord(parsed))
7093
+ return [];
7094
+ if (typeof parsed.hooks === "string" && parsed.hooks.trim() !== "") {
7095
+ return [join8(pluginRoot, stripDotSlash(parsed.hooks))];
7096
+ }
7097
+ if (Array.isArray(parsed.hooks)) {
7098
+ return parsed.hooks.filter((hookPath) => typeof hookPath === "string" && hookPath.trim() !== "").map((hookPath) => join8(pluginRoot, stripDotSlash(hookPath)));
7099
+ }
7100
+ return [];
7101
+ }
7102
+ function stripDotSlash(path) {
7103
+ return path.startsWith("./") ? path.slice(2) : path;
7104
+ }
7105
+ async function assertHookCommandTargets(pluginRoot) {
7106
+ const missing = await findMissingHookCommandTargets(pluginRoot);
7107
+ if (missing.length === 0)
7108
+ return;
7109
+ const relativeMissing = missing.map((path) => path.split(`${pluginRoot}${sep4}`).join("").split(sep4).join("/"));
7110
+ throw new Error(`Plugin payload is missing ${missing.length} hook command target(s) referenced by hooks.json: ${relativeMissing.join(", ")}. ` + "The previous plugin cache was left untouched; this payload was not activated.");
7111
+ }
7112
+ function collectCommands(value, commands) {
7113
+ if (Array.isArray(value)) {
7114
+ for (const entry of value)
7115
+ collectCommands(entry, commands);
7116
+ return;
7117
+ }
7118
+ if (!isPlainRecord(value))
7119
+ return;
7120
+ if (value["type"] === "command" && typeof value["command"] === "string")
7121
+ commands.push(value["command"]);
7122
+ if (value["type"] === "command" && typeof value["commandWindows"] === "string")
7123
+ commands.push(value["commandWindows"]);
7124
+ for (const entry of Object.values(value))
7125
+ collectCommands(entry, commands);
7126
+ }
7127
+
7055
7128
  // packages/omo-codex/src/install/codex-cache-install.ts
7056
7129
  async function installCachedPlugin(input) {
7057
7130
  if (input.buildSource !== false) {
7058
7131
  await maybeRunNpmInstall(input.sourcePath, input.runCommand);
7059
7132
  await maybeRunNpmBuild(input.sourcePath, input.runCommand);
7060
7133
  }
7061
- const targetPath = join8(input.codexHome, "plugins", "cache", input.marketplaceName, input.name, input.version);
7134
+ const targetPath = join9(input.codexHome, "plugins", "cache", input.marketplaceName, input.name, input.version);
7062
7135
  const tempPath = createTempSiblingPath(targetPath);
7063
7136
  await rm3(tempPath, { recursive: true, force: true });
7064
7137
  try {
@@ -7068,6 +7141,7 @@ async function installCachedPlugin(input) {
7068
7141
  await maybeRunNpmInstall(tempPath, input.runCommand, ["ci", "--omit=dev"]);
7069
7142
  await rewriteCachedMcpManifest(tempPath, input.sourcePath);
7070
7143
  await rewriteCachedManifestRoot(tempPath, tempPath, targetPath);
7144
+ await assertHookCommandTargets(tempPath);
7071
7145
  await promoteDirectory(tempPath, targetPath, input.renameDirectory ?? rename);
7072
7146
  } catch (error) {
7073
7147
  await rm3(tempPath, { recursive: true, force: true });
@@ -7076,14 +7150,14 @@ async function installCachedPlugin(input) {
7076
7150
  return { name: input.name, version: input.version, path: targetPath };
7077
7151
  }
7078
7152
  async function maybeRunNpmInstall(cwd, runCommand, args = ["install"]) {
7079
- if (!await fileExistsStrict(join8(cwd, "package.json")))
7153
+ if (!await fileExistsStrict(join9(cwd, "package.json")))
7080
7154
  return;
7081
7155
  await runCommand("npm", args, { cwd });
7082
7156
  }
7083
7157
  async function maybeRunNpmBuild(cwd, runCommand) {
7084
- if (!await fileExistsStrict(join8(cwd, "package.json")))
7158
+ if (!await fileExistsStrict(join9(cwd, "package.json")))
7085
7159
  return;
7086
- const packageJson = JSON.parse(await readFile6(join8(cwd, "package.json"), "utf8"));
7160
+ const packageJson = JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
7087
7161
  if (!isPlainRecord(packageJson))
7088
7162
  return;
7089
7163
  const scripts = packageJson.scripts;
@@ -7092,10 +7166,10 @@ async function maybeRunNpmBuild(cwd, runCommand) {
7092
7166
  await runCommand("npm", ["run", "build"], { cwd });
7093
7167
  }
7094
7168
  function createTempSiblingPath(targetPath) {
7095
- return join8(dirname3(targetPath), `.tmp-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7169
+ return join9(dirname3(targetPath), `.tmp-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7096
7170
  }
7097
7171
  function createBackupSiblingPath(targetPath) {
7098
- return join8(dirname3(targetPath), `.backup-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7172
+ return join9(dirname3(targetPath), `.backup-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7099
7173
  }
7100
7174
  async function copyDirectory(sourcePath, targetPath) {
7101
7175
  await mkdir3(dirname3(targetPath), { recursive: true });
@@ -7126,17 +7200,17 @@ async function restoreBackupDirectory(backupPath, targetPath, renameDirectory) {
7126
7200
  await renameDirectory(backupPath, targetPath);
7127
7201
  }
7128
7202
  function shouldCopyPluginPath(path, root) {
7129
- const relative4 = path === root ? "" : path.slice(root.length + sep4.length);
7203
+ const relative4 = path === root ? "" : path.slice(root.length + sep5.length);
7130
7204
  if (relative4 === "")
7131
7205
  return true;
7132
- const parts = relative4.split(sep4);
7206
+ const parts = relative4.split(sep5);
7133
7207
  return !parts.some((part) => part === ".git" || part === "node_modules");
7134
7208
  }
7135
7209
  // packages/omo-codex/src/install/codex-cache-prune.ts
7136
7210
  import { lstat as lstat4, readdir as readdir3, rm as rm4, stat as stat3 } from "node:fs/promises";
7137
- import { join as join9 } from "node:path";
7211
+ import { join as join10 } from "node:path";
7138
7212
  async function pruneMarketplaceCache(input) {
7139
- const cacheRoot = join9(input.codexHome, "plugins", "cache", input.marketplaceName);
7213
+ const cacheRoot = join10(input.codexHome, "plugins", "cache", input.marketplaceName);
7140
7214
  if (!await fileExistsStrict(cacheRoot))
7141
7215
  return;
7142
7216
  const keep = new Set(input.keepPluginNames);
@@ -7144,15 +7218,15 @@ async function pruneMarketplaceCache(input) {
7144
7218
  for (const entry of entries) {
7145
7219
  if (!entry.isDirectory() || keep.has(entry.name))
7146
7220
  continue;
7147
- await rm4(join9(cacheRoot, entry.name), { recursive: true, force: true });
7221
+ await rm4(join10(cacheRoot, entry.name), { recursive: true, force: true });
7148
7222
  }
7149
7223
  }
7150
7224
  async function pruneMarketplacePluginCaches(input) {
7151
- const cacheRoot = join9(input.codexHome, "plugins", "cache", input.marketplaceName);
7225
+ const cacheRoot = join10(input.codexHome, "plugins", "cache", input.marketplaceName);
7152
7226
  if (!await fileExistsStrict(cacheRoot))
7153
7227
  return;
7154
7228
  for (const pluginName of input.pluginNames) {
7155
- await rm4(join9(cacheRoot, pluginName), { recursive: true, force: true });
7229
+ await rm4(join10(cacheRoot, pluginName), { recursive: true, force: true });
7156
7230
  }
7157
7231
  const remainingEntries = await readCacheEntryNames(cacheRoot);
7158
7232
  if (remainingEntries.length === 0) {
@@ -7199,11 +7273,11 @@ async function isBrokenCacheSymlink(path) {
7199
7273
  }
7200
7274
  // packages/omo-codex/src/install/codex-cached-marketplace-manifest.ts
7201
7275
  import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
7202
- import { join as join10 } from "node:path";
7276
+ import { join as join11 } from "node:path";
7203
7277
  async function writeCachedMarketplaceManifest(input) {
7204
- const marketplaceDir = join10(input.marketplaceRoot, ".agents", "plugins");
7278
+ const marketplaceDir = join11(input.marketplaceRoot, ".agents", "plugins");
7205
7279
  await mkdir4(marketplaceDir, { recursive: true });
7206
- await writeFile4(join10(marketplaceDir, "marketplace.json"), `${JSON.stringify({
7280
+ await writeFile4(join11(marketplaceDir, "marketplace.json"), `${JSON.stringify({
7207
7281
  name: input.marketplaceName,
7208
7282
  plugins: input.plugins.map((plugin) => ({
7209
7283
  name: plugin.name,
@@ -7215,8 +7289,8 @@ async function writeCachedMarketplaceManifest(input) {
7215
7289
 
7216
7290
  // packages/omo-codex/src/install/codex-package-layout.ts
7217
7291
  import { existsSync as existsSync2 } from "node:fs";
7218
- import { readFile as readFile7 } from "node:fs/promises";
7219
- import { join as join11 } from "node:path";
7292
+ import { readFile as readFile8 } from "node:fs/promises";
7293
+ import { join as join12 } from "node:path";
7220
7294
  var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
7221
7295
  "@code-yeongyu/lazycodex",
7222
7296
  "@code-yeongyu/lazycodex-ai",
@@ -7226,19 +7300,19 @@ var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
7226
7300
  "oh-my-openagent"
7227
7301
  ]);
7228
7302
  async function shouldBuildSourcePackages(repoRoot) {
7229
- if (existsSync2(join11(repoRoot, "packages", "omo-opencode", "src", "index.ts")))
7303
+ if (existsSync2(join12(repoRoot, "packages", "omo-opencode", "src", "index.ts")))
7230
7304
  return true;
7231
- const packageJsonPath = join11(repoRoot, "package.json");
7305
+ const packageJsonPath = join12(repoRoot, "package.json");
7232
7306
  if (!existsSync2(packageJsonPath))
7233
7307
  return true;
7234
- const packageJson = JSON.parse(await readFile7(packageJsonPath, "utf8"));
7308
+ const packageJson = JSON.parse(await readFile8(packageJsonPath, "utf8"));
7235
7309
  if (!isPlainRecord(packageJson) || typeof packageJson.name !== "string")
7236
7310
  return true;
7237
7311
  return !PACKAGED_CODEX_INSTALLER_NAMES.has(packageJson.name);
7238
7312
  }
7239
7313
 
7240
7314
  // packages/omo-codex/src/install/codex-config-toml.ts
7241
- import { mkdir as mkdir5, readFile as readFile9 } from "node:fs/promises";
7315
+ import { mkdir as mkdir5, readFile as readFile10 } from "node:fs/promises";
7242
7316
  import { dirname as dirname5 } from "node:path";
7243
7317
 
7244
7318
  // packages/omo-codex/src/install/toml-section-editor.ts
@@ -7426,12 +7500,12 @@ function tomlKeySegment(value) {
7426
7500
 
7427
7501
  // packages/omo-codex/src/install/codex-config-atomic-write.ts
7428
7502
  import { lstat as lstat5, readlink as readlink3, realpath, rename as rename2, unlink, writeFile as writeFile5 } from "node:fs/promises";
7429
- import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, resolve as resolve5 } from "node:path";
7503
+ import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute4, join as join13, resolve as resolve5 } from "node:path";
7430
7504
  var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
7431
7505
  var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
7432
7506
  async function writeFileAtomic(targetPath, data) {
7433
7507
  const writeTarget = await resolveSymlinkTarget(targetPath);
7434
- const temporaryPath = join12(dirname4(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
7508
+ const temporaryPath = join13(dirname4(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
7435
7509
  await writeFile5(temporaryPath, data);
7436
7510
  try {
7437
7511
  await renameWithRetry(temporaryPath, writeTarget);
@@ -7701,8 +7775,8 @@ function isRootSetting(line, key) {
7701
7775
  }
7702
7776
 
7703
7777
  // packages/omo-codex/src/install/codex-model-catalog.ts
7704
- import { readFile as readFile8 } from "node:fs/promises";
7705
- import { join as join13 } from "node:path";
7778
+ import { readFile as readFile9 } from "node:fs/promises";
7779
+ import { join as join14 } from "node:path";
7706
7780
  var FALLBACK_CODEX_MODEL_CATALOG = {
7707
7781
  current: {
7708
7782
  model: "gpt-5.5",
@@ -7721,9 +7795,9 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
7721
7795
  ]
7722
7796
  };
7723
7797
  async function readCodexModelCatalog(codexPackageRoot) {
7724
- const catalogPath = join13(codexPackageRoot, "plugin", "model-catalog.json");
7798
+ const catalogPath = join14(codexPackageRoot, "plugin", "model-catalog.json");
7725
7799
  try {
7726
- const parsed = JSON.parse(await readFile8(catalogPath, "utf8"));
7800
+ const parsed = JSON.parse(await readFile9(catalogPath, "utf8"));
7727
7801
  return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
7728
7802
  } catch (error) {
7729
7803
  if (error instanceof Error)
@@ -7804,7 +7878,7 @@ async function updateCodexConfig(input) {
7804
7878
  await mkdir5(dirname5(input.configPath), { recursive: true });
7805
7879
  let config = "";
7806
7880
  if (await exists(input.configPath))
7807
- config = await readFile9(input.configPath, "utf8");
7881
+ config = await readFile10(input.configPath, "utf8");
7808
7882
  const pluginSet = new Set(input.pluginNames);
7809
7883
  for (const legacyMarketplaceName of legacyMarketplaceNames(input.marketplaceName)) {
7810
7884
  config = removeMarketplaceBlock(config, legacyMarketplaceName);
@@ -7840,7 +7914,7 @@ async function updateCodexConfig(input) {
7840
7914
  }
7841
7915
  async function exists(path) {
7842
7916
  try {
7843
- await readFile9(path, "utf8");
7917
+ await readFile10(path, "utf8");
7844
7918
  return true;
7845
7919
  } catch (error) {
7846
7920
  if (error instanceof Error)
@@ -7851,8 +7925,8 @@ async function exists(path) {
7851
7925
 
7852
7926
  // packages/omo-codex/src/install/codex-hook-trust.ts
7853
7927
  import { createHash } from "node:crypto";
7854
- import { readFile as readFile10 } from "node:fs/promises";
7855
- import { join as join14 } from "node:path";
7928
+ import { readFile as readFile11 } from "node:fs/promises";
7929
+ import { join as join15 } from "node:path";
7856
7930
  var EVENT_LABELS = new Map([
7857
7931
  ["PreToolUse", "pre_tool_use"],
7858
7932
  ["PermissionRequest", "permission_request"],
@@ -7866,21 +7940,37 @@ var EVENT_LABELS = new Map([
7866
7940
  ["Stop", "stop"]
7867
7941
  ]);
7868
7942
  async function trustedHookStatesForPlugin(input) {
7869
- const manifestPath = join14(input.pluginRoot, ".codex-plugin", "plugin.json");
7943
+ const manifestPath = join15(input.pluginRoot, ".codex-plugin", "plugin.json");
7870
7944
  if (!await exists2(manifestPath))
7871
7945
  return [];
7872
- const manifest = JSON.parse(await readFile10(manifestPath, "utf8"));
7873
- if (!isPlainRecord(manifest) || typeof manifest.hooks !== "string")
7946
+ const manifest = JSON.parse(await readFile11(manifestPath, "utf8"));
7947
+ if (!isPlainRecord(manifest))
7874
7948
  return [];
7875
- const hooksPath = join14(input.pluginRoot, manifest.hooks);
7876
- if (!await exists2(hooksPath))
7877
- return [];
7878
- const parsed = JSON.parse(await readFile10(hooksPath, "utf8"));
7879
- if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
7949
+ const states = [];
7950
+ for (const hookPath of hookManifestPaths2(manifest.hooks)) {
7951
+ const hooksPath = join15(input.pluginRoot, hookPath);
7952
+ if (!await exists2(hooksPath))
7953
+ continue;
7954
+ const parsed = JSON.parse(await readFile11(hooksPath, "utf8"));
7955
+ if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
7956
+ continue;
7957
+ states.push(...trustedHookStatesForHooksFile({
7958
+ keySource: `${input.pluginName}@${input.marketplaceName}:${hookPath}`,
7959
+ hooks: parsed.hooks
7960
+ }));
7961
+ }
7962
+ return states;
7963
+ }
7964
+ function hookManifestPaths2(value) {
7965
+ if (typeof value === "string" && value.trim() !== "")
7966
+ return [stripDotSlash2(value)];
7967
+ if (!Array.isArray(value))
7880
7968
  return [];
7881
- const keySource = `${input.pluginName}@${input.marketplaceName}:${stripDotSlash(manifest.hooks)}`;
7969
+ return value.filter((item) => typeof item === "string" && item.trim() !== "").map(stripDotSlash2);
7970
+ }
7971
+ function trustedHookStatesForHooksFile(input) {
7882
7972
  const states = [];
7883
- for (const [eventName, groups] of Object.entries(parsed.hooks)) {
7973
+ for (const [eventName, groups] of Object.entries(input.hooks)) {
7884
7974
  if (!Array.isArray(groups))
7885
7975
  continue;
7886
7976
  const eventLabel = EVENT_LABELS.get(eventName);
@@ -7896,7 +7986,7 @@ async function trustedHookStatesForPlugin(input) {
7896
7986
  continue;
7897
7987
  if (typeof handler.command !== "string" || handler.command.trim() === "")
7898
7988
  continue;
7899
- const key = `${keySource}:${eventLabel}:${groupIndex}:${handlerIndex}`;
7989
+ const key = `${input.keySource}:${eventLabel}:${groupIndex}:${handlerIndex}`;
7900
7990
  states.push({ key, trustedHash: commandHookHash(eventLabel, group.matcher, handler) });
7901
7991
  }
7902
7992
  }
@@ -7930,12 +8020,12 @@ function canonicalJson(value) {
7930
8020
  }
7931
8021
  return result;
7932
8022
  }
7933
- function stripDotSlash(value) {
8023
+ function stripDotSlash2(value) {
7934
8024
  return value.startsWith("./") ? value.slice(2) : value;
7935
8025
  }
7936
8026
  async function exists2(path) {
7937
8027
  try {
7938
- await readFile10(path, "utf8");
8028
+ await readFile11(path, "utf8");
7939
8029
  return true;
7940
8030
  } catch (error) {
7941
8031
  if (error instanceof Error)
@@ -7986,12 +8076,12 @@ function toCodexResolution(resolution) {
7986
8076
  }
7987
8077
 
7988
8078
  // packages/omo-codex/src/install/link-cached-plugin-agents.ts
7989
- import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile12, readdir as readdir4, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
7990
- import { basename as basename4, join as join16 } from "node:path";
8079
+ import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile13, readdir as readdir4, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
8080
+ import { basename as basename4, join as join17 } from "node:path";
7991
8081
 
7992
8082
  // packages/omo-codex/src/install/retired-managed-agent-purge.ts
7993
- import { lstat as lstat6, readFile as readFile11, rm as rm5 } from "node:fs/promises";
7994
- import { join as join15 } from "node:path";
8083
+ import { lstat as lstat6, readFile as readFile12, rm as rm5 } from "node:fs/promises";
8084
+ import { join as join16 } from "node:path";
7995
8085
  var RETIRED_MANAGED_AGENT_FILES = [
7996
8086
  {
7997
8087
  fileName: "codex-ultrawork-reviewer.toml",
@@ -8003,11 +8093,11 @@ var RETIRED_MANAGED_AGENT_FILES = [
8003
8093
  }
8004
8094
  ];
8005
8095
  async function purgeRetiredManagedAgentFiles(input) {
8006
- const agentsDir = join15(input.codexHome, "agents");
8096
+ const agentsDir = join16(input.codexHome, "agents");
8007
8097
  if (!await exists3(agentsDir))
8008
8098
  return;
8009
8099
  for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
8010
- const agentPath = join15(agentsDir, retiredAgent.fileName);
8100
+ const agentPath = join16(agentsDir, retiredAgent.fileName);
8011
8101
  if (!await exists3(agentPath))
8012
8102
  continue;
8013
8103
  const agentStat = await lstat6(agentPath);
@@ -8024,7 +8114,7 @@ function hasRequiredMarkers(content, markers) {
8024
8114
  }
8025
8115
  async function readTextIfExists(path) {
8026
8116
  try {
8027
- return await readFile11(path, "utf8");
8117
+ return await readFile12(path, "utf8");
8028
8118
  } catch (error) {
8029
8119
  if (nodeErrorCode(error) === "ENOENT")
8030
8120
  return null;
@@ -8050,7 +8140,7 @@ function nodeErrorCode(error) {
8050
8140
  // packages/omo-codex/src/install/link-cached-plugin-agents.ts
8051
8141
  var MANIFEST_FILE = ".installed-agents.json";
8052
8142
  async function capturePreservedAgentReasoning(input) {
8053
- const agentsDir = join16(input.codexHome, "agents");
8143
+ const agentsDir = join17(input.codexHome, "agents");
8054
8144
  if (!await exists4(agentsDir))
8055
8145
  return new Map;
8056
8146
  const preserved = new Map;
@@ -8058,7 +8148,7 @@ async function capturePreservedAgentReasoning(input) {
8058
8148
  for (const entry of agentEntries) {
8059
8149
  if (!entry.name.endsWith(".toml"))
8060
8150
  continue;
8061
- const content = await readTextIfExists2(join16(agentsDir, entry.name));
8151
+ const content = await readTextIfExists2(join17(agentsDir, entry.name));
8062
8152
  if (content === null)
8063
8153
  continue;
8064
8154
  const effort = extractReasoningEffort(content);
@@ -8068,7 +8158,7 @@ async function capturePreservedAgentReasoning(input) {
8068
8158
  return preserved;
8069
8159
  }
8070
8160
  async function capturePreservedAgentServiceTier(input) {
8071
- const agentsDir = join16(input.codexHome, "agents");
8161
+ const agentsDir = join17(input.codexHome, "agents");
8072
8162
  if (!await exists4(agentsDir))
8073
8163
  return new Map;
8074
8164
  const preserved = new Map;
@@ -8076,7 +8166,7 @@ async function capturePreservedAgentServiceTier(input) {
8076
8166
  for (const entry of agentEntries) {
8077
8167
  if (!entry.name.endsWith(".toml"))
8078
8168
  continue;
8079
- const content = await readTextIfExists2(join16(agentsDir, entry.name));
8169
+ const content = await readTextIfExists2(join17(agentsDir, entry.name));
8080
8170
  if (content === null)
8081
8171
  continue;
8082
8172
  preserved.set(agentNameFromToml(entry.name), extractServiceTier(content));
@@ -8090,13 +8180,13 @@ async function linkCachedPluginAgents(input) {
8090
8180
  await writeManifest(input.pluginRoot, []);
8091
8181
  return [];
8092
8182
  }
8093
- const agentsDir = join16(input.codexHome, "agents");
8183
+ const agentsDir = join17(input.codexHome, "agents");
8094
8184
  await mkdir6(agentsDir, { recursive: true });
8095
8185
  const linked = [];
8096
8186
  for (const agentPath of bundledAgents) {
8097
8187
  const agentFileName = basename4(agentPath);
8098
8188
  const agentName = agentNameFromToml(agentFileName);
8099
- const linkPath = join16(agentsDir, agentFileName);
8189
+ const linkPath = join17(agentsDir, agentFileName);
8100
8190
  await replaceWithCopy(linkPath, agentPath);
8101
8191
  await restorePreservedReasoning({
8102
8192
  agentName,
@@ -8117,7 +8207,7 @@ async function linkCachedPluginAgents(input) {
8117
8207
  async function restorePreservedServiceTier(input) {
8118
8208
  if (!input.preserved)
8119
8209
  return;
8120
- const content = await readFile12(input.linkPath, "utf8");
8210
+ const content = await readFile13(input.linkPath, "utf8");
8121
8211
  if (extractServiceTier(content) === input.value)
8122
8212
  return;
8123
8213
  const replacement = replaceServiceTier(content, input.value);
@@ -8126,7 +8216,7 @@ async function restorePreservedServiceTier(input) {
8126
8216
  await writeFile6(input.linkPath, replacement.content);
8127
8217
  }
8128
8218
  async function discoverBundledAgents(pluginRoot) {
8129
- const componentsRoot = join16(pluginRoot, "components");
8219
+ const componentsRoot = join17(pluginRoot, "components");
8130
8220
  if (!await exists4(componentsRoot))
8131
8221
  return [];
8132
8222
  const componentEntries = await readdir4(componentsRoot, { withFileTypes: true });
@@ -8134,14 +8224,14 @@ async function discoverBundledAgents(pluginRoot) {
8134
8224
  for (const entry of componentEntries) {
8135
8225
  if (!entry.isDirectory())
8136
8226
  continue;
8137
- const agentsRoot = join16(componentsRoot, entry.name, "agents");
8227
+ const agentsRoot = join17(componentsRoot, entry.name, "agents");
8138
8228
  if (!await exists4(agentsRoot))
8139
8229
  continue;
8140
8230
  const agentEntries = await readdir4(agentsRoot, { withFileTypes: true });
8141
8231
  for (const file2 of agentEntries) {
8142
8232
  if (!file2.isFile() || !file2.name.endsWith(".toml"))
8143
8233
  continue;
8144
- agents.push(join16(agentsRoot, file2.name));
8234
+ agents.push(join17(agentsRoot, file2.name));
8145
8235
  }
8146
8236
  }
8147
8237
  agents.sort();
@@ -8161,7 +8251,7 @@ async function prepareReplacement(linkPath) {
8161
8251
  await rm6(linkPath, { force: true });
8162
8252
  }
8163
8253
  async function writeManifest(pluginRoot, agentPaths) {
8164
- const manifestPath = join16(pluginRoot, MANIFEST_FILE);
8254
+ const manifestPath = join17(pluginRoot, MANIFEST_FILE);
8165
8255
  const payload = { agents: [...agentPaths].sort() };
8166
8256
  await writeFile6(manifestPath, `${JSON.stringify(payload, null, "\t")}
8167
8257
  `);
@@ -8169,7 +8259,7 @@ async function writeManifest(pluginRoot, agentPaths) {
8169
8259
  async function restorePreservedReasoning(input) {
8170
8260
  if (input.value === undefined)
8171
8261
  return;
8172
- const content = await readFile12(input.target, "utf8");
8262
+ const content = await readFile13(input.target, "utf8");
8173
8263
  const bundledEffort = extractReasoningEffort(content);
8174
8264
  if (bundledEffort === input.value)
8175
8265
  return;
@@ -8180,7 +8270,7 @@ async function restorePreservedReasoning(input) {
8180
8270
  }
8181
8271
  async function readTextIfExists2(path) {
8182
8272
  try {
8183
- return await readFile12(path, "utf8");
8273
+ return await readFile13(path, "utf8");
8184
8274
  } catch (error) {
8185
8275
  if (nodeErrorCode2(error) === "ENOENT")
8186
8276
  return null;
@@ -8288,12 +8378,12 @@ function nodeErrorCode2(error) {
8288
8378
  }
8289
8379
 
8290
8380
  // packages/omo-codex/src/install/codex-marketplace.ts
8291
- import { readFile as readFile13 } from "node:fs/promises";
8292
- import { join as join17 } from "node:path";
8381
+ import { readFile as readFile14 } from "node:fs/promises";
8382
+ import { join as join18 } from "node:path";
8293
8383
  var DEFAULT_MARKETPLACE_PATH = "packages/omo-codex/marketplace.json";
8294
8384
  async function readMarketplace(repoRoot, options) {
8295
- const marketplacePath = options?.marketplacePath ?? join17(repoRoot, DEFAULT_MARKETPLACE_PATH);
8296
- const raw = await readFile13(marketplacePath, "utf8");
8385
+ const marketplacePath = options?.marketplacePath ?? join18(repoRoot, DEFAULT_MARKETPLACE_PATH);
8386
+ const raw = await readFile14(marketplacePath, "utf8");
8297
8387
  const parsed = JSON.parse(raw);
8298
8388
  if (!isPlainRecord(parsed))
8299
8389
  throw new Error("marketplace.json must be an object");
@@ -8311,10 +8401,10 @@ async function readMarketplace(repoRoot, options) {
8311
8401
  function resolvePluginSource(repoRoot, plugin, options) {
8312
8402
  const sourcePath = localSourcePath(options?.pathOverride ?? plugin.source);
8313
8403
  const relativePath = sourcePath.slice(2);
8314
- return join17(repoRoot, ...relativePath.split(/[\\/]/));
8404
+ return join18(repoRoot, ...relativePath.split(/[\\/]/));
8315
8405
  }
8316
8406
  async function readPluginManifest(pluginRoot) {
8317
- const raw = await readFile13(join17(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
8407
+ const raw = await readFile14(join18(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
8318
8408
  const parsed = JSON.parse(raw);
8319
8409
  if (!isPlainRecord(parsed))
8320
8410
  throw new Error(`${pluginRoot} plugin.json must be an object`);
@@ -8324,15 +8414,27 @@ async function readPluginManifest(pluginRoot) {
8324
8414
  if (parsed.version !== undefined && (typeof parsed.version !== "string" || parsed.version.trim() === "")) {
8325
8415
  throw new Error(`${pluginRoot} plugin.json version must be a non-empty string`);
8326
8416
  }
8327
- if (parsed.hooks !== undefined && (typeof parsed.hooks !== "string" || parsed.hooks.trim() === "")) {
8328
- throw new Error(`${pluginRoot} plugin.json hooks must be a non-empty string`);
8417
+ if (parsed.hooks !== undefined && !isPluginHooksManifestValue(parsed.hooks)) {
8418
+ throw new Error(`${pluginRoot} plugin.json hooks must be a non-empty string or string array`);
8329
8419
  }
8330
8420
  return {
8331
8421
  name: parsed.name,
8332
8422
  version: typeof parsed.version === "string" ? parsed.version.trim() : undefined,
8333
- hooks: typeof parsed.hooks === "string" ? parsed.hooks.trim() : undefined
8423
+ hooks: normalizePluginHooksManifestValue(parsed.hooks)
8334
8424
  };
8335
8425
  }
8426
+ function isPluginHooksManifestValue(value) {
8427
+ if (typeof value === "string")
8428
+ return value.trim() !== "";
8429
+ return Array.isArray(value) && value.every((item) => typeof item === "string" && item.trim() !== "");
8430
+ }
8431
+ function normalizePluginHooksManifestValue(value) {
8432
+ if (typeof value === "string")
8433
+ return value.trim();
8434
+ if (Array.isArray(value))
8435
+ return value.map((item) => item.trim());
8436
+ return;
8437
+ }
8336
8438
  function validatePathSegment(value, label) {
8337
8439
  if (!/^[A-Za-z0-9._+-]+$/.test(value)) {
8338
8440
  throw new Error(`${label} contains unsupported characters: ${value}`);
@@ -8384,7 +8486,7 @@ function validateLocalSourcePath(path) {
8384
8486
 
8385
8487
  // packages/omo-codex/src/install/codex-marketplace-snapshot.ts
8386
8488
  import { cp as cp3, mkdir as mkdir7, rename as rename3, rm as rm7, writeFile as writeFile7 } from "node:fs/promises";
8387
- import { join as join18, sep as sep5 } from "node:path";
8489
+ import { join as join19, sep as sep6 } from "node:path";
8388
8490
  var INSTALLED_MARKETPLACES_DIR = ".tmp/marketplaces";
8389
8491
  async function writeInstalledMarketplaceSnapshot(input) {
8390
8492
  const marketplaceRoot = installedMarketplaceRoot(input.codexHome, input.marketplace.name);
@@ -8397,21 +8499,21 @@ async function writeInstalledMarketplaceSnapshot(input) {
8397
8499
  return snapshotPlugins;
8398
8500
  }
8399
8501
  function installedMarketplaceRoot(codexHome, marketplaceName) {
8400
- return join18(codexHome, INSTALLED_MARKETPLACES_DIR, marketplaceName);
8502
+ return join19(codexHome, INSTALLED_MARKETPLACES_DIR, marketplaceName);
8401
8503
  }
8402
8504
  async function writeMarketplaceManifest(marketplaceRoot, marketplace) {
8403
- const manifestDir = join18(marketplaceRoot, ".agents", "plugins");
8505
+ const manifestDir = join19(marketplaceRoot, ".agents", "plugins");
8404
8506
  await mkdir7(manifestDir, { recursive: true });
8405
- const tempPath = join18(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
8507
+ const tempPath = join19(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
8406
8508
  await writeFile7(tempPath, `${JSON.stringify(marketplace, null, "\t")}
8407
8509
  `);
8408
- await rename3(tempPath, join18(manifestDir, "marketplace.json"));
8510
+ await rename3(tempPath, join19(manifestDir, "marketplace.json"));
8409
8511
  }
8410
8512
  async function writeSnapshotPlugin(marketplaceRoot, plugin) {
8411
- const pluginsDir = join18(marketplaceRoot, "plugins");
8513
+ const pluginsDir = join19(marketplaceRoot, "plugins");
8412
8514
  await mkdir7(pluginsDir, { recursive: true });
8413
- const targetPath = join18(pluginsDir, plugin.name);
8414
- const tempPath = join18(pluginsDir, `.tmp-${plugin.name}-${process.pid}-${Date.now()}`);
8515
+ const targetPath = join19(pluginsDir, plugin.name);
8516
+ const tempPath = join19(pluginsDir, `.tmp-${plugin.name}-${process.pid}-${Date.now()}`);
8415
8517
  await rm7(tempPath, { recursive: true, force: true });
8416
8518
  await cp3(plugin.sourcePath, tempPath, {
8417
8519
  recursive: true,
@@ -8424,19 +8526,19 @@ async function writeSnapshotPlugin(marketplaceRoot, plugin) {
8424
8526
  return { name: plugin.name, path: targetPath };
8425
8527
  }
8426
8528
  function shouldCopyMarketplaceSourcePath(path, root) {
8427
- const relative4 = path === root ? "" : path.slice(root.length + sep5.length);
8529
+ const relative4 = path === root ? "" : path.slice(root.length + sep6.length);
8428
8530
  if (relative4 === "")
8429
8531
  return true;
8430
- const parts = relative4.split(sep5);
8532
+ const parts = relative4.split(sep6);
8431
8533
  return !parts.some((part) => part === ".git" || part === "node_modules");
8432
8534
  }
8433
8535
 
8434
8536
  // packages/omo-codex/src/install/lazycodex-version-stamp.ts
8435
- import { readdir as readdir5, readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
8436
- import { join as join19 } from "node:path";
8537
+ import { readdir as readdir5, readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
8538
+ import { join as join20 } from "node:path";
8437
8539
  async function readDistributionManifest(repoRoot) {
8438
8540
  try {
8439
- const parsed = JSON.parse(await readFile14(join19(repoRoot, "package.json"), "utf8"));
8541
+ const parsed = JSON.parse(await readFile15(join20(repoRoot, "package.json"), "utf8"));
8440
8542
  if (!isPlainRecord(parsed) || typeof parsed.version !== "string" || parsed.version.trim().length === 0)
8441
8543
  return;
8442
8544
  return {
@@ -8456,15 +8558,19 @@ function resolveLazyCodexPluginVersion(input) {
8456
8558
  return input.manifestVersion ?? "local";
8457
8559
  }
8458
8560
  async function stampLazyCodexPluginVersion(input) {
8459
- await stampJsonVersion(join19(input.pluginRoot, ".codex-plugin", "plugin.json"), input.version);
8460
- await stampJsonVersion(join19(input.pluginRoot, "package.json"), input.version);
8461
- await stampHookStatusMessages(join19(input.pluginRoot, "hooks", "hooks.json"), input.version);
8561
+ const manifestPath = join20(input.pluginRoot, ".codex-plugin", "plugin.json");
8562
+ const hookPaths = await readPluginHookPaths(manifestPath);
8563
+ await stampJsonVersion(manifestPath, input.version);
8564
+ await stampJsonVersion(join20(input.pluginRoot, "package.json"), input.version);
8565
+ for (const hookPath of hookPaths) {
8566
+ await stampHookStatusMessages(join20(input.pluginRoot, hookPath), input.version);
8567
+ }
8462
8568
  await stampComponentVersions(input);
8463
8569
  }
8464
8570
  async function writeLazyCodexInstallSnapshot(input) {
8465
8571
  if (input.distributionManifest === undefined)
8466
8572
  return;
8467
- await writeFile8(join19(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
8573
+ await writeFile8(join20(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
8468
8574
  packageName: input.distributionManifest.name,
8469
8575
  version: input.distributionManifest.version
8470
8576
  }, null, "\t")}
@@ -8472,7 +8578,7 @@ async function writeLazyCodexInstallSnapshot(input) {
8472
8578
  }
8473
8579
  async function stampJsonVersion(path, version) {
8474
8580
  try {
8475
- const parsed = JSON.parse(await readFile14(path, "utf8"));
8581
+ const parsed = JSON.parse(await readFile15(path, "utf8"));
8476
8582
  if (!isPlainRecord(parsed))
8477
8583
  return;
8478
8584
  parsed.version = version;
@@ -8484,9 +8590,29 @@ async function stampJsonVersion(path, version) {
8484
8590
  throw error;
8485
8591
  }
8486
8592
  }
8593
+ async function readPluginHookPaths(manifestPath) {
8594
+ try {
8595
+ const parsed = JSON.parse(await readFile15(manifestPath, "utf8"));
8596
+ if (!isPlainRecord(parsed))
8597
+ return [];
8598
+ if (typeof parsed.hooks === "string" && parsed.hooks.trim().length > 0)
8599
+ return [stripDotSlash3(parsed.hooks)];
8600
+ if (Array.isArray(parsed.hooks)) {
8601
+ return parsed.hooks.filter((hookPath) => typeof hookPath === "string" && hookPath.trim().length > 0).map(stripDotSlash3);
8602
+ }
8603
+ return [];
8604
+ } catch (error) {
8605
+ if (error instanceof Error)
8606
+ return [];
8607
+ throw error;
8608
+ }
8609
+ }
8610
+ function stripDotSlash3(path) {
8611
+ return path.startsWith("./") ? path.slice(2) : path;
8612
+ }
8487
8613
  async function stampHookStatusMessages(path, version) {
8488
8614
  try {
8489
- const parsed = JSON.parse(await readFile14(path, "utf8"));
8615
+ const parsed = JSON.parse(await readFile15(path, "utf8"));
8490
8616
  if (!isPlainRecord(parsed))
8491
8617
  return;
8492
8618
  stampHookGroups(parsed.hooks, version);
@@ -8501,16 +8627,16 @@ async function stampHookStatusMessages(path, version) {
8501
8627
  async function stampComponentVersions(input) {
8502
8628
  let entries;
8503
8629
  try {
8504
- entries = await readdir5(join19(input.pluginRoot, "components"));
8630
+ entries = await readdir5(join20(input.pluginRoot, "components"));
8505
8631
  } catch (error) {
8506
8632
  if (error instanceof Error)
8507
8633
  return;
8508
8634
  throw error;
8509
8635
  }
8510
8636
  for (const entry of entries) {
8511
- const componentRoot = join19(input.pluginRoot, "components", entry);
8512
- await stampJsonVersion(join19(componentRoot, "package.json"), input.version);
8513
- await stampHookStatusMessages(join19(componentRoot, "hooks", "hooks.json"), input.version);
8637
+ const componentRoot = join20(input.pluginRoot, "components", entry);
8638
+ await stampJsonVersion(join20(componentRoot, "package.json"), input.version);
8639
+ await stampHookStatusMessages(join20(componentRoot, "hooks", "hooks.json"), input.version);
8514
8640
  }
8515
8641
  }
8516
8642
  function stampHookGroups(hooks, version) {
@@ -8531,12 +8657,12 @@ function stampHookGroups(hooks, version) {
8531
8657
  function stampHookStatusMessage(hook, version) {
8532
8658
  if (!isPlainRecord(hook) || typeof hook.statusMessage !== "string")
8533
8659
  return;
8534
- hook.statusMessage = hook.statusMessage.replace(/^LazyCodex\([^)]+\):/, `LazyCodex(${version}):`);
8660
+ hook.statusMessage = hook.statusMessage.replace(/^LazyCodex\([^)]+\):\s*/, "(OmO) ");
8535
8661
  }
8536
8662
 
8537
8663
  // packages/omo-codex/src/install/codex-project-local-cleanup.ts
8538
- import { copyFile as copyFile2, lstat as lstat8, readFile as readFile15, writeFile as writeFile9 } from "node:fs/promises";
8539
- import { dirname as dirname6, join as join20, resolve as resolve6 } from "node:path";
8664
+ import { copyFile as copyFile2, lstat as lstat8, readFile as readFile16, writeFile as writeFile9 } from "node:fs/promises";
8665
+ import { dirname as dirname6, join as join21, resolve as resolve6 } from "node:path";
8540
8666
  var LEGACY_AGENT_CONFLICT_KEYS = ["max_threads"];
8541
8667
  var PROJECT_LOCAL_ARTIFACT_PATHS = [
8542
8668
  ".codex/hooks.json",
@@ -8555,7 +8681,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
8555
8681
  const artifacts = await collectProjectLocalArtifacts(project.artifactRoots);
8556
8682
  const configs = [];
8557
8683
  for (const configPath of project.configPaths) {
8558
- const original = await readFile15(configPath, "utf8");
8684
+ const original = await readFile16(configPath, "utf8");
8559
8685
  const repair = repairProjectLocalCodexConfigText(original);
8560
8686
  if (!repair.changed) {
8561
8687
  configs.push({
@@ -8639,17 +8765,17 @@ async function findProjectLocalCodexConfigs(startDirectory, codexHome) {
8639
8765
  if (startDirectoryStat !== null && !startDirectoryStat.isDirectory()) {
8640
8766
  throw new ProjectLocalCleanupStartDirectoryError(startDirectory);
8641
8767
  }
8642
- const codexHomeConfigPath = codexHome === undefined ? null : join20(resolve6(codexHome), "config.toml");
8768
+ const codexHomeConfigPath = codexHome === undefined ? null : join21(resolve6(codexHome), "config.toml");
8643
8769
  let current = resolve6(startDirectory);
8644
8770
  const configPathsFromCwd = [];
8645
8771
  while (true) {
8646
- const configPath = join20(current, ".codex", "config.toml");
8772
+ const configPath = join21(current, ".codex", "config.toml");
8647
8773
  if (await isRegularProjectLocalConfig(current, configPath)) {
8648
8774
  if (codexHomeConfigPath === null || resolve6(configPath) !== codexHomeConfigPath) {
8649
8775
  configPathsFromCwd.push(configPath);
8650
8776
  }
8651
8777
  }
8652
- if (await exists5(join20(current, ".git"))) {
8778
+ if (await exists5(join21(current, ".git"))) {
8653
8779
  return configPathsFromCwd.length === 0 ? null : {
8654
8780
  projectRoot: current,
8655
8781
  configPaths: [...configPathsFromCwd].reverse(),
@@ -8669,7 +8795,7 @@ async function findProjectLocalCodexConfigs(startDirectory, codexHome) {
8669
8795
  }
8670
8796
  }
8671
8797
  async function isRegularProjectLocalConfig(directory, configPath) {
8672
- const codexDirStat = await maybeLstat(join20(directory, ".codex"));
8798
+ const codexDirStat = await maybeLstat(join21(directory, ".codex"));
8673
8799
  if (codexDirStat === null || !codexDirStat.isDirectory() || codexDirStat.isSymbolicLink())
8674
8800
  return false;
8675
8801
  const configStat = await maybeLstat(configPath);
@@ -8689,7 +8815,7 @@ async function collectProjectLocalArtifacts(projectRoots) {
8689
8815
  const seenPaths = new Set;
8690
8816
  for (const projectRoot of projectRoots) {
8691
8817
  for (const relativePath of PROJECT_LOCAL_ARTIFACT_PATHS) {
8692
- const artifactPath = join20(projectRoot, relativePath);
8818
+ const artifactPath = join21(projectRoot, relativePath);
8693
8819
  if (seenPaths.has(artifactPath))
8694
8820
  continue;
8695
8821
  const entryStat = await maybeLstat(artifactPath);
@@ -8764,13 +8890,13 @@ function formatUnknownError(error) {
8764
8890
  }
8765
8891
 
8766
8892
  // packages/omo-codex/src/install/lsp-daemon-reaper.ts
8767
- import { readFile as readFile16, readdir as readdir6, rm as rm8 } from "node:fs/promises";
8893
+ import { readFile as readFile17, readdir as readdir6, rm as rm8 } from "node:fs/promises";
8768
8894
  import { connect } from "node:net";
8769
- import { join as join21 } from "node:path";
8895
+ import { join as join22 } from "node:path";
8770
8896
  async function reapLspDaemons(codexHome, deps = {}) {
8771
8897
  const killProcess = deps.killProcess ?? sendSigterm;
8772
8898
  const isDaemonLive = deps.isDaemonLive ?? probeSocketLive;
8773
- const daemonRoot = join21(codexHome, "codex-lsp", "daemon");
8899
+ const daemonRoot = join22(codexHome, "codex-lsp", "daemon");
8774
8900
  const reaped = [];
8775
8901
  let entries;
8776
8902
  try {
@@ -8779,9 +8905,9 @@ async function reapLspDaemons(codexHome, deps = {}) {
8779
8905
  return reaped;
8780
8906
  }
8781
8907
  for (const entry of entries) {
8782
- const versionDir = join21(daemonRoot, entry);
8783
- const pid = await readPidFile(join21(versionDir, "daemon.pid"));
8784
- const socketPath = await readEndpointFile(join21(versionDir, "daemon.endpoint"));
8908
+ const versionDir = join22(daemonRoot, entry);
8909
+ const pid = await readPidFile(join22(versionDir, "daemon.pid"));
8910
+ const socketPath = await readEndpointFile(join22(versionDir, "daemon.endpoint"));
8785
8911
  if (pid !== null && socketPath !== null && await isDaemonLive(socketPath) && killProcess(pid)) {
8786
8912
  reaped.push(pid);
8787
8913
  }
@@ -8791,7 +8917,7 @@ async function reapLspDaemons(codexHome, deps = {}) {
8791
8917
  }
8792
8918
  async function readEndpointFile(path) {
8793
8919
  try {
8794
- const content = (await readFile16(path, "utf8")).trim();
8920
+ const content = (await readFile17(path, "utf8")).trim();
8795
8921
  return content.length > 0 ? content : null;
8796
8922
  } catch {
8797
8923
  return null;
@@ -8799,7 +8925,7 @@ async function readEndpointFile(path) {
8799
8925
  }
8800
8926
  async function readPidFile(path) {
8801
8927
  try {
8802
- const pid = Number.parseInt((await readFile16(path, "utf8")).trim(), 10);
8928
+ const pid = Number.parseInt((await readFile17(path, "utf8")).trim(), 10);
8803
8929
  return Number.isInteger(pid) && pid > 0 ? pid : null;
8804
8930
  } catch {
8805
8931
  return null;
@@ -8835,7 +8961,7 @@ function sendSigterm(pid) {
8835
8961
 
8836
8962
  // packages/omo-codex/src/install/codex-installer-bin-dir.ts
8837
8963
  import { homedir } from "node:os";
8838
- import { join as join22, resolve as resolve7 } from "node:path";
8964
+ import { join as join23, resolve as resolve7 } from "node:path";
8839
8965
  function resolveCodexInstallerBinDir(input) {
8840
8966
  const explicitBinDir = input.binDir ?? input.env?.CODEX_LOCAL_BIN_DIR;
8841
8967
  if (explicitBinDir !== undefined && explicitBinDir.trim().length > 0)
@@ -8844,15 +8970,15 @@ function resolveCodexInstallerBinDir(input) {
8844
8970
  const defaultCodexHome = resolve7(homeDir, ".codex");
8845
8971
  const resolvedCodexHome = resolve7(input.codexHome);
8846
8972
  if (resolvedCodexHome !== defaultCodexHome)
8847
- return join22(resolvedCodexHome, "bin");
8973
+ return join23(resolvedCodexHome, "bin");
8848
8974
  return resolve7(homeDir, ".local", "bin");
8849
8975
  }
8850
8976
 
8851
8977
  // packages/omo-codex/src/install/omo-sot-migration.ts
8852
- import { join as join23 } from "node:path";
8978
+ import { join as join24 } from "node:path";
8853
8979
  async function seedAndMigrateOmoSot(input) {
8854
8980
  const commandEnv = { ...input.env };
8855
- const scriptPath = join23(input.repoRoot, "packages", "omo-codex", "plugin", "scripts", "migrate-omo-sot.mjs");
8981
+ const scriptPath = join24(input.repoRoot, "packages", "omo-codex", "plugin", "scripts", "migrate-omo-sot.mjs");
8856
8982
  try {
8857
8983
  await input.runCommand(process.execPath, [scriptPath, "--seed"], {
8858
8984
  cwd: input.repoRoot,
@@ -8866,7 +8992,7 @@ async function seedAndMigrateOmoSot(input) {
8866
8992
  }
8867
8993
 
8868
8994
  // packages/omo-codex/src/install/install-ast-grep-sg.ts
8869
- import { join as join25 } from "node:path";
8995
+ import { join as join26 } from "node:path";
8870
8996
 
8871
8997
  // packages/utils/src/deep-merge.ts
8872
8998
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
@@ -11838,11 +11964,11 @@ function runtimeSlug(platform = process.platform, arch = process.arch) {
11838
11964
  // packages/utils/src/ast-grep/install-script.ts
11839
11965
  import { spawn as spawn3 } from "node:child_process";
11840
11966
  import { existsSync as existsSync3 } from "node:fs";
11841
- import { join as join24 } from "node:path";
11967
+ import { join as join25 } from "node:path";
11842
11968
  var AST_GREP_BIN_DIR_ENV_KEY = "OMO_AST_GREP_BIN_DIR";
11843
11969
  var AST_GREP_INSTALL_TIMEOUT_MS = 30000;
11844
11970
  function astGrepRuntimeDir(baseDir, platform = process.platform, arch = process.arch) {
11845
- return join24(baseDir, "runtime", "ast-grep", runtimeSlug(platform, arch));
11971
+ return join25(baseDir, "runtime", "ast-grep", runtimeSlug(platform, arch));
11846
11972
  }
11847
11973
  function isMissingExecutable(error) {
11848
11974
  if (!("code" in error))
@@ -11880,7 +12006,7 @@ function defaultSpawnProcess(command, args, options) {
11880
12006
  };
11881
12007
  }
11882
12008
  function scriptPathForPlatform(skillDir, platform) {
11883
- return join24(skillDir, platform === "win32" ? "install.ps1" : "install.sh");
12009
+ return join25(skillDir, platform === "win32" ? "install.ps1" : "install.sh");
11884
12010
  }
11885
12011
  function invocationsForPlatform(scriptPath, platform) {
11886
12012
  if (platform !== "win32")
@@ -12648,7 +12774,7 @@ async function installAstGrepForCodex(options) {
12648
12774
  return;
12649
12775
  const platform = options.platform ?? process.platform;
12650
12776
  const targetDir = astGrepRuntimeDir(options.codexHome, platform, options.arch ?? process.arch);
12651
- const skillDir = join25(plugin.path, "skills", "ast-grep");
12777
+ const skillDir = join26(plugin.path, "skills", "ast-grep");
12652
12778
  const installer = options.installer ?? runAstGrepSkillInstall;
12653
12779
  try {
12654
12780
  const result = await installer({ platform, skillDir, targetDir });
@@ -12681,7 +12807,7 @@ async function runCodexInstaller(options = {}) {
12681
12807
  const env3 = options.env ?? process.env;
12682
12808
  const platform = options.platform ?? process.platform;
12683
12809
  const repoRoot = resolve10(options.repoRoot ?? findRepoRoot({ importerDir: import.meta.dir, env: env3 }));
12684
- const codexHome = resolve10(options.codexHome ?? env3.CODEX_HOME ?? join28(homedir2(), ".codex"));
12810
+ const codexHome = resolve10(options.codexHome ?? env3.CODEX_HOME ?? join29(homedir2(), ".codex"));
12685
12811
  const projectDirectory = resolve10(options.projectDirectory ?? env3.OMO_CODEX_PROJECT ?? process.cwd());
12686
12812
  const binDir = resolveCodexInstallerBinDir({ binDir: options.binDir, codexHome, env: env3 });
12687
12813
  const runCommand = options.runCommand ?? defaultRunCommand;
@@ -12699,9 +12825,9 @@ async function runCodexInstaller(options = {}) {
12699
12825
  if (!gitBashResolution.found) {
12700
12826
  throw new Error(gitBashResolution.installHint);
12701
12827
  }
12702
- const codexPackageRoot = join28(repoRoot, "packages", "omo-codex");
12828
+ const codexPackageRoot = join29(repoRoot, "packages", "omo-codex");
12703
12829
  const marketplace = await readMarketplace(repoRoot, {
12704
- marketplacePath: join28(codexPackageRoot, "marketplace.json")
12830
+ marketplacePath: join29(codexPackageRoot, "marketplace.json")
12705
12831
  });
12706
12832
  const distributionManifest = await readDistributionManifest(repoRoot);
12707
12833
  const installed = [];
@@ -12743,7 +12869,7 @@ async function runCodexInstaller(options = {}) {
12743
12869
  if (runtimeLink !== null)
12744
12870
  log2(`Linked ${runtimeLink.name} -> ${runtimeLink.target}`);
12745
12871
  else
12746
- log2(`Warning: skipped the omo runtime wrapper because ${join28(repoRoot, "dist", "cli", "index.js")} is missing; omo sparkshell/ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
12872
+ log2(`Warning: skipped the omo runtime wrapper because ${join29(repoRoot, "dist", "cli", "index.js")} is missing; omo sparkshell/ulw-loop commands will be unavailable until a package shipping dist/cli is installed`);
12747
12873
  }
12748
12874
  pluginSources.push({ name: entry.name, sourcePath });
12749
12875
  installed.push(plugin);
@@ -12796,13 +12922,13 @@ async function runCodexInstaller(options = {}) {
12796
12922
  });
12797
12923
  }
12798
12924
  await reapLspDaemons(codexHome).catch(() => []);
12799
- const marketplaceRoot = join28(codexHome, "plugins", "cache", marketplace.name);
12925
+ const marketplaceRoot = join29(codexHome, "plugins", "cache", marketplace.name);
12800
12926
  await writeCachedMarketplaceManifest({
12801
12927
  marketplaceName: marketplace.name,
12802
12928
  marketplaceRoot,
12803
12929
  plugins: installed
12804
12930
  });
12805
- const configPath = join28(codexHome, "config.toml");
12931
+ const configPath = join29(codexHome, "config.toml");
12806
12932
  await updateCodexConfig({
12807
12933
  configPath,
12808
12934
  repoRoot: codexPackageRoot,
@@ -12861,7 +12987,7 @@ function findRepoRootFromImporter(importerDir) {
12861
12987
  for (let depth = 0;depth <= 7; depth += 1) {
12862
12988
  if (isRepoRootWithCodexPlugin(current))
12863
12989
  return current;
12864
- for (const wrapperPackageRoot of [join28(current, "node_modules", "oh-my-openagent"), join28(current, "oh-my-openagent")]) {
12990
+ for (const wrapperPackageRoot of [join29(current, "node_modules", "oh-my-openagent"), join29(current, "oh-my-openagent")]) {
12865
12991
  if (isRepoRootWithCodexPlugin(wrapperPackageRoot))
12866
12992
  return wrapperPackageRoot;
12867
12993
  }
@@ -12879,7 +13005,7 @@ function findRepoRoot(input) {
12879
13005
  return findRepoRootFromImporter(input.importerDir);
12880
13006
  }
12881
13007
  function isRepoRootWithCodexPlugin(repoRoot) {
12882
- return existsSync6(join28(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
13008
+ return existsSync6(join29(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
12883
13009
  }
12884
13010
  function codexMarketplaceSource(marketplaceRoot) {
12885
13011
  return { sourceType: "local", source: marketplaceRoot };
@@ -13089,11 +13215,48 @@ function buildDelegatedOmoInvocation(parsed) {
13089
13215
  // packages/omo-codex/src/install/lazycodex-manual-update.ts
13090
13216
  import { spawn as spawn4, spawnSync as spawnSync2 } from "node:child_process";
13091
13217
  import { readFileSync as readFileSync3 } from "node:fs";
13092
- import { dirname as dirname8, join as join29 } from "node:path";
13218
+ import { dirname as dirname8, join as join31 } from "node:path";
13219
+ import { createInterface as createInterface2 } from "node:readline/promises";
13093
13220
  import { fileURLToPath } from "node:url";
13221
+
13222
+ // packages/omo-codex/src/install/lazycodex-bun-global-paths.ts
13223
+ import { join as join30 } from "node:path";
13224
+ function isBunGlobalEntrypointPath(invokedPath, env3) {
13225
+ if (typeof invokedPath !== "string" || invokedPath.trim().length === 0)
13226
+ return false;
13227
+ const normalizedPath = normalizePathForPrefix(invokedPath);
13228
+ return resolveBunGlobalRoots(env3).some((root) => normalizedPath.startsWith(root));
13229
+ }
13230
+ function resolveBunGlobalRoots(env3) {
13231
+ const bunInstallRoot = env3.BUN_INSTALL?.trim();
13232
+ const homeRoot = env3.HOME?.trim();
13233
+ return [
13234
+ ...bunInstallRoot ? [join30(bunInstallRoot, "bin"), join30(bunInstallRoot, "install", "global", "node_modules")] : [],
13235
+ ...homeRoot ? [join30(homeRoot, ".bun", "bin"), join30(homeRoot, ".bun", "install", "global", "node_modules")] : []
13236
+ ].map(normalizePathForPrefix);
13237
+ }
13238
+ function normalizePathForPrefix(path2) {
13239
+ const normalized = path2.replaceAll("\\", "/").replace(/\/+$/, "");
13240
+ return normalized.endsWith("/node_modules") || normalized.endsWith("/bin") ? `${normalized}/` : normalized;
13241
+ }
13242
+
13243
+ // packages/omo-codex/src/install/lazycodex-manual-update.ts
13094
13244
  var DEFAULT_UPDATE_COMMAND = "npx";
13095
13245
  var DEFAULT_UPDATE_ARGS = ["--yes", "lazycodex-ai@latest", "install", "--no-tui", "--codex-autonomous"];
13246
+ var BUN_UPDATE_COMMAND = "bun";
13247
+ var BUN_GLOBAL_UPDATE_ARGS = ["update", "-g", "lazycodex-ai@latest"];
13248
+ var BUN_GLOBAL_UNTRUSTED_ARGS = ["pm", "-g", "untrusted"];
13249
+ var BUN_GLOBAL_TRUST_ARGS = ["pm", "-g", "trust"];
13096
13250
  var INSTALLED_VERSION_FILE = "lazycodex-install.json";
13251
+ var KNOWN_LAZYCODEX_BUN_TRUST_PACKAGES = new Set([
13252
+ "@ast-grep/cli",
13253
+ "@code-yeongyu/comment-checker",
13254
+ "@sisyphuslabs/omo-codex-plugin",
13255
+ "lazycodex-ai",
13256
+ "oh-my-openagent",
13257
+ "oh-my-opencode"
13258
+ ]);
13259
+ var KNOWN_LAZYCODEX_BUN_TRUST_PREFIXES = ["@oh-my-opencode/", "oh-my-openagent-", "oh-my-opencode-"];
13097
13260
  async function runLazyCodexManualUpdate(input = {}) {
13098
13261
  const env3 = input.env ?? process.env;
13099
13262
  const log2 = input.log ?? console.log;
@@ -13104,7 +13267,9 @@ async function runLazyCodexManualUpdate(input = {}) {
13104
13267
  currentVersion,
13105
13268
  latestVersion,
13106
13269
  command: resolveCommand2(env3),
13107
- args: resolveArgs(env3)
13270
+ args: resolveArgs(env3),
13271
+ env: env3,
13272
+ invokedPath: input.invokedPath ?? process.argv[1]
13108
13273
  });
13109
13274
  if (!plan.shouldUpdate) {
13110
13275
  const printableVersion = currentVersion ?? "unknown";
@@ -13113,9 +13278,20 @@ async function runLazyCodexManualUpdate(input = {}) {
13113
13278
  }
13114
13279
  if (input.dryRun) {
13115
13280
  log2(`${plan.command} ${plan.args.join(" ")}`);
13281
+ if (plan.postUpdate === "bun-global-trust")
13282
+ log2(`${DEFAULT_UPDATE_COMMAND} ${DEFAULT_UPDATE_ARGS.join(" ")}`);
13116
13283
  return 0;
13117
13284
  }
13118
13285
  await commandRunner(plan.command, plan.args, { cwd: process.cwd(), env: env3 });
13286
+ if (plan.postUpdate === "bun-global-trust") {
13287
+ await handleBunGlobalTrust({
13288
+ env: env3,
13289
+ log: log2,
13290
+ commandRunner,
13291
+ isInteractive: input.isInteractive ?? (process.stdin.isTTY === true && process.stdout.isTTY === true)
13292
+ });
13293
+ await commandRunner(DEFAULT_UPDATE_COMMAND, DEFAULT_UPDATE_ARGS, { cwd: process.cwd(), env: env3 });
13294
+ }
13119
13295
  return 0;
13120
13296
  }
13121
13297
  function resolveLazyCodexUpdatePlan(input = {}) {
@@ -13127,7 +13303,10 @@ function resolveLazyCodexUpdatePlan(input = {}) {
13127
13303
  return { shouldUpdate: false, reason: "unknown-latest" };
13128
13304
  if (compareVersions(latest, current) <= 0)
13129
13305
  return { shouldUpdate: false, reason: "up-to-date" };
13130
- return { shouldUpdate: true, command: input.command ?? DEFAULT_UPDATE_COMMAND, args: input.args ?? DEFAULT_UPDATE_ARGS };
13306
+ if (isBunGlobalEntrypoint(input.invokedPath, input.env ?? process.env)) {
13307
+ return { shouldUpdate: true, command: BUN_UPDATE_COMMAND, args: BUN_GLOBAL_UPDATE_ARGS, postUpdate: "bun-global-trust" };
13308
+ }
13309
+ return { shouldUpdate: true, command: input.command ?? DEFAULT_UPDATE_COMMAND, args: input.args ?? DEFAULT_UPDATE_ARGS, postUpdate: "none" };
13131
13310
  }
13132
13311
  function resolveCommand2(env3) {
13133
13312
  return env3.LAZYCODEX_AUTO_UPDATE_COMMAND?.trim() || DEFAULT_UPDATE_COMMAND;
@@ -13146,7 +13325,7 @@ function resolveCurrentVersion(env3) {
13146
13325
  if (env3.LAZYCODEX_CURRENT_VERSION?.trim())
13147
13326
  return env3.LAZYCODEX_CURRENT_VERSION.trim();
13148
13327
  const pluginRoot = dirname8(dirname8(fileURLToPath(import.meta.url)));
13149
- return readVersionManifest(resolveInstalledVersionPath(env3, pluginRoot)) ?? readVersionManifest(join29(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join29(pluginRoot, ".codex-plugin", "plugin.json"));
13328
+ return readVersionManifest(resolveInstalledVersionPath(env3, pluginRoot)) ?? readVersionManifest(join31(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join31(pluginRoot, ".codex-plugin", "plugin.json"));
13150
13329
  }
13151
13330
  function resolveLatestVersion(env3) {
13152
13331
  if (env3.LAZYCODEX_LATEST_VERSION?.trim())
@@ -13160,6 +13339,57 @@ function resolveLatestVersion(env3) {
13160
13339
  const version2 = result.stdout.trim();
13161
13340
  return version2.length > 0 ? version2 : undefined;
13162
13341
  }
13342
+ async function handleBunGlobalTrust(input) {
13343
+ const packageNames = resolveKnownBunGlobalUntrustedPackages(input.env);
13344
+ if (packageNames.length === 0)
13345
+ return;
13346
+ const trustArgs = [...BUN_GLOBAL_TRUST_ARGS, ...packageNames];
13347
+ const trustCommand = [BUN_UPDATE_COMMAND, ...trustArgs].join(" ");
13348
+ if (!input.isInteractive) {
13349
+ input.log(`Bun blocked LazyCodex-related postinstall scripts. Run this command to trust them:
13350
+ ${trustCommand}`);
13351
+ return;
13352
+ }
13353
+ if (await confirmBunGlobalTrust(packageNames)) {
13354
+ await input.commandRunner(BUN_UPDATE_COMMAND, trustArgs, { cwd: process.cwd(), env: input.env });
13355
+ return;
13356
+ }
13357
+ input.log(`Skipped Bun postinstall trust. To run it later:
13358
+ ${trustCommand}`);
13359
+ }
13360
+ function resolveKnownBunGlobalUntrustedPackages(env3) {
13361
+ const result = spawnSync2(BUN_UPDATE_COMMAND, BUN_GLOBAL_UNTRUSTED_ARGS, {
13362
+ encoding: "utf8",
13363
+ env: env3,
13364
+ stdio: ["ignore", "pipe", "ignore"]
13365
+ });
13366
+ if (result.status !== 0)
13367
+ return [];
13368
+ const names = [];
13369
+ for (const match of result.stdout.matchAll(/^\.\/node_modules\/((?:@[^/\s]+\/)?[^\s]+)\s+@/gm)) {
13370
+ const packageName = match[1];
13371
+ if (packageName !== undefined && isKnownLazyCodexBunTrustPackage(packageName) && !names.includes(packageName)) {
13372
+ names.push(packageName);
13373
+ }
13374
+ }
13375
+ return names;
13376
+ }
13377
+ async function confirmBunGlobalTrust(packageNames) {
13378
+ const prompt = `Trust Bun postinstall scripts for ${packageNames.join(", ")}? [y/N] `;
13379
+ const readline = createInterface2({ input: process.stdin, output: process.stdout });
13380
+ try {
13381
+ const answer = (await readline.question(prompt)).trim().toLowerCase();
13382
+ return answer === "y" || answer === "yes";
13383
+ } finally {
13384
+ readline.close();
13385
+ }
13386
+ }
13387
+ function isKnownLazyCodexBunTrustPackage(packageName) {
13388
+ return KNOWN_LAZYCODEX_BUN_TRUST_PACKAGES.has(packageName) || KNOWN_LAZYCODEX_BUN_TRUST_PREFIXES.some((prefix) => packageName.startsWith(prefix));
13389
+ }
13390
+ function isBunGlobalEntrypoint(invokedPath, env3) {
13391
+ return isBunGlobalEntrypointPath(invokedPath, env3);
13392
+ }
13163
13393
  function defaultRunCommandForManualUpdate(command, args, options) {
13164
13394
  return new Promise((resolve11, reject) => {
13165
13395
  const child = spawn4(command, args, {
@@ -13211,7 +13441,7 @@ function compareVersions(left, right) {
13211
13441
  function resolveInstalledVersionPath(env3, pluginRoot) {
13212
13442
  if (env3.LAZYCODEX_INSTALLED_VERSION_FILE?.trim())
13213
13443
  return env3.LAZYCODEX_INSTALLED_VERSION_FILE.trim();
13214
- return join29(pluginRoot, INSTALLED_VERSION_FILE);
13444
+ return join31(pluginRoot, INSTALLED_VERSION_FILE);
13215
13445
  }
13216
13446
  function readVersionManifest(path2) {
13217
13447
  try {
@@ -13227,80 +13457,46 @@ function readVersionManifest(path2) {
13227
13457
  }
13228
13458
  }
13229
13459
  // packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
13230
- import { readFile as readFile17, writeFile as writeFile10 } from "node:fs/promises";
13231
- import { join as join30 } from "node:path";
13460
+ import { readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
13461
+ import { join as join32 } from "node:path";
13232
13462
  var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
13463
+ var CODEGRAPH_RELATIVE_ARGS2 = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
13233
13464
  async function stampGitBashMcpEnv(input) {
13234
- if (input.platform !== "win32")
13235
- return false;
13236
- const rawOverride = input.env?.[GIT_BASH_ENV_KEY2];
13237
- const override = typeof rawOverride === "string" ? rawOverride.trim() : "";
13238
- if (override === "")
13239
- return false;
13240
- const manifestPath = join30(input.pluginRoot, ".mcp.json");
13465
+ const manifestPath = join32(input.pluginRoot, ".mcp.json");
13241
13466
  if (!await fileExistsStrict(manifestPath))
13242
13467
  return false;
13243
- const parsed = JSON.parse(await readFile17(manifestPath, "utf8"));
13468
+ const parsed = JSON.parse(await readFile18(manifestPath, "utf8"));
13244
13469
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
13245
13470
  return false;
13246
- const gitBashServer = parsed["mcpServers"]["git_bash"];
13247
- if (!isPlainRecord(gitBashServer))
13248
- return false;
13249
- const serverEnv = isPlainRecord(gitBashServer["env"]) ? gitBashServer["env"] : {};
13250
- if (serverEnv[GIT_BASH_ENV_KEY2] === override)
13471
+ let changed = stampCodegraphMcpPath(parsed["mcpServers"], input.pluginRoot);
13472
+ if (input.platform === "win32") {
13473
+ const rawOverride = input.env?.[GIT_BASH_ENV_KEY2];
13474
+ const override = typeof rawOverride === "string" ? rawOverride.trim() : "";
13475
+ const gitBashServer = parsed["mcpServers"]["git_bash"];
13476
+ if (override !== "" && isPlainRecord(gitBashServer)) {
13477
+ const serverEnv = isPlainRecord(gitBashServer["env"]) ? gitBashServer["env"] : {};
13478
+ if (serverEnv[GIT_BASH_ENV_KEY2] !== override) {
13479
+ gitBashServer["env"] = { ...serverEnv, [GIT_BASH_ENV_KEY2]: override };
13480
+ changed = true;
13481
+ }
13482
+ }
13483
+ }
13484
+ if (!changed)
13251
13485
  return false;
13252
- gitBashServer["env"] = { ...serverEnv, [GIT_BASH_ENV_KEY2]: override };
13253
13486
  await writeFile10(manifestPath, `${JSON.stringify(parsed, null, "\t")}
13254
13487
  `);
13255
13488
  return true;
13256
13489
  }
13257
- // packages/omo-codex/src/install/codex-hook-targets.ts
13258
- import { readFile as readFile18 } from "node:fs/promises";
13259
- import { join as join31, sep as sep8 } from "node:path";
13260
- var PLUGIN_ROOT_TARGET_PATTERN = /\$\{PLUGIN_ROOT\}\/([^"']+)/g;
13261
- async function findMissingHookCommandTargets(pluginRoot) {
13262
- const manifestPath = join31(pluginRoot, "hooks", "hooks.json");
13263
- if (!await fileExistsStrict(manifestPath))
13264
- return [];
13265
- const commands = [];
13266
- const parsed = JSON.parse(await readFile18(manifestPath, "utf8"));
13267
- collectCommands(parsed, commands);
13268
- const missing = [];
13269
- const seen = new Set;
13270
- for (const command of commands) {
13271
- for (const match of command.matchAll(PLUGIN_ROOT_TARGET_PATTERN)) {
13272
- const targetSuffix = match[1];
13273
- if (targetSuffix === undefined)
13274
- continue;
13275
- const target = join31(pluginRoot, ...targetSuffix.split("/"));
13276
- if (seen.has(target))
13277
- continue;
13278
- seen.add(target);
13279
- if (!await fileExistsStrict(target))
13280
- missing.push(target);
13281
- }
13282
- }
13283
- return missing;
13284
- }
13285
- async function assertHookCommandTargets(pluginRoot) {
13286
- const missing = await findMissingHookCommandTargets(pluginRoot);
13287
- if (missing.length === 0)
13288
- return;
13289
- const relativeMissing = missing.map((path2) => path2.split(`${pluginRoot}${sep8}`).join("").split(sep8).join("/"));
13290
- throw new Error(`Plugin payload is missing ${missing.length} hook command target(s) referenced by hooks.json: ${relativeMissing.join(", ")}. ` + "The previous plugin cache was left untouched; this payload was not activated.");
13291
- }
13292
- function collectCommands(value, commands) {
13293
- if (Array.isArray(value)) {
13294
- for (const entry of value)
13295
- collectCommands(entry, commands);
13296
- return;
13297
- }
13298
- if (!isPlainRecord(value))
13299
- return;
13300
- if (value["type"] === "command" && typeof value["command"] === "string")
13301
- commands.push(value["command"]);
13302
- for (const entry of Object.values(value))
13303
- collectCommands(entry, commands);
13490
+ function stampCodegraphMcpPath(mcpServers, pluginRoot) {
13491
+ const codegraphServer = mcpServers["codegraph"];
13492
+ if (!isPlainRecord(codegraphServer) || !Array.isArray(codegraphServer["args"]))
13493
+ return false;
13494
+ const args = codegraphServer["args"];
13495
+ const entrypoint = args[0];
13496
+ if (typeof entrypoint !== "string" || !CODEGRAPH_RELATIVE_ARGS2.has(entrypoint))
13497
+ return false;
13498
+ codegraphServer["args"] = [join32(pluginRoot, "components", "codegraph", "dist", "serve.js"), ...args.slice(1)];
13499
+ return true;
13304
13500
  }
13305
13501
 
13306
13502
  // packages/omo-codex/src/install/install-local-cli.ts
@@ -13320,7 +13516,7 @@ async function runLazyCodexInstallLocalCli(input) {
13320
13516
  return 0;
13321
13517
  }
13322
13518
  if (parsed.kind === "version") {
13323
- const packageJson = JSON.parse(await readFile19(join32(input.defaultRepoRoot, "package.json"), "utf8"));
13519
+ const packageJson = JSON.parse(await readFile19(join33(input.defaultRepoRoot, "package.json"), "utf8"));
13324
13520
  const version2 = typeof packageJson.version === "string" ? packageJson.version : "unknown";
13325
13521
  input.log(`lazycodex-ai ${version2}`);
13326
13522
  return 0;
@@ -13343,7 +13539,7 @@ async function runLazyCodexInstallLocalCli(input) {
13343
13539
  input.log(`Installed ${result2.installed.length} plugin(s) from ${result2.marketplaceName}.`);
13344
13540
  return 0;
13345
13541
  }
13346
- return runLazyCodexManualUpdate({ env: input.env, dryRun: parsed.dryRun, log: input.log });
13542
+ return runLazyCodexManualUpdate({ env: input.env, dryRun: parsed.dryRun, log: input.log, invokedPath: input.invokedPath });
13347
13543
  }
13348
13544
  const repoRoot = parsed.repoRoot ? resolve11(parsed.repoRoot) : input.defaultRepoRoot;
13349
13545
  const result = await installMarketplaceLocally({