oh-my-opencode 4.11.1 → 4.12.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 (170) 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/types.d.ts +7 -6
  7. package/dist/cli/index.js +460 -309
  8. package/dist/cli-node/index.js +460 -309
  9. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
  10. package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
  11. package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
  12. package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
  13. package/dist/index.js +593 -310
  14. package/dist/plugin/tool-execute-before.d.ts +2 -0
  15. package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
  16. package/dist/skills/ultraresearch/SKILL.md +11 -2
  17. package/dist/skills/ulw-plan/SKILL.md +2 -1
  18. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  19. package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
  20. package/dist/tools/background-task/constants.d.ts +1 -1
  21. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
  22. package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
  23. package/dist/tui.js +25 -10
  24. package/package.json +13 -13
  25. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
  26. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
  27. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +336 -173
  30. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
  31. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
  33. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
  34. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
  35. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
  36. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
  37. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
  38. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
  39. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
  40. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
  41. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
  42. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
  43. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
  46. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  47. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  49. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  51. package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
  52. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
  53. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  54. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
  56. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
  57. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  58. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
  59. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
  60. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
  61. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
  62. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
  63. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
  64. package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
  65. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
  66. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
  67. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
  68. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
  69. package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
  70. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
  71. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
  72. package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
  73. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  74. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  75. package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
  76. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  77. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  78. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  79. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
  82. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
  83. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  84. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  85. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
  86. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
  87. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
  88. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
  89. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
  90. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
  91. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
  92. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
  93. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.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 +30 -22
  109. package/packages/omo-codex/plugin/package.json +2 -1
  110. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
  111. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
  112. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
  113. package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
  114. package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
  115. package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
  116. package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
  117. package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
  118. package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
  119. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  120. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  121. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  122. package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
  123. package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
  124. package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
  125. package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
  126. package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
  127. package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
  128. package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
  129. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
  130. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
  131. package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
  132. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
  133. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
  134. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
  135. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
  136. package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
  137. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
  138. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  139. package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
  140. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  141. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
  142. package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
  143. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
  144. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
  145. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
  146. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
  147. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
  148. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
  149. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
  150. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
  151. package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
  152. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
  153. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
  154. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
  155. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  156. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
  157. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
  158. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
  159. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
  160. package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
  161. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
  162. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
  163. package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
  164. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
  165. package/packages/omo-codex/scripts/install-local.mjs +1 -0
  166. package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
  167. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  168. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  169. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
  170. 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.1",
