lazycodex-ai 5.0.1 → 5.1.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 (80) hide show
  1. package/README.ja.md +2 -1
  2. package/README.ko.md +2 -1
  3. package/README.md +2 -1
  4. package/README.ru.md +2 -1
  5. package/README.zh-cn.md +2 -1
  6. package/dist/cli/index.js +851 -546
  7. package/dist/cli-node/index.js +851 -546
  8. package/package.json +6 -1
  9. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  10. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +341 -157
  11. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  12. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  13. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +7 -4
  14. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  15. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  16. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  17. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  19. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  21. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  22. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  24. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  30. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/ulw-execute-continuation/AGENTS.md +1 -1
  32. package/packages/omo-codex/plugin/components/ulw-execute-continuation/dist/cli.js +42 -32
  33. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  34. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  35. package/packages/omo-codex/plugin/components/ulw-execute-continuation/src/plan-checklist.ts +55 -29
  36. package/packages/omo-codex/plugin/components/ulw-execute-continuation/test/boulder-reader.test.ts +51 -0
  37. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  38. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  60. package/packages/omo-codex/plugin/package-lock.json +12 -12
  61. package/packages/omo-codex/plugin/package.json +1 -1
  62. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  63. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +1 -1
  64. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +3 -0
  65. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +4 -0
  66. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +6 -2
  67. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +7 -1
  68. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +3 -1
  69. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/types.py +3 -1
  70. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +4 -0
  71. package/packages/omo-codex/scripts/install-dist/install-local.mjs +10465 -10270
  72. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  73. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +1 -1
  74. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +3 -0
  75. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +4 -0
  76. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/file_scanners.py +6 -2
  77. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +7 -1
  78. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/transcript.py +3 -1
  79. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/types.py +3 -1
  80. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +4 -0
@@ -438,9 +438,9 @@ async function readOptionalFile(path) {
438
438
  }
439
439
 
440
440
  // components/bootstrap/src/worker.ts
441
- import { appendFile as appendFile2, mkdir as mkdir8, readFile as readFile15 } from "node:fs/promises";
441
+ import { appendFile as appendFile2, mkdir as mkdir8, readFile as readFile17 } from "node:fs/promises";
442
442
  import { homedir as homedir5 } from "node:os";
443
- import { dirname as dirname10, join as join24, resolve as resolve8 } from "node:path";
443
+ import { dirname as dirname10, join as join25, resolve as resolve8 } from "node:path";
444
444
  import { fileURLToPath as fileURLToPath2 } from "node:url";
445
445
 
446
446
  // components/bootstrap/src/provision.ts
@@ -1000,8 +1000,8 @@ async function defaultVersionProbe2(binaryPath) {
1000
1000
  }
1001
1001
 
1002
1002
  // components/bootstrap/src/setup.ts
1003
- import { copyFile as copyFile2, mkdir as mkdir7, readFile as readFile14, readdir as readdir5, rm as rm11, stat as stat5 } from "node:fs/promises";
1004
- import { join as join23 } from "node:path";
1003
+ import { copyFile as copyFile2, mkdir as mkdir7, readFile as readFile16, readdir as readdir5, rm as rm12, stat as stat5 } from "node:fs/promises";
1004
+ import { join as join24 } from "node:path";
1005
1005
 
1006
1006
  // ../../../node_modules/.bun/zod@4.6.5/node_modules/zod/v4/core/util.js
