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.
- package/dist/cli/index.js +672 -464
- package/dist/cli-node/index.js +672 -464
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +315 -154
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +7 -4
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +10441 -10269
- 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
|
|
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
|
|
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
|
|
1004
|
-
import { join as
|
|
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-
|
|
8995
|
-
|
|
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
|
-
|
|
8999
|
-
|
|
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
|
|
9005
|
-
import { basename as basename4, join as
|
|
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
|
|
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
|
|
9910
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
10088
|
+
const agentPath = join11(agentsDir, retiredAgent.fileName);
|
|
9927
10089
|
if (!await exists2(agentPath))
|
|
9928
10090
|
continue;
|
|
9929
|
-
const agentStat = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
9969
|
-
import { join as
|
|
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
|
|
9973
|
-
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute2, join as
|
|
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 =
|
|
9979
|
-
await
|
|
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
|
|
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 =
|
|
10085
|
-
const receipt =
|
|
10086
|
-
const configPath =
|
|
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
|
|
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
|
|
10110
|
-
await
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
10154
|
-
await
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
10389
|
+
await rm8(linkPath, { force: true });
|
|
10211
10390
|
}
|
|
10212
10391
|
async function writeManifest(pluginRoot, agentPaths) {
|
|
10213
|
-
const manifestPath =
|
|
10392
|
+
const manifestPath = join14(pluginRoot, MANIFEST_FILE);
|
|
10214
10393
|
const payload = { agents: [...agentPaths].sort() };
|
|
10215
|
-
await
|
|
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
|
|
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
|
|
10239
|
-
import { basename as basename5, isAbsolute as isAbsolute4, join as
|
|
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
|
|
10284
|
-
import { dirname as dirname7, isAbsolute as isAbsolute3, join as
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10394
|
-
import { join as
|
|
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 =
|
|
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
|
|
10577
|
+
await rm10(linkPath, { force: true });
|
|
10420
10578
|
return;
|
|
10421
10579
|
}
|
|
10422
10580
|
if (!stat.isFile())
|
|
10423
10581
|
return;
|
|
10424
|
-
const content = await
|
|
10582
|
+
const content = await readFile10(linkPath, "utf8");
|
|
10425
10583
|
if (content.includes(COMMAND_SHIM_MARKER))
|
|
10426
|
-
await
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
10732
|
+
const cliPath = join18(input.repoRoot, "dist", "cli", "index.js");
|
|
10575
10733
|
const platform = input.platform ?? process.platform;
|
|
10576
|
-
const legacyPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
10756
|
+
const linkPath = join18(binDir, `${link.name}.cmd`);
|
|
10599
10757
|
await replaceCommandShim(linkPath, link.target);
|
|
10600
10758
|
return linkPath;
|
|
10601
10759
|
}
|
|
10602
|
-
const linkPath =
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10695
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
11208
|
-
import { join as
|
|
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 =
|
|
11397
|
+
const catalogPath = join19(codexPackageRoot, "plugin", "model-catalog.json");
|
|
11240
11398
|
try {
|
|
11241
|
-
const parsed = JSON.parse(await
|
|
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
|
|
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
|
|
11352
|
-
return isAbsolute5(configuredPath) ? 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
|
|
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
|
|
11513
|
-
import { join as
|
|
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 =
|
|
11674
|
+
const manifestPath = join21(input.pluginRoot, ".mcp.json");
|
|
11517
11675
|
if (!await fileExistsStrict(manifestPath))
|
|
11518
11676
|
return false;
|
|
11519
|
-
const parsed = JSON.parse(await
|
|
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
|
|
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
|
|
11545
|
-
import { join as
|
|
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 =
|
|
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
|
|
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 =
|
|
11725
|
+
const hooksPath = join22(input.pluginRoot, hookPath);
|
|
11568
11726
|
if (!await exists4(hooksPath))
|
|
11569
11727
|
continue;
|
|
11570
|
-
const parsed = JSON.parse(await
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
11987
|
+
const agentsTarget = join24(options.codexHome, "agents");
|
|
11830
11988
|
try {
|
|
11831
|
-
const stageRoot =
|
|
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 =
|
|
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.
|
|
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:
|
|
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
|
|
12023
|
+
await rm12(stageRoot, { force: true, recursive: true });
|
|
11863
12024
|
await mkdir7(stageRoot, { recursive: true });
|
|
11864
|
-
const componentsRoot =
|
|
12025
|
+
const componentsRoot = join24(pluginRoot, "components");
|
|
11865
12026
|
for (const componentName of await directoryNames(componentsRoot)) {
|
|
11866
|
-
const agentsDir =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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 =
|
|
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 ${
|
|
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
|
|
12207
|
+
return join25(homedir5(), ".local", "share", "lazycodex");
|
|
12047
12208
|
}
|
|
12048
12209
|
async function readPluginVersion(pluginRoot) {
|
|
12049
12210
|
try {
|
|
12050
|
-
const parsed = JSON.parse(await
|
|
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 ${
|
|
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 =
|
|
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
|
`);
|