lazycodex-ai 5.1.0 → 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 (55) hide show
  1. package/dist/cli/index.js +672 -464
  2. package/dist/cli-node/index.js +672 -464
  3. package/package.json +1 -1
  4. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  5. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +315 -154
  6. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  7. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  8. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +7 -4
  9. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  10. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  11. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  12. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  13. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  14. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  15. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  16. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  17. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  19. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  21. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  22. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  23. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  25. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  27. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  29. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  30. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  31. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  32. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  33. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  34. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  35. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  36. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  37. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  38. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  51. package/packages/omo-codex/plugin/package-lock.json +12 -12
  52. package/packages/omo-codex/plugin/package.json +1 -1
  53. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  54. package/packages/omo-codex/scripts/install-dist/install-local.mjs +10441 -10269
  55. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
@@ -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) {
@@ -7379,6 +7379,7 @@ var OmoTaskSettingsSchema = object({
7379
7379
  process_runner: _enum(["host", "child-process"]).default("host"),
7380
7380
  host_engine_policy: _enum(["upgrade", "fallback"]).default("upgrade"),
7381
7381
  host_idle_exit_ms: number2().int().positive().optional(),
7382
+ host_shard_prewarm: _enum(["off", "first-turn", "session-start"]).default("first-turn"),
7382
7383
  default_concurrency: number2().int().nonnegative().default(5),
7383
7384
  global_concurrency: number2().int().nonnegative().default(8),
7384
7385
  provider_concurrency: record(string2(), number2().int().nonnegative()).optional(),
@@ -7428,6 +7429,7 @@ var OmoTaskSettingsLayerSchema = object({
7428
7429
  process_runner: _enum(["host", "child-process"]).optional(),
7429
7430
  host_engine_policy: _enum(["upgrade", "fallback"]).optional(),
7430
7431
  host_idle_exit_ms: number2().int().positive().optional(),
7432
+ host_shard_prewarm: _enum(["off", "first-turn", "session-start"]).optional(),
7431
7433
  default_concurrency: number2().int().nonnegative().optional(),
7432
7434
  global_concurrency: number2().int().nonnegative().optional(),
7433
7435
  provider_concurrency: record(string2(), number2().int().nonnegative()).optional(),
@@ -8991,21 +8993,93 @@ function loadOmoConfig(options = {}) {
8991
8993
  };
8992
8994
  }
8993
8995
 
8994
- // ../src/install/codex-default-role-config.ts
8995
- 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 = {}) {
8996
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);
8997
9056
  return {
8998
- enabled: result.config.agents?.default?.disable !== true,
8999
- warnings: result.diagnostics.map((diagnostic) => diagnostic.message)
9057
+ ...split === undefined || split.base === "" ? {} : { model: split.base },
9058
+ ...effort === undefined ? {} : { reasoningEffort: effort }
9000
9059
  };
9001
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
+ }
9002
9072
 
9003
9073
  // ../src/install/link-cached-plugin-agents.ts
9004
- import { copyFile, lstat as lstat5, mkdir as mkdir4, readdir as readdir2, rm as rm7, writeFile as writeFile5 } from "node:fs/promises";
9005
- 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";
9006
9080
 
9007
9081
  // ../src/install/preserved-agent-settings.ts
9008
- 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";
9009
9083
  import { join as join9 } from "node:path";
9010
9084
 
9011
9085
  // ../src/install/toml-section-editor.ts
@@ -9809,6 +9883,17 @@ async function restorePreservedServiceTier(input) {
9809
9883
  return;
9810
9884
  await writeFile3(input.linkPath, replacement.content);
9811
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
+ }
9812
9897
  async function readTextIfExists(path) {
9813
9898
  try {
9814
9899
  return await readFile4(path, "utf8");
@@ -9891,7 +9976,7 @@ function agentNameFromToml(fileName) {
9891
9976
  }
9892
9977
  async function exists(path) {
9893
9978
  try {
9894
- await lstat(path);
9979
+ await lstat2(path);
9895
9980
  return true;
9896
9981
  } catch (error) {
9897
9982
  if (nodeErrorCode(error) !== "ENOENT")
@@ -9905,9 +9990,86 @@ function nodeErrorCode(error) {
9905
9990
  return typeof error.code === "string" ? error.code : null;
9906
9991
  }
9907
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
+
9908
10070
  // ../src/install/retired-managed-agent-purge.ts
9909
- import { lstat as lstat2, readFile as readFile5, rm as rm5 } from "node:fs/promises";
9910
- 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";
9911
10073
  var RETIRED_MANAGED_AGENT_FILES = [
9912
10074
  {
9913
10075
  fileName: "codex-ultrawork-reviewer.toml",
@@ -9919,20 +10081,20 @@ var RETIRED_MANAGED_AGENT_FILES = [
9919
10081
  }
9920
10082
  ];
9921
10083
  async function purgeRetiredManagedAgentFiles(input) {
9922
- const agentsDir = join10(input.codexHome, "agents");
10084
+ const agentsDir = join11(input.codexHome, "agents");
9923
10085
  if (!await exists2(agentsDir))
9924
10086
  return;
9925
10087
  for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
9926
- const agentPath = join10(agentsDir, retiredAgent.fileName);
10088
+ const agentPath = join11(agentsDir, retiredAgent.fileName);
9927
10089
  if (!await exists2(agentPath))
9928
10090
  continue;
9929
- const agentStat = await lstat2(agentPath);
10091
+ const agentStat = await lstat3(agentPath);
9930
10092
  if (agentStat.isDirectory() && !agentStat.isSymbolicLink())
9931
10093
  continue;
9932
10094
  const content = await readTextIfExists2(agentPath);
9933
10095
  if (content === null || !hasRequiredMarkers(content, retiredAgent.requiredMarkers))
9934
10096
  continue;
9935
- await rm5(agentPath, { force: true });
10097
+ await rm6(agentPath, { force: true });
9936
10098
  }
9937
10099
  }
9938
10100
  function hasRequiredMarkers(content, markers) {
@@ -9940,7 +10102,7 @@ function hasRequiredMarkers(content, markers) {
9940
10102
  }
9941
10103
  async function readTextIfExists2(path) {
9942
10104
  try {
9943
- return await readFile5(path, "utf8");
10105
+ return await readFile6(path, "utf8");
9944
10106
  } catch (error) {
9945
10107
  if (nodeErrorCode2(error) === "ENOENT")
9946
10108
  return null;
@@ -9949,7 +10111,7 @@ async function readTextIfExists2(path) {
9949
10111
  }
9950
10112
  async function exists2(path) {
9951
10113
  try {
9952
- await lstat2(path);
10114
+ await lstat3(path);
9953
10115
  return true;
9954
10116
  } catch (error) {
9955
10117
  if (nodeErrorCode2(error) !== "ENOENT")
@@ -9965,18 +10127,18 @@ function nodeErrorCode2(error) {
9965
10127
 
9966
10128
  // ../src/install/default-agent-role.ts
9967
10129
  import { createHash as createHash3 } from "node:crypto";
9968
- import { lstat as lstat4, readFile as readFile6, rm as rm6 } from "node:fs/promises";
9969
- 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";
9970
10132
 
9971
10133
  // ../src/install/codex-config-atomic-write.ts
9972
- import { lstat as lstat3, readlink, realpath, rename as rename3, unlink, writeFile as writeFile4 } from "node:fs/promises";
9973
- 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";
9974
10136
  var RENAME_RETRY_DELAYS_MS = [10, 25, 50];
9975
10137
  var RETRIABLE_RENAME_CODES = new Set(["EPERM", "EBUSY"]);
9976
10138
  async function writeFileAtomic(targetPath, data) {
9977
10139
  const writeTarget = await resolveSymlinkTarget(targetPath);
9978
- const temporaryPath = join11(dirname6(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
9979
- await writeFile4(temporaryPath, data);
10140
+ const temporaryPath = join12(dirname6(writeTarget), `.tmp-${basename3(writeTarget)}-${process.pid}-${Date.now()}`);
10141
+ await writeFile5(temporaryPath, data);
9980
10142
  try {
9981
10143
  await renameWithRetry(temporaryPath, writeTarget);
9982
10144
  } catch (error) {
@@ -9990,7 +10152,7 @@ async function writeFileAtomic(targetPath, data) {
9990
10152
  }
9991
10153
  async function resolveSymlinkTarget(targetPath) {
9992
10154
  try {
9993
- const linkStats = await lstat3(targetPath);
10155
+ const linkStats = await lstat4(targetPath);
9994
10156
  if (!linkStats.isSymbolicLink())
9995
10157
  return targetPath;
9996
10158
  } catch (error) {
@@ -10081,11 +10243,11 @@ function tomlKeySegment(value) {
10081
10243
  // ../src/install/default-agent-role.ts
10082
10244
  var REGISTRATION = { name: "default", configFile: "./agents/default.toml" };
10083
10245
  async function installDefaultAgentRole(input) {
10084
- const target = join12(input.codexHome, "agents", "default.toml");
10085
- const receipt = join12(input.codexHome, "agents", ".lazycodex-default.sha256");
10086
- 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");
10087
10249
  const config = await readIfPresent(configPath);
10088
- const entry = await lstat4(target).catch((error) => {
10250
+ const entry = await lstat5(target).catch((error) => {
10089
10251
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
10090
10252
  return null;
10091
10253
  throw error;
@@ -10106,15 +10268,15 @@ async function installDefaultAgentRole(input) {
10106
10268
  if (next !== config)
10107
10269
  await writeFileAtomic(configPath, next);
10108
10270
  }
10109
- await rm6(target);
10110
- await rm6(receipt);
10271
+ await rm7(target);
10272
+ await rm7(receipt);
10111
10273
  }
10112
10274
  return null;
10113
10275
  }
10114
10276
  if (foreign || existing !== null && !owned) {
10115
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.");
10116
10278
  }
10117
- const worker = await readFile6(input.worker.path, "utf8");
10279
+ const worker = await readFile7(input.worker.path, "utf8");
10118
10280
  const content = worker.replace(/^name\s*=\s*["']lazycodex-worker-medium["']\s*$/m, 'name = "default"');
10119
10281
  if (content === worker)
10120
10282
  throw new Error("Cannot derive default: medium worker has no matching internal name");
@@ -10124,7 +10286,7 @@ async function installDefaultAgentRole(input) {
10124
10286
  }
10125
10287
  async function readIfPresent(path) {
10126
10288
  try {
10127
- return await readFile6(path, "utf8");
10289
+ return await readFile7(path, "utf8");
10128
10290
  } catch (error) {
10129
10291
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
10130
10292
  return null;
@@ -10144,27 +10306,19 @@ async function linkCachedPluginAgents(input) {
10144
10306
  await writeManifest(input.pluginRoot, []);
10145
10307
  return [];
10146
10308
  }
10147
- const agentsDir = join13(input.codexHome, "agents");
10309
+ const agentsDir = join14(input.codexHome, "agents");
10148
10310
  await mkdir4(agentsDir, { recursive: true });
10311
+ const previousReceipts = await readAgentModelReceipts(input.codexHome);
10312
+ const receipts = new Map;
10149
10313
  const linked = [];
10150
10314
  for (const agentPath of bundledAgents) {
10151
10315
  const agentFileName = basename4(agentPath);
10152
10316
  const agentName = agentNameFromToml2(agentFileName);
10153
- const linkPath = join13(agentsDir, agentFileName);
10154
- await replaceWithCopy(linkPath, agentPath);
10155
- await restorePreservedReasoning({
10156
- agentName,
10157
- linkPath,
10158
- target: agentPath,
10159
- value: input.preservedReasoning?.get(agentName)
10160
- });
10161
- await restorePreservedServiceTier({
10162
- linkPath,
10163
- preserved: input.preservedServiceTier?.has(agentName) ?? false,
10164
- value: input.preservedServiceTier?.get(agentName) ?? null
10165
- });
10317
+ const linkPath = join14(agentsDir, agentFileName);
10318
+ receipts.set(agentName, await syncAgentFile({ ...input, agentName, agentPath, linkPath, previousReceipt: previousReceipts.get(agentName) }));
10166
10319
  linked.push({ name: agentFileName, path: linkPath, target: agentPath });
10167
10320
  }
10321
+ await writeAgentModelReceipts(input.codexHome, receipts);
10168
10322
  const worker = linked.find((entry) => entry.name === "lazycodex-worker-medium.toml");
10169
10323
  if (worker !== undefined) {
10170
10324
  const fallback = await installDefaultAgentRole({ codexHome: input.codexHome, worker, enabled: input.defaultRoleEnabled !== false });
@@ -10174,8 +10328,33 @@ async function linkCachedPluginAgents(input) {
10174
10328
  await writeManifest(input.pluginRoot, linked.map((entry) => entry.path));
10175
10329
  return linked;
10176
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
+ }
10177
10356
  async function discoverBundledAgents(pluginRoot) {
10178
- const componentsRoot = join13(pluginRoot, "components");
10357
+ const componentsRoot = join14(pluginRoot, "components");
10179
10358
  if (!await exists3(componentsRoot))
10180
10359
  return [];
10181
10360
  const componentEntries = await readdir2(componentsRoot, { withFileTypes: true });
@@ -10183,14 +10362,14 @@ async function discoverBundledAgents(pluginRoot) {
10183
10362
  for (const entry of componentEntries) {
10184
10363
  if (!entry.isDirectory())
10185
10364
  continue;
10186
- const agentsRoot = join13(componentsRoot, entry.name, "agents");
10365
+ const agentsRoot = join14(componentsRoot, entry.name, "agents");
10187
10366
  if (!await exists3(agentsRoot))
10188
10367
  continue;
10189
10368
  const agentEntries = await readdir2(agentsRoot, { withFileTypes: true });
10190
10369
  for (const file of agentEntries) {
10191
10370
  if (!file.isFile() || !file.name.endsWith(".toml"))
10192
10371
  continue;
10193
- agents.push(join13(agentsRoot, file.name));
10372
+ agents.push(join14(agentsRoot, file.name));
10194
10373
  }
10195
10374
  }
10196
10375
  agents.sort();
@@ -10203,16 +10382,16 @@ async function replaceWithCopy(linkPath, target) {
10203
10382
  async function prepareReplacement(linkPath) {
10204
10383
  if (!await exists3(linkPath))
10205
10384
  return;
10206
- const entryStat = await lstat5(linkPath);
10385
+ const entryStat = await lstat6(linkPath);
10207
10386
  if (entryStat.isDirectory() && !entryStat.isSymbolicLink()) {
10208
10387
  throw new Error(`${linkPath} already exists and is a directory; refusing to replace`);
10209
10388
  }
10210
- await rm7(linkPath, { force: true });
10389
+ await rm8(linkPath, { force: true });
10211
10390
  }
10212
10391
  async function writeManifest(pluginRoot, agentPaths) {
10213
- const manifestPath = join13(pluginRoot, MANIFEST_FILE);
10392
+ const manifestPath = join14(pluginRoot, MANIFEST_FILE);
10214
10393
  const payload = { agents: [...agentPaths].sort() };
10215
- await writeFile5(manifestPath, `${JSON.stringify(payload, null, "\t")}
10394
+ await writeFile6(manifestPath, `${JSON.stringify(payload, null, "\t")}
10216
10395
  `);
10217
10396
  }
10218
10397
  function agentNameFromToml2(fileName) {
@@ -10220,7 +10399,7 @@ function agentNameFromToml2(fileName) {
10220
10399
  }
10221
10400
  async function exists3(path) {
10222
10401
  try {
10223
- await lstat5(path);
10402
+ await lstat6(path);
10224
10403
  return true;
10225
10404
  } catch (error) {
10226
10405
  if (nodeErrorCode3(error) !== "ENOENT")
@@ -10235,8 +10414,8 @@ function nodeErrorCode3(error) {
10235
10414
  }
10236
10415
 
10237
10416
  // ../src/install/codex-cache-bins.ts
10238
- 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";
10239
- 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";
10240
10419
 
10241
10420
  // ../src/install/codex-cache-command-shim.ts
10242
10421
  var COMMAND_SHIM_MARKER = ":: generated by oh-my-openagent Codex installer";
@@ -10280,36 +10459,15 @@ function windowsCommandShim(targetPath) {
10280
10459
  }
10281
10460
 
10282
10461
  // ../src/install/codex-cache-dangling-bins.ts
10283
- import { lstat as lstat7, readFile as readFile7, readdir as readdir3, readlink as readlink2, rm as rm8, stat as stat3 } from "node:fs/promises";
10284
- import { dirname as dirname7, isAbsolute as isAbsolute3, join as join14, resolve as resolve5 } from "node:path";
10285
-
10286
- // ../src/install/codex-cache-fs.ts
10287
- import { lstat as lstat6 } from "node:fs/promises";
10288
- async function fileExistsStrict(path) {
10289
- try {
10290
- await lstat6(path);
10291
- return true;
10292
- } catch (error) {
10293
- if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10294
- return false;
10295
- throw error;
10296
- }
10297
- }
10298
- function isPlainRecord(value) {
10299
- return typeof value === "object" && value !== null && !Array.isArray(value);
10300
- }
10301
- function isNodeErrorWithCode(error) {
10302
- return typeof error === "object" && error !== null && "code" in error;
10303
- }
10304
-
10305
- // ../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";
10306
10464
  async function removeDanglingManagedComponentBins(binDir, platform, managedBinNames) {
10307
10465
  const entries = await readdir3(binDir, { withFileTypes: true });
10308
10466
  for (const entry of entries) {
10309
10467
  const binName = managedBinNameForEntry(entry.name, platform);
10310
10468
  if (binName === null || !managedBinNames.has(binName))
10311
10469
  continue;
10312
- const linkPath = join14(binDir, entry.name);
10470
+ const linkPath = join15(binDir, entry.name);
10313
10471
  if (platform === "win32") {
10314
10472
  await removeDanglingGeneratedCommandShim(linkPath);
10315
10473
  continue;
@@ -10330,7 +10488,7 @@ async function removeDanglingManagedSymlink(linkPath) {
10330
10488
  const linkTarget = await readlink2(linkPath);
10331
10489
  const target = isAbsolute3(linkTarget) ? linkTarget : resolve5(dirname7(linkPath), linkTarget);
10332
10490
  if (!await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
10333
- await rm8(linkPath, { force: true });
10491
+ await rm9(linkPath, { force: true });
10334
10492
  } catch (error) {
10335
10493
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10336
10494
  return;
@@ -10342,12 +10500,12 @@ async function removeDanglingGeneratedCommandShim(linkPath) {
10342
10500
  const linkStat = await lstat7(linkPath);
10343
10501
  if (!linkStat.isFile())
10344
10502
  return;
10345
- const content = await readFile7(linkPath, "utf8");
10503
+ const content = await readFile9(linkPath, "utf8");
10346
10504
  if (!content.includes(COMMAND_SHIM_MARKER))
10347
10505
  return;
10348
10506
  const target = extractCommandShimTarget(content);
10349
10507
  if (target !== null && !await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
10350
- await rm8(linkPath, { force: true });
10508
+ await rm9(linkPath, { force: true });
10351
10509
  } catch (error) {
10352
10510
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10353
10511
  return;
@@ -10390,8 +10548,8 @@ function hasOmoCodexPluginPrefix(parts, endExclusive) {
10390
10548
  }
10391
10549
 
10392
10550
  // ../src/install/codex-cache-legacy-bins.ts
10393
- import { lstat as lstat8, readFile as readFile8, readlink as readlink3, rm as rm9 } from "node:fs/promises";
10394
- 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";
10395
10553
  var LEGACY_CODEX_COMPONENT_BINS = [
10396
10554
  { name: "omo", component: "ulw-loop" },
10397
10555
  { name: "codex-comment-checker", component: "comment-checker" },
@@ -10404,7 +10562,7 @@ var LEGACY_CODEX_COMPONENT_BINS = [
10404
10562
  var LEGACY_CODEX_COMPONENT_BIN_NAMES = LEGACY_CODEX_COMPONENT_BINS.map((entry) => entry.name);
10405
10563
  async function removeLegacyCodexComponentBins(binDir, platform) {
10406
10564
  for (const entry of LEGACY_CODEX_COMPONENT_BINS) {
10407
- const linkPath = join15(binDir, platform === "win32" ? `${entry.name}.cmd` : entry.name);
10565
+ const linkPath = join16(binDir, platform === "win32" ? `${entry.name}.cmd` : entry.name);
10408
10566
  await removeLegacyCodexComponentBin(linkPath, entry.component, platform);
10409
10567
  }
10410
10568
  }
@@ -10416,14 +10574,14 @@ async function removeLegacyCodexComponentBin(linkPath, component, platform) {
10416
10574
  return;
10417
10575
  const target = await readlink3(linkPath);
10418
10576
  if (isManagedLegacyComponentTarget(target, component))
10419
- await rm9(linkPath, { force: true });
10577
+ await rm10(linkPath, { force: true });
10420
10578
  return;
10421
10579
  }
10422
10580
  if (!stat.isFile())
10423
10581
  return;
10424
- const content = await readFile8(linkPath, "utf8");
10582
+ const content = await readFile10(linkPath, "utf8");
10425
10583
  if (content.includes(COMMAND_SHIM_MARKER))
10426
- await rm9(linkPath, { force: true });
10584
+ await rm10(linkPath, { force: true });
10427
10585
  } catch (error) {
10428
10586
  if (isNodeErrorWithCode2(error) && error.code === "ENOENT")
10429
10587
  return;
@@ -10455,10 +10613,10 @@ function isNodeErrorWithCode2(error) {
10455
10613
  }
10456
10614
 
10457
10615
  // ../src/install/codex-cache-runtime-wrapper.ts
10458
- import { join as join16 } from "node:path";
10616
+ import { join as join17 } from "node:path";
10459
10617
  var RUNTIME_WRAPPER_MARKER = "OMO_GENERATED_RUNTIME_WRAPPER";
10460
10618
  function posixRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10461
- const ulwLoopBin = toPosixPath2(join16(binDir, "omo-ulw-loop"));
10619
+ const ulwLoopBin = toPosixPath2(join17(binDir, "omo-ulw-loop"));
10462
10620
  const nodeCli = escapePosixDoubleQuoted(toPosixPath2(nodeCliPath));
10463
10621
  const escapedCliPath = escapePosixDoubleQuoted(toPosixPath2(cliPath));
10464
10622
  const escapedCodexHome = escapePosixDoubleQuoted(toPosixPath2(codexHome));
@@ -10505,7 +10663,7 @@ function posixRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10505
10663
  `);
10506
10664
  }
10507
10665
  function windowsRuntimeWrapper(binName, cliPath, codexHome, binDir, nodeCliPath) {
10508
- const ulwLoopBin = join16(binDir, "omo-ulw-loop.cmd");
10666
+ const ulwLoopBin = join17(binDir, "omo-ulw-loop.cmd");
10509
10667
  return [
10510
10668
  "@echo off",
10511
10669
  `rem ${RUNTIME_WRAPPER_MARKER}`,
@@ -10571,23 +10729,23 @@ async function linkCachedPluginBins(input) {
10571
10729
  return linked;
10572
10730
  }
10573
10731
  async function linkRootRuntimeBin(input) {
10574
- const cliPath = join17(input.repoRoot, "dist", "cli", "index.js");
10732
+ const cliPath = join18(input.repoRoot, "dist", "cli", "index.js");
10575
10733
  const platform = input.platform ?? process.platform;
10576
- const legacyPath = join17(input.binDir, platform === "win32" ? "omo.cmd" : "omo");
10734
+ const legacyPath = join18(input.binDir, platform === "win32" ? "omo.cmd" : "omo");
10577
10735
  if (!await isFile2(cliPath)) {
10578
10736
  await removeGeneratedRuntimeWrapper(legacyPath);
10579
10737
  return null;
10580
10738
  }
10581
10739
  const binName = "omo-agent-toolkit";
10582
- const nodeCliPath = join17(input.repoRoot, "dist", "cli-node", "index.js");
10740
+ const nodeCliPath = join18(input.repoRoot, "dist", "cli-node", "index.js");
10583
10741
  await mkdir5(input.binDir, { recursive: true });
10584
10742
  if (platform === "win32") {
10585
- const linkPath = join17(input.binDir, `${binName}.cmd`);
10743
+ const linkPath = join18(input.binDir, `${binName}.cmd`);
10586
10744
  await replaceRuntimeWrapper(linkPath, windowsRuntimeWrapper(binName, cliPath, input.codexHome, input.binDir, nodeCliPath));
10587
10745
  await removeGeneratedRuntimeWrapper(legacyPath);
10588
10746
  return { name: binName, path: linkPath, target: cliPath };
10589
10747
  }
10590
- const linkPath = join17(input.binDir, binName);
10748
+ const linkPath = join18(input.binDir, binName);
10591
10749
  await replaceRuntimeWrapper(linkPath, posixRuntimeWrapper(binName, cliPath, input.codexHome, input.binDir, nodeCliPath));
10592
10750
  await chmod2(linkPath, 493);
10593
10751
  await removeGeneratedRuntimeWrapper(legacyPath);
@@ -10595,11 +10753,11 @@ async function linkRootRuntimeBin(input) {
10595
10753
  }
10596
10754
  async function linkCachedPluginBin(binDir, link, platform) {
10597
10755
  if (platform === "win32") {
10598
- const linkPath = join17(binDir, `${link.name}.cmd`);
10756
+ const linkPath = join18(binDir, `${link.name}.cmd`);
10599
10757
  await replaceCommandShim(linkPath, link.target);
10600
10758
  return linkPath;
10601
10759
  }
10602
- const linkPath = join17(binDir, link.name);
10760
+ const linkPath = join18(binDir, link.name);
10603
10761
  await replaceSymlink(linkPath, link.target);
10604
10762
  return linkPath;
10605
10763
  }
@@ -10620,21 +10778,21 @@ async function discoverPackageBins(root) {
10620
10778
  async function collectPackageBins(directory, root, links) {
10621
10779
  const entries = await readdir4(directory, { withFileTypes: true });
10622
10780
  if (entries.some((entry) => entry.isFile() && entry.name === "package.json")) {
10623
- await appendPackageBinLinks(join17(directory, "package.json"), directory, root, links);
10781
+ await appendPackageBinLinks(join18(directory, "package.json"), directory, root, links);
10624
10782
  }
10625
10783
  for (const entry of entries) {
10626
10784
  if (!entry.isDirectory())
10627
10785
  continue;
10628
10786
  if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")
10629
10787
  continue;
10630
- const childPath = join17(directory, entry.name);
10788
+ const childPath = join18(directory, entry.name);
10631
10789
  if (!childPath.startsWith(root))
10632
10790
  continue;
10633
10791
  await collectPackageBins(childPath, root, links);
10634
10792
  }
10635
10793
  }
10636
10794
  async function appendPackageBinLinks(packageJsonPath, packageRoot, root, links) {
10637
- const packageJson = JSON.parse(await readFile9(packageJsonPath, "utf8"));
10795
+ const packageJson = JSON.parse(await readFile11(packageJsonPath, "utf8"));
10638
10796
  if (!isPlainRecord(packageJson))
10639
10797
  return;
10640
10798
  const packageName = packageJson.name;
@@ -10680,19 +10838,19 @@ function resolvePackageBinTarget(packageRoot, target) {
10680
10838
  async function replaceSymlink(linkPath, targetPath) {
10681
10839
  if (await existingNonSymlink(linkPath))
10682
10840
  throw new Error(`${linkPath} already exists and is not a symlink`);
10683
- await rm10(linkPath, { force: true });
10841
+ await rm11(linkPath, { force: true });
10684
10842
  await symlink(targetPath, linkPath);
10685
10843
  }
10686
10844
  async function replaceCommandShim(linkPath, targetPath) {
10687
10845
  if (await existingNonShim(linkPath))
10688
10846
  throw new Error(`${linkPath} already exists and is not a command shim`);
10689
- await writeFile6(linkPath, windowsCommandShim(targetPath));
10847
+ await writeFile7(linkPath, windowsCommandShim(targetPath));
10690
10848
  }
10691
10849
  async function replaceRuntimeWrapper(linkPath, content) {
10692
10850
  if (await existingNonRuntimeWrapper(linkPath))
10693
10851
  throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
10694
- await rm10(linkPath, { force: true });
10695
- await writeFile6(linkPath, content);
10852
+ await rm11(linkPath, { force: true });
10853
+ await writeFile7(linkPath, content);
10696
10854
  }
10697
10855
  async function removeGeneratedRuntimeWrapper(path) {
10698
10856
  try {
@@ -10701,7 +10859,7 @@ async function removeGeneratedRuntimeWrapper(path) {
10701
10859
  return;
10702
10860
  const content = await readGeneratedWrapperContent(path);
10703
10861
  if (content.includes(RUNTIME_WRAPPER_MARKER))
10704
- await rm10(path, { force: true });
10862
+ await rm11(path, { force: true });
10705
10863
  } catch (error) {
10706
10864
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
10707
10865
  return;
@@ -10710,7 +10868,7 @@ async function removeGeneratedRuntimeWrapper(path) {
10710
10868
  }
10711
10869
  async function readGeneratedWrapperContent(path) {
10712
10870
  try {
10713
- return await readFile9(path, "utf8");
10871
+ return await readFile11(path, "utf8");
10714
10872
  } catch (error) {
10715
10873
  if (isNodeErrorWithCode(error) && (error.code === "ENOENT" || error.code === "EISDIR"))
10716
10874
  return "";
@@ -10724,7 +10882,7 @@ async function existingNonRuntimeWrapper(path) {
10724
10882
  return false;
10725
10883
  if (!stat.isFile())
10726
10884
  return true;
10727
- const content = await readFile9(path, "utf8");
10885
+ const content = await readFile11(path, "utf8");
10728
10886
  return !content.includes(RUNTIME_WRAPPER_MARKER);
10729
10887
  } catch (error) {
10730
10888
  if (isNodeErrorWithCode(error) && error.code === "ENOENT")
@@ -10737,7 +10895,7 @@ async function existingNonShim(path) {
10737
10895
  const stat = await lstat9(path);
10738
10896
  if (!stat.isFile())
10739
10897
  return true;
10740
- const content = await readFile9(path, "utf8");
10898
+ const content = await readFile11(path, "utf8");
10741
10899
  if (content.includes(COMMAND_SHIM_MARKER))
10742
10900
  return false;
10743
10901
  throw new Error(`${path} already exists and is not a generated command shim`);
@@ -10762,7 +10920,7 @@ async function existingNonSymlink(path) {
10762
10920
  }
10763
10921
 
10764
10922
  // ../src/install/codex-config-toml.ts
10765
- import { mkdir as mkdir6, readFile as readFile11 } from "node:fs/promises";
10923
+ import { mkdir as mkdir6, readFile as readFile13 } from "node:fs/promises";
10766
10924
  import { dirname as dirname9 } from "node:path";
10767
10925
 
10768
10926
  // ../src/install/toml-setting-reader.ts
@@ -11204,8 +11362,8 @@ function isRootSetting(line, key) {
11204
11362
  }
11205
11363
 
11206
11364
  // ../src/install/codex-model-catalog.ts
11207
- import { readFile as readFile10 } from "node:fs/promises";
11208
- import { join as join18 } from "node:path";
11365
+ import { readFile as readFile12 } from "node:fs/promises";
11366
+ import { join as join19 } from "node:path";
11209
11367
  var FALLBACK_CODEX_MODEL_CATALOG = {
11210
11368
  current: {
11211
11369
  model: "gpt-6-astra",
@@ -11236,9 +11394,9 @@ var FALLBACK_CODEX_MODEL_CATALOG = {
11236
11394
  ]
11237
11395
  };
11238
11396
  async function readCodexModelCatalog(codexPackageRoot) {
11239
- const catalogPath = join18(codexPackageRoot, "plugin", "model-catalog.json");
11397
+ const catalogPath = join19(codexPackageRoot, "plugin", "model-catalog.json");
11240
11398
  try {
11241
- const parsed = JSON.parse(await readFile10(catalogPath, "utf8"));
11399
+ const parsed = JSON.parse(await readFile12(catalogPath, "utf8"));
11242
11400
  return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
11243
11401
  } catch (error) {
11244
11402
  if (error instanceof Error)
@@ -11320,7 +11478,7 @@ function isRootSetting2(line, key) {
11320
11478
 
11321
11479
  // ../src/install/codex-multi-agent-v2-config.ts
11322
11480
  import { readFileSync as readFileSync2 } from "node:fs";
11323
- 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";
11324
11482
  var CODEX_AGENTS_HEADER = "agents";
11325
11483
  var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
11326
11484
  function ensureCodexMultiAgentV2Config(config, options = {}) {
@@ -11348,8 +11506,8 @@ function resolveCodexMultiAgentVersion(config, configPath) {
11348
11506
  }
11349
11507
  function resolveCatalogPath(configuredPath, configPath) {
11350
11508
  if (configuredPath === null)
11351
- return join19(dirname8(configPath), "models_cache.json");
11352
- 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);
11353
11511
  }
11354
11512
  function readCatalogMultiAgentVersion(model, cachePath) {
11355
11513
  let raw;
@@ -11463,7 +11621,7 @@ async function updateCodexConfig(input) {
11463
11621
  await mkdir6(dirname9(input.configPath), { recursive: true });
11464
11622
  let config;
11465
11623
  try {
11466
- config = await readFile11(input.configPath, "utf8");
11624
+ config = await readFile13(input.configPath, "utf8");
11467
11625
  } catch (error) {
11468
11626
  if (!isMissingFileError(error))
11469
11627
  throw error;
@@ -11509,14 +11667,14 @@ function isMissingFileError(error) {
11509
11667
  }
11510
11668
 
11511
11669
  // ../src/install/codex-git-bash-mcp-env.ts
11512
- import { readFile as readFile12, writeFile as writeFile7 } from "node:fs/promises";
11513
- 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";
11514
11672
  var GIT_BASH_ENV_KEY = "OMO_CODEX_GIT_BASH_PATH";
11515
11673
  async function stampGitBashMcpEnv(input) {
11516
- const manifestPath = join20(input.pluginRoot, ".mcp.json");
11674
+ const manifestPath = join21(input.pluginRoot, ".mcp.json");
11517
11675
  if (!await fileExistsStrict(manifestPath))
11518
11676
  return false;
11519
- const parsed = JSON.parse(await readFile12(manifestPath, "utf8"));
11677
+ const parsed = JSON.parse(await readFile14(manifestPath, "utf8"));
11520
11678
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed["mcpServers"]))
11521
11679
  return false;
11522
11680
  let changed = false;
@@ -11534,15 +11692,15 @@ async function stampGitBashMcpEnv(input) {
11534
11692
  }
11535
11693
  if (!changed)
11536
11694
  return false;
11537
- await writeFile7(manifestPath, `${JSON.stringify(parsed, null, "\t")}
11695
+ await writeFile8(manifestPath, `${JSON.stringify(parsed, null, "\t")}
11538
11696
  `);
11539
11697
  return true;
11540
11698
  }
11541
11699
 
11542
11700
  // ../src/install/codex-hook-trust.ts
11543
11701
  import { createHash as createHash4 } from "node:crypto";
11544
- import { readFile as readFile13 } from "node:fs/promises";
11545
- import { join as join21 } from "node:path";
11702
+ import { readFile as readFile15 } from "node:fs/promises";
11703
+ import { join as join22 } from "node:path";
11546
11704
  var EVENT_LABELS = new Map([
11547
11705
  ["PreToolUse", "pre_tool_use"],
11548
11706
  ["PermissionRequest", "permission_request"],
@@ -11556,18 +11714,18 @@ var EVENT_LABELS = new Map([
11556
11714
  ["Stop", "stop"]
11557
11715
  ]);
11558
11716
  async function trustedHookStatesForPlugin(input) {
11559
- const manifestPath = join21(input.pluginRoot, ".codex-plugin", "plugin.json");
11717
+ const manifestPath = join22(input.pluginRoot, ".codex-plugin", "plugin.json");
11560
11718
  if (!await exists4(manifestPath))
11561
11719
  return [];
11562
- const manifest = JSON.parse(await readFile13(manifestPath, "utf8"));
11720
+ const manifest = JSON.parse(await readFile15(manifestPath, "utf8"));
11563
11721
  if (!isPlainRecord(manifest))
11564
11722
  return [];
11565
11723
  const states = [];
11566
11724
  for (const hookPath of hookManifestPaths(manifest.hooks)) {
11567
- const hooksPath = join21(input.pluginRoot, hookPath);
11725
+ const hooksPath = join22(input.pluginRoot, hookPath);
11568
11726
  if (!await exists4(hooksPath))
11569
11727
  continue;
11570
- const parsed = JSON.parse(await readFile13(hooksPath, "utf8"));
11728
+ const parsed = JSON.parse(await readFile15(hooksPath, "utf8"));
11571
11729
  if (!isPlainRecord(parsed) || !isPlainRecord(parsed.hooks))
11572
11730
  continue;
11573
11731
  states.push(...trustedHookStatesForHooksFile({
@@ -11650,7 +11808,7 @@ function stripDotSlash(value) {
11650
11808
  }
11651
11809
  async function exists4(path) {
11652
11810
  try {
11653
- await readFile13(path, "utf8");
11811
+ await readFile15(path, "utf8");
11654
11812
  return true;
11655
11813
  } catch (error) {
11656
11814
  if (error instanceof Error)
@@ -11661,7 +11819,7 @@ async function exists4(path) {
11661
11819
 
11662
11820
  // ../src/install/codex-installer-bin-dir.ts
11663
11821
  import { homedir as homedir4 } from "node:os";
11664
- import { join as join22, resolve as resolve7 } from "node:path";
11822
+ import { join as join23, resolve as resolve7 } from "node:path";
11665
11823
  function resolveCodexInstallerBinDir(input) {
11666
11824
  const explicitBinDir = input.binDir ?? input.env?.CODEX_LOCAL_BIN_DIR;
11667
11825
  if (explicitBinDir !== undefined && explicitBinDir.trim().length > 0)
@@ -11670,7 +11828,7 @@ function resolveCodexInstallerBinDir(input) {
11670
11828
  const defaultCodexHome = resolve7(homeDir, ".codex");
11671
11829
  const resolvedCodexHome = resolve7(input.codexHome);
11672
11830
  if (resolvedCodexHome !== defaultCodexHome)
11673
- return join22(resolvedCodexHome, "bin");
11831
+ return join23(resolvedCodexHome, "bin");
11674
11832
  return resolve7(homeDir, ".local", "bin");
11675
11833
  }
11676
11834
 
@@ -11826,24 +11984,27 @@ async function resolveGitBashStep(options, degraded) {
11826
11984
  return false;
11827
11985
  }
11828
11986
  async function linkBundledAgentsStep(options) {
11829
- const agentsTarget = join23(options.codexHome, "agents");
11987
+ const agentsTarget = join24(options.codexHome, "agents");
11830
11988
  try {
11831
- const stageRoot = join23(options.pluginData, "bootstrap", "agents-stage");
11989
+ const stageRoot = join24(options.pluginData, "bootstrap", "agents-stage");
11832
11990
  await stageBundledAgents(options.pluginRoot, stageRoot);
11833
11991
  const preservedReasoning = await capturePreservedAgentReasoning({ codexHome: options.codexHome });
11834
11992
  const preservedServiceTier = await capturePreservedAgentServiceTier({ codexHome: options.codexHome });
11835
- const config = readDefaultRoleConfig({ env: options.env });
11993
+ const config = readCodexAgentConfig({ env: options.env });
11836
11994
  const linked = await linkCachedPluginAgents({
11837
11995
  codexHome: options.codexHome,
11838
11996
  pluginRoot: stageRoot,
11839
11997
  preservedReasoning,
11840
11998
  preservedServiceTier,
11841
- defaultRoleEnabled: config.enabled
11999
+ defaultRoleEnabled: config.defaultRoleEnabled,
12000
+ agentOverrides: config.agentOverrides
11842
12001
  });
12002
+ const managedAgentNames = new Set(linked.map((link) => agentNameFromToml3(link.name)));
12003
+ const warnings = [...config.warnings, ...unmanagedAgentOverrideWarnings(config.agentOverrides, managedAgentNames)];
11843
12004
  const agentConfigs = linked.map((link) => ({ configFile: `./agents/${link.name}`, name: agentNameFromToml3(link.name) })).sort((left, right) => left.name.localeCompare(right.name));
11844
12005
  return {
11845
12006
  agentConfigs,
11846
- 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 }))
11847
12008
  };
11848
12009
  } catch (error) {
11849
12010
  return {
@@ -11859,23 +12020,23 @@ async function linkBundledAgentsStep(options) {
11859
12020
  }
11860
12021
  }
11861
12022
  async function stageBundledAgents(pluginRoot, stageRoot) {
11862
- await rm11(stageRoot, { force: true, recursive: true });
12023
+ await rm12(stageRoot, { force: true, recursive: true });
11863
12024
  await mkdir7(stageRoot, { recursive: true });
11864
- const componentsRoot = join23(pluginRoot, "components");
12025
+ const componentsRoot = join24(pluginRoot, "components");
11865
12026
  for (const componentName of await directoryNames(componentsRoot)) {
11866
- const agentsDir = join23(componentsRoot, componentName, "agents");
12027
+ const agentsDir = join24(componentsRoot, componentName, "agents");
11867
12028
  const agentFiles = (await fileNames(agentsDir)).filter((name) => name.endsWith(".toml"));
11868
12029
  if (agentFiles.length === 0)
11869
12030
  continue;
11870
- const stagedAgentsDir = join23(stageRoot, "components", componentName, "agents");
12031
+ const stagedAgentsDir = join24(stageRoot, "components", componentName, "agents");
11871
12032
  await mkdir7(stagedAgentsDir, { recursive: true });
11872
12033
  for (const agentFile of agentFiles) {
11873
- await copyFile2(join23(agentsDir, agentFile), join23(stagedAgentsDir, agentFile));
12034
+ await copyFile2(join24(agentsDir, agentFile), join24(stagedAgentsDir, agentFile));
11874
12035
  }
11875
12036
  }
11876
12037
  }
11877
12038
  async function updateConfigStep(options, inputs, degraded) {
11878
- const configPath = join23(options.codexHome, "config.toml");
12039
+ const configPath = join24(options.codexHome, "config.toml");
11879
12040
  try {
11880
12041
  await assertWritableConfigIfPresent(configPath);
11881
12042
  const existingConfig = await readConfigIfPresent(configPath);
@@ -11921,7 +12082,7 @@ function errorCode(error) {
11921
12082
  }
11922
12083
  async function readConfigIfPresent(configPath) {
11923
12084
  try {
11924
- return await readFile14(configPath, "utf8");
12085
+ return await readFile16(configPath, "utf8");
11925
12086
  } catch (error) {
11926
12087
  if (errorCode(error) === "ENOENT")
11927
12088
  return "";
@@ -11942,7 +12103,7 @@ async function linkComponentBinsStep(options, degraded) {
11942
12103
  await linkRuntimeWrapperStep(options, binDir, degraded);
11943
12104
  }
11944
12105
  async function linkRuntimeWrapperStep(options, binDir, degraded) {
11945
- const cliPath = join23(options.pluginRoot, "dist", "cli", "index.js");
12106
+ const cliPath = join24(options.pluginRoot, "dist", "cli", "index.js");
11946
12107
  try {
11947
12108
  const linked = await linkRootRuntimeBin({
11948
12109
  binDir,
@@ -11975,7 +12136,7 @@ async function stampGitBashEnvStep(options, degraded) {
11975
12136
  degraded.push({
11976
12137
  component: "git-bash-env",
11977
12138
  hint: BOOTSTRAP_DOCTOR_HINT,
11978
- reason: `failed to stamp ${join23(options.pluginRoot, ".mcp.json")}: ${errorMessage(error)}`
12139
+ reason: `failed to stamp ${join24(options.pluginRoot, ".mcp.json")}: ${errorMessage(error)}`
11979
12140
  });
11980
12141
  }
11981
12142
  }
@@ -12043,11 +12204,11 @@ function resolvePluginDataRoot(env) {
12043
12204
  const fromEnv = env["PLUGIN_DATA"]?.trim();
12044
12205
  if (fromEnv !== undefined && fromEnv.length > 0)
12045
12206
  return fromEnv;
12046
- return join24(homedir5(), ".local", "share", "lazycodex");
12207
+ return join25(homedir5(), ".local", "share", "lazycodex");
12047
12208
  }
12048
12209
  async function readPluginVersion(pluginRoot) {
12049
12210
  try {
12050
- 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"));
12051
12212
  if (typeof parsed !== "object" || parsed === null)
12052
12213
  return;
12053
12214
  const version = parsed["version"];
@@ -12117,7 +12278,7 @@ async function runBootstrapWorker(options = {}) {
12117
12278
  degraded.push({
12118
12279
  component: "bootstrap",
12119
12280
  hint: BOOTSTRAP_DOCTOR_HINT,
12120
- reason: `plugin version unresolved from ${join24(pluginRoot, ".codex-plugin", "plugin.json")}`
12281
+ reason: `plugin version unresolved from ${join25(pluginRoot, ".codex-plugin", "plugin.json")}`
12121
12282
  });
12122
12283
  }
12123
12284
  for (const step of steps) {
@@ -12160,7 +12321,7 @@ function resolvePluginRoot(env) {
12160
12321
  }
12161
12322
  async function appendBootstrapLog(pluginData, now, event, details) {
12162
12323
  try {
12163
- const logPath = join24(pluginData, "bootstrap", "bootstrap.log");
12324
+ const logPath = join25(pluginData, "bootstrap", "bootstrap.log");
12164
12325
  await mkdir8(dirname10(logPath), { recursive: true });
12165
12326
  await appendFile2(logPath, `${JSON.stringify({ timestamp: new Date(now).toISOString(), event, ...details })}
12166
12327
  `);