1007
1007
  function getEnumValues(entries) {
@@ -7059,6 +7059,25 @@ var OmoCategoryConfigObjectSchema = object({
7059
7059
  var OmoCategoryConfigSchema = preprocess((value) => isRecord4(value) ? normalizeLegacyModelFields(value) : value, OmoCategoryConfigObjectSchema);
7060
7060
  var OmoCategoriesConfigSchema = record(string2(), OmoCategoryConfigSchema);
7061
7061
 
7062
+ // ../../omo-config-core/src/schema/computer.ts
7063
+ var positiveInteger = number2().int().positive();
7064
+ var nonNegativeInteger = number2().int().nonnegative();
7065
+ var OmoComputerSettingsLayerSchema = object({
7066
+ enabled: boolean2().describe("Experimental: register the computer tool in OmO Native sessions (default: on where the host is supported; false leaves it unregistered)"),
7067
+ display: string2().min(1),
7068
+ max_width: positiveInteger,
7069
+ max_height: positiveInteger,
7070
+ screenshot_max_bytes: positiveInteger,
7071
+ stop_hotkey: string2().min(1),
7072
+ allow_host_relay_only_stop: boolean2(),
7073
+ macos_canary: _enum(["session", "off"]),
7074
+ audit_log: object({ enabled: boolean2() }).partial().strict(),
7075
+ screenshot_gc: object({ enabled: boolean2(), stale_ms: nonNegativeInteger, scan_interval_ms: nonNegativeInteger }).partial().strict(),
7076
+ engine_path: string2().min(1),
7077
+ cua_adapter: boolean2()
7078
+ }).partial().strict().describe("Experimental computer use in OmO Native: screenshots, windows, accessibility trees and native mouse and keyboard input. Every key is optional; defaults depend on the host.");
7079
+ var OmoComputerSettingsSchema = OmoComputerSettingsLayerSchema;
7080
+
7062
7081
  // ../../omo-config-core/src/schema/git-master.ts
7063
7082
  var OmoGitMasterSettingsShape = {
7064
7083
  commit_footer: union([boolean2(), string2()]),
@@ -7304,7 +7323,7 @@ var OmoModelProfilesLayerSchema = record(string2(), OmoModelProfileLayerSchema);
7304
7323
 
7305
7324
  // ../../omo-config-core/src/schema/task.ts
7306
7325
  import { availableParallelism } from "node:os";
7307
- var DEFAULT_RESIDENCY_MAX_CHILDREN = 16;
7326
+ var DEFAULT_RESIDENCY_MAX_CHILDREN = "unlimited";
7308
7327
  var ResidencyMaxChildrenInputSchema = union([number2().int().nonnegative(), literal("unlimited")]);
7309
7328
  var OmoTaskWaitSchema = object({
7310
7329
  min_ms: number2().int().positive().default(5000),
@@ -7360,12 +7379,13 @@ var OmoTaskSettingsSchema = object({
7360
7379
  process_runner: _enum(["host", "child-process"]).default("host"),
7361
7380
  host_engine_policy: _enum(["upgrade", "fallback"]).default("upgrade"),
7362
7381
  host_idle_exit_ms: number2().int().positive().optional(),
7382
+ host_shard_prewarm: _enum(["off", "first-turn", "session-start"]).default("first-turn"),
7363
7383
  default_concurrency: number2().int().nonnegative().default(5),
7364
7384
  global_concurrency: number2().int().nonnegative().default(8),
7365
7385
  provider_concurrency: record(string2(), number2().int().nonnegative()).optional(),
7366
7386
  model_concurrency: record(string2(), number2().int().nonnegative()).optional(),
7367
7387
  max_depth: number2().int().nonnegative().default(1),
7368
- residency_max_children: ResidencyMaxChildrenInputSchema.default(8),
7388
+ residency_max_children: ResidencyMaxChildrenInputSchema.default(DEFAULT_RESIDENCY_MAX_CHILDREN),
7369
7389
  resident_idle_timeout_ms: number2().int().positive().max(Number.MAX_SAFE_INTEGER).default(900000),
7370
7390
  ttl_ms: number2().int().positive().default(86400000),
7371
7391
  state_dir: string2().optional(),
@@ -7409,6 +7429,7 @@ var OmoTaskSettingsLayerSchema = object({
7409
7429
  process_runner: _enum(["host", "child-process"]).optional(),
7410
7430
  host_engine_policy: _enum(["upgrade", "fallback"]).optional(),
7411
7431
  host_idle_exit_ms: number2().int().positive().optional(),
7432
+ host_shard_prewarm: _enum(["off", "first-turn", "session-start"]).optional(),
7412
7433
  default_concurrency: number2().int().nonnegative().optional(),
7413
7434
  global_concurrency: number2().int().nonnegative().optional(),
7414
7435
  provider_concurrency: record(string2(), number2().int().nonnegative()).optional(),
@@ -7429,7 +7450,7 @@ function resolveOmoTaskSettings(input, resolveParallelism = availableParallelism
7429
7450
  const record2 = record(string2(), unknown()).parse(input);
7430
7451
  return OmoTaskSettingsSchema.parse({
7431
7452
  ...record2,
7432
- residency_max_children: record2["residency_max_children"] ?? Math.min(DEFAULT_RESIDENCY_MAX_CHILDREN, Math.max(8, resolveParallelism() * 2)),
7453
+ residency_max_children: record2["residency_max_children"] ?? DEFAULT_RESIDENCY_MAX_CHILDREN,
7433
7454
  global_concurrency: record2["global_concurrency"] ?? Math.max(8, resolveParallelism() * 2)
7434
7455
  });
7435
7456
  }
@@ -7520,6 +7541,7 @@ var OmoTypedHarnessConfigSchema = object({
7520
7541
  model_profile: string2().optional(),
7521
7542
  memory: OmoMemorySettingsLayerSchema.optional(),
7522
7543
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
7544
+ computer: OmoComputerSettingsLayerSchema.optional(),
7523
7545
  disabled_skills: OmoDisabledSkillsSchema.optional()
7524
7546
  }).strict();
7525
7547
  var OmoConfigProfileSchema = object({
@@ -7534,6 +7556,7 @@ var OmoConfigProfileSchema = object({
7534
7556
  model_profile: string2().optional(),
7535
7557
  memory: OmoMemorySettingsLayerSchema.optional(),
7536
7558
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
7559
+ computer: OmoComputerSettingsLayerSchema.optional(),
7537
7560
  disabled_skills: OmoDisabledSkillsSchema.optional(),
7538
7561
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
7539
7562
  "[native]": OmoTypedHarnessConfigSchema.optional(),
@@ -7553,6 +7576,7 @@ var OmoConfigSchema = object({
7553
7576
  model_profile: string2().optional(),
7554
7577
  memory: OmoMemorySettingsSchema.optional(),
7555
7578
  telemetry: OmoTelemetrySettingsSchema.optional(),
7579
+ computer: OmoComputerSettingsSchema.optional(),
7556
7580
  disabled_skills: OmoDisabledSkillsSchema.optional(),
7557
7581
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
7558
7582
  "[native]": OmoTypedHarnessConfigSchema.optional(),
@@ -7575,6 +7599,7 @@ var OmoConfigLayerSchema = object({
7575
7599
  model_profile: string2().optional(),
7576
7600
  memory: OmoMemorySettingsLayerSchema.optional(),
7577
7601
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
7602
+ computer: OmoComputerSettingsLayerSchema.optional(),
7578
7603
  disabled_skills: OmoDisabledSkillsSchema.optional(),
7579
7604
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
7580
7605
  "[native]": OmoTypedHarnessConfigSchema.optional(),
@@ -8968,21 +8993,93 @@ function loadOmoConfig(options = {}) {
8968
8993
  };
8969
8994
  }
8970
8995
 
8971
- // ../src/install/codex-default-role-config.ts
8972
- function readDefaultRoleConfig(options = {}) {
8996
+ // ../src/install/codex-cache-fs.ts
8997
+ import { lstat } from "node:fs/promises";
8998
+ async function fileExistsStrict(path) {
8999
+ try {
9000
+ await lstat(path);
9001
+ return true;
9002
+ } catch (error) {
9003
+ if (isNodeErrorWithCode(error) && error.code === "ENOENT")
9004
+ return false;
9005
+ throw error;
9006
+ }
9007
+ }
9008
+ function isPlainRecord(value) {
9009
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9010
+ }
9011
+ function isNodeErrorWithCode(error) {
9012
+ return typeof error === "object" && error !== null && "code" in error;
9013
+ }
9014
+
9015
+ // ../src/install/codex-agent-config.ts
9016
+ function readCodexAgentConfig(options = {}) {
8973
9017
  const result = loadOmoConfig({ ...options, harness: "codex" });
9018
+ const overrides = readAgentOverrides(result);
9019
+ return {
9020
+ defaultRoleEnabled: result.config.agents?.default?.disable !== true,
9021
+ agentOverrides: overrides.agentOverrides,
9022
+ warnings: [...result.diagnostics.map((diagnostic) => diagnostic.message), ...overrides.warnings]
9023
+ };
9024
+ }
9025
+ function unmanagedAgentOverrideWarnings(agentOverrides, managedAgentNames) {
9026
+ return [...agentOverrides.keys()].filter((name) => !managedAgentNames.has(name)).map((name) => `[codex].agents.${name} does not name a LazyCodex-managed agent role; its model override was not applied`);
9027
+ }
9028
+ function readAgentOverrides(result) {
9029
+ let merged = {};
9030
+ for (const layer of result.layers)
9031
+ merged = mergeOmoConfigRecords(merged, layer.config);
9032
+ const profile = result.profile === undefined ? undefined : recordAt(recordAt(merged, "profiles"), result.profile);
9033
+ let agents = {};
9034
+ for (const scope of [merged, profile]) {
9035
+ agents = mergeOmoConfigRecords(agents, recordAt(recordAt(scope, "[codex]"), "agents") ?? {});
9036
+ }
9037
+ const agentOverrides = new Map;
9038
+ const warnings = [];
9039
+ for (const [name, value] of Object.entries(agents)) {
9040
+ if (name === "default")
9041
+ continue;
9042
+ const parsed = OmoAgentDefSchema.safeParse(value);
9043
+ if (!parsed.success) {
9044
+ warnings.push(`[codex].agents.${name} is invalid and was ignored: ${parsed.error.issues[0]?.message ?? "unknown error"}`);
9045
+ continue;
9046
+ }
9047
+ const override = toCodexAgentOverride(parsed.data.model, parsed.data.reasoning);
9048
+ if (override.model !== undefined || override.reasoningEffort !== undefined)
9049
+ agentOverrides.set(name, override);
9050
+ }
9051
+ return { agentOverrides, warnings };
9052
+ }
9053
+ function toCodexAgentOverride(model, reasoning) {
9054
+ const split = model === undefined ? undefined : splitReasoningSuffix(model);
9055
+ const effort = codexReasoningEffort(reasoning ?? split?.level);
8974
9056
  return {
8975
- enabled: result.config.agents?.default?.disable !== true,
8976
- warnings: result.diagnostics.map((diagnostic) => diagnostic.message)
9057
+ ...split === undefined || split.base === "" ? {} : { model: split.base },
9058
+ ...effort === undefined ? {} : { reasoningEffort: effort }
8977
9059
  };
8978
9060
  }
9061
+ function codexReasoningEffort(reasoning) {
9062
+ if (reasoning === undefined || reasoning === "auto")
9063
+ return;
9064
+ return reasoning === "off" ? "none" : reasoning;
9065
+ }
9066
+ function recordAt(value, key) {
9067
+ if (!isPlainRecord(value))
9068
+ return;
9069
+ const child = value[key];
9070
+ return isPlainRecord(child) ? child : undefined;
9071
+ }
8979
9072
 
8980
9073
  // ../src/install/link-cached-plugin-agents.ts
8981
- import { copyFile, lstat as lstat5, mkdir as mkdir4, readdir as readdir2, rm as rm7, writeFile as writeFile5 } from "node:fs/promises";
8982
- import { basename as basename4, join as join13 } from "node:path";
9074
+ import { copyFile, lstat as lstat6, mkdir as mkdir4, readdir as readdir2, readFile as readFile8, rm as rm8, writeFile as writeFile6 } from "node:fs/promises";
9075
+ import { basename as basename4, join as join14 } from "node:path";
9076
+
9077
+ // ../src/install/agent-model-overrides.ts
9078
+ import { readFile as readFile5, rm as rm5, writeFile as writeFile4 } from "node:fs/promises";
9079
+ import { join as join10 } from "node:path";
8983
9080
 
8984
9081
  // ../src/install/preserved-agent-settings.ts
8985
- import { lstat, readFile as readFile4, readdir, writeFile as writeFile3 } from "node:fs/promises";
9082
+ import { lstat as lstat2, readFile as readFile4, readdir, writeFile as writeFile3 } from "node:fs/promises";
8986
9083
  import { join as join9 } from "node:path";
8987
9084
 
8988
9085
  // ../src/install/toml-section-editor.ts
@@ -9786,6 +9883,17 @@ async function restorePreservedServiceTier(input) {
9786
9883
  return;
9787
9884
  await writeFile3(input.linkPath, replacement.content);
9788
9885
  }
9886
+ async function restorePreservedModel(input) {
9887
+ if (input.value === null)
9888
+ return;
9889
+ const content = await readFile4(input.linkPath, "utf8");
9890
+ if (extractModel(content) === input.value)
9891
+ return;
9892
+ const replacement = replaceTopLevelStringSetting(content, "model", input.value, { insertIfMissing: true });
9893
+ if (!replacement.replaced)
9894
+ return;
9895
+ await writeFile3(input.linkPath, replacement.content);
9896
+ }
9789
9897
  async function readTextIfExists(path) {
9790
9898
  try {
9791
9899
  return await readFile4(path, "utf8");
@@ -9868,7 +9976,7 @@ function agentNameFromToml(fileName) {
9868
9976
  }
9869
9977
  async function exists(path) {
9870
9978
  try {
9871
- await lstat(path);
9979
+ await lstat2(path);
9872
9980
  return true;
9873
9981
  } catch (error) {
9874
9982
  if (nodeErrorCode(error) !== "ENOENT")
@@ -9882,9 +9990,86 @@ function nodeErrorCode(error) {
9882
9990
  return typeof error.code === "string" ? error.code : null;
9883
9991
  }
9884
9992
 
9993
+ // ../src/install/agent-model-overrides.ts
9994
+ var RECEIPT_FILE = ".lazycodex-agent-models.json";
9995
+ async function readAgentModelReceipts(codexHome) {
9996
+ const content = await readTextIfExists(receiptPath(codexHome));
9997
+ if (content === null)
9998
+ return new Map;
9999
+ const parsed = parseJson(content);
10000
+ if (!isPlainRecord(parsed))
10001
+ return new Map;
10002
+ const receipts = new Map;
10003
+ for (const [name, value] of Object.entries(parsed)) {
10004
+ if (!isPlainRecord(value))
10005
+ continue;
10006
+ const model = value["model"];
10007
+ const reasoningEffort = value["reasoningEffort"];
10008
+ receipts.set(name, {
10009
+ ...typeof model === "string" ? { model } : {},
10010
+ ...typeof reasoningEffort === "string" ? { reasoningEffort } : {}
10011
+ });
10012
+ }
10013
+ return receipts;
10014
+ }
10015
+ async function writeAgentModelReceipts(codexHome, receipts) {
10016
+ const path = receiptPath(codexHome);
10017
+ if (receipts.size === 0) {
10018
+ await rm5(path, { force: true });
10019
+ return;
10020
+ }
10021
+ await writeFile4(path, `${JSON.stringify(Object.fromEntries(receipts), null, "\t")}
10022
+ `);
10023
+ }
10024
+ async function applyAgentOverride(input) {
10025
+ if (input.override === undefined)
10026
+ return;
10027
+ let content = await readFile5(input.linkPath, "utf8");
10028
+ if (input.override.model !== undefined) {
10029
+ content = replaceTopLevelStringSetting(content, "model", input.override.model, { insertIfMissing: true }).content;
10030
+ }
10031
+ if (input.override.reasoningEffort !== undefined) {
10032
+ content = replaceTopLevelStringSetting(content, "model_reasoning_effort", input.override.reasoningEffort, {
10033
+ insertIfMissing: true
10034
+ }).content;
10035
+ }
10036
+ await writeFile4(input.linkPath, content);
10037
+ }
10038
+ function receiptPath(codexHome) {
10039
+ return join10(codexHome, "agents", RECEIPT_FILE);
10040
+ }
10041
+ function parseJson(content) {
10042
+ try {
10043
+ return JSON.parse(content);
10044
+ } catch (error) {
10045
+ if (error instanceof SyntaxError)
10046
+ return null;
10047
+ throw error;
10048
+ }
10049
+ }
10050
+
10051
+ // ../src/install/managed-agent-model-defaults.ts
10052
+ var PREVIOUSLY_BUNDLED_AGENT_MODELS = new Set([
10053
+ "gpt-5.2",
10054
+ "gpt-5.4-mini",
10055
+ "gpt-5.5",
10056
+ "gpt-5.6-luna",
10057
+ "gpt-5.6-luna-fast",
10058
+ "gpt-5.6-sol",
10059
+ "gpt-5.6-terra",
10060
+ "gpt-6-astra"
10061
+ ]);
10062
+ function handEditedAgentModel(installedModel, receipt) {
10063
+ if (installedModel === null)
10064
+ return null;
10065
+ if (receipt?.model !== undefined)
10066
+ return installedModel === receipt.model ? null : installedModel;
10067
+ return PREVIOUSLY_BUNDLED_AGENT_MODELS.has(installedModel) ? null : installedModel;
10068
+ }
10069
+
9885
10070
  // ../src/install/retired-managed-agent-purge.ts
9886
- import { lstat as lstat2, readFile as readFile5, rm as rm5 } from "node:fs/promises";
9887
- import { join as join10 } from "node:path";
10071
+ import { lstat as lstat3, readFile as readFile6, rm as rm6 } from "node:fs/promises";
10072
+ import { join as join11 } from "node:path";
9888
10073
  var RETIRED_MANAGED_AGENT_FILES = [
9889
10074
  {
9890
10075
  fileName: "codex-ultrawork-reviewer.toml",
@@ -9896,20 +10081,20 @@ var RETIRED_MANAGED_AGENT_FILES = [
9896
10081
  }
9897
10082
  ];
9898
10083
  async function purgeRetiredManagedAgentFiles(input) {
9899
- const agentsDir = join10(input.codexHome, "agents");
10084
+ const agentsDir = join11(input.codexHome, "agents");
9900
10085
  if (!await exists2(agentsDir))
9901
10086
  return;
9902
10087
  for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
9903
- const agentPath = join10(agentsDir, retiredAgent.fileName);
10088
+ const agentPath = join11(agentsDir, retiredAgent.fileName);
9904
10089
  if (!await exists2(agentPath))
9905
10090
  continue;
9906
- const agentStat = await lstat2(agentPath);
10091
+ const agentStat = await lstat3(agentPath);
9907
10092
  if (agentStat.isDirectory() && !agentStat.isSymbolicLink())
9908
10093
  continue;
9909
10094
  const content = await readTextIfExists2(agentPath);
9910
10095
  if (content === null || !hasRequiredMarkers(content, retiredAgent.requiredMarkers))
9911
10096
  continue;
9912
- await rm5(agentPath, { force: true });
10097
+ await rm6(agentPath, { force: true });
9913
10098
  }
9914
10099
  }
9915
10100
  function hasRequiredMarkers(content, markers) {
@@ -9917,7 +10102,7 @@ function hasRequiredMarkers(content, markers) {
9917
10102
  }
9918
10103
  async function readTextIfExists2(path) {
9919
10104
  try {
9920
- return await readFile5(path, "utf8");
10105
+ return await readFile6(path, "utf8");
9921
10106
  } catch (error) {
9922
10107
  if (nodeErrorCode2(error) === "ENOENT")
9923
10108
  return null;
@@ -9926,7 +10111,7 @@ async function readTextIfExists2(path) {
9926
10111
  }
9927
10112
  async function exists2(path) {
9928
10113
  try {
9929
- await lstat2(path);
10114
+ await lstat3(path);
9930
10115
  return true;
9931
10116
  } catch (error) {
9932
10117
  if (nodeErrorCode2(error) !== "ENOENT")
@@ -9942,18 +10127,18 @@ function nodeErrorCode2(error) {
9942
10127
 
9943
10128
  // ../src/install/default-agent-role.ts
9944
10129
  import { createHash as createHash3 } from "node:crypto";
9945
- import { lstat as lstat4, readFile as readFile6, rm as rm6 } from "node:fs/promises";
9946
- import { join as join12 } from "node:path";
10130
+ import { lstat as lstat5, readFile as readFile7, rm as rm7 } from "node:fs/promises";
10131
+ import { join as join13 } from "node:path";
9947
10132
 
9948
10133
  // ../src/install/codex-config-atomic-write.ts
9949
- import { lstat as lstat3, readlink, realpath, rename as rename3, unlink, writeFile as writeFile4 } from "node:fs/promises";
9950
- import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute2, join as join11, resolve as resolve4 } from "node:path";
10134
+ import { lstat as lstat4, readlink, realpath, rename as rename3, unlink, writeFile as writeFile5 } from "node:fs/promises";
10135
+ import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute2, join as join12, resolve as resolve4 } from "node:path";
9951
10136
  var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
9952
10137
  var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
9953
10138
  async function writeFileAtomic(targetPath, data) {
9954
10139
  const writeTarget = await resolveSymlinkTarget(targetPath);
9955
- const temporaryPath = join11(dirname6(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
9956
- await writeFile4(temporaryPath, data);
10140
+ const temporaryPath = join12(dirname6(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
10141
+ await writeFile5(temporaryPath, data);
9957
10142
  try {
9958
10143
  await renameWithRetry(temporaryPath, writeTarget);
9959
10144
  } catch (error) {
@@ -9967,7 +10152,7 @@ async function writeFileAtomic(targetPath, data) {
9967
10152
  }
9968
10153
  async function resolveSymlinkTarget(targetPath) {
9969
10154
  try {
9970
- const linkStats = await lstat3(targetPath);
10155
+ const linkStats = await lstat4(targetPath);
9971
10156
  if (!linkStats.isSymbolicLink())
9972
10157
  return targetPath;
9973
10158
  } catch (error) {
@@ -10058,11 +10243,11 @@ function tomlKeySegment(value) {
10058
10243
  // ../src/install/default-agent-role.ts
10059
10244
  var REGISTRATION = { name: "default", configFile: "./agents/default.toml" };
10060
10245
  async function installDefaultAgentRole(input) {
10061
- const target = join12(input.codexHome, "agents", "default.toml");
10062
- const receipt = join12(input.codexHome, "agents", ".lazycodex-default.sha256");
10063
- const configPath = join12(input.codexHome, "config.toml");
10246
+ const target = join13(input.codexHome, "agents", "default.toml");
10247
+ const receipt = join13(input.codexHome, "agents", ".lazycodex-default.sha256");
10248
+ const configPath = join13(input.codexHome, "config.toml");
10064
10249
  const config = await readIfPresent(configPath);
10065
- const entry = await lstat4(target).catch((error) => {
10250
+ const entry = await lstat5(target).catch((error) => {
10066
10251
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
10067
10252
  return null;
10068
10253
  throw error;
@@ -10083,15 +10268,15 @@ async function installDefaultAgentRole(input) {
10083
10268
  if (next !== config)
10084
10269
  await writeFileAtomic(configPath, next);
10085
10270
  }
10086
- await rm6(target);
10087
- await rm6(receipt);
10271
+ await rm7(target);
10272
+ await rm7(receipt);
10088
10273
  }
10089
10274
  return null;
10090
10275
  }
10091
10276
  if (foreign || existing !== null && !owned) {
10092
10277
  throw new Error("Preserved user-owned agents.default / agents/default.toml. Move it aside to install the LazyCodex fallback, or set [codex].agents.default.disable = true in omo.jsonc. Explicit LazyCodex roles remain required.");
10093
10278
  }
10094
- const worker = await readFile6(input.worker.path, "utf8");
10279
+ const worker = await readFile7(input.worker.path, "utf8");
10095
10280
  const content = worker.replace(/^name\s*=\s*["']lazycodex-worker-medium["']\s*$/m, 'name = "default"');
10096
10281
  if (content === worker)
10097
10282
  throw new Error("Cannot derive default: medium worker has no matching internal name");
@@ -10101,7 +10286,7 @@ async function installDefaultAgentRole(input) {
10101
10286
  }
10102
10287
  async function readIfPresent(path) {
10103
10288
  try {
10104
- return await readFile6(path, "utf8");
10289
+ return await readFile7(path, "utf8");
10105
10290
  } catch (error) {
10106
10291
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
10107
10292
  return null;
@@ -10121,27 +10306,19 @@ async function linkCachedPluginAgents(input) {
10121
10306
  await writeManifest(input.pluginRoot, []);
10122
10307
  return [];
10123
10308
  }
10124
- const agentsDir = join13(input.codexHome, "agents");
10309
+ const agentsDir = join14(input.codexHome, "agents");
10125
10310
  await mkdir4(agentsDir, { recursive: true });
10311
+ const previousReceipts = await readAgentModelReceipts(input.codexHome);
10312
+ const receipts = new Map;
10126
10313
  const linked = [];
10127
10314
  for (const agentPath of bundledAgents) {
10128
10315
  const agentFileName = basename4(agentPath);
10129
10316
  const agentName = agentNameFromToml2(agentFileName);
10130
- const linkPath = join13(agentsDir, agentFileName);
10131
- await replaceWithCopy(linkPath, agentPath);
10132
- await restorePreservedReasoning({
10133
- agentName,
10134
- linkPath,
10135
- target: agentPath,
10136
- value: input.preservedReasoning?.get(agentName)
10137
- });
10138
- await restorePreservedServiceTier({
10139
- linkPath,
10140
- preserved: input.preservedServiceTier?.has(agentName) ?? false,
10141
- value: input.preservedServiceTier?.get(agentName) ?? null
10142
- });
10317
+ const linkPath = join14(agentsDir, agentFileName);
10318
+ receipts.set(agentName, await syncAgentFile({ ...input, agentName, agentPath, linkPath, previousReceipt: previousReceipts.get(agentName) }));
10143
10319
  linked.push({ name: agentFileName, path: linkPath, target: agentPath });
10144
10320
  }
10321
+ await writeAgentModelReceipts(input.codexHome, receipts);
10145
10322
  const worker = linked.find((entry) => entry.name === "lazycodex-worker-medium.toml");
10146
10323
  if (worker !== undefined) {
10147
10324
  const fallback = await installDefaultAgentRole({ codexHome: input.codexHome, worker, enabled: input.defaultRoleEnabled !== false });
@@ -10151,8 +10328,33 @@ async function linkCachedPluginAgents(input) {
10151
10328
  await writeManifest(input.pluginRoot, linked.map((entry) => entry.path));
10152
10329
  return linked;
10153
10330
  }
10331
+ async function syncAgentFile(input) {
10332
+ const installed = await readTextIfExists(input.linkPath);
10333
+ const installedModel = installed === null ? null : extractModel(installed);
10334
+ const preservedReasoning = input.preservedReasoning?.get(input.agentName);
10335
+ const override = input.agentOverrides?.get(input.agentName);
10336
+ await replaceWithCopy(input.linkPath, input.agentPath);
10337
+ await restorePreservedModel({ linkPath: input.linkPath, value: handEditedAgentModel(installedModel, input.previousReceipt) });
10338
+ await restorePreservedReasoning({
10339
+ agentName: input.agentName,
10340
+ linkPath: input.linkPath,
10341
+ target: input.agentPath,
10342
+ value: preservedReasoning?.effort === input.previousReceipt?.reasoningEffort ? undefined : preservedReasoning
10343
+ });
10344
+ await restorePreservedServiceTier({
10345
+ linkPath: input.linkPath,
10346
+ preserved: input.preservedServiceTier?.has(input.agentName) ?? false,
10347
+ value: input.preservedServiceTier?.get(input.agentName) ?? null
10348
+ });
10349
+ await applyAgentOverride({ linkPath: input.linkPath, override });
10350
+ const model = override?.model ?? extractModel(await readFile8(input.agentPath, "utf8"));
10351
+ return {
10352
+ ...model === null ? {} : { model },
10353
+ ...override?.reasoningEffort === undefined ? {} : { reasoningEffort: override.reasoningEffort }
10354
+ };
10355
+ }
10154
10356
  async function discoverBundledAgents(pluginRoot) {
10155
- const componentsRoot = join13(pluginRoot, "components");
10357
+ const componentsRoot = join14(pluginRoot, "components");
10156
10358
  if (!await exists3(componentsRoot))
10157
10359
  return [];
10158
10360
  const componentEntries = await readdir2(componentsRoot, { withFileTypes: true });
@@ -10160,14 +10362,14 @@ async function discoverBundledAgents(pluginRoot) {
10160
10362
  for (const entry of componentEntries) {
10161
10363
  if (!entry.isDirectory())
10162
10364
  continue;
10163
- const agentsRoot = join13(componentsRoot, entry.name, "agents");
10365
+ const agentsRoot = join14(componentsRoot, entry.name, "agents");
10164
10366
  if (!await exists3(agentsRoot))
10165
10367
  continue;
10166
10368
  const agentEntries = await readdir2(agentsRoot, { withFileTypes: true });
10167
10369
  for (const file of agentEntries) {
10168
10370
  if (!file.isFile() || !file.name.endsWith(".toml"))
10169
10371
  continue;
10170
- agents.push(join13(agentsRoot, file.name));
10372
+ agents.push(join14(agentsRoot, file.name));
10171
10373
  }
10172
10374
  }
10173
10375
  agents.sort();
@@ -10180,16 +10382,16 @@ async function replaceWithCopy(linkPath, target) {
10180
10382
  async function prepareReplacement(linkPath) {
10181
10383
  if (!await exists3(linkPath))
10182
10384
  return;
10183
- const entryStat = await lstat5(linkPath);
10385
+ const entryStat = await lstat6(linkPath);
10184
10386
  if (entryStat.isDirectory() && !entryStat.isSymbolicLink()) {
10185
10387
  throw new Error(`${linkPath} already exists and is a directory; refusing to replace`);
10186
10388
  }
10187
- await rm7(linkPath, { force: true });
10389
+ await rm8(linkPath, { force: true });
10188
10390
  }
10189
10391
  async function writeManifest(pluginRoot, agentPaths) {
10190
- const manifestPath = join13(pluginRoot, MANIFEST_FILE);
10392
+ const manifestPath = join14(pluginRoot, MANIFEST_FILE);
10191
10393
  const payload = { agents: [...agentPaths].sort() };
10192
- await writeFile5(manifestPath, `${JSON.stringify(payload, null, "\t")}
10394
+ await writeFile6(manifestPath, `${JSON.stringify(payload, null, "\t")}
10193
10395
  `);
10194
10396
  }
10195
10397
  function agentNameFromToml2(fileName) {
@@ -10197,7 +10399,7 @@ function agentNameFromToml2(fileName) {
10197
10399
  }
10198
10400
  async function exists3(path) {
10199
10401
  try {
10200
- await lstat5(path);
10402
+ await lstat6(path);
10201
10403
  return true;
10202
10404
  } catch (error) {
10203
10405
  if (nodeErrorCode3(error) !== "ENOENT")
@@ -10212,8 +10414,8 @@ function nodeErrorCode3(error) {
10212
10414
  }
10213
10415
 
10214
10416
  // ../src/install/codex-cache-bins.ts
10215
- import { chmod as chmod2, lstat as lstat9, mkdir as mkdir5, readFile as readFile9, readdir as readdir4, readlink as readlink4, rm as rm10, stat as stat4, symlink, writeFile as writeFile6 } from "node:fs/promises";
10216
- import { basename as basename5, isAbsolute as isAbsolute4, join as join17, relative as relative2, resolve as resolve6, sep } from "node:path";
10417
+ import { chmod as chmod2, lstat as lstat9, mkdir as mkdir5, readFile as readFile11, readdir as readdir4, readlink as readlink4, rm as rm11, stat as stat4, symlink, writeFile as writeFile7 } from "node:fs/promises";
10418
+ import { basename as basename5, isAbsolute as isAbsolute4, join as join18, relative as relative2, resolve as resolve6, sep } from "node:path";
10217
10419
 
10218
10420
  // ../src/install/codex-cache-command-shim.ts
10219
10421
  var COMMAND_SHIM_MARKER = ":: generated by oh-my-openagent Codex installer";
@@ -10257,36 +10459,15 @@ function windowsCommandShim(targetPath) {
10257
10459
  }
10258
10460
 
10259
10461
  // ../src/install/codex-cache-dangling-bins.ts
10260
- import { lstat as lstat7, readFile as readFile7, readdir as readdir3, readlink as readlink2, rm as rm8, stat as stat3 } from "node:fs/promises";
10261
- import { dirname as dirname7, isAbsolute as isAbsolute3, join as join14, resolve as resolve5 } from "node:path";
10262
-
10263
- // ../src/install/codex-cache-fs.ts
10264
- import { lstat as lstat6 } from "node:fs/promises";
10265
- async function fileExistsStrict(path) {
10266
- try {
10267
- await lstat6(path);
10268
- return true;
10269
- } catch (error) {
10270
- if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10271
- return false;
10272
- throw error;
10273
- }
10274
- }
10275
- function isPlainRecord(value) {
10276
- return typeof value === "object" && value !== null && !Array.isArray(value);
10277
- }
10278
- function isNodeErrorWithCode(error) {
10279
- return typeof error === "object" && error !== null && "code" in error;
10280
- }
10281
-
10282
- // ../src/install/codex-cache-dangling-bins.ts
10462
+ import { lstat as lstat7, readFile as readFile9, readdir as readdir3, readlink as readlink2, rm as rm9, stat as stat3 } from "node:fs/promises";
10463
+ import { dirname as dirname7, isAbsolute as isAbsolute3, join as join15, resolve as resolve5 } from "node:path";
10283
10464
  async function removeDanglingManagedComponentBins(binDir, platform, managedBinNames) {
10284
10465
  const entries = await readdir3(binDir, { withFileTypes: true });
10285
10466
  for (const entry of entries) {
10286
10467
  const binName = managedBinNameForEntry(entry.name, platform);
10287
10468
  if (binName === null || !managedBinNames.has(binName))
10288
10469
  continue;
10289
- const linkPath = join14(binDir, entry.name);
10470
+ const linkPath = join15(binDir, entry.name);
10290
10471
  if (platform === "win32") {
10291
10472
  await removeDanglingGeneratedCommandShim(linkPath);
10292
10473
  continue;
@@ -10307,7 +10488,7 @@ async function removeDanglingManagedSymlink(linkPath) {
10307
10488
  const linkTarget = await readlink2(linkPath);
10308
10489
  const target = isAbsolute3(linkTarget) ? linkTarget : resolve5(dirname7(linkPath), linkTarget);
10309
10490
  if (!await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
10310
- await rm8(linkPath, { force: true });
10491
+ await rm9(linkPath, { force: true });
10311
10492
  } catch (error) {
10312
10493
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10313
10494
  return;
@@ -10319,12 +10500,12 @@ async function removeDanglingGeneratedCommandShim(linkPath) {
10319
10500
  const linkStat = await lstat7(linkPath);
10320
10501
  if (!linkStat.isFile())
10321
10502
  return;
10322
- const content = await readFile7(linkPath, "utf8");
10503
+ const content = await readFile9(linkPath, "utf8");
10323
10504
  if (!content.includes(COMMAND_SHIM_MARKER))
10324
10505
  return;
10325
10506
  const target = extractCommandShimTarget(content);
10326
10507
  if (target !== null && !await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
10327
- await rm8(linkPath, { force: true });
10508
+ await rm9(linkPath, { force: true });
10328
10509
  } catch (error) {
10329
10510
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10330
10511
  return;
@@ -10367,8 +10548,8 @@ function hasOmoCodexPluginPrefix(parts, endExclusive) {
10367
10548
  }
10368
10549
 
10369
10550
  // ../src/install/codex-cache-legacy-bins.ts
10370
- import { lstat as lstat8, readFile as readFile8, readlink as readlink3, rm as rm9 } from "node:fs/promises";
10371
- import { join as join15 } from "node:path";
10551
+ import { lstat as lstat8, readFile as readFile10, readlink as readlink3, rm as rm10 } from "node:fs/promises";
10552
+ import { join as join16 } from "node:path";
10372
10553
  var LEGACY_CODEX_COMPONENT_BINS = [
10373
10554
  { name: "omo", component: "ulw-loop" },
10374
10555
  { name: "codex-comment-checker", component: "comment-checker" },
@@ -10381,7 +10562,7 @@ var LEGACY_CODEX_COMPONENT_BINS = [
10381
10562
  var LEGACY_CODEX_COMPONENT_BIN_NAMES = LEGACY_CODEX_COMPONENT_BINS.map((entry) => entry.name);
10382
10563
  async function removeLegacyCodexComponentBins(binDir, platform) {
10383
10564
  for (const entry of LEGACY_CODEX_COMPONENT_BINS) {
10384
- const linkPath = join15(binDir, platform === "win32" ? `${entry.name}.cmd` : entry.name);
10565
+ const linkPath = join16(binDir, platform === "win32" ? `${entry.name}.cmd` : entry.name);
10385
10566
  await removeLegacyCodexComponentBin(linkPath, entry.component, platform);
10386
10567
  }
10387
10568
  }
@@ -10393,14 +10574,14 @@ async function removeLegacyCodexComponentBin(linkPath, component, platform) {
10393
10574
  return;
10394
10575
  const target = await readlink3(linkPath);
10395
10576
  if (isManagedLegacyComponentTarget(target, component))
10396
- await rm9(linkPath, { force: true });
10577
+ await rm10(linkPath, { force: true });
10397
10578
  return;
10398
10579
  }
10399
10580
  if (!stat.isFile())
10400
10581
  return;
10401
- const content = await readFile8(linkPath, "utf8");
10582
+ const content = await readFile10(linkPath, "utf8");
10402
10583
  if (content.includes(COMMAND_SHIM_MARKER))
10403
- await rm9(linkPath, { force: true });
10584
+ await rm10(linkPath, { force: true });
10404
10585
  } catch (error) {
10405
10586
  if (isNodeErrorWithCode2(error) && error.code === "ENOENT")
10406
10587
  return;
@@ -10432,10 +10613,10 @@ function isNodeErrorWithCode2(error) {
10432
10613
  }
10433
10614
 
10434
10615
  // ../src/install/codex-cache-runtime-wrapper.ts
10435
- import { join as join16 } from "node:path";
10616
+ import { join as join17 } from "node:path";
10436
10617
  var RUNTIME_WRAPPER_MARKER = "OMO_GENERATED_RUNTIME_WRAPPER";
10437
10618
  function posixRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10438
- const ulwLoopBin = toPosixPath2(join16(binDir, "omo-ulw-loop"));
10619
+ const ulwLoopBin = toPosixPath2(join17(binDir, "omo-ulw-loop"));
10439
10620
  const nodeCli = escapePosixDoubleQuoted(toPosixPath2(nodeCliPath));
10440
10621
  const escapedCliPath = escapePosixDoubleQuoted(toPosixPath2(cliPath));
10441
10622
  const escapedCodexHome = escapePosixDoubleQuoted(toPosixPath2(codexHome));
@@ -10482,7 +10663,7 @@ function posixRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10482
10663
  `);
10483
10664
  }
10484
10665
  function windowsRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10485
- const ulwLoopBin = join16(binDir, "omo-ulw-loop.cmd");
10666
+ const ulwLoopBin = join17(binDir, "omo-ulw-loop.cmd");
10486
10667
  return [
10487
10668
  "@echo off",
10488
10669
  `rem ${RUNTIME_WRAPPER_MARKER}`,
@@ -10548,23 +10729,23 @@ async function linkCachedPluginBins(input) {
10548
10729
  return linked;
10549
10730
  }
10550
10731
  async function linkRootRuntimeBin(input) {
10551
- const cliPath = join17(input.repoRoot, "dist", "cli", "index.js");
10732
+ const cliPath = join18(input.repoRoot, "dist", "cli", "index.js");
10552
10733
  const platform = input.platform ?? process.platform;
10553
- const legacyPath = join17(input.binDir, platform === "win32" ? "omo.cmd" : "omo");
10734
+ const legacyPath = join18(input.binDir, platform === "win32" ? "omo.cmd" : "omo");
10554
10735
  if (!await isFile2(cliPath)) {
10555
10736
  await removeGeneratedRuntimeWrapper(legacyPath);
10556
10737
  return null;
10557
10738
  }
10558
10739
  const binName = "omo-agent-toolkit";
10559
- const nodeCliPath = join17(input.repoRoot, "dist", "cli-node", "index.js");
10740
+ const nodeCliPath = join18(input.repoRoot, "dist", "cli-node", "index.js");
10560
10741
  await mkdir5(input.binDir, { recursive: true });
10561
10742
  if (platform === "win32") {
10562
- const linkPath = join17(input.binDir, `${binName}.cmd`);
10743
+ const linkPath = join18(input.binDir, `${binName}.cmd`);
10563
10744
  await replaceRuntimeWrapper(linkPath, windowsRuntimeWrapper(binName, cliPath, input.codexHome, input.binDir, nodeCliPath));
10564
10745
  await removeGeneratedRuntimeWrapper(legacyPath);
10565
10746
  return { name: binName, path: linkPath, target: cliPath };
10566
10747
  }
10567
- const linkPath = join17(input.binDir, binName);
10748
+ const linkPath = join18(input.binDir, binName);
10568
10749
  await replaceRuntimeWrapper(linkPath, posixRuntimeWrapper(binName, cliPath, input.codexHome, input.binDir, nodeCliPath));
10569
10750
  await chmod2(linkPath, 493);
10570
10751
  await removeGeneratedRuntimeWrapper(legacyPath);
@@ -10572,11 +10753,11 @@ async function linkRootRuntimeBin(input) {
10572
10753
  }
10573
10754
  async function linkCachedPluginBin(binDir, link, platform) {
10574
10755
  if (platform === "win32") {
10575
- const linkPath = join17(binDir, `${link.name}.cmd`);
10756
+ const linkPath = join18(binDir, `${link.name}.cmd`);
10576
10757
  await replaceCommandShim(linkPath, link.target);
10577
10758
  return linkPath;
10578
10759
  }
10579
- const linkPath = join17(binDir, link.name);
10760
+ const linkPath = join18(binDir, link.name);
10580
10761
  await replaceSymlink(linkPath, link.target);
10581
10762
  return linkPath;
10582
10763
  }
@@ -10597,21 +10778,21 @@ async function discoverPackageBins(root) {
10597
10778
  async function collectPackageBins(directory, root, links) {
10598
10779
  const entries = await readdir4(directory, { withFileTypes: true });
10599
10780
  if (entries.some((entry) => entry.isFile() && entry.name === "package.json")) {
10600
- await appendPackageBinLinks(join17(directory, "package.json"), directory, root, links);
10781
+ await appendPackageBinLinks(join18(directory, "package.json"), directory, root, links);
10601
10782
  }
10602
10783
  for (const entry of entries) {
10603
10784
  if (!entry.isDirectory())
10604
10785
  continue;
10605
10786
  if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")
10606
10787
  continue;
10607
- const childPath = join17(directory, entry.name);
10788
+ const childPath = join18(directory, entry.name);
10608
10789
  if (!childPath.startsWith(root))
10609
10790
  continue;
10610
10791
  await collectPackageBins(childPath, root, links);
10611
10792
  }
10612
10793
  }
10613
10794
  async function appendPackageBinLinks(packageJsonPath, packageRoot, root, links) {
10614
- const packageJson = JSON.parse(await readFile9(packageJsonPath, "utf8"));
10795
+ const packageJson = JSON.parse(await readFile11(packageJsonPath, "utf8"));
10615
10796
  if (!isPlainRecord(packageJson))
10616
10797
  return;
10617
10798
  const packageName = packageJson.name;
@@ -10657,19 +10838,19 @@ function resolvePackageBinTarget(packageRoot, target) {
10657
10838
  async function replaceSymlink(linkPath, targetPath) {
10658
10839
  if (await existingNonSymlink(linkPath))
10659
10840
  throw new Error(`${linkPath} already exists and is not a symlink`);
10660
- await rm10(linkPath, { force: true });
10841
+ await rm11(linkPath, { force: true });
10661
10842
  await symlink(targetPath, linkPath);
10662
10843
  }
10663
10844
  async function replaceCommandShim(linkPath, targetPath) {
10664
10845
  if (await existingNonShim(linkPath))
10665
10846
  throw new Error(`${linkPath} already exists and is not a command shim`);
10666
- await writeFile6(linkPath, windowsCommandShim(targetPath));
10847
+ await writeFile7(linkPath, windowsCommandShim(targetPath));
10667
10848
  }
10668
10849
  async function replaceRuntimeWrapper(linkPath, content) {
10669
10850
  if (await existingNonRuntimeWrapper(linkPath))
10670
10851
  throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
10671
- await rm10(linkPath, { force: true });
10672
- await writeFile6(linkPath, content);
10852
+ await rm11(linkPath, { force: true });
10853
+ await writeFile7(linkPath, content);
10673
10854
  }
10674
10855
  async function removeGeneratedRuntimeWrapper(path) {
10675
10856
  try {
@@ -10678,7 +10859,7 @@ async function removeGeneratedRuntimeWrapper(path) {
10678
10859
  return;
10679
10860
  const content = await readGeneratedWrapperContent(path);
10680
10861
  if (content.includes(RUNTIME_WRAPPER_MARKER))
10681
- await rm10(path, { force: true });
10862
+ await rm11(path, { force: true });
10682
10863
  } catch (error) {
10683
10864
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10684
10865
  return;
@@ -10687,7 +10868,7 @@ async function removeGeneratedRuntimeWrapper(path) {
10687
10868
  }
10688
10869
  async function readGeneratedWrapperContent(path) {
10689
10870
  try {
10690
- return await readFile9(path, "utf8");
10871
+ return await readFile11(path, "utf8");
10691
10872
  } catch (error) {
10692
10873
  if (isNodeErrorWithCode(error) && (error.code === "ENOENT" || error.code === "EISDIR"))
10693
10874
  return "";
@@ -10701,7 +10882,7 @@ async function existingNonRuntimeWrapper(path) {
10701
10882
  return false;
10702
10883
  if (!stat.isFile())
10703
10884
  return true;
10704
- const content = await readFile9(path, "utf8");
10885
+ const content = await readFile11(path, "utf8");
10705
10886
  return !content.includes(RUNTIME_WRAPPER_MARKER);
10706
10887
  } catch (error) {
10707
10888
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
@@ -10714,7 +10895,7 @@ async function existingNonShim(path) {
10714
10895
  const stat = await lstat9(path);
10715
10896
  if (!stat.isFile())
10716
10897
  return true;
10717
- const content = await readFile9(path, "utf8");
10898
+ const content = await readFile11(path, "utf8");
10718
10899
  if (content.includes(COMMAND_SHIM_MARKER))
10719
10900
  return false;
10720
10901
  throw new Error(`${path} already exists and is not a generated command shim`);
@@ -10739,7 +10920,7 @@ async function existingNonSymlink(path) {
10739
10920
  }
10740
10921
 
10741
10922
  // ../src/install/codex-config-toml.ts
10742
- import { mkdir as mkdir6, readFile as readFile11 } from "node:fs/promises";
10923
+ import { mkdir as mkdir6, readFile as readFile13 } from "node:fs/promises";
10743
10924
  import { dirname as dirname9 } from "node:path";
10744
10925
 
10745
10926
  // ../src/install/toml-setting-reader.ts
@@ -11181,8 +11362,8 @@ function isRootSetting(line, key) {
11181
11362
  }
11182
11363
 
11183
11364
  // ../src/install/codex-model-catalog.ts
11184
- import { readFile as readFile10 } from "node:fs/promises";
11185
- import { join as join18 } from "node:path";
11365
+ import { readFile as readFile12 } from "node:fs/promises";
11366
+ import { join as join19 } from "node:path";
11186
11367
  var FALLBACK_CODEX_MODEL_CATALOG = {
11187
11368
  current: {
11188
11369
  model: "gpt-6-astra",
@@ -11213,9 +11394,9 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
11213
11394
  ]
11214
11395
  };
11215
11396
  async function readCodexModelCatalog(codexPackageRoot) {
11216
- const catalogPath = join18(codexPackageRoot, "plugin", "model-catalog.json");
11397
+ const catalogPath = join19(codexPackageRoot, "plugin", "model-catalog.json");
11217
11398
  try {
11218
- const parsed = JSON.parse(await readFile10(catalogPath, "utf8"));
11399
+ const parsed = JSON.parse(await readFile12(catalogPath, "utf8"));
11219
11400
  return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
11220
11401
  } catch (error) {
11221
11402
  if (error instanceof Error)
@@ -11297,7 +11478,7 @@ function isRootSetting2(line, key) {
11297
11478
 
11298
11479
  // ../src/install/codex-multi-agent-v2-config.ts
11299
11480
  import { readFileSync as readFileSync2 } from "node:fs";
11300
- import { dirname as dirname8, isAbsolute as isAbsolute5, join as join19 } from "node:path";
11481
+ import { dirname as dirname8, isAbsolute as isAbsolute5, join as join20 } from "node:path";
11301
11482
  var CODEX_AGENTS_HEADER = "agents";
11302
11483
  var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
11303
11484
  function ensureCodexMultiAgentV2Config(config, options = {}) {
@@ -11325,8 +11506,8 @@ function resolveCodexMultiAgentVersion(config, configPath) {
11325
11506
  }
11326
11507
  function resolveCatalogPath(configuredPath, configPath) {
11327
11508
  if (configuredPath === null)
11328
- return join19(dirname8(configPath), "models_cache.json");
11329
- return isAbsolute5(configuredPath) ? configuredPath : join19(dirname8(configPath), configuredPath);
11509
+ return join20(dirname8(configPath), "models_cache.json");
11510
+ return isAbsolute5(configuredPath) ? configuredPath : join20(dirname8(configPath), configuredPath);
11330
11511
  }
11331
11512
  function readCatalogMultiAgentVersion(model, cachePath) {
11332
11513
  let raw;
@@ -11440,7 +11621,7 @@ async function updateCodexConfig(input) {
11440
11621
  await mkdir6(dirname9(input.configPath), { recursive: true });
11441
11622
  let config;
11442
11623
  try {
11443
- config = await readFile11(input.configPath, "utf8");
11624
+ config = await readFile13(input.configPath, "utf8");
11444
11625
  } catch (error) {
11445
11626
  if (!isMissingFileError(error))
11446
11627
  throw error;
@@ -11486,14 +11667,14 @@ function isMissingFileError(error) {
11486
11667
  }
11487
11668
 
11488
11669
  // ../src/install/codex-git-bash-mcp-env.ts
11489
- import { readFile as readFile12, writeFile as writeFile7 } from "node:fs/promises";
11490
- import { join as join20 } from "node:path";
11670
+ import { readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
11671
+ import { join as join21 } from "node:path";
11491
11672
  var GIT_BASH_ENV_KEY = "OMO_CODEX_GIT_BASH_PATH";
11492
11673
  async function stampGitBashMcpEnv(input) {
11493
- const manifestPath = join20(input.pluginRoot, ".mcp.json");
11674
+ const manifestPath = join21(input.pluginRoot, ".mcp.json");
11494
11675
  if (!await fileExistsStrict(manifestPath))
11495
11676
  return false;
11496
- const parsed = JSON.parse(await readFile12(manifestPath, "utf8"));
11677
+ const parsed = JSON.parse(await readFile14(manifestPath, "utf8"));
11497
11678
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
11498
11679
  return false;
11499
11680
  let changed = false;
@@ -11511,15 +11692,15 @@ async function stampGitBashMcpEnv(input) {
11511
11692
  }
11512
11693
  if (!changed)
11513
11694
  return false;
11514
- await writeFile7(manifestPath, `${JSON.stringify(parsed, null, "\t")}
11695
+ await writeFile8(manifestPath, `${JSON.stringify(parsed, null, "\t")}
11515
11696
  `);
11516
11697
  return true;
11517
11698
  }
11518
11699
 
11519
11700
  // ../src/install/codex-hook-trust.ts
11520
11701
  import { createHash as createHash4 } from "node:crypto";
11521
- import { readFile as readFile13 } from "node:fs/promises";
11522
- import { join as join21 } from "node:path";
11702
+ import { readFile as readFile15 } from "node:fs/promises";
11703
+ import { join as join22 } from "node:path";
11523
11704
  var EVENT_LABELS = new Map([
11524
11705
  ["PreToolUse", "pre_tool_use"],
11525
11706
  ["PermissionRequest", "permission_request"],
@@ -11533,18 +11714,18 @@ var EVENT_LABELS = new Map([
11533
11714
  ["Stop", "stop"]
11534
11715
  ]);
11535
11716
  async function trustedHookStatesForPlugin(input) {
11536
- const manifestPath = join21(input.pluginRoot, ".codex-plugin", "plugin.json");
11717
+ const manifestPath = join22(input.pluginRoot, ".codex-plugin", "plugin.json");
11537
11718
  if (!await exists4(manifestPath))
11538
11719
  return [];
11539
- const manifest = JSON.parse(await readFile13(manifestPath, "utf8"));
11720
+ const manifest = JSON.parse(await readFile15(manifestPath, "utf8"));
11540
11721
  if (!isPlainRecord(manifest))
11541
11722
  return [];
11542
11723
  const states = [];
11543
11724
  for (const hookPath of hookManifestPaths(manifest.hooks)) {
11544
- const hooksPath = join21(input.pluginRoot, hookPath);
11725
+ const hooksPath = join22(input.pluginRoot, hookPath);
11545
11726
  if (!await exists4(hooksPath))
11546
11727
  continue;
11547
- const parsed = JSON.parse(await readFile13(hooksPath, "utf8"));
11728
+ const parsed = JSON.parse(await readFile15(hooksPath, "utf8"));
11548
11729
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
11549
11730
  continue;
11550
11731
  states.push(...trustedHookStatesForHooksFile({
@@ -11627,7 +11808,7 @@ function stripDotSlash(value) {
11627
11808
  }
11628
11809
  async function exists4(path) {
11629
11810
  try {
11630
- await readFile13(path, "utf8");
11811
+ await readFile15(path, "utf8");
11631
11812
  return true;
11632
11813
  } catch (error) {
11633
11814
  if (error instanceof Error)
@@ -11638,7 +11819,7 @@ async function exists4(path) {
11638
11819
 
11639
11820
  // ../src/install/codex-installer-bin-dir.ts
11640
11821
  import { homedir as homedir4 } from "node:os";
11641
- import { join as join22, resolve as resolve7 } from "node:path";
11822
+ import { join as join23, resolve as resolve7 } from "node:path";
11642
11823
  function resolveCodexInstallerBinDir(input) {
11643
11824
  const explicitBinDir = input.binDir ?? input.env?.CODEX_LOCAL_BIN_DIR;
11644
11825
  if (explicitBinDir !== undefined && explicitBinDir.trim().length > 0)
@@ -11647,7 +11828,7 @@ function resolveCodexInstallerBinDir(input) {
11647
11828
  const defaultCodexHome = resolve7(homeDir, ".codex");
11648
11829
  const resolvedCodexHome = resolve7(input.codexHome);
11649
11830
  if (resolvedCodexHome !== defaultCodexHome)
11650
- return join22(resolvedCodexHome, "bin");
11831
+ return join23(resolvedCodexHome, "bin");
11651
11832
  return resolve7(homeDir, ".local", "bin");
11652
11833
  }
11653
11834
 
@@ -11803,24 +11984,27 @@ async function resolveGitBashStep(options, degraded) {
11803
11984
  return false;
11804
11985
  }
11805
11986
  async function linkBundledAgentsStep(options) {
11806
- const agentsTarget = join23(options.codexHome, "agents");
11987
+ const agentsTarget = join24(options.codexHome, "agents");
11807
11988
  try {
11808
- const stageRoot = join23(options.pluginData, "bootstrap", "agents-stage");
11989
+ const stageRoot = join24(options.pluginData, "bootstrap", "agents-stage");
11809
11990
  await stageBundledAgents(options.pluginRoot, stageRoot);
11810
11991
  const preservedReasoning = await capturePreservedAgentReasoning({ codexHome: options.codexHome });
11811
11992
  const preservedServiceTier = await capturePreservedAgentServiceTier({ codexHome: options.codexHome });
11812
- const config = readDefaultRoleConfig({ env: options.env });
11993
+ const config = readCodexAgentConfig({ env: options.env });
11813
11994
  const linked = await linkCachedPluginAgents({
11814
11995
  codexHome: options.codexHome,
11815
11996
  pluginRoot: stageRoot,
11816
11997
  preservedReasoning,
11817
11998
  preservedServiceTier,
11818
- defaultRoleEnabled: config.enabled
11999
+ defaultRoleEnabled: config.defaultRoleEnabled,
12000
+ agentOverrides: config.agentOverrides
11819
12001
  });
12002
+ const managedAgentNames = new Set(linked.map((link) => agentNameFromToml3(link.name)));
12003
+ const warnings = [...config.warnings, ...unmanagedAgentOverrideWarnings(config.agentOverrides, managedAgentNames)];
11820
12004
  const agentConfigs = linked.map((link) => ({ configFile: `./agents/${link.name}`, name: agentNameFromToml3(link.name) })).sort((left, right) => left.name.localeCompare(right.name));
11821
12005
  return {
11822
12006
  agentConfigs,
11823
- degraded: config.warnings.map((reason) => ({ component: "agents-config", hint: BOOTSTRAP_DOCTOR_HINT, reason }))
12007
+ degraded: warnings.map((reason) => ({ component: "agents-config", hint: BOOTSTRAP_DOCTOR_HINT, reason }))
11824
12008
  };
11825
12009
  } catch (error) {
11826
12010
  return {
@@ -11836,23 +12020,23 @@ async function linkBundledAgentsStep(options) {
11836
12020
  }
11837
12021
  }
11838
12022
  async function stageBundledAgents(pluginRoot, stageRoot) {
11839
- await rm11(stageRoot, { force: true, recursive: true });
12023
+ await rm12(stageRoot, { force: true, recursive: true });
11840
12024
  await mkdir7(stageRoot, { recursive: true });
11841
- const componentsRoot = join23(pluginRoot, "components");
12025
+ const componentsRoot = join24(pluginRoot, "components");
11842
12026
  for (const componentName of await directoryNames(componentsRoot)) {
11843
- const agentsDir = join23(componentsRoot, componentName, "agents");
12027
+ const agentsDir = join24(componentsRoot, componentName, "agents");
11844
12028
  const agentFiles = (await fileNames(agentsDir)).filter((name) => name.endsWith(".toml"));
11845
12029
  if (agentFiles.length === 0)
11846
12030
  continue;
11847
- const stagedAgentsDir = join23(stageRoot, "components", componentName, "agents");
12031
+ const stagedAgentsDir = join24(stageRoot, "components", componentName, "agents");
11848
12032
  await mkdir7(stagedAgentsDir, { recursive: true });
11849
12033
  for (const agentFile of agentFiles) {
11850
- await copyFile2(join23(agentsDir, agentFile), join23(stagedAgentsDir, agentFile));
12034
+ await copyFile2(join24(agentsDir, agentFile), join24(stagedAgentsDir, agentFile));
11851
12035
  }
11852
12036
  }
11853
12037
  }
11854
12038
  async function updateConfigStep(options, inputs, degraded) {
11855
- const configPath = join23(options.codexHome, "config.toml");
12039
+ const configPath = join24(options.codexHome, "config.toml");
11856
12040
  try {
11857
12041
  await assertWritableConfigIfPresent(configPath);
11858
12042
  const existingConfig = await readConfigIfPresent(configPath);
@@ -11898,7 +12082,7 @@ function errorCode(error) {
11898
12082
  }
11899
12083
  async function readConfigIfPresent(configPath) {
11900
12084
  try {
11901
- return await readFile14(configPath, "utf8");
12085
+ return await readFile16(configPath, "utf8");
11902
12086
  } catch (error) {
11903
12087
  if (errorCode(error) === "ENOENT")
11904
12088
  return "";
@@ -11919,7 +12103,7 @@ async function linkComponentBinsStep(options, degraded) {
11919
12103
  await linkRuntimeWrapperStep(options, binDir, degraded);
11920
12104
  }
11921
12105
  async function linkRuntimeWrapperStep(options, binDir, degraded) {
11922
- const cliPath = join23(options.pluginRoot, "dist", "cli", "index.js");
12106
+ const cliPath = join24(options.pluginRoot, "dist", "cli", "index.js");
11923
12107
  try {
11924
12108
  const linked = await linkRootRuntimeBin({
11925
12109
  binDir,
@@ -11952,7 +12136,7 @@ async function stampGitBashEnvStep(options, degraded) {
11952
12136
  degraded.push({
11953
12137
  component: "git-bash-env",
11954
12138
  hint: BOOTSTRAP_DOCTOR_HINT,
11955
- reason: `failed to stamp ${join23(options.pluginRoot, ".mcp.json")}: ${errorMessage(error)}`
12139
+ reason: `failed to stamp ${join24(options.pluginRoot, ".mcp.json")}: ${errorMessage(error)}`
11956
12140
  });
11957
12141
  }
11958
12142
  }
@@ -12020,11 +12204,11 @@ function resolvePluginDataRoot(env) {
12020
12204
  const fromEnv = env["PLUGIN_DATA"]?.trim();
12021
12205
  if (fromEnv !== undefined && fromEnv.length > 0)
12022
12206
  return fromEnv;
12023
- return join24(homedir5(), ".local", "share", "lazycodex");
12207
+ return join25(homedir5(), ".local", "share", "lazycodex");
12024
12208
  }
12025
12209
  async function readPluginVersion(pluginRoot) {
12026
12210
  try {
12027
- const parsed = JSON.parse(await readFile15(join24(pluginRoot, ".codex-plugin", "plugin.json"), "utf8"));
12211
+ const parsed = JSON.parse(await readFile17(join25(pluginRoot, ".codex-plugin", "plugin.json"), "utf8"));
12028
12212
  if (typeof parsed !== "object" || parsed === null)
12029
12213
  return;
12030
12214
  const version = parsed["version"];
@@ -12094,7 +12278,7 @@ async function runBootstrapWorker(options = {}) {
12094
12278
  degraded.push({
12095
12279
  component: "bootstrap",
12096
12280
  hint: BOOTSTRAP_DOCTOR_HINT,
12097
- reason: `plugin version unresolved from ${join24(pluginRoot, ".codex-plugin", "plugin.json")}`
12281
+ reason: `plugin version unresolved from ${join25(pluginRoot, ".codex-plugin", "plugin.json")}`
12098
12282
  });
12099
12283
  }
12100
12284
  for (const step of steps) {
@@ -12137,7 +12321,7 @@ function resolvePluginRoot(env) {
12137
12321
  }
12138
12322
  async function appendBootstrapLog(pluginData, now, event, details) {
12139
12323
  try {
12140
- const logPath = join24(pluginData, "bootstrap", "bootstrap.log");
12324
+ const logPath = join25(pluginData, "bootstrap", "bootstrap.log");
12141
12325
  await mkdir8(dirname10(logPath), { recursive: true });
12142
12326
  await appendFile2(logPath, `${JSON.stringify({ timestamp: new Date(now).toISOString(), event, ...details })}
12143
12327
  `);