5910
+ version: "4.12.1",
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";
@@ -7055,13 +7055,83 @@ async function rewriteCachedManifestRoot(pluginRoot, fromRoot, toRoot) {
7055
7055
  `);
7056
7056
  }
7057
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
+
7058
7128
  // packages/omo-codex/src/install/codex-cache-install.ts
7059
7129
  async function installCachedPlugin(input) {
7060
7130
  if (input.buildSource !== false) {
7061
7131
  await maybeRunNpmInstall(input.sourcePath, input.runCommand);
7062
7132
  await maybeRunNpmBuild(input.sourcePath, input.runCommand);
7063
7133
  }
7064
- 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);
7065
7135
  const tempPath = createTempSiblingPath(targetPath);
7066
7136
  await rm3(tempPath, { recursive: true, force: true });
7067
7137
  try {
@@ -7069,8 +7139,11 @@ async function installCachedPlugin(input) {
7069
7139
  await rewriteCachedPackageLocalFileDependencies(tempPath, input.sourcePath);
7070
7140
  await copyBundledMcpRuntimeDists({ pluginRoot: tempPath, sourceRoot: input.sourcePath });
7071
7141
  await maybeRunNpmInstall(tempPath, input.runCommand, ["ci", "--omit=dev"]);
7142
+ if (input.buildSource === false)
7143
+ await maybeRunNpmSyncSkills(tempPath, input.runCommand);
7072
7144
  await rewriteCachedMcpManifest(tempPath, input.sourcePath);
7073
7145
  await rewriteCachedManifestRoot(tempPath, tempPath, targetPath);
7146
+ await assertHookCommandTargets(tempPath);
7074
7147
  await promoteDirectory(tempPath, targetPath, input.renameDirectory ?? rename);
7075
7148
  } catch (error) {
7076
7149
  await rm3(tempPath, { recursive: true, force: true });
@@ -7079,14 +7152,14 @@ async function installCachedPlugin(input) {
7079
7152
  return { name: input.name, version: input.version, path: targetPath };
7080
7153
  }
7081
7154
  async function maybeRunNpmInstall(cwd, runCommand, args = ["install"]) {
7082
- if (!await fileExistsStrict(join8(cwd, "package.json")))
7155
+ if (!await fileExistsStrict(join9(cwd, "package.json")))
7083
7156
  return;
7084
7157
  await runCommand("npm", args, { cwd });
7085
7158
  }
7086
7159
  async function maybeRunNpmBuild(cwd, runCommand) {
7087
- if (!await fileExistsStrict(join8(cwd, "package.json")))
7160
+ if (!await fileExistsStrict(join9(cwd, "package.json")))
7088
7161
  return;
7089
- const packageJson = JSON.parse(await readFile6(join8(cwd, "package.json"), "utf8"));
7162
+ const packageJson = JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
7090
7163
  if (!isPlainRecord(packageJson))
7091
7164
  return;
7092
7165
  const scripts = packageJson.scripts;
@@ -7094,11 +7167,22 @@ async function maybeRunNpmBuild(cwd, runCommand) {
7094
7167
  return;
7095
7168
  await runCommand("npm", ["run", "build"], { cwd });
7096
7169
  }
7170
+ async function maybeRunNpmSyncSkills(cwd, runCommand) {
7171
+ if (!await fileExistsStrict(join9(cwd, "package.json")))
7172
+ return;
7173
+ const packageJson = JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
7174
+ if (!isPlainRecord(packageJson))
7175
+ return;
7176
+ const scripts = packageJson.scripts;
7177
+ if (!isPlainRecord(scripts) || typeof scripts["sync:skills"] !== "string")
7178
+ return;
7179
+ await runCommand("npm", ["run", "sync:skills"], { cwd });
7180
+ }
7097
7181
  function createTempSiblingPath(targetPath) {
7098
- return join8(dirname3(targetPath), `.tmp-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7182
+ return join9(dirname3(targetPath), `.tmp-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7099
7183
  }
7100
7184
  function createBackupSiblingPath(targetPath) {
7101
- return join8(dirname3(targetPath), `.backup-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7185
+ return join9(dirname3(targetPath), `.backup-${basename2(targetPath)}-${process.pid}-${Date.now()}`);
7102
7186
  }
7103
7187
  async function copyDirectory(sourcePath, targetPath) {
7104
7188
  await mkdir3(dirname3(targetPath), { recursive: true });
@@ -7129,17 +7213,17 @@ async function restoreBackupDirectory(backupPath, targetPath, renameDirectory) {
7129
7213
  await renameDirectory(backupPath, targetPath);
7130
7214
  }
7131
7215
  function shouldCopyPluginPath(path, root) {
7132
- const relative4 = path === root ? "" : path.slice(root.length + sep4.length);
7216
+ const relative4 = path === root ? "" : path.slice(root.length + sep5.length);
7133
7217
  if (relative4 === "")
7134
7218
  return true;
7135
- const parts = relative4.split(sep4);
7219
+ const parts = relative4.split(sep5);
7136
7220
  return !parts.some((part) => part === ".git" || part === "node_modules");
7137
7221
  }
7138
7222
  // packages/omo-codex/src/install/codex-cache-prune.ts
7139
7223
  import { lstat as lstat4, readdir as readdir3, rm as rm4, stat as stat3 } from "node:fs/promises";
7140
- import { join as join9 } from "node:path";
7224
+ import { join as join10 } from "node:path";
7141
7225
  async function pruneMarketplaceCache(input) {
7142
- const cacheRoot = join9(input.codexHome, "plugins", "cache", input.marketplaceName);
7226
+ const cacheRoot = join10(input.codexHome, "plugins", "cache", input.marketplaceName);
7143
7227
  if (!await fileExistsStrict(cacheRoot))
7144
7228
  return;
7145
7229
  const keep = new Set(input.keepPluginNames);
@@ -7147,15 +7231,15 @@ async function pruneMarketplaceCache(input) {
7147
7231
  for (const entry of entries) {
7148
7232
  if (!entry.isDirectory() || keep.has(entry.name))
7149
7233
  continue;
7150
- await rm4(join9(cacheRoot, entry.name), { recursive: true, force: true });
7234
+ await rm4(join10(cacheRoot, entry.name), { recursive: true, force: true });
7151
7235
  }
7152
7236
  }
7153
7237
  async function pruneMarketplacePluginCaches(input) {
7154
- const cacheRoot = join9(input.codexHome, "plugins", "cache", input.marketplaceName);
7238
+ const cacheRoot = join10(input.codexHome, "plugins", "cache", input.marketplaceName);
7155
7239
  if (!await fileExistsStrict(cacheRoot))
7156
7240
  return;
7157
7241
  for (const pluginName of input.pluginNames) {
7158
- await rm4(join9(cacheRoot, pluginName), { recursive: true, force: true });
7242
+ await rm4(join10(cacheRoot, pluginName), { recursive: true, force: true });
7159
7243
  }
7160
7244
  const remainingEntries = await readCacheEntryNames(cacheRoot);
7161
7245
  if (remainingEntries.length === 0) {
@@ -7202,11 +7286,11 @@ async function isBrokenCacheSymlink(path) {
7202
7286
  }
7203
7287
  // packages/omo-codex/src/install/codex-cached-marketplace-manifest.ts
7204
7288
  import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
7205
- import { join as join10 } from "node:path";
7289
+ import { join as join11 } from "node:path";
7206
7290
  async function writeCachedMarketplaceManifest(input) {
7207
- const marketplaceDir = join10(input.marketplaceRoot, ".agents", "plugins");
7291
+ const marketplaceDir = join11(input.marketplaceRoot, ".agents", "plugins");
7208
7292
  await mkdir4(marketplaceDir, { recursive: true });
7209
- await writeFile4(join10(marketplaceDir, "marketplace.json"), `${JSON.stringify({
7293
+ await writeFile4(join11(marketplaceDir, "marketplace.json"), `${JSON.stringify({
7210
7294
  name: input.marketplaceName,
7211
7295
  plugins: input.plugins.map((plugin) => ({
7212
7296
  name: plugin.name,
@@ -7218,8 +7302,8 @@ async function writeCachedMarketplaceManifest(input) {
7218
7302
 
7219
7303
  // packages/omo-codex/src/install/codex-package-layout.ts
7220
7304
  import { existsSync as existsSync2 } from "node:fs";
7221
- import { readFile as readFile7 } from "node:fs/promises";
7222
- import { join as join11 } from "node:path";
7305
+ import { readFile as readFile8 } from "node:fs/promises";
7306
+ import { join as join12 } from "node:path";
7223
7307
  var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
7224
7308
  "@code-yeongyu/lazycodex",
7225
7309
  "@code-yeongyu/lazycodex-ai",
@@ -7229,19 +7313,19 @@ var PACKAGED_CODEX_INSTALLER_NAMES = new Set([
7229
7313
  "oh-my-openagent"
7230
7314
  ]);
7231
7315
  async function shouldBuildSourcePackages(repoRoot) {
7232
- if (existsSync2(join11(repoRoot, "packages", "omo-opencode", "src", "index.ts")))
7316
+ if (existsSync2(join12(repoRoot, "packages", "omo-opencode", "src", "index.ts")))
7233
7317
  return true;
7234
- const packageJsonPath = join11(repoRoot, "package.json");
7318
+ const packageJsonPath = join12(repoRoot, "package.json");
7235
7319
  if (!existsSync2(packageJsonPath))
7236
7320
  return true;
7237
- const packageJson = JSON.parse(await readFile7(packageJsonPath, "utf8"));
7321
+ const packageJson = JSON.parse(await readFile8(packageJsonPath, "utf8"));
7238
7322
  if (!isPlainRecord(packageJson) || typeof packageJson.name !== "string")
7239
7323
  return true;
7240
7324
  return !PACKAGED_CODEX_INSTALLER_NAMES.has(packageJson.name);
7241
7325
  }
7242
7326
 
7243
7327
  // packages/omo-codex/src/install/codex-config-toml.ts
7244
- import { mkdir as mkdir5, readFile as readFile9 } from "node:fs/promises";
7328
+ import { mkdir as mkdir5, readFile as readFile10 } from "node:fs/promises";
7245
7329
  import { dirname as dirname5 } from "node:path";
7246
7330
 
7247
7331
  // packages/omo-codex/src/install/toml-section-editor.ts
@@ -7429,12 +7513,12 @@ function tomlKeySegment(value) {
7429
7513
 
7430
7514
  // packages/omo-codex/src/install/codex-config-atomic-write.ts
7431
7515
  import { lstat as lstat5, readlink as readlink3, realpath, rename as rename2, unlink, writeFile as writeFile5 } from "node:fs/promises";
7432
- import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute4, join as join12, resolve as resolve5 } from "node:path";
7516
+ import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute4, join as join13, resolve as resolve5 } from "node:path";
7433
7517
  var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
7434
7518
  var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
7435
7519
  async function writeFileAtomic(targetPath, data) {
7436
7520
  const writeTarget = await resolveSymlinkTarget(targetPath);
7437
- const temporaryPath = join12(dirname4(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
7521
+ const temporaryPath = join13(dirname4(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
7438
7522
  await writeFile5(temporaryPath, data);
7439
7523
  try {
7440
7524
  await renameWithRetry(temporaryPath, writeTarget);
@@ -7704,8 +7788,8 @@ function isRootSetting(line, key) {
7704
7788
  }
7705
7789
 
7706
7790
  // packages/omo-codex/src/install/codex-model-catalog.ts
7707
- import { readFile as readFile8 } from "node:fs/promises";
7708
- import { join as join13 } from "node:path";
7791
+ import { readFile as readFile9 } from "node:fs/promises";
7792
+ import { join as join14 } from "node:path";
7709
7793
  var FALLBACK_CODEX_MODEL_CATALOG = {
7710
7794
  current: {
7711
7795
  model: "gpt-5.5",
@@ -7724,9 +7808,9 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
7724
7808
  ]
7725
7809
  };
7726
7810
  async function readCodexModelCatalog(codexPackageRoot) {
7727
- const catalogPath = join13(codexPackageRoot, "plugin", "model-catalog.json");
7811
+ const catalogPath = join14(codexPackageRoot, "plugin", "model-catalog.json");
7728
7812
  try {
7729
- const parsed = JSON.parse(await readFile8(catalogPath, "utf8"));
7813
+ const parsed = JSON.parse(await readFile9(catalogPath, "utf8"));
7730
7814
  return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
7731
7815
  } catch (error) {
7732
7816
  if (error instanceof Error)
@@ -7807,7 +7891,7 @@ async function updateCodexConfig(input) {
7807
7891
  await mkdir5(dirname5(input.configPath), { recursive: true });
7808
7892
  let config = "";
7809
7893
  if (await exists(input.configPath))
7810
- config = await readFile9(input.configPath, "utf8");
7894
+ config = await readFile10(input.configPath, "utf8");
7811
7895
  const pluginSet = new Set(input.pluginNames);
7812
7896
  for (const legacyMarketplaceName of legacyMarketplaceNames(input.marketplaceName)) {
7813
7897
  config = removeMarketplaceBlock(config, legacyMarketplaceName);
@@ -7843,7 +7927,7 @@ async function updateCodexConfig(input) {
7843
7927
  }
7844
7928
  async function exists(path) {
7845
7929
  try {
7846
- await readFile9(path, "utf8");
7930
+ await readFile10(path, "utf8");
7847
7931
  return true;
7848
7932
  } catch (error) {
7849
7933
  if (error instanceof Error)
@@ -7854,8 +7938,8 @@ async function exists(path) {
7854
7938
 
7855
7939
  // packages/omo-codex/src/install/codex-hook-trust.ts
7856
7940
  import { createHash } from "node:crypto";
7857
- import { readFile as readFile10 } from "node:fs/promises";
7858
- import { join as join14 } from "node:path";
7941
+ import { readFile as readFile11 } from "node:fs/promises";
7942
+ import { join as join15 } from "node:path";
7859
7943
  var EVENT_LABELS = new Map([
7860
7944
  ["PreToolUse", "pre_tool_use"],
7861
7945
  ["PermissionRequest", "permission_request"],
@@ -7869,21 +7953,37 @@ var EVENT_LABELS = new Map([
7869
7953
  ["Stop", "stop"]
7870
7954
  ]);
7871
7955
  async function trustedHookStatesForPlugin(input) {
7872
- const manifestPath = join14(input.pluginRoot, ".codex-plugin", "plugin.json");
7956
+ const manifestPath = join15(input.pluginRoot, ".codex-plugin", "plugin.json");
7873
7957
  if (!await exists2(manifestPath))
7874
7958
  return [];
7875
- const manifest = JSON.parse(await readFile10(manifestPath, "utf8"));
7876
- if (!isPlainRecord(manifest) || typeof manifest.hooks !== "string")
7877
- return [];
7878
- const hooksPath = join14(input.pluginRoot, manifest.hooks);
7879
- if (!await exists2(hooksPath))
7959
+ const manifest = JSON.parse(await readFile11(manifestPath, "utf8"));
7960
+ if (!isPlainRecord(manifest))
7880
7961
  return [];
7881
- const parsed = JSON.parse(await readFile10(hooksPath, "utf8"));
7882
- if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
7962
+ const states = [];
7963
+ for (const hookPath of hookManifestPaths2(manifest.hooks)) {
7964
+ const hooksPath = join15(input.pluginRoot, hookPath);
7965
+ if (!await exists2(hooksPath))
7966
+ continue;
7967
+ const parsed = JSON.parse(await readFile11(hooksPath, "utf8"));
7968
+ if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
7969
+ continue;
7970
+ states.push(...trustedHookStatesForHooksFile({
7971
+ keySource: `${input.pluginName}@${input.marketplaceName}:${hookPath}`,
7972
+ hooks: parsed.hooks
7973
+ }));
7974
+ }
7975
+ return states;
7976
+ }
7977
+ function hookManifestPaths2(value) {
7978
+ if (typeof value === "string" && value.trim() !== "")
7979
+ return [stripDotSlash2(value)];
7980
+ if (!Array.isArray(value))
7883
7981
  return [];
7884
- const keySource = `${input.pluginName}@${input.marketplaceName}:${stripDotSlash(manifest.hooks)}`;
7982
+ return value.filter((item) => typeof item === "string" && item.trim() !== "").map(stripDotSlash2);
7983
+ }
7984
+ function trustedHookStatesForHooksFile(input) {
7885
7985
  const states = [];
7886
- for (const [eventName, groups] of Object.entries(parsed.hooks)) {
7986
+ for (const [eventName, groups] of Object.entries(input.hooks)) {
7887
7987
  if (!Array.isArray(groups))
7888
7988
  continue;
7889
7989
  const eventLabel = EVENT_LABELS.get(eventName);
@@ -7899,7 +7999,7 @@ async function trustedHookStatesForPlugin(input) {
7899
7999
  continue;
7900
8000
  if (typeof handler.command !== "string" || handler.command.trim() === "")
7901
8001
  continue;
7902
- const key = `${keySource}:${eventLabel}:${groupIndex}:${handlerIndex}`;
8002
+ const key = `${input.keySource}:${eventLabel}:${groupIndex}:${handlerIndex}`;
7903
8003
  states.push({ key, trustedHash: commandHookHash(eventLabel, group.matcher, handler) });
7904
8004
  }
7905
8005
  }
@@ -7933,12 +8033,12 @@ function canonicalJson(value) {
7933
8033
  }
7934
8034
  return result;
7935
8035
  }
7936
- function stripDotSlash(value) {
8036
+ function stripDotSlash2(value) {
7937
8037
  return value.startsWith("./") ? value.slice(2) : value;
7938
8038
  }
7939
8039
  async function exists2(path) {
7940
8040
  try {
7941
- await readFile10(path, "utf8");
8041
+ await readFile11(path, "utf8");
7942
8042
  return true;
7943
8043
  } catch (error) {
7944
8044
  if (error instanceof Error)
@@ -7989,12 +8089,12 @@ function toCodexResolution(resolution) {
7989
8089
  }
7990
8090
 
7991
8091
  // packages/omo-codex/src/install/link-cached-plugin-agents.ts
7992
- import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile12, readdir as readdir4, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
7993
- import { basename as basename4, join as join16 } from "node:path";
8092
+ import { copyFile, lstat as lstat7, mkdir as mkdir6, readFile as readFile13, readdir as readdir4, rm as rm6, writeFile as writeFile6 } from "node:fs/promises";
8093
+ import { basename as basename4, join as join17 } from "node:path";
7994
8094
 
7995
8095
  // packages/omo-codex/src/install/retired-managed-agent-purge.ts
7996
- import { lstat as lstat6, readFile as readFile11, rm as rm5 } from "node:fs/promises";
7997
- import { join as join15 } from "node:path";
8096
+ import { lstat as lstat6, readFile as readFile12, rm as rm5 } from "node:fs/promises";
8097
+ import { join as join16 } from "node:path";
7998
8098
  var RETIRED_MANAGED_AGENT_FILES = [
7999
8099
  {
8000
8100
  fileName: "codex-ultrawork-reviewer.toml",
@@ -8006,11 +8106,11 @@ var RETIRED_MANAGED_AGENT_FILES = [
8006
8106
  }
8007
8107
  ];
8008
8108
  async function purgeRetiredManagedAgentFiles(input) {
8009
- const agentsDir = join15(input.codexHome, "agents");
8109
+ const agentsDir = join16(input.codexHome, "agents");
8010
8110
  if (!await exists3(agentsDir))
8011
8111
  return;
8012
8112
  for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
8013
- const agentPath = join15(agentsDir, retiredAgent.fileName);
8113
+ const agentPath = join16(agentsDir, retiredAgent.fileName);
8014
8114
  if (!await exists3(agentPath))
8015
8115
  continue;
8016
8116
  const agentStat = await lstat6(agentPath);
@@ -8027,7 +8127,7 @@ function hasRequiredMarkers(content, markers) {
8027
8127
  }
8028
8128
  async function readTextIfExists(path) {
8029
8129
  try {
8030
- return await readFile11(path, "utf8");
8130
+ return await readFile12(path, "utf8");
8031
8131
  } catch (error) {
8032
8132
  if (nodeErrorCode(error) === "ENOENT")
8033
8133
  return null;
@@ -8053,7 +8153,7 @@ function nodeErrorCode(error) {
8053
8153
  // packages/omo-codex/src/install/link-cached-plugin-agents.ts
8054
8154
  var MANIFEST_FILE = ".installed-agents.json";
8055
8155
  async function capturePreservedAgentReasoning(input) {
8056
- const agentsDir = join16(input.codexHome, "agents");
8156
+ const agentsDir = join17(input.codexHome, "agents");
8057
8157
  if (!await exists4(agentsDir))
8058
8158
  return new Map;
8059
8159
  const preserved = new Map;
@@ -8061,7 +8161,7 @@ async function capturePreservedAgentReasoning(input) {
8061
8161
  for (const entry of agentEntries) {
8062
8162
  if (!entry.name.endsWith(".toml"))
8063
8163
  continue;
8064
- const content = await readTextIfExists2(join16(agentsDir, entry.name));
8164
+ const content = await readTextIfExists2(join17(agentsDir, entry.name));
8065
8165
  if (content === null)
8066
8166
  continue;
8067
8167
  const effort = extractReasoningEffort(content);
@@ -8071,7 +8171,7 @@ async function capturePreservedAgentReasoning(input) {
8071
8171
  return preserved;
8072
8172
  }
8073
8173
  async function capturePreservedAgentServiceTier(input) {
8074
- const agentsDir = join16(input.codexHome, "agents");
8174
+ const agentsDir = join17(input.codexHome, "agents");
8075
8175
  if (!await exists4(agentsDir))
8076
8176
  return new Map;
8077
8177
  const preserved = new Map;
@@ -8079,7 +8179,7 @@ async function capturePreservedAgentServiceTier(input) {
8079
8179
  for (const entry of agentEntries) {
8080
8180
  if (!entry.name.endsWith(".toml"))
8081
8181
  continue;
8082
- const content = await readTextIfExists2(join16(agentsDir, entry.name));
8182
+ const content = await readTextIfExists2(join17(agentsDir, entry.name));
8083
8183
  if (content === null)
8084
8184
  continue;
8085
8185
  preserved.set(agentNameFromToml(entry.name), extractServiceTier(content));
@@ -8093,13 +8193,13 @@ async function linkCachedPluginAgents(input) {
8093
8193
  await writeManifest(input.pluginRoot, []);
8094
8194
  return [];
8095
8195
  }
8096
- const agentsDir = join16(input.codexHome, "agents");
8196
+ const agentsDir = join17(input.codexHome, "agents");
8097
8197
  await mkdir6(agentsDir, { recursive: true });
8098
8198
  const linked = [];
8099
8199
  for (const agentPath of bundledAgents) {
8100
8200
  const agentFileName = basename4(agentPath);
8101
8201
  const agentName = agentNameFromToml(agentFileName);
8102
- const linkPath = join16(agentsDir, agentFileName);
8202
+ const linkPath = join17(agentsDir, agentFileName);
8103
8203
  await replaceWithCopy(linkPath, agentPath);
8104
8204
  await restorePreservedReasoning({
8105
8205
  agentName,
@@ -8120,7 +8220,7 @@ async function linkCachedPluginAgents(input) {
8120
8220
  async function restorePreservedServiceTier(input) {
8121
8221
  if (!input.preserved)
8122
8222
  return;
8123
- const content = await readFile12(input.linkPath, "utf8");
8223
+ const content = await readFile13(input.linkPath, "utf8");
8124
8224
  if (extractServiceTier(content) === input.value)
8125
8225
  return;
8126
8226
  const replacement = replaceServiceTier(content, input.value);
@@ -8129,7 +8229,7 @@ async function restorePreservedServiceTier(input) {
8129
8229
  await writeFile6(input.linkPath, replacement.content);
8130
8230
  }
8131
8231
  async function discoverBundledAgents(pluginRoot) {
8132
- const componentsRoot = join16(pluginRoot, "components");
8232
+ const componentsRoot = join17(pluginRoot, "components");
8133
8233
  if (!await exists4(componentsRoot))
8134
8234
  return [];
8135
8235
  const componentEntries = await readdir4(componentsRoot, { withFileTypes: true });
@@ -8137,14 +8237,14 @@ async function discoverBundledAgents(pluginRoot) {
8137
8237
  for (const entry of componentEntries) {
8138
8238
  if (!entry.isDirectory())
8139
8239
  continue;
8140
- const agentsRoot = join16(componentsRoot, entry.name, "agents");
8240
+ const agentsRoot = join17(componentsRoot, entry.name, "agents");
8141
8241
  if (!await exists4(agentsRoot))
8142
8242
  continue;
8143
8243
  const agentEntries = await readdir4(agentsRoot, { withFileTypes: true });
8144
8244
  for (const file2 of agentEntries) {
8145
8245
  if (!file2.isFile() || !file2.name.endsWith(".toml"))
8146
8246
  continue;
8147
- agents.push(join16(agentsRoot, file2.name));
8247
+ agents.push(join17(agentsRoot, file2.name));
8148
8248
  }
8149
8249
  }
8150
8250
  agents.sort();
@@ -8164,7 +8264,7 @@ async function prepareReplacement(linkPath) {
8164
8264
  await rm6(linkPath, { force: true });
8165
8265
  }
8166
8266
  async function writeManifest(pluginRoot, agentPaths) {
8167
- const manifestPath = join16(pluginRoot, MANIFEST_FILE);
8267
+ const manifestPath = join17(pluginRoot, MANIFEST_FILE);
8168
8268
  const payload = { agents: [...agentPaths].sort() };
8169
8269
  await writeFile6(manifestPath, `${JSON.stringify(payload, null, "\t")}
8170
8270
  `);
@@ -8172,7 +8272,7 @@ async function writeManifest(pluginRoot, agentPaths) {
8172
8272
  async function restorePreservedReasoning(input) {
8173
8273
  if (input.value === undefined)
8174
8274
  return;
8175
- const content = await readFile12(input.target, "utf8");
8275
+ const content = await readFile13(input.target, "utf8");
8176
8276
  const bundledEffort = extractReasoningEffort(content);
8177
8277
  if (bundledEffort === input.value)
8178
8278
  return;
@@ -8183,7 +8283,7 @@ async function restorePreservedReasoning(input) {
8183
8283
  }
8184
8284
  async function readTextIfExists2(path) {
8185
8285
  try {
8186
- return await readFile12(path, "utf8");
8286
+ return await readFile13(path, "utf8");
8187
8287
  } catch (error) {
8188
8288
  if (nodeErrorCode2(error) === "ENOENT")
8189
8289
  return null;
@@ -8291,12 +8391,12 @@ function nodeErrorCode2(error) {
8291
8391
  }
8292
8392
 
8293
8393
  // packages/omo-codex/src/install/codex-marketplace.ts
8294
- import { readFile as readFile13 } from "node:fs/promises";
8295
- import { join as join17 } from "node:path";
8394
+ import { readFile as readFile14 } from "node:fs/promises";
8395
+ import { join as join18 } from "node:path";
8296
8396
  var DEFAULT_MARKETPLACE_PATH = "packages/omo-codex/marketplace.json";
8297
8397
  async function readMarketplace(repoRoot, options) {
8298
- const marketplacePath = options?.marketplacePath ?? join17(repoRoot, DEFAULT_MARKETPLACE_PATH);
8299
- const raw = await readFile13(marketplacePath, "utf8");
8398
+ const marketplacePath = options?.marketplacePath ?? join18(repoRoot, DEFAULT_MARKETPLACE_PATH);
8399
+ const raw = await readFile14(marketplacePath, "utf8");
8300
8400
  const parsed = JSON.parse(raw);
8301
8401
  if (!isPlainRecord(parsed))
8302
8402
  throw new Error("marketplace.json must be an object");
@@ -8314,10 +8414,10 @@ async function readMarketplace(repoRoot, options) {
8314
8414
  function resolvePluginSource(repoRoot, plugin, options) {
8315
8415
  const sourcePath = localSourcePath(options?.pathOverride ?? plugin.source);
8316
8416
  const relativePath = sourcePath.slice(2);
8317
- return join17(repoRoot, ...relativePath.split(/[\\/]/));
8417
+ return join18(repoRoot, ...relativePath.split(/[\\/]/));
8318
8418
  }
8319
8419
  async function readPluginManifest(pluginRoot) {
8320
- const raw = await readFile13(join17(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
8420
+ const raw = await readFile14(join18(pluginRoot, ".codex-plugin", "plugin.json"), "utf8");
8321
8421
  const parsed = JSON.parse(raw);
8322
8422
  if (!isPlainRecord(parsed))
8323
8423
  throw new Error(`${pluginRoot} plugin.json must be an object`);
@@ -8327,15 +8427,27 @@ async function readPluginManifest(pluginRoot) {
8327
8427
  if (parsed.version !== undefined && (typeof parsed.version !== "string" || parsed.version.trim() === "")) {
8328
8428
  throw new Error(`${pluginRoot} plugin.json version must be a non-empty string`);
8329
8429
  }
8330
- if (parsed.hooks !== undefined && (typeof parsed.hooks !== "string" || parsed.hooks.trim() === "")) {
8331
- throw new Error(`${pluginRoot} plugin.json hooks must be a non-empty string`);
8430
+ if (parsed.hooks !== undefined && !isPluginHooksManifestValue(parsed.hooks)) {
8431
+ throw new Error(`${pluginRoot} plugin.json hooks must be a non-empty string or string array`);
8332
8432
  }
8333
8433
  return {
8334
8434
  name: parsed.name,
8335
8435
  version: typeof parsed.version === "string" ? parsed.version.trim() : undefined,
8336
- hooks: typeof parsed.hooks === "string" ? parsed.hooks.trim() : undefined
8436
+ hooks: normalizePluginHooksManifestValue(parsed.hooks)
8337
8437
  };
8338
8438
  }
8439
+ function isPluginHooksManifestValue(value) {
8440
+ if (typeof value === "string")
8441
+ return value.trim() !== "";
8442
+ return Array.isArray(value) && value.every((item) => typeof item === "string" && item.trim() !== "");
8443
+ }
8444
+ function normalizePluginHooksManifestValue(value) {
8445
+ if (typeof value === "string")
8446
+ return value.trim();
8447
+ if (Array.isArray(value))
8448
+ return value.map((item) => item.trim());
8449
+ return;
8450
+ }
8339
8451
  function validatePathSegment(value, label) {
8340
8452
  if (!/^[A-Za-z0-9._+-]+$/.test(value)) {
8341
8453
  throw new Error(`${label} contains unsupported characters: ${value}`);
@@ -8387,7 +8499,7 @@ function validateLocalSourcePath(path) {
8387
8499
 
8388
8500
  // packages/omo-codex/src/install/codex-marketplace-snapshot.ts
8389
8501
  import { cp as cp3, mkdir as mkdir7, rename as rename3, rm as rm7, writeFile as writeFile7 } from "node:fs/promises";
8390
- import { join as join18, sep as sep5 } from "node:path";
8502
+ import { join as join19, sep as sep6 } from "node:path";
8391
8503
  var INSTALLED_MARKETPLACES_DIR = ".tmp/marketplaces";
8392
8504
  async function writeInstalledMarketplaceSnapshot(input) {
8393
8505
  const marketplaceRoot = installedMarketplaceRoot(input.codexHome, input.marketplace.name);
@@ -8400,21 +8512,21 @@ async function writeInstalledMarketplaceSnapshot(input) {
8400
8512
  return snapshotPlugins;
8401
8513
  }
8402
8514
  function installedMarketplaceRoot(codexHome, marketplaceName) {
8403
- return join18(codexHome, INSTALLED_MARKETPLACES_DIR, marketplaceName);
8515
+ return join19(codexHome, INSTALLED_MARKETPLACES_DIR, marketplaceName);
8404
8516
  }
8405
8517
  async function writeMarketplaceManifest(marketplaceRoot, marketplace) {
8406
- const manifestDir = join18(marketplaceRoot, ".agents", "plugins");
8518
+ const manifestDir = join19(marketplaceRoot, ".agents", "plugins");
8407
8519
  await mkdir7(manifestDir, { recursive: true });
8408
- const tempPath = join18(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
8520
+ const tempPath = join19(manifestDir, `.marketplace-${process.pid}-${Date.now()}.json.tmp`);
8409
8521
  await writeFile7(tempPath, `${JSON.stringify(marketplace, null, "\t")}
8410
8522
  `);
8411
- await rename3(tempPath, join18(manifestDir, "marketplace.json"));
8523
+ await rename3(tempPath, join19(manifestDir, "marketplace.json"));
8412
8524
  }
8413
8525
  async function writeSnapshotPlugin(marketplaceRoot, plugin) {
8414
- const pluginsDir = join18(marketplaceRoot, "plugins");
8526
+ const pluginsDir = join19(marketplaceRoot, "plugins");
8415
8527
  await mkdir7(pluginsDir, { recursive: true });
8416
- const targetPath = join18(pluginsDir, plugin.name);
8417
- const tempPath = join18(pluginsDir, `.tmp-${plugin.name}-${process.pid}-${Date.now()}`);
8528
+ const targetPath = join19(pluginsDir, plugin.name);
8529
+ const tempPath = join19(pluginsDir, `.tmp-${plugin.name}-${process.pid}-${Date.now()}`);
8418
8530
  await rm7(tempPath, { recursive: true, force: true });
8419
8531
  await cp3(plugin.sourcePath, tempPath, {
8420
8532
  recursive: true,
@@ -8427,19 +8539,19 @@ async function writeSnapshotPlugin(marketplaceRoot, plugin) {
8427
8539
  return { name: plugin.name, path: targetPath };
8428
8540
  }
8429
8541
  function shouldCopyMarketplaceSourcePath(path, root) {
8430
- const relative4 = path === root ? "" : path.slice(root.length + sep5.length);
8542
+ const relative4 = path === root ? "" : path.slice(root.length + sep6.length);
8431
8543
  if (relative4 === "")
8432
8544
  return true;
8433
- const parts = relative4.split(sep5);
8545
+ const parts = relative4.split(sep6);
8434
8546
  return !parts.some((part) => part === ".git" || part === "node_modules");
8435
8547
  }
8436
8548
 
8437
8549
  // packages/omo-codex/src/install/lazycodex-version-stamp.ts
8438
- import { readdir as readdir5, readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
8439
- import { join as join19 } from "node:path";
8550
+ import { readdir as readdir5, readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
8551
+ import { join as join20 } from "node:path";
8440
8552
  async function readDistributionManifest(repoRoot) {
8441
8553
  try {
8442
- const parsed = JSON.parse(await readFile14(join19(repoRoot, "package.json"), "utf8"));
8554
+ const parsed = JSON.parse(await readFile15(join20(repoRoot, "package.json"), "utf8"));
8443
8555
  if (!isPlainRecord(parsed) || typeof parsed.version !== "string" || parsed.version.trim().length === 0)
8444
8556
  return;
8445
8557
  return {
@@ -8459,15 +8571,19 @@ function resolveLazyCodexPluginVersion(input) {
8459
8571
  return input.manifestVersion ?? "local";
8460
8572
  }
8461
8573
  async function stampLazyCodexPluginVersion(input) {
8462
- await stampJsonVersion(join19(input.pluginRoot, ".codex-plugin", "plugin.json"), input.version);
8463
- await stampJsonVersion(join19(input.pluginRoot, "package.json"), input.version);
8464
- await stampHookStatusMessages(join19(input.pluginRoot, "hooks", "hooks.json"), input.version);
8574
+ const manifestPath = join20(input.pluginRoot, ".codex-plugin", "plugin.json");
8575
+ const hookPaths = await readPluginHookPaths(manifestPath);
8576
+ await stampJsonVersion(manifestPath, input.version);
8577
+ await stampJsonVersion(join20(input.pluginRoot, "package.json"), input.version);
8578
+ for (const hookPath of hookPaths) {
8579
+ await stampHookStatusMessages(join20(input.pluginRoot, hookPath), input.version);
8580
+ }
8465
8581
  await stampComponentVersions(input);
8466
8582
  }
8467
8583
  async function writeLazyCodexInstallSnapshot(input) {
8468
8584
  if (input.distributionManifest === undefined)
8469
8585
  return;
8470
- await writeFile8(join19(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
8586
+ await writeFile8(join20(input.pluginRoot, "lazycodex-install.json"), `${JSON.stringify({
8471
8587
  packageName: input.distributionManifest.name,
8472
8588
  version: input.distributionManifest.version
8473
8589
  }, null, "\t")}
@@ -8475,7 +8591,7 @@ async function writeLazyCodexInstallSnapshot(input) {
8475
8591
  }
8476
8592
  async function stampJsonVersion(path, version) {
8477
8593
  try {
8478
- const parsed = JSON.parse(await readFile14(path, "utf8"));
8594
+ const parsed = JSON.parse(await readFile15(path, "utf8"));
8479
8595
  if (!isPlainRecord(parsed))
8480
8596
  return;
8481
8597
  parsed.version = version;
@@ -8487,9 +8603,29 @@ async function stampJsonVersion(path, version) {
8487
8603
  throw error;
8488
8604
  }
8489
8605
  }
8606
+ async function readPluginHookPaths(manifestPath) {
8607
+ try {
8608
+ const parsed = JSON.parse(await readFile15(manifestPath, "utf8"));
8609
+ if (!isPlainRecord(parsed))
8610
+ return [];
8611
+ if (typeof parsed.hooks === "string" && parsed.hooks.trim().length > 0)
8612
+ return [stripDotSlash3(parsed.hooks)];
8613
+ if (Array.isArray(parsed.hooks)) {
8614
+ return parsed.hooks.filter((hookPath) => typeof hookPath === "string" && hookPath.trim().length > 0).map(stripDotSlash3);
8615
+ }
8616
+ return [];
8617
+ } catch (error) {
8618
+ if (error instanceof Error)
8619
+ return [];
8620
+ throw error;
8621
+ }
8622
+ }
8623
+ function stripDotSlash3(path) {
8624
+ return path.startsWith("./") ? path.slice(2) : path;
8625
+ }
8490
8626
  async function stampHookStatusMessages(path, version) {
8491
8627
  try {
8492
- const parsed = JSON.parse(await readFile14(path, "utf8"));
8628
+ const parsed = JSON.parse(await readFile15(path, "utf8"));
8493
8629
  if (!isPlainRecord(parsed))
8494
8630
  return;
8495
8631
  stampHookGroups(parsed.hooks, version);
@@ -8504,16 +8640,16 @@ async function stampHookStatusMessages(path, version) {
8504
8640
  async function stampComponentVersions(input) {
8505
8641
  let entries;
8506
8642
  try {
8507
- entries = await readdir5(join19(input.pluginRoot, "components"));
8643
+ entries = await readdir5(join20(input.pluginRoot, "components"));
8508
8644
  } catch (error) {
8509
8645
  if (error instanceof Error)
8510
8646
  return;
8511
8647
  throw error;
8512
8648
  }
8513
8649
  for (const entry of entries) {
8514
- const componentRoot = join19(input.pluginRoot, "components", entry);
8515
- await stampJsonVersion(join19(componentRoot, "package.json"), input.version);
8516
- await stampHookStatusMessages(join19(componentRoot, "hooks", "hooks.json"), input.version);
8650
+ const componentRoot = join20(input.pluginRoot, "components", entry);
8651
+ await stampJsonVersion(join20(componentRoot, "package.json"), input.version);
8652
+ await stampHookStatusMessages(join20(componentRoot, "hooks", "hooks.json"), input.version);
8517
8653
  }
8518
8654
  }
8519
8655
  function stampHookGroups(hooks, version) {
@@ -8534,12 +8670,12 @@ function stampHookGroups(hooks, version) {
8534
8670
  function stampHookStatusMessage(hook, version) {
8535
8671
  if (!isPlainRecord(hook) || typeof hook.statusMessage !== "string")
8536
8672
  return;
8537
- hook.statusMessage = hook.statusMessage.replace(/^LazyCodex\([^)]+\):/, `LazyCodex(${version}):`);
8673
+ hook.statusMessage = hook.statusMessage.replace(/^LazyCodex\([^)]+\):\s*/, "(OmO) ");
8538
8674
  }
8539
8675
 
8540
8676
  // packages/omo-codex/src/install/codex-project-local-cleanup.ts
8541
- import { copyFile as copyFile2, lstat as lstat8, readFile as readFile15, writeFile as writeFile9 } from "node:fs/promises";
8542
- import { dirname as dirname6, join as join20, resolve as resolve6 } from "node:path";
8677
+ import { copyFile as copyFile2, lstat as lstat8, readFile as readFile16, writeFile as writeFile9 } from "node:fs/promises";
8678
+ import { dirname as dirname6, join as join21, resolve as resolve6 } from "node:path";
8543
8679
  var LEGACY_AGENT_CONFLICT_KEYS = ["max_threads"];
8544
8680
  var PROJECT_LOCAL_ARTIFACT_PATHS = [
8545
8681
  ".codex/hooks.json",
@@ -8558,7 +8694,7 @@ async function repairNearestProjectLocalCodexArtifacts(input) {
8558
8694
  const artifacts = await collectProjectLocalArtifacts(project.artifactRoots);
8559
8695
  const configs = [];
8560
8696
  for (const configPath of project.configPaths) {
8561
- const original = await readFile15(configPath, "utf8");
8697
+ const original = await readFile16(configPath, "utf8");
8562
8698
  const repair = repairProjectLocalCodexConfigText(original);
8563
8699
  if (!repair.changed) {
8564
8700
  configs.push({
@@ -8642,17 +8778,17 @@ async function findProjectLocalCodexConfigs(startDirectory, codexHome) {
8642
8778
  if (startDirectoryStat !== null && !startDirectoryStat.isDirectory()) {
8643
8779
  throw new ProjectLocalCleanupStartDirectoryError(startDirectory);
8644
8780
  }
8645
- const codexHomeConfigPath = codexHome === undefined ? null : join20(resolve6(codexHome), "config.toml");
8781
+ const codexHomeConfigPath = codexHome === undefined ? null : join21(resolve6(codexHome), "config.toml");
8646
8782
  let current = resolve6(startDirectory);
8647
8783
  const configPathsFromCwd = [];
8648
8784
  while (true) {
8649
- const configPath = join20(current, ".codex", "config.toml");
8785
+ const configPath = join21(current, ".codex", "config.toml");
8650
8786
  if (await isRegularProjectLocalConfig(current, configPath)) {
8651
8787
  if (codexHomeConfigPath === null || resolve6(configPath) !== codexHomeConfigPath) {
8652
8788
  configPathsFromCwd.push(configPath);
8653
8789
  }
8654
8790
  }
8655
- if (await exists5(join20(current, ".git"))) {
8791
+ if (await exists5(join21(current, ".git"))) {
8656
8792
  return configPathsFromCwd.length === 0 ? null : {
8657
8793
  projectRoot: current,
8658
8794
  configPaths: [...configPathsFromCwd].reverse(),
@@ -8672,7 +8808,7 @@ async function findProjectLocalCodexConfigs(startDirectory, codexHome) {
8672
8808
  }
8673
8809
  }
8674
8810
  async function isRegularProjectLocalConfig(directory, configPath) {
8675
- const codexDirStat = await maybeLstat(join20(directory, ".codex"));
8811
+ const codexDirStat = await maybeLstat(join21(directory, ".codex"));
8676
8812
  if (codexDirStat === null || !codexDirStat.isDirectory() || codexDirStat.isSymbolicLink())
8677
8813
  return false;
8678
8814
  const configStat = await maybeLstat(configPath);
@@ -8692,7 +8828,7 @@ async function collectProjectLocalArtifacts(projectRoots) {
8692
8828
  const seenPaths = new Set;
8693
8829
  for (const projectRoot of projectRoots) {
8694
8830
  for (const relativePath of PROJECT_LOCAL_ARTIFACT_PATHS) {
8695
- const artifactPath = join20(projectRoot, relativePath);
8831
+ const artifactPath = join21(projectRoot, relativePath);
8696
8832
  if (seenPaths.has(artifactPath))
8697
8833
  continue;
8698
8834
  const entryStat = await maybeLstat(artifactPath);
@@ -8767,13 +8903,13 @@ function formatUnknownError(error) {
8767
8903
  }
8768
8904
 
8769
8905
  // packages/omo-codex/src/install/lsp-daemon-reaper.ts
8770
- import { readFile as readFile16, readdir as readdir6, rm as rm8 } from "node:fs/promises";
8906
+ import { readFile as readFile17, readdir as readdir6, rm as rm8 } from "node:fs/promises";
8771
8907
  import { connect } from "node:net";
8772
- import { join as join21 } from "node:path";
8908
+ import { join as join22 } from "node:path";
8773
8909
  async function reapLspDaemons(codexHome, deps = {}) {
8774
8910
  const killProcess = deps.killProcess ?? sendSigterm;
8775
8911
  const isDaemonLive = deps.isDaemonLive ?? probeSocketLive;
8776
- const daemonRoot = join21(codexHome, "codex-lsp", "daemon");
8912
+ const daemonRoot = join22(codexHome, "codex-lsp", "daemon");
8777
8913
  const reaped = [];
8778
8914
  let entries;
8779
8915
  try {
@@ -8782,9 +8918,9 @@ async function reapLspDaemons(codexHome, deps = {}) {
8782
8918
  return reaped;
8783
8919
  }
8784
8920
  for (const entry of entries) {
8785
- const versionDir = join21(daemonRoot, entry);
8786
- const pid = await readPidFile(join21(versionDir, "daemon.pid"));
8787
- const socketPath = await readEndpointFile(join21(versionDir, "daemon.endpoint"));
8921
+ const versionDir = join22(daemonRoot, entry);
8922
+ const pid = await readPidFile(join22(versionDir, "daemon.pid"));
8923
+ const socketPath = await readEndpointFile(join22(versionDir, "daemon.endpoint"));
8788
8924
  if (pid !== null && socketPath !== null && await isDaemonLive(socketPath) && killProcess(pid)) {
8789
8925
  reaped.push(pid);
8790
8926
  }
@@ -8794,7 +8930,7 @@ async function reapLspDaemons(codexHome, deps = {}) {
8794
8930
  }
8795
8931
  async function readEndpointFile(path) {
8796
8932
  try {
8797
- const content = (await readFile16(path, "utf8")).trim();
8933
+ const content = (await readFile17(path, "utf8")).trim();
8798
8934
  return content.length > 0 ? content : null;
8799
8935
  } catch {
8800
8936
  return null;
@@ -8802,7 +8938,7 @@ async function readEndpointFile(path) {
8802
8938
  }
8803
8939
  async function readPidFile(path) {
8804
8940
  try {
8805
- const pid = Number.parseInt((await readFile16(path, "utf8")).trim(), 10);
8941
+ const pid = Number.parseInt((await readFile17(path, "utf8")).trim(), 10);
8806
8942
  return Number.isInteger(pid) && pid > 0 ? pid : null;
8807
8943
  } catch {
8808
8944
  return null;
@@ -8838,7 +8974,7 @@ function sendSigterm(pid) {
8838
8974
 
8839
8975
  // packages/omo-codex/src/install/codex-installer-bin-dir.ts
8840
8976
  import { homedir } from "node:os";
8841
- import { join as join22, resolve as resolve7 } from "node:path";
8977
+ import { join as join23, resolve as resolve7 } from "node:path";
8842
8978
  function resolveCodexInstallerBinDir(input) {
8843
8979
  const explicitBinDir = input.binDir ?? input.env?.CODEX_LOCAL_BIN_DIR;
8844
8980
  if (explicitBinDir !== undefined && explicitBinDir.trim().length > 0)
@@ -8847,15 +8983,15 @@ function resolveCodexInstallerBinDir(input) {
8847
8983
  const defaultCodexHome = resolve7(homeDir, ".codex");
8848
8984
  const resolvedCodexHome = resolve7(input.codexHome);
8849
8985
  if (resolvedCodexHome !== defaultCodexHome)
8850
- return join22(resolvedCodexHome, "bin");
8986
+ return join23(resolvedCodexHome, "bin");
8851
8987
  return resolve7(homeDir, ".local", "bin");
8852
8988
  }
8853
8989
 
8854
8990
  // packages/omo-codex/src/install/omo-sot-migration.ts
8855
- import { join as join23 } from "node:path";
8991
+ import { join as join24 } from "node:path";
8856
8992
  async function seedAndMigrateOmoSot(input) {
8857
8993
  const commandEnv = { ...input.env };
8858
- const scriptPath = join23(input.repoRoot, "packages", "omo-codex", "plugin", "scripts", "migrate-omo-sot.mjs");
8994
+ const scriptPath = join24(input.repoRoot, "packages", "omo-codex", "plugin", "scripts", "migrate-omo-sot.mjs");
8859
8995
  try {
8860
8996
  await input.runCommand(process.execPath, [scriptPath, "--seed"], {
8861
8997
  cwd: input.repoRoot,
@@ -8869,7 +9005,7 @@ async function seedAndMigrateOmoSot(input) {
8869
9005
  }
8870
9006
 
8871
9007
  // packages/omo-codex/src/install/install-ast-grep-sg.ts
8872
- import { join as join25 } from "node:path";
9008
+ import { join as join26 } from "node:path";
8873
9009
 
8874
9010
  // packages/utils/src/deep-merge.ts
8875
9011
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
@@ -11841,11 +11977,11 @@ function runtimeSlug(platform = process.platform, arch = process.arch) {
11841
11977
  // packages/utils/src/ast-grep/install-script.ts
11842
11978
  import { spawn as spawn3 } from "node:child_process";
11843
11979
  import { existsSync as existsSync3 } from "node:fs";
11844
- import { join as join24 } from "node:path";
11980
+ import { join as join25 } from "node:path";
11845
11981
  var AST_GREP_BIN_DIR_ENV_KEY = "OMO_AST_GREP_BIN_DIR";
11846
11982
  var AST_GREP_INSTALL_TIMEOUT_MS = 30000;
11847
11983
  function astGrepRuntimeDir(baseDir, platform = process.platform, arch = process.arch) {
11848
- return join24(baseDir, "runtime", "ast-grep", runtimeSlug(platform, arch));
11984
+ return join25(baseDir, "runtime", "ast-grep", runtimeSlug(platform, arch));
11849
11985
  }
11850
11986
  function isMissingExecutable(error) {
11851
11987
  if (!("code" in error))
@@ -11883,7 +12019,7 @@ function defaultSpawnProcess(command, args, options) {
11883
12019
  };
11884
12020
  }
11885
12021
  function scriptPathForPlatform(skillDir, platform) {
11886
- return join24(skillDir, platform === "win32" ? "install.ps1" : "install.sh");
12022
+ return join25(skillDir, platform === "win32" ? "install.ps1" : "install.sh");
11887
12023
  }
11888
12024
  function invocationsForPlatform(scriptPath, platform) {
11889
12025
  if (platform !== "win32")
@@ -12651,7 +12787,7 @@ async function installAstGrepForCodex(options) {
12651
12787
  return;
12652
12788
  const platform = options.platform ?? process.platform;
12653
12789
  const targetDir = astGrepRuntimeDir(options.codexHome, platform, options.arch ?? process.arch);
12654
- const skillDir = join25(plugin.path, "skills", "ast-grep");
12790
+ const skillDir = join26(plugin.path, "skills", "ast-grep");
12655
12791
  const installer = options.installer ?? runAstGrepSkillInstall;
12656
12792
  try {
12657
12793
  const result = await installer({ platform, skillDir, targetDir });
@@ -12684,7 +12820,7 @@ async function runCodexInstaller(options = {}) {
12684
12820
  const env3 = options.env ?? process.env;
12685
12821
  const platform = options.platform ?? process.platform;
12686
12822
  const repoRoot = resolve10(options.repoRoot ?? findRepoRoot({ importerDir: import.meta.dir, env: env3 }));
12687
- const codexHome = resolve10(options.codexHome ?? env3.CODEX_HOME ?? join28(homedir2(), ".codex"));
12823
+ const codexHome = resolve10(options.codexHome ?? env3.CODEX_HOME ?? join29(homedir2(), ".codex"));
12688
12824
  const projectDirectory = resolve10(options.projectDirectory ?? env3.OMO_CODEX_PROJECT ?? process.cwd());
12689
12825
  const binDir = resolveCodexInstallerBinDir({ binDir: options.binDir, codexHome, env: env3 });
12690
12826
  const runCommand = options.runCommand ?? defaultRunCommand;
@@ -12702,9 +12838,9 @@ async function runCodexInstaller(options = {}) {
12702
12838
  if (!gitBashResolution.found) {
12703
12839
  throw new Error(gitBashResolution.installHint);
12704
12840
  }
12705
- const codexPackageRoot = join28(repoRoot, "packages", "omo-codex");
12841
+ const codexPackageRoot = join29(repoRoot, "packages", "omo-codex");
12706
12842
  const marketplace = await readMarketplace(repoRoot, {
12707
- marketplacePath: join28(codexPackageRoot, "marketplace.json")
12843
+ marketplacePath: join29(codexPackageRoot, "marketplace.json")
12708
12844
  });
12709
12845
  const distributionManifest = await readDistributionManifest(repoRoot);
12710
12846
  const installed = [];
@@ -12746,7 +12882,7 @@ async function runCodexInstaller(options = {}) {
12746
12882
  if (runtimeLink !== null)
12747
12883
  log2(`Linked ${runtimeLink.name} -> ${runtimeLink.target}`);
12748
12884
  else
12749
- 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`);
12885
+ 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`);
12750
12886
  }
12751
12887
  pluginSources.push({ name: entry.name, sourcePath });
12752
12888
  installed.push(plugin);
@@ -12799,13 +12935,13 @@ async function runCodexInstaller(options = {}) {
12799
12935
  });
12800
12936
  }
12801
12937
  await reapLspDaemons(codexHome).catch(() => []);
12802
- const marketplaceRoot = join28(codexHome, "plugins", "cache", marketplace.name);
12938
+ const marketplaceRoot = join29(codexHome, "plugins", "cache", marketplace.name);
12803
12939
  await writeCachedMarketplaceManifest({
12804
12940
  marketplaceName: marketplace.name,
12805
12941
  marketplaceRoot,
12806
12942
  plugins: installed
12807
12943
  });
12808
- const configPath = join28(codexHome, "config.toml");
12944
+ const configPath = join29(codexHome, "config.toml");
12809
12945
  await updateCodexConfig({
12810
12946
  configPath,
12811
12947
  repoRoot: codexPackageRoot,
@@ -12864,7 +13000,7 @@ function findRepoRootFromImporter(importerDir) {
12864
13000
  for (let depth = 0;depth <= 7; depth += 1) {
12865
13001
  if (isRepoRootWithCodexPlugin(current))
12866
13002
  return current;
12867
- for (const wrapperPackageRoot of [join28(current, "node_modules", "oh-my-openagent"), join28(current, "oh-my-openagent")]) {
13003
+ for (const wrapperPackageRoot of [join29(current, "node_modules", "oh-my-openagent"), join29(current, "oh-my-openagent")]) {
12868
13004
  if (isRepoRootWithCodexPlugin(wrapperPackageRoot))
12869
13005
  return wrapperPackageRoot;
12870
13006
  }
@@ -12882,7 +13018,7 @@ function findRepoRoot(input) {
12882
13018
  return findRepoRootFromImporter(input.importerDir);
12883
13019
  }
12884
13020
  function isRepoRootWithCodexPlugin(repoRoot) {
12885
- return existsSync6(join28(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
13021
+ return existsSync6(join29(repoRoot, "packages", "omo-codex", "plugin", ".codex-plugin", "plugin.json"));
12886
13022
  }
12887
13023
  function codexMarketplaceSource(marketplaceRoot) {
12888
13024
  return { sourceType: "local", source: marketplaceRoot };
@@ -13092,11 +13228,48 @@ function buildDelegatedOmoInvocation(parsed) {
13092
13228
  // packages/omo-codex/src/install/lazycodex-manual-update.ts
13093
13229
  import { spawn as spawn4, spawnSync as spawnSync2 } from "node:child_process";
13094
13230
  import { readFileSync as readFileSync3 } from "node:fs";
13095
- import { dirname as dirname8, join as join29 } from "node:path";
13231
+ import { dirname as dirname8, join as join31 } from "node:path";
13232
+ import { createInterface as createInterface2 } from "node:readline/promises";
13096
13233
  import { fileURLToPath } from "node:url";
13234
+
13235
+ // packages/omo-codex/src/install/lazycodex-bun-global-paths.ts
13236
+ import { join as join30 } from "node:path";
13237
+ function isBunGlobalEntrypointPath(invokedPath, env3) {
13238
+ if (typeof invokedPath !== "string" || invokedPath.trim().length === 0)
13239
+ return false;
13240
+ const normalizedPath = normalizePathForPrefix(invokedPath);
13241
+ return resolveBunGlobalRoots(env3).some((root) => normalizedPath.startsWith(root));
13242
+ }
13243
+ function resolveBunGlobalRoots(env3) {
13244
+ const bunInstallRoot = env3.BUN_INSTALL?.trim();
13245
+ const homeRoot = env3.HOME?.trim();
13246
+ return [
13247
+ ...bunInstallRoot ? [join30(bunInstallRoot, "bin"), join30(bunInstallRoot, "install", "global", "node_modules")] : [],
13248
+ ...homeRoot ? [join30(homeRoot, ".bun", "bin"), join30(homeRoot, ".bun", "install", "global", "node_modules")] : []
13249
+ ].map(normalizePathForPrefix);
13250
+ }
13251
+ function normalizePathForPrefix(path2) {
13252
+ const normalized = path2.replaceAll("\\", "/").replace(/\/+$/, "");
13253
+ return normalized.endsWith("/node_modules") || normalized.endsWith("/bin") ? `${normalized}/` : normalized;
13254
+ }
13255
+
13256
+ // packages/omo-codex/src/install/lazycodex-manual-update.ts
13097
13257
  var DEFAULT_UPDATE_COMMAND = "npx";
13098
13258
  var DEFAULT_UPDATE_ARGS = ["--yes", "lazycodex-ai@latest", "install", "--no-tui", "--codex-autonomous"];
13259
+ var BUN_UPDATE_COMMAND = "bun";
13260
+ var BUN_GLOBAL_UPDATE_ARGS = ["update", "-g", "lazycodex-ai@latest"];
13261
+ var BUN_GLOBAL_UNTRUSTED_ARGS = ["pm", "-g", "untrusted"];
13262
+ var BUN_GLOBAL_TRUST_ARGS = ["pm", "-g", "trust"];
13099
13263
  var INSTALLED_VERSION_FILE = "lazycodex-install.json";
13264
+ var KNOWN_LAZYCODEX_BUN_TRUST_PACKAGES = new Set([
13265
+ "@ast-grep/cli",
13266
+ "@code-yeongyu/comment-checker",
13267
+ "@sisyphuslabs/omo-codex-plugin",
13268
+ "lazycodex-ai",
13269
+ "oh-my-openagent",
13270
+ "oh-my-opencode"
13271
+ ]);
13272
+ var KNOWN_LAZYCODEX_BUN_TRUST_PREFIXES = ["@oh-my-opencode/", "oh-my-openagent-", "oh-my-opencode-"];
13100
13273
  async function runLazyCodexManualUpdate(input = {}) {
13101
13274
  const env3 = input.env ?? process.env;
13102
13275
  const log2 = input.log ?? console.log;
@@ -13107,7 +13280,9 @@ async function runLazyCodexManualUpdate(input = {}) {
13107
13280
  currentVersion,
13108
13281
  latestVersion,
13109
13282
  command: resolveCommand2(env3),
13110
- args: resolveArgs(env3)
13283
+ args: resolveArgs(env3),
13284
+ env: env3,
13285
+ invokedPath: input.invokedPath ?? process.argv[1]
13111
13286
  });
13112
13287
  if (!plan.shouldUpdate) {
13113
13288
  const printableVersion = currentVersion ?? "unknown";
@@ -13116,9 +13291,20 @@ async function runLazyCodexManualUpdate(input = {}) {
13116
13291
  }
13117
13292
  if (input.dryRun) {
13118
13293
  log2(`${plan.command} ${plan.args.join(" ")}`);
13294
+ if (plan.postUpdate === "bun-global-trust")
13295
+ log2(`${DEFAULT_UPDATE_COMMAND} ${DEFAULT_UPDATE_ARGS.join(" ")}`);
13119
13296
  return 0;
13120
13297
  }
13121
13298
  await commandRunner(plan.command, plan.args, { cwd: process.cwd(), env: env3 });
13299
+ if (plan.postUpdate === "bun-global-trust") {
13300
+ await handleBunGlobalTrust({
13301
+ env: env3,
13302
+ log: log2,
13303
+ commandRunner,
13304
+ isInteractive: input.isInteractive ?? (process.stdin.isTTY === true && process.stdout.isTTY === true)
13305
+ });
13306
+ await commandRunner(DEFAULT_UPDATE_COMMAND, DEFAULT_UPDATE_ARGS, { cwd: process.cwd(), env: env3 });
13307
+ }
13122
13308
  return 0;
13123
13309
  }
13124
13310
  function resolveLazyCodexUpdatePlan(input = {}) {
@@ -13130,7 +13316,10 @@ function resolveLazyCodexUpdatePlan(input = {}) {
13130
13316
  return { shouldUpdate: false, reason: "unknown-latest" };
13131
13317
  if (compareVersions(latest, current) <= 0)
13132
13318
  return { shouldUpdate: false, reason: "up-to-date" };
13133
- return { shouldUpdate: true, command: input.command ?? DEFAULT_UPDATE_COMMAND, args: input.args ?? DEFAULT_UPDATE_ARGS };
13319
+ if (isBunGlobalEntrypoint(input.invokedPath, input.env ?? process.env)) {
13320
+ return { shouldUpdate: true, command: BUN_UPDATE_COMMAND, args: BUN_GLOBAL_UPDATE_ARGS, postUpdate: "bun-global-trust" };
13321
+ }
13322
+ return { shouldUpdate: true, command: input.command ?? DEFAULT_UPDATE_COMMAND, args: input.args ?? DEFAULT_UPDATE_ARGS, postUpdate: "none" };
13134
13323
  }
13135
13324
  function resolveCommand2(env3) {
13136
13325
  return env3.LAZYCODEX_AUTO_UPDATE_COMMAND?.trim() || DEFAULT_UPDATE_COMMAND;
@@ -13149,7 +13338,7 @@ function resolveCurrentVersion(env3) {
13149
13338
  if (env3.LAZYCODEX_CURRENT_VERSION?.trim())
13150
13339
  return env3.LAZYCODEX_CURRENT_VERSION.trim();
13151
13340
  const pluginRoot = dirname8(dirname8(fileURLToPath(import.meta.url)));
13152
- return readVersionManifest(resolveInstalledVersionPath(env3, pluginRoot)) ?? readVersionManifest(join29(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join29(pluginRoot, ".codex-plugin", "plugin.json"));
13341
+ return readVersionManifest(resolveInstalledVersionPath(env3, pluginRoot)) ?? readVersionManifest(join31(pluginRoot, "..", "..", "..", "package.json")) ?? readVersionManifest(join31(pluginRoot, ".codex-plugin", "plugin.json"));
13153
13342
  }
13154
13343
  function resolveLatestVersion(env3) {
13155
13344
  if (env3.LAZYCODEX_LATEST_VERSION?.trim())
@@ -13163,6 +13352,57 @@ function resolveLatestVersion(env3) {
13163
13352
  const version2 = result.stdout.trim();
13164
13353
  return version2.length > 0 ? version2 : undefined;
13165
13354
  }
13355
+ async function handleBunGlobalTrust(input) {
13356
+ const packageNames = resolveKnownBunGlobalUntrustedPackages(input.env);
13357
+ if (packageNames.length === 0)
13358
+ return;
13359
+ const trustArgs = [...BUN_GLOBAL_TRUST_ARGS, ...packageNames];
13360
+ const trustCommand = [BUN_UPDATE_COMMAND, ...trustArgs].join(" ");
13361
+ if (!input.isInteractive) {
13362
+ input.log(`Bun blocked LazyCodex-related postinstall scripts. Run this command to trust them:
13363
+ ${trustCommand}`);
13364
+ return;
13365
+ }
13366
+ if (await confirmBunGlobalTrust(packageNames)) {
13367
+ await input.commandRunner(BUN_UPDATE_COMMAND, trustArgs, { cwd: process.cwd(), env: input.env });
13368
+ return;
13369
+ }
13370
+ input.log(`Skipped Bun postinstall trust. To run it later:
13371
+ ${trustCommand}`);
13372
+ }
13373
+ function resolveKnownBunGlobalUntrustedPackages(env3) {
13374
+ const result = spawnSync2(BUN_UPDATE_COMMAND, BUN_GLOBAL_UNTRUSTED_ARGS, {
13375
+ encoding: "utf8",
13376
+ env: env3,
13377
+ stdio: ["ignore", "pipe", "ignore"]
13378
+ });
13379
+ if (result.status !== 0)
13380
+ return [];
13381
+ const names = [];
13382
+ for (const match of result.stdout.matchAll(/^\.\/node_modules\/((?:@[^/\s]+\/)?[^\s]+)\s+@/gm)) {
13383
+ const packageName = match[1];
13384
+ if (packageName !== undefined && isKnownLazyCodexBunTrustPackage(packageName) && !names.includes(packageName)) {
13385
+ names.push(packageName);
13386
+ }
13387
+ }
13388
+ return names;
13389
+ }
13390
+ async function confirmBunGlobalTrust(packageNames) {
13391
+ const prompt = `Trust Bun postinstall scripts for ${packageNames.join(", ")}? [y/N] `;
13392
+ const readline = createInterface2({ input: process.stdin, output: process.stdout });
13393
+ try {
13394
+ const answer = (await readline.question(prompt)).trim().toLowerCase();
13395
+ return answer === "y" || answer === "yes";
13396
+ } finally {
13397
+ readline.close();
13398
+ }
13399
+ }
13400
+ function isKnownLazyCodexBunTrustPackage(packageName) {
13401
+ return KNOWN_LAZYCODEX_BUN_TRUST_PACKAGES.has(packageName) || KNOWN_LAZYCODEX_BUN_TRUST_PREFIXES.some((prefix) => packageName.startsWith(prefix));
13402
+ }
13403
+ function isBunGlobalEntrypoint(invokedPath, env3) {
13404
+ return isBunGlobalEntrypointPath(invokedPath, env3);
13405
+ }
13166
13406
  function defaultRunCommandForManualUpdate(command, args, options) {
13167
13407
  return new Promise((resolve11, reject) => {
13168
13408
  const child = spawn4(command, args, {
@@ -13214,7 +13454,7 @@ function compareVersions(left, right) {
13214
13454
  function resolveInstalledVersionPath(env3, pluginRoot) {
13215
13455
  if (env3.LAZYCODEX_INSTALLED_VERSION_FILE?.trim())
13216
13456
  return env3.LAZYCODEX_INSTALLED_VERSION_FILE.trim();
13217
- return join29(pluginRoot, INSTALLED_VERSION_FILE);
13457
+ return join31(pluginRoot, INSTALLED_VERSION_FILE);
13218
13458
  }
13219
13459
  function readVersionManifest(path2) {
13220
13460
  try {
@@ -13230,15 +13470,15 @@ function readVersionManifest(path2) {
13230
13470
  }
13231
13471
  }
13232
13472
  // packages/omo-codex/src/install/codex-git-bash-mcp-env.ts
13233
- import { readFile as readFile17, writeFile as writeFile10 } from "node:fs/promises";
13234
- import { join as join30 } from "node:path";
13473
+ import { readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
13474
+ import { join as join32 } from "node:path";
13235
13475
  var GIT_BASH_ENV_KEY2 = "OMO_CODEX_GIT_BASH_PATH";
13236
13476
  var CODEGRAPH_RELATIVE_ARGS2 = new Set(["components/codegraph/dist/serve.js", "./components/codegraph/dist/serve.js"]);
13237
13477
  async function stampGitBashMcpEnv(input) {
13238
- const manifestPath = join30(input.pluginRoot, ".mcp.json");
13478
+ const manifestPath = join32(input.pluginRoot, ".mcp.json");
13239
13479
  if (!await fileExistsStrict(manifestPath))
13240
13480
  return false;
13241
- const parsed = JSON.parse(await readFile17(manifestPath, "utf8"));
13481
+ const parsed = JSON.parse(await readFile18(manifestPath, "utf8"));
13242
13482
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
13243
13483
  return false;
13244
13484
  let changed = stampCodegraphMcpPath(parsed["mcpServers"], input.pluginRoot);
@@ -13268,57 +13508,9 @@ function stampCodegraphMcpPath(mcpServers, pluginRoot) {
13268
13508
  const entrypoint = args[0];
13269
13509
  if (typeof entrypoint !== "string" || !CODEGRAPH_RELATIVE_ARGS2.has(entrypoint))
13270
13510
  return false;
13271
- codegraphServer["args"] = [join30(pluginRoot, "components", "codegraph", "dist", "serve.js"), ...args.slice(1)];
13511
+ codegraphServer["args"] = [join32(pluginRoot, "components", "codegraph", "dist", "serve.js"), ...args.slice(1)];
13272
13512
  return true;
13273
13513
  }
13274
- // packages/omo-codex/src/install/codex-hook-targets.ts
13275
- import { readFile as readFile18 } from "node:fs/promises";
13276
- import { join as join31, sep as sep8 } from "node:path";
13277
- var PLUGIN_ROOT_TARGET_PATTERN = /\$\{PLUGIN_ROOT\}\/([^"']+)/g;
13278
- async function findMissingHookCommandTargets(pluginRoot) {
13279
- const manifestPath = join31(pluginRoot, "hooks", "hooks.json");
13280
- if (!await fileExistsStrict(manifestPath))
13281
- return [];
13282
- const commands = [];
13283
- const parsed = JSON.parse(await readFile18(manifestPath, "utf8"));
13284
- collectCommands(parsed, commands);
13285
- const missing = [];
13286
- const seen = new Set;
13287
- for (const command of commands) {
13288
- for (const match of command.matchAll(PLUGIN_ROOT_TARGET_PATTERN)) {
13289
- const targetSuffix = match[1];
13290
- if (targetSuffix === undefined)
13291
- continue;
13292
- const target = join31(pluginRoot, ...targetSuffix.split("/"));
13293
- if (seen.has(target))
13294
- continue;
13295
- seen.add(target);
13296
- if (!await fileExistsStrict(target))
13297
- missing.push(target);
13298
- }
13299
- }
13300
- return missing;
13301
- }
13302
- async function assertHookCommandTargets(pluginRoot) {
13303
- const missing = await findMissingHookCommandTargets(pluginRoot);
13304
- if (missing.length === 0)
13305
- return;
13306
- const relativeMissing = missing.map((path2) => path2.split(`${pluginRoot}${sep8}`).join("").split(sep8).join("/"));
13307
- 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.");
13308
- }
13309
- function collectCommands(value, commands) {
13310
- if (Array.isArray(value)) {
13311
- for (const entry of value)
13312
- collectCommands(entry, commands);
13313
- return;
13314
- }
13315
- if (!isPlainRecord(value))
13316
- return;
13317
- if (value["type"] === "command" && typeof value["command"] === "string")
13318
- commands.push(value["command"]);
13319
- for (const entry of Object.values(value))
13320
- collectCommands(entry, commands);
13321
- }
13322
13514
 
13323
13515
  // packages/omo-codex/src/install/install-local-cli.ts
13324
13516
  async function installMarketplaceLocally(options = {}) {
@@ -13337,7 +13529,7 @@ async function runLazyCodexInstallLocalCli(input) {
13337
13529
  return 0;
13338
13530
  }
13339
13531
  if (parsed.kind === "version") {
13340
- const packageJson = JSON.parse(await readFile19(join32(input.defaultRepoRoot, "package.json"), "utf8"));
13532
+ const packageJson = JSON.parse(await readFile19(join33(input.defaultRepoRoot, "package.json"), "utf8"));
13341
13533
  const version2 = typeof packageJson.version === "string" ? packageJson.version : "unknown";
13342
13534
  input.log(`lazycodex-ai ${version2}`);
13343
13535
  return 0;
@@ -13360,7 +13552,7 @@ async function runLazyCodexInstallLocalCli(input) {
13360
13552
  input.log(`Installed ${result2.installed.length} plugin(s) from ${result2.marketplaceName}.`);
13361
13553
  return 0;
13362
13554
  }
13363
- return runLazyCodexManualUpdate({ env: input.env, dryRun: parsed.dryRun, log: input.log });
13555
+ return runLazyCodexManualUpdate({ env: input.env, dryRun: parsed.dryRun, log: input.log, invokedPath: input.invokedPath });
13364
13556
  }
13365
13557
  const repoRoot = parsed.repoRoot ? resolve11(parsed.repoRoot) : input.defaultRepoRoot;
13366
13558
  const result = await installMarketplaceLocally({