oh-my-opencode 4.16.3 → 4.17.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/.agents/command/omomomo.md +1 -1
- package/.agents/command/publish.md +31 -58
- package/.agents/skills/hyperplan/SKILL.md +3 -3
- package/.agents/skills/omomomo/SKILL.md +1 -1
- package/.agents/skills/pre-publish-review/SKILL.md +1 -1
- package/.agents/skills/publish/SKILL.md +32 -59
- package/.opencode/command/omomomo.md +1 -1
- package/.opencode/command/publish.md +31 -58
- package/.opencode/skills/hyperplan/SKILL.md +3 -3
- package/.opencode/skills/pre-publish-review/SKILL.md +4 -1
- package/README.ja.md +4 -4
- package/README.ko.md +4 -4
- package/README.md +2 -2
- package/README.ru.md +4 -4
- package/README.zh-cn.md +4 -4
- package/dist/cli/index.js +195 -76
- package/dist/cli-node/index.js +195 -76
- package/dist/features/team-mode/test-support/async-test-helpers.d.ts +2 -2
- package/dist/index.js +310 -299
- package/dist/plugin/chat-message/types.d.ts +4 -0
- package/dist/plugin/command-execute-before.d.ts +1 -0
- package/dist/plugin/stop-continuation.d.ts +17 -0
- package/dist/skills/remove-ai-slops/SKILL.md +2 -2
- package/dist/skills/review-work/SKILL.md +10 -2
- package/dist/skills/start-work/SKILL.md +6 -3
- package/dist/skills/ultimate-browsing/ATTRIBUTION.md +2 -2
- package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/dist/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
- package/dist/skills/ulw-plan/SKILL.md +2 -1
- package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
- package/dist/skills/ulw-plan/references/intent-unclear.md +4 -4
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/dist/skills/visual-qa/SKILL.md +9 -5
- package/dist/tui.js +79 -32
- package/package.json +15 -14
- package/packages/git-bash-mcp/package.json +27 -0
- package/packages/lsp-daemon/dist/cli.js +7 -13
- package/packages/lsp-daemon/dist/daemon-client.js +3 -5
- package/packages/lsp-daemon/dist/index.js +12 -18
- package/packages/lsp-daemon/dist/request-routing.js +6 -8
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +1080 -1017
- 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/codegraph/package.json +1 -1
- 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/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +6 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +6 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +6 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +67 -2
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +14 -14
- 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/lsp/test/package-smoke.test.ts +0 -13
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +2 -2
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +3 -3
- 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/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -79
- package/packages/omo-codex/plugin/components/teammode/AGENTS.md +2 -2
- 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/teammode/skills/teammode/SKILL.md +33 -16
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +2 -1
- package/packages/omo-codex/plugin/components/teammode/test/v2-spawn-schema.test.ts +69 -0
- 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/agents/explorer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +6 -6
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +6 -4
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +7 -7
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +76 -37
- 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/ultrawork/skills/ultrawork/SKILL.md +76 -37
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +25 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -68
- package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +76 -37
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +6 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +405 -25
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +16 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +20 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +12 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +148 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +209 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +25 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -15
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +30 -28
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +14 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +10 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +27 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +23 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +16 -9
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +138 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +208 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +12 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +4 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +8 -35
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +24 -13
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +43 -8
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +55 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +228 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +193 -0
- 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-codegraph-init-guidance.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/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +18 -0
- 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-checking-codegraph-bootstrap.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-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +17 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -2
- 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/model-catalog.json +16 -7
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +8 -2
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +18 -4
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +6 -3
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +33 -16
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +2 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +76 -37
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +30 -28
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +4 -4
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +11 -7
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +76 -16
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +14 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +11 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +5 -3
- package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +25 -0
- package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +24 -0
- package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +9 -40
- package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +4 -277
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +5 -5
- package/packages/omo-codex/scripts/install-config.test.mjs +22 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +98 -30
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
- package/packages/shared-skills/skills/review-work/SKILL.md +10 -2
- package/packages/shared-skills/skills/start-work/SKILL.md +6 -3
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +4 -4
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/packages/shared-skills/skills/visual-qa/SKILL.md +9 -5
- package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
- package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +0 -70
- package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +0 -98
- package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
|
@@ -875,1172 +875,1229 @@ import { basename as basename3, join as join10 } from "node:path";
|
|
|
875
875
|
import { lstat, readFile as readFile4, readdir, writeFile as writeFile3 } from "node:fs/promises";
|
|
876
876
|
import { join as join8 } from "node:path";
|
|
877
877
|
|
|
878
|
-
// ../src/install/
|
|
879
|
-
|
|
880
|
-
[
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
{
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
[
|
|
895
|
-
"momus",
|
|
896
|
-
{
|
|
897
|
-
previous: { model: "gpt-5.5", effort: "xhigh" },
|
|
898
|
-
current: { model: "gpt-5.6-sol", effort: "ultra" }
|
|
899
|
-
}
|
|
900
|
-
]
|
|
901
|
-
]);
|
|
902
|
-
function resolveManagedAgentReasoning(input) {
|
|
903
|
-
const upgrade = MANAGED_REASONING_DEFAULT_UPGRADES.get(input.agentName);
|
|
904
|
-
if (upgrade !== undefined && input.preserved.model === upgrade.previous.model && input.preserved.effort === upgrade.previous.effort && input.bundledModel === upgrade.current.model && input.bundledEffort === upgrade.current.effort) {
|
|
905
|
-
return upgrade.current.effort;
|
|
906
|
-
}
|
|
907
|
-
return input.preserved.effort;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
// ../src/install/preserved-agent-settings.ts
|
|
911
|
-
async function capturePreservedAgentReasoning(input) {
|
|
912
|
-
const agentsDir = join8(input.codexHome, "agents");
|
|
913
|
-
if (!await exists(agentsDir))
|
|
914
|
-
return new Map;
|
|
915
|
-
const preserved = new Map;
|
|
916
|
-
const agentEntries = await readdir(agentsDir, { withFileTypes: true });
|
|
917
|
-
for (const entry of agentEntries) {
|
|
918
|
-
if (!entry.name.endsWith(".toml"))
|
|
919
|
-
continue;
|
|
920
|
-
const content = await readTextIfExists(join8(agentsDir, entry.name));
|
|
921
|
-
if (content === null)
|
|
922
|
-
continue;
|
|
923
|
-
const effort = extractReasoningEffort(content);
|
|
924
|
-
if (effort !== null) {
|
|
925
|
-
preserved.set(agentNameFromToml(entry.name), {
|
|
926
|
-
model: extractModel(content),
|
|
927
|
-
effort
|
|
928
|
-
});
|
|
878
|
+
// ../src/install/toml-section-editor.ts
|
|
879
|
+
function findTomlSection(config, header) {
|
|
880
|
+
const headerLine = `[${header}]`;
|
|
881
|
+
const targetHeaderPath = parseTomlDottedKey(header);
|
|
882
|
+
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
883
|
+
let offset = 0;
|
|
884
|
+
let start = -1;
|
|
885
|
+
for (const line of lines) {
|
|
886
|
+
if (line.length === 0)
|
|
887
|
+
break;
|
|
888
|
+
const trimmed = line.trim();
|
|
889
|
+
if (start === -1) {
|
|
890
|
+
if (tomlTableHeaderMatches(trimmed, headerLine, targetHeaderPath))
|
|
891
|
+
start = offset;
|
|
892
|
+
} else if (isTomlTableHeaderLine(line)) {
|
|
893
|
+
return { start, end: offset, text: config.slice(start, offset) };
|
|
929
894
|
}
|
|
895
|
+
offset += line.length;
|
|
930
896
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
const agentsDir = join8(input.codexHome, "agents");
|
|
935
|
-
if (!await exists(agentsDir))
|
|
936
|
-
return new Map;
|
|
937
|
-
const preserved = new Map;
|
|
938
|
-
const agentEntries = await readdir(agentsDir, { withFileTypes: true });
|
|
939
|
-
for (const entry of agentEntries) {
|
|
940
|
-
if (!entry.name.endsWith(".toml"))
|
|
941
|
-
continue;
|
|
942
|
-
const content = await readTextIfExists(join8(agentsDir, entry.name));
|
|
943
|
-
if (content === null)
|
|
944
|
-
continue;
|
|
945
|
-
preserved.set(agentNameFromToml(entry.name), extractServiceTier(content));
|
|
946
|
-
}
|
|
947
|
-
return preserved;
|
|
948
|
-
}
|
|
949
|
-
async function restorePreservedReasoning(input) {
|
|
950
|
-
if (input.value === undefined)
|
|
951
|
-
return;
|
|
952
|
-
const content = await readFile4(input.target, "utf8");
|
|
953
|
-
const bundledEffort = extractReasoningEffort(content);
|
|
954
|
-
const effort = resolveManagedAgentReasoning({
|
|
955
|
-
agentName: input.agentName,
|
|
956
|
-
bundledModel: extractModel(content),
|
|
957
|
-
bundledEffort,
|
|
958
|
-
preserved: input.value
|
|
959
|
-
});
|
|
960
|
-
if (bundledEffort === effort)
|
|
961
|
-
return;
|
|
962
|
-
const replacement = replaceTopLevelStringSetting(content, "model_reasoning_effort", effort, { insertIfMissing: false });
|
|
963
|
-
if (!replacement.replaced)
|
|
964
|
-
return;
|
|
965
|
-
await writeFile3(input.linkPath, replacement.content);
|
|
966
|
-
}
|
|
967
|
-
async function restorePreservedServiceTier(input) {
|
|
968
|
-
if (!input.preserved)
|
|
969
|
-
return;
|
|
970
|
-
const content = await readFile4(input.linkPath, "utf8");
|
|
971
|
-
if (extractServiceTier(content) === input.value)
|
|
972
|
-
return;
|
|
973
|
-
const replacement = replaceTopLevelStringSetting(content, "service_tier", input.value, { insertIfMissing: true });
|
|
974
|
-
if (!replacement.replaced)
|
|
975
|
-
return;
|
|
976
|
-
await writeFile3(input.linkPath, replacement.content);
|
|
977
|
-
}
|
|
978
|
-
async function readTextIfExists(path) {
|
|
979
|
-
try {
|
|
980
|
-
return await readFile4(path, "utf8");
|
|
981
|
-
} catch (error) {
|
|
982
|
-
if (nodeErrorCode(error) === "ENOENT")
|
|
983
|
-
return null;
|
|
984
|
-
throw error;
|
|
985
|
-
}
|
|
897
|
+
if (start === -1)
|
|
898
|
+
return null;
|
|
899
|
+
return { start, end: config.length, text: config.slice(start) };
|
|
986
900
|
}
|
|
987
|
-
function
|
|
988
|
-
|
|
901
|
+
function replaceOrInsertSetting(config, section, key, value) {
|
|
902
|
+
const linePattern = new RegExp(`^[ \\t]*${escapeRegExp(key)}[ \\t]*=.*$`, "m");
|
|
903
|
+
const replacement = linePattern.test(section.text) ? section.text.replace(linePattern, `${key} = ${value}`) : insertSetting(section.text, key, value);
|
|
904
|
+
return config.slice(0, section.start) + replacement + config.slice(section.end);
|
|
989
905
|
}
|
|
990
|
-
function
|
|
991
|
-
|
|
906
|
+
function removeSetting(config, section, key) {
|
|
907
|
+
const linePattern = new RegExp(`^[ \\t]*${escapeRegExp(key)}[ \\t]*=.*(?:\\n|$)`, "m");
|
|
908
|
+
const replacement = section.text.replace(linePattern, "");
|
|
909
|
+
return config.slice(0, section.start) + replacement + config.slice(section.end);
|
|
992
910
|
}
|
|
993
|
-
function
|
|
994
|
-
|
|
911
|
+
function replaceOrInsertRootSetting(config, key, value) {
|
|
912
|
+
const sectionStart = findFirstTableStart(config);
|
|
913
|
+
const root = config.slice(0, sectionStart);
|
|
914
|
+
const suffix = config.slice(sectionStart);
|
|
915
|
+
const linePattern = new RegExp(`^[ \\t]*${escapeRegExp(key)}[ \\t]*=.*$`, "m");
|
|
916
|
+
const replacement = linePattern.test(root) ? root.replace(linePattern, `${key} = ${value}`) : `${root.trimEnd()}${root.trimEnd().length > 0 ? `
|
|
917
|
+
` : ""}${key} = ${value}
|
|
918
|
+
`;
|
|
919
|
+
if (suffix.length === 0)
|
|
920
|
+
return replacement;
|
|
921
|
+
return `${replacement.trimEnd()}
|
|
922
|
+
|
|
923
|
+
${suffix.trimStart()}`;
|
|
995
924
|
}
|
|
996
|
-
function
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
continue;
|
|
1003
|
-
const parsed = parseJsonString(rawValue);
|
|
1004
|
-
if (parsed !== null)
|
|
1005
|
-
return parsed;
|
|
1006
|
-
}
|
|
1007
|
-
return null;
|
|
925
|
+
function appendBlock(config, block) {
|
|
926
|
+
const prefix = config.trimEnd();
|
|
927
|
+
return `${prefix}${prefix.length > 0 ? `
|
|
928
|
+
|
|
929
|
+
` : ""}${block.trimEnd()}
|
|
930
|
+
`;
|
|
1008
931
|
}
|
|
1009
|
-
function
|
|
1010
|
-
const lines =
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
if (line ===
|
|
932
|
+
function findFirstTableStart(config) {
|
|
933
|
+
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
934
|
+
let offset = 0;
|
|
935
|
+
for (const line of lines) {
|
|
936
|
+
if (line.length === 0)
|
|
1014
937
|
break;
|
|
1015
|
-
if (
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
lines.splice(index, 1);
|
|
1019
|
-
return { content: lines.join(`
|
|
1020
|
-
`), replaced: true };
|
|
1021
|
-
}
|
|
1022
|
-
lines[index] = line.replace(/=\s*"(?:[^"\\]|\\.)*"/, `= ${JSON.stringify(value)}`);
|
|
1023
|
-
return { content: lines.join(`
|
|
1024
|
-
`), replaced: true };
|
|
1025
|
-
}
|
|
1026
|
-
if (value === null || !options.insertIfMissing)
|
|
1027
|
-
return { content, replaced: false };
|
|
1028
|
-
lines.splice(topLevelInsertionIndex(lines), 0, `${key} = ${JSON.stringify(value)}`);
|
|
1029
|
-
return { content: lines.join(`
|
|
1030
|
-
`), replaced: true };
|
|
1031
|
-
}
|
|
1032
|
-
function topLevelStringSettingRawValue(line, key) {
|
|
1033
|
-
const match = line.match(/^\s*([A-Za-z0-9_]+)\s*=\s*("(?:[^"\\]|\\.)*")/);
|
|
1034
|
-
if (match === null)
|
|
1035
|
-
return;
|
|
1036
|
-
const settingKey = match[1];
|
|
1037
|
-
const rawValue = match[2];
|
|
1038
|
-
if (settingKey !== key || rawValue === undefined)
|
|
1039
|
-
return;
|
|
1040
|
-
return rawValue;
|
|
1041
|
-
}
|
|
1042
|
-
function topLevelInsertionIndex(lines) {
|
|
1043
|
-
const sectionIndex = lines.findIndex((line) => isSectionHeader(line));
|
|
1044
|
-
const topLevelEnd = sectionIndex === -1 ? lines.length : sectionIndex;
|
|
1045
|
-
let insertionIndex = topLevelEnd;
|
|
1046
|
-
while (insertionIndex > 0 && lines[insertionIndex - 1] === "") {
|
|
1047
|
-
insertionIndex -= 1;
|
|
938
|
+
if (isTomlTableHeaderLine(line))
|
|
939
|
+
return offset;
|
|
940
|
+
offset += line.length;
|
|
1048
941
|
}
|
|
1049
|
-
return
|
|
1050
|
-
}
|
|
1051
|
-
function isSectionHeader(line) {
|
|
1052
|
-
const trimmed = line.trim();
|
|
1053
|
-
return trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
942
|
+
return config.length;
|
|
1054
943
|
}
|
|
1055
|
-
function
|
|
1056
|
-
|
|
944
|
+
function insertSetting(sectionText, key, value) {
|
|
945
|
+
const lines = sectionText.split(`
|
|
946
|
+
`);
|
|
947
|
+
lines.splice(1, 0, `${key} = ${value}`);
|
|
948
|
+
return lines.join(`
|
|
949
|
+
`);
|
|
1057
950
|
}
|
|
1058
|
-
function
|
|
1059
|
-
|
|
1060
|
-
const parsed = JSON.parse(value);
|
|
1061
|
-
return typeof parsed === "string" ? parsed : null;
|
|
1062
|
-
} catch (error) {
|
|
1063
|
-
if (error instanceof Error)
|
|
1064
|
-
return null;
|
|
1065
|
-
return null;
|
|
1066
|
-
}
|
|
951
|
+
function escapeRegExp(value) {
|
|
952
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1067
953
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
954
|
+
function tomlTableHeaderMatches(line, headerLine, targetHeaderPath) {
|
|
955
|
+
const normalizedLine = stripUnquotedInlineComment(line).trim();
|
|
956
|
+
if (normalizedLine === headerLine)
|
|
1071
957
|
return true;
|
|
1072
|
-
|
|
1073
|
-
if (nodeErrorCode(error) !== "ENOENT")
|
|
1074
|
-
throw error;
|
|
958
|
+
if (!targetHeaderPath)
|
|
1075
959
|
return false;
|
|
1076
|
-
|
|
960
|
+
const candidateHeaderPath = parseTomlTableHeader(normalizedLine);
|
|
961
|
+
if (!candidateHeaderPath || candidateHeaderPath.length !== targetHeaderPath.length)
|
|
962
|
+
return false;
|
|
963
|
+
return candidateHeaderPath.every((part, index) => part === targetHeaderPath[index]);
|
|
1077
964
|
}
|
|
1078
|
-
function
|
|
1079
|
-
|
|
965
|
+
function parseTomlTableHeader(line) {
|
|
966
|
+
const normalizedLine = stripUnquotedInlineComment(line).trim();
|
|
967
|
+
if (!normalizedLine.startsWith("[") || !normalizedLine.endsWith("]") || normalizedLine.startsWith("[["))
|
|
1080
968
|
return null;
|
|
1081
|
-
return
|
|
969
|
+
return parseTomlDottedKey(normalizedLine.slice(1, -1).trim());
|
|
1082
970
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
return;
|
|
1101
|
-
for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
|
|
1102
|
-
const agentPath = join9(agentsDir, retiredAgent.fileName);
|
|
1103
|
-
if (!await exists2(agentPath))
|
|
971
|
+
function isTomlTableHeaderLine(line) {
|
|
972
|
+
const normalizedLine = stripUnquotedInlineComment(line).trim();
|
|
973
|
+
return normalizedLine.startsWith("[") && normalizedLine.endsWith("]");
|
|
974
|
+
}
|
|
975
|
+
function stripUnquotedInlineComment(line) {
|
|
976
|
+
let quote = null;
|
|
977
|
+
let index = 0;
|
|
978
|
+
while (index < line.length) {
|
|
979
|
+
const char = line[index];
|
|
980
|
+
if (quote === '"') {
|
|
981
|
+
if (char === "\\") {
|
|
982
|
+
index += 2;
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
if (char === '"')
|
|
986
|
+
quote = null;
|
|
987
|
+
index += 1;
|
|
1104
988
|
continue;
|
|
1105
|
-
|
|
1106
|
-
if (
|
|
989
|
+
}
|
|
990
|
+
if (quote === "'") {
|
|
991
|
+
if (char === "'")
|
|
992
|
+
quote = null;
|
|
993
|
+
index += 1;
|
|
1107
994
|
continue;
|
|
1108
|
-
|
|
1109
|
-
if (
|
|
995
|
+
}
|
|
996
|
+
if (char === '"' || char === "'") {
|
|
997
|
+
quote = char;
|
|
998
|
+
index += 1;
|
|
1110
999
|
continue;
|
|
1111
|
-
|
|
1000
|
+
}
|
|
1001
|
+
if (char === "#")
|
|
1002
|
+
return line.slice(0, index);
|
|
1003
|
+
index += 1;
|
|
1112
1004
|
}
|
|
1005
|
+
return line;
|
|
1113
1006
|
}
|
|
1114
|
-
function
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
if (nodeErrorCode2(error) === "ENOENT")
|
|
1007
|
+
function parseTomlDottedKey(input) {
|
|
1008
|
+
const parts = [];
|
|
1009
|
+
let index = 0;
|
|
1010
|
+
while (index < input.length) {
|
|
1011
|
+
index = skipWhitespace(input, index);
|
|
1012
|
+
const parsedKey = parseTomlKeyPart(input, index);
|
|
1013
|
+
if (!parsedKey)
|
|
1122
1014
|
return null;
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
if (nodeErrorCode2(error) !== "ENOENT")
|
|
1132
|
-
throw error;
|
|
1133
|
-
return false;
|
|
1015
|
+
parts.push(parsedKey.value);
|
|
1016
|
+
index = skipWhitespace(input, parsedKey.nextIndex);
|
|
1017
|
+
if (index === input.length)
|
|
1018
|
+
return parts;
|
|
1019
|
+
if (input[index] !== ".")
|
|
1020
|
+
return null;
|
|
1021
|
+
index += 1;
|
|
1134
1022
|
}
|
|
1023
|
+
return parts.length > 0 ? parts : null;
|
|
1135
1024
|
}
|
|
1136
|
-
function
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1025
|
+
function parseTomlKeyPart(input, startIndex) {
|
|
1026
|
+
const quote = input[startIndex];
|
|
1027
|
+
if (quote === "'")
|
|
1028
|
+
return parseLiteralTomlString(input, startIndex);
|
|
1029
|
+
if (quote === '"')
|
|
1030
|
+
return parseBasicTomlString(input, startIndex);
|
|
1031
|
+
return parseBareTomlKey(input, startIndex);
|
|
1140
1032
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
}
|
|
1151
|
-
const agentsDir = join10(input.codexHome, "agents");
|
|
1152
|
-
await mkdir4(agentsDir, { recursive: true });
|
|
1153
|
-
const linked = [];
|
|
1154
|
-
for (const agentPath of bundledAgents) {
|
|
1155
|
-
const agentFileName = basename3(agentPath);
|
|
1156
|
-
const agentName = agentNameFromToml2(agentFileName);
|
|
1157
|
-
const linkPath = join10(agentsDir, agentFileName);
|
|
1158
|
-
await replaceWithCopy(linkPath, agentPath);
|
|
1159
|
-
await restorePreservedReasoning({
|
|
1160
|
-
agentName,
|
|
1161
|
-
linkPath,
|
|
1162
|
-
target: agentPath,
|
|
1163
|
-
value: input.preservedReasoning?.get(agentName)
|
|
1164
|
-
});
|
|
1165
|
-
await restorePreservedServiceTier({
|
|
1166
|
-
linkPath,
|
|
1167
|
-
preserved: input.preservedServiceTier?.has(agentName) ?? false,
|
|
1168
|
-
value: input.preservedServiceTier?.get(agentName) ?? null
|
|
1169
|
-
});
|
|
1170
|
-
linked.push({ name: agentFileName, path: linkPath, target: agentPath });
|
|
1033
|
+
function parseLiteralTomlString(input, startIndex) {
|
|
1034
|
+
let index = startIndex + 1;
|
|
1035
|
+
let value = "";
|
|
1036
|
+
while (index < input.length) {
|
|
1037
|
+
const char = input[index];
|
|
1038
|
+
if (char === "'")
|
|
1039
|
+
return { value, nextIndex: index + 1 };
|
|
1040
|
+
value += char;
|
|
1041
|
+
index += 1;
|
|
1171
1042
|
}
|
|
1172
|
-
|
|
1173
|
-
return linked;
|
|
1043
|
+
return null;
|
|
1174
1044
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
if (
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
if (!await exists3(agentsRoot))
|
|
1045
|
+
function parseBasicTomlString(input, startIndex) {
|
|
1046
|
+
let index = startIndex + 1;
|
|
1047
|
+
let value = "";
|
|
1048
|
+
while (index < input.length) {
|
|
1049
|
+
const char = input[index];
|
|
1050
|
+
if (char === '"')
|
|
1051
|
+
return { value, nextIndex: index + 1 };
|
|
1052
|
+
if (char !== "\\") {
|
|
1053
|
+
value += char;
|
|
1054
|
+
index += 1;
|
|
1186
1055
|
continue;
|
|
1187
|
-
const agentEntries = await readdir2(agentsRoot, { withFileTypes: true });
|
|
1188
|
-
for (const file of agentEntries) {
|
|
1189
|
-
if (!file.isFile() || !file.name.endsWith(".toml"))
|
|
1190
|
-
continue;
|
|
1191
|
-
agents.push(join10(agentsRoot, file.name));
|
|
1192
1056
|
}
|
|
1057
|
+
const escaped = parseBasicTomlEscape(input, index);
|
|
1058
|
+
if (!escaped)
|
|
1059
|
+
return null;
|
|
1060
|
+
value += escaped.value;
|
|
1061
|
+
index = escaped.nextIndex;
|
|
1193
1062
|
}
|
|
1194
|
-
|
|
1195
|
-
return agents;
|
|
1196
|
-
}
|
|
1197
|
-
async function replaceWithCopy(linkPath, target) {
|
|
1198
|
-
await prepareReplacement(linkPath);
|
|
1199
|
-
await copyFile(target, linkPath);
|
|
1200
|
-
}
|
|
1201
|
-
async function prepareReplacement(linkPath) {
|
|
1202
|
-
if (!await exists3(linkPath))
|
|
1203
|
-
return;
|
|
1204
|
-
const entryStat = await lstat3(linkPath);
|
|
1205
|
-
if (entryStat.isDirectory() && !entryStat.isSymbolicLink()) {
|
|
1206
|
-
throw new Error(`${linkPath} already exists and is a directory; refusing to replace`);
|
|
1207
|
-
}
|
|
1208
|
-
await rm6(linkPath, { force: true });
|
|
1209
|
-
}
|
|
1210
|
-
async function writeManifest(pluginRoot, agentPaths) {
|
|
1211
|
-
const manifestPath = join10(pluginRoot, MANIFEST_FILE);
|
|
1212
|
-
const payload = { agents: [...agentPaths].sort() };
|
|
1213
|
-
await writeFile4(manifestPath, `${JSON.stringify(payload, null, "\t")}
|
|
1214
|
-
`);
|
|
1063
|
+
return null;
|
|
1215
1064
|
}
|
|
1216
|
-
function
|
|
1217
|
-
|
|
1065
|
+
function parseBasicTomlEscape(input, backslashIndex) {
|
|
1066
|
+
const escape = input[backslashIndex + 1];
|
|
1067
|
+
if (escape === undefined)
|
|
1068
|
+
return null;
|
|
1069
|
+
if (escape === "b")
|
|
1070
|
+
return { value: "\b", nextIndex: backslashIndex + 2 };
|
|
1071
|
+
if (escape === "t")
|
|
1072
|
+
return { value: "\t", nextIndex: backslashIndex + 2 };
|
|
1073
|
+
if (escape === "n")
|
|
1074
|
+
return { value: `
|
|
1075
|
+
`, nextIndex: backslashIndex + 2 };
|
|
1076
|
+
if (escape === "f")
|
|
1077
|
+
return { value: "\f", nextIndex: backslashIndex + 2 };
|
|
1078
|
+
if (escape === "r")
|
|
1079
|
+
return { value: "\r", nextIndex: backslashIndex + 2 };
|
|
1080
|
+
if (escape === '"')
|
|
1081
|
+
return { value: '"', nextIndex: backslashIndex + 2 };
|
|
1082
|
+
if (escape === "\\")
|
|
1083
|
+
return { value: "\\", nextIndex: backslashIndex + 2 };
|
|
1084
|
+
if (escape === "u")
|
|
1085
|
+
return parseUnicodeEscape(input, backslashIndex + 2, 4);
|
|
1086
|
+
if (escape === "U")
|
|
1087
|
+
return parseUnicodeEscape(input, backslashIndex + 2, 8);
|
|
1088
|
+
return null;
|
|
1218
1089
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
return
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
}
|
|
1090
|
+
function parseUnicodeEscape(input, digitsStart, digitCount) {
|
|
1091
|
+
const digits = input.slice(digitsStart, digitsStart + digitCount);
|
|
1092
|
+
if (digits.length !== digitCount || !/^[0-9A-Fa-f]+$/.test(digits))
|
|
1093
|
+
return null;
|
|
1094
|
+
const codePoint = Number.parseInt(digits, 16);
|
|
1095
|
+
if (codePoint > 1114111)
|
|
1096
|
+
return null;
|
|
1097
|
+
return { value: String.fromCodePoint(codePoint), nextIndex: digitsStart + digitCount };
|
|
1228
1098
|
}
|
|
1229
|
-
function
|
|
1230
|
-
|
|
1099
|
+
function parseBareTomlKey(input, startIndex) {
|
|
1100
|
+
let index = startIndex;
|
|
1101
|
+
while (index < input.length && /[A-Za-z0-9_-]/.test(input[index]))
|
|
1102
|
+
index += 1;
|
|
1103
|
+
if (index === startIndex)
|
|
1231
1104
|
return null;
|
|
1232
|
-
return
|
|
1105
|
+
return { value: input.slice(startIndex, index), nextIndex: index };
|
|
1106
|
+
}
|
|
1107
|
+
function skipWhitespace(input, startIndex) {
|
|
1108
|
+
let index = startIndex;
|
|
1109
|
+
while (index < input.length && /\s/.test(input[index]))
|
|
1110
|
+
index += 1;
|
|
1111
|
+
return index;
|
|
1233
1112
|
}
|
|
1234
1113
|
|
|
1235
|
-
// ../src/install/codex-
|
|
1236
|
-
|
|
1237
|
-
|
|
1114
|
+
// ../src/install/codex-config-toml-sections.ts
|
|
1115
|
+
function removeTomlSections(config, shouldRemove) {
|
|
1116
|
+
return splitTomlSections(config).filter((section) => section.header === null || !shouldRemove(section.header, section)).map((section) => section.text).join("").replace(/\n{3,}/g, `
|
|
1238
1117
|
|
|
1239
|
-
// ../src/install/codex-cache-command-shim.ts
|
|
1240
|
-
var COMMAND_SHIM_MARKER = ":: generated by oh-my-openagent Codex installer";
|
|
1241
|
-
function windowsNodeDiscoveryLines() {
|
|
1242
|
-
return [
|
|
1243
|
-
"setlocal EnableExtensions EnableDelayedExpansion",
|
|
1244
|
-
'set "OMO_NODE_BINARY="',
|
|
1245
|
-
'set "OMO_NODE_REPL_NODE_PATH=%NODE_REPL_NODE_PATH%"',
|
|
1246
|
-
'if exist "%CODEX_HOME%\\config.toml" (',
|
|
1247
|
-
` for /f "tokens=1,* delims==" %%A in ('findstr /R /C:"NODE_REPL_NODE_PATH[ ]*=" "%CODEX_HOME%\\config.toml" 2^>nul') do (`,
|
|
1248
|
-
' set "OMO_NODE_REPL_NODE_PATH=%%B"',
|
|
1249
|
-
" )",
|
|
1250
|
-
")",
|
|
1251
|
-
"if defined OMO_NODE_REPL_NODE_PATH (",
|
|
1252
|
-
' set "OMO_NODE_BINARY=!OMO_NODE_REPL_NODE_PATH!"',
|
|
1253
|
-
' for /f "tokens=* delims= " %%N in ("!OMO_NODE_BINARY!") do set "OMO_NODE_BINARY=%%N"',
|
|
1254
|
-
` if "!OMO_NODE_BINARY:~0,1!"=="'" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~1!"`,
|
|
1255
|
-
` if "!OMO_NODE_BINARY:~-1!"=="'" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~0,-1!"`,
|
|
1256
|
-
' if "!OMO_NODE_BINARY:~0,1!"=="^"" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~1!"',
|
|
1257
|
-
' if "!OMO_NODE_BINARY:~-1!"=="^"" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~0,-1!"',
|
|
1258
|
-
' if defined OMO_NODE_BINARY if not exist "!OMO_NODE_BINARY!" set "OMO_NODE_BINARY="',
|
|
1259
|
-
")",
|
|
1260
|
-
'if not defined OMO_NODE_BINARY where node >nul 2>nul && set "OMO_NODE_BINARY=node"'
|
|
1261
|
-
];
|
|
1262
|
-
}
|
|
1263
|
-
function windowsCommandShim(targetPath) {
|
|
1264
|
-
return [
|
|
1265
|
-
"@echo off",
|
|
1266
|
-
COMMAND_SHIM_MARKER,
|
|
1267
|
-
'if not defined CODEX_HOME set "CODEX_HOME=%USERPROFILE%\\.codex"',
|
|
1268
|
-
...windowsNodeDiscoveryLines(),
|
|
1269
|
-
"if not defined OMO_NODE_BINARY (",
|
|
1270
|
-
" echo omo: no Node runtime was discovered from NODE_REPL_NODE_PATH or PATH; rerun LazyCodex install from Codex Desktop 1>&2",
|
|
1271
|
-
" exit /b 127",
|
|
1272
|
-
")",
|
|
1273
|
-
`"%OMO_NODE_BINARY%" "${targetPath}" %*`,
|
|
1274
|
-
"exit /b %ERRORLEVEL%",
|
|
1275
|
-
""
|
|
1276
|
-
].join(`\r
|
|
1277
1118
|
`);
|
|
1278
1119
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
throw error;
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
function isPlainRecord(value) {
|
|
1297
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1298
|
-
}
|
|
1299
|
-
function isNodeErrorWithCode(error) {
|
|
1300
|
-
return typeof error === "object" && error !== null && "code" in error;
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// ../src/install/codex-cache-dangling-bins.ts
|
|
1304
|
-
async function removeDanglingManagedComponentBins(binDir, platform, managedBinNames) {
|
|
1305
|
-
const entries = await readdir3(binDir, { withFileTypes: true });
|
|
1306
|
-
for (const entry of entries) {
|
|
1307
|
-
const binName = managedBinNameForEntry(entry.name, platform);
|
|
1308
|
-
if (binName === null || !managedBinNames.has(binName))
|
|
1309
|
-
continue;
|
|
1310
|
-
const linkPath = join11(binDir, entry.name);
|
|
1311
|
-
if (platform === "win32") {
|
|
1312
|
-
await removeDanglingGeneratedCommandShim(linkPath);
|
|
1313
|
-
continue;
|
|
1120
|
+
function splitTomlSections(config) {
|
|
1121
|
+
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
1122
|
+
const sections = [];
|
|
1123
|
+
let current = { header: null, text: "" };
|
|
1124
|
+
for (const line of lines) {
|
|
1125
|
+
if (line.length === 0)
|
|
1126
|
+
break;
|
|
1127
|
+
const header = parseTomlHeader2(line);
|
|
1128
|
+
if (header !== null) {
|
|
1129
|
+
if (current.text.length > 0)
|
|
1130
|
+
sections.push(current);
|
|
1131
|
+
current = { header, text: line };
|
|
1132
|
+
} else {
|
|
1133
|
+
current = { ...current, text: current.text + line };
|
|
1314
1134
|
}
|
|
1315
|
-
await removeDanglingManagedSymlink(linkPath);
|
|
1316
1135
|
}
|
|
1136
|
+
if (current.text.length > 0)
|
|
1137
|
+
sections.push(current);
|
|
1138
|
+
return sections;
|
|
1317
1139
|
}
|
|
1318
|
-
function
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
return name;
|
|
1322
|
-
}
|
|
1323
|
-
async function removeDanglingManagedSymlink(linkPath) {
|
|
1324
|
-
try {
|
|
1325
|
-
const linkStat = await lstat5(linkPath);
|
|
1326
|
-
if (!linkStat.isSymbolicLink())
|
|
1327
|
-
return;
|
|
1328
|
-
const linkTarget = await readlink(linkPath);
|
|
1329
|
-
const target = isAbsolute2(linkTarget) ? linkTarget : resolve3(dirname5(linkPath), linkTarget);
|
|
1330
|
-
if (!await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
|
|
1331
|
-
await rm7(linkPath, { force: true });
|
|
1332
|
-
} catch (error) {
|
|
1333
|
-
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1334
|
-
return;
|
|
1335
|
-
throw error;
|
|
1336
|
-
}
|
|
1140
|
+
function parsePluginHeaderKey(header) {
|
|
1141
|
+
const path = parseTomlDottedKey(header);
|
|
1142
|
+
return path?.[0] === "plugins" ? path[1] ?? null : null;
|
|
1337
1143
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
if (!linkStat.isFile())
|
|
1342
|
-
return;
|
|
1343
|
-
const content = await readFile6(linkPath, "utf8");
|
|
1344
|
-
if (!content.includes(COMMAND_SHIM_MARKER))
|
|
1345
|
-
return;
|
|
1346
|
-
const target = extractCommandShimTarget(content);
|
|
1347
|
-
if (target !== null && !await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
|
|
1348
|
-
await rm7(linkPath, { force: true });
|
|
1349
|
-
} catch (error) {
|
|
1350
|
-
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1351
|
-
return;
|
|
1352
|
-
throw error;
|
|
1353
|
-
}
|
|
1144
|
+
function parseAgentHeaderName(header) {
|
|
1145
|
+
const path = parseTomlDottedKey(header);
|
|
1146
|
+
return path?.[0] === "agents" ? path[1] ?? null : null;
|
|
1354
1147
|
}
|
|
1355
|
-
|
|
1148
|
+
function parseJsonString(value) {
|
|
1356
1149
|
try {
|
|
1357
|
-
|
|
1358
|
-
return
|
|
1359
|
-
} catch
|
|
1360
|
-
|
|
1361
|
-
return false;
|
|
1362
|
-
throw error;
|
|
1150
|
+
const parsed = JSON.parse(value);
|
|
1151
|
+
return typeof parsed === "string" ? parsed : null;
|
|
1152
|
+
} catch {
|
|
1153
|
+
return null;
|
|
1363
1154
|
}
|
|
1364
1155
|
}
|
|
1365
|
-
function
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1156
|
+
function parseHookStateHeaderKey(header) {
|
|
1157
|
+
const path = parseTomlDottedKey(header);
|
|
1158
|
+
if (path?.[0] !== "hooks" || path[1] !== "state")
|
|
1159
|
+
return null;
|
|
1160
|
+
return path[2] ?? null;
|
|
1368
1161
|
}
|
|
1369
|
-
function
|
|
1370
|
-
const
|
|
1371
|
-
|
|
1372
|
-
|
|
1162
|
+
function parseTomlHeader2(line) {
|
|
1163
|
+
const trimmed = stripTomlLineComment(line).trim();
|
|
1164
|
+
if (!trimmed.startsWith("[") || !trimmed.endsWith("]") || trimmed.startsWith("[["))
|
|
1165
|
+
return null;
|
|
1166
|
+
return trimmed.slice(1, -1);
|
|
1373
1167
|
}
|
|
1374
|
-
function
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1168
|
+
function stripTomlLineComment(line) {
|
|
1169
|
+
let quote = null;
|
|
1170
|
+
let index = 0;
|
|
1171
|
+
while (index < line.length) {
|
|
1172
|
+
const char = line[index];
|
|
1173
|
+
if (quote === '"') {
|
|
1174
|
+
if (char === "\\") {
|
|
1175
|
+
index += 2;
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
if (char === '"')
|
|
1179
|
+
quote = null;
|
|
1180
|
+
index += 1;
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
if (quote === "'") {
|
|
1184
|
+
if (char === "'")
|
|
1185
|
+
quote = null;
|
|
1186
|
+
index += 1;
|
|
1187
|
+
continue;
|
|
1188
|
+
}
|
|
1189
|
+
if (char === '"' || char === "'") {
|
|
1190
|
+
quote = char;
|
|
1191
|
+
index += 1;
|
|
1192
|
+
continue;
|
|
1378
1193
|
}
|
|
1194
|
+
if (char === "#")
|
|
1195
|
+
return line.slice(0, index);
|
|
1196
|
+
index += 1;
|
|
1379
1197
|
}
|
|
1380
|
-
return
|
|
1198
|
+
return line;
|
|
1381
1199
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1200
|
+
|
|
1201
|
+
// ../src/install/managed-agent-reasoning-defaults.ts
|
|
1202
|
+
var MANAGED_REASONING_DEFAULT_UPGRADES = new Map([
|
|
1203
|
+
[
|
|
1204
|
+
"explorer",
|
|
1205
|
+
[
|
|
1206
|
+
{
|
|
1207
|
+
previous: { model: "gpt-5.4-mini", effort: "low" },
|
|
1208
|
+
current: { model: "gpt-5.6-terra", effort: "medium" }
|
|
1209
|
+
},
|
|
1210
|
+
{
|
|
1211
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
1212
|
+
current: { model: "gpt-5.6-luna", effort: "low" }
|
|
1213
|
+
}
|
|
1214
|
+
]
|
|
1215
|
+
],
|
|
1216
|
+
[
|
|
1217
|
+
"librarian",
|
|
1218
|
+
[
|
|
1219
|
+
{
|
|
1220
|
+
previous: { model: "gpt-5.4-mini", effort: "low" },
|
|
1221
|
+
current: { model: "gpt-5.6-terra", effort: "medium" }
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
1225
|
+
current: { model: "gpt-5.6-luna", effort: "low" }
|
|
1226
|
+
}
|
|
1227
|
+
]
|
|
1228
|
+
],
|
|
1229
|
+
[
|
|
1230
|
+
"momus",
|
|
1231
|
+
[
|
|
1232
|
+
{
|
|
1233
|
+
previous: { model: "gpt-5.5", effort: "xhigh" },
|
|
1234
|
+
current: { model: "gpt-5.6-sol", effort: "ultra" }
|
|
1235
|
+
}
|
|
1236
|
+
]
|
|
1237
|
+
],
|
|
1238
|
+
[
|
|
1239
|
+
"plan",
|
|
1240
|
+
[
|
|
1241
|
+
{
|
|
1242
|
+
previous: { model: "gpt-5.6-sol", effort: "xhigh" },
|
|
1243
|
+
current: { model: "gpt-5.6-sol", effort: "max" }
|
|
1244
|
+
}
|
|
1245
|
+
]
|
|
1246
|
+
],
|
|
1247
|
+
[
|
|
1248
|
+
"lazycodex-worker-medium",
|
|
1249
|
+
[
|
|
1250
|
+
{
|
|
1251
|
+
previous: { model: "gpt-5.6-sol", effort: "high" },
|
|
1252
|
+
current: { model: "gpt-5.6-luna", effort: "max" }
|
|
1253
|
+
}
|
|
1254
|
+
]
|
|
1255
|
+
],
|
|
1256
|
+
[
|
|
1257
|
+
"lazycodex-qa-executor",
|
|
1258
|
+
[
|
|
1259
|
+
{
|
|
1260
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
1261
|
+
current: { model: "gpt-5.6-luna", effort: "high" }
|
|
1262
|
+
}
|
|
1263
|
+
]
|
|
1264
|
+
],
|
|
1265
|
+
[
|
|
1266
|
+
"lazycodex-gate-reviewer",
|
|
1267
|
+
[
|
|
1268
|
+
{
|
|
1269
|
+
previous: { model: "gpt-5.6-sol", effort: "xhigh" },
|
|
1270
|
+
current: { model: "gpt-5.6-sol", effort: "high" }
|
|
1271
|
+
}
|
|
1272
|
+
]
|
|
1273
|
+
]
|
|
1274
|
+
]);
|
|
1275
|
+
function resolveManagedAgentReasoning(input) {
|
|
1276
|
+
const steps = MANAGED_REASONING_DEFAULT_UPGRADES.get(input.agentName);
|
|
1277
|
+
if (steps === undefined)
|
|
1278
|
+
return input.preserved.effort;
|
|
1279
|
+
const latest = steps[steps.length - 1];
|
|
1280
|
+
if (latest === undefined)
|
|
1281
|
+
return input.preserved.effort;
|
|
1282
|
+
if (input.bundledModel !== latest.current.model || input.bundledEffort !== latest.current.effort) {
|
|
1283
|
+
return input.preserved.effort;
|
|
1284
|
+
}
|
|
1285
|
+
const preservedMatchesAnyStep = steps.some((step) => input.preserved.model === step.previous.model && input.preserved.effort === step.previous.effort);
|
|
1286
|
+
return preservedMatchesAnyStep ? latest.current.effort : input.preserved.effort;
|
|
1388
1287
|
}
|
|
1389
1288
|
|
|
1390
|
-
// ../src/install/
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1289
|
+
// ../src/install/preserved-agent-settings.ts
|
|
1290
|
+
async function capturePreservedAgentReasoning(input) {
|
|
1291
|
+
const agentsDir = join8(input.codexHome, "agents");
|
|
1292
|
+
if (!await exists(agentsDir))
|
|
1293
|
+
return new Map;
|
|
1294
|
+
const preserved = new Map;
|
|
1295
|
+
const agentEntries = await readdir(agentsDir, { withFileTypes: true });
|
|
1296
|
+
for (const entry of agentEntries) {
|
|
1297
|
+
if (!entry.name.endsWith(".toml"))
|
|
1298
|
+
continue;
|
|
1299
|
+
const content = await readTextIfExists(join8(agentsDir, entry.name));
|
|
1300
|
+
if (content === null)
|
|
1301
|
+
continue;
|
|
1302
|
+
const effort = extractReasoningEffort(content);
|
|
1303
|
+
if (effort !== null) {
|
|
1304
|
+
preserved.set(agentNameFromToml(entry.name), {
|
|
1305
|
+
model: extractModel(content),
|
|
1306
|
+
effort
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1406
1309
|
}
|
|
1310
|
+
return preserved;
|
|
1407
1311
|
}
|
|
1408
|
-
async function
|
|
1312
|
+
async function capturePreservedAgentServiceTier(input) {
|
|
1313
|
+
const agentsDir = join8(input.codexHome, "agents");
|
|
1314
|
+
if (!await exists(agentsDir))
|
|
1315
|
+
return new Map;
|
|
1316
|
+
const preserved = new Map;
|
|
1317
|
+
const agentEntries = await readdir(agentsDir, { withFileTypes: true });
|
|
1318
|
+
for (const entry of agentEntries) {
|
|
1319
|
+
if (!entry.name.endsWith(".toml"))
|
|
1320
|
+
continue;
|
|
1321
|
+
const content = await readTextIfExists(join8(agentsDir, entry.name));
|
|
1322
|
+
if (content === null)
|
|
1323
|
+
continue;
|
|
1324
|
+
preserved.set(agentNameFromToml(entry.name), extractServiceTier(content));
|
|
1325
|
+
}
|
|
1326
|
+
return preserved;
|
|
1327
|
+
}
|
|
1328
|
+
async function restorePreservedReasoning(input) {
|
|
1329
|
+
if (input.value === undefined)
|
|
1330
|
+
return;
|
|
1331
|
+
const content = await readFile4(input.target, "utf8");
|
|
1332
|
+
const bundledEffort = extractReasoningEffort(content);
|
|
1333
|
+
const effort = resolveManagedAgentReasoning({
|
|
1334
|
+
agentName: input.agentName,
|
|
1335
|
+
bundledModel: extractModel(content),
|
|
1336
|
+
bundledEffort,
|
|
1337
|
+
preserved: input.value
|
|
1338
|
+
});
|
|
1339
|
+
if (bundledEffort === effort)
|
|
1340
|
+
return;
|
|
1341
|
+
const replacement = replaceTopLevelStringSetting(content, "model_reasoning_effort", effort, { insertIfMissing: false });
|
|
1342
|
+
if (!replacement.replaced)
|
|
1343
|
+
return;
|
|
1344
|
+
await writeFile3(input.linkPath, replacement.content);
|
|
1345
|
+
}
|
|
1346
|
+
async function restorePreservedServiceTier(input) {
|
|
1347
|
+
if (!input.preserved)
|
|
1348
|
+
return;
|
|
1349
|
+
const content = await readFile4(input.linkPath, "utf8");
|
|
1350
|
+
if (extractServiceTier(content) === input.value)
|
|
1351
|
+
return;
|
|
1352
|
+
const replacement = replaceTopLevelStringSetting(content, "service_tier", input.value, { insertIfMissing: true });
|
|
1353
|
+
if (!replacement.replaced)
|
|
1354
|
+
return;
|
|
1355
|
+
await writeFile3(input.linkPath, replacement.content);
|
|
1356
|
+
}
|
|
1357
|
+
async function readTextIfExists(path) {
|
|
1409
1358
|
try {
|
|
1410
|
-
|
|
1411
|
-
if (platform !== "win32") {
|
|
1412
|
-
if (!stat4.isSymbolicLink())
|
|
1413
|
-
return;
|
|
1414
|
-
const target = await readlink2(linkPath);
|
|
1415
|
-
if (isManagedLegacyComponentTarget(target, component))
|
|
1416
|
-
await rm8(linkPath, { force: true });
|
|
1417
|
-
return;
|
|
1418
|
-
}
|
|
1419
|
-
if (!stat4.isFile())
|
|
1420
|
-
return;
|
|
1421
|
-
const content = await readFile7(linkPath, "utf8");
|
|
1422
|
-
if (content.includes(COMMAND_SHIM_MARKER))
|
|
1423
|
-
await rm8(linkPath, { force: true });
|
|
1359
|
+
return await readFile4(path, "utf8");
|
|
1424
1360
|
} catch (error) {
|
|
1425
|
-
if (
|
|
1426
|
-
return;
|
|
1361
|
+
if (nodeErrorCode(error) === "ENOENT")
|
|
1362
|
+
return null;
|
|
1427
1363
|
throw error;
|
|
1428
1364
|
}
|
|
1429
1365
|
}
|
|
1430
|
-
function
|
|
1431
|
-
|
|
1432
|
-
const suffixStart = parts.length - 4;
|
|
1433
|
-
const suffix = parts.slice(-4);
|
|
1434
|
-
return suffix[0] === "components" && suffix[1] === component && suffix[2] === "dist" && suffix[3] === "cli.js" && (hasPluginCachePrefix(parts, suffixStart) || hasOmoCodexPluginPrefix2(parts, suffixStart));
|
|
1366
|
+
function extractModel(content) {
|
|
1367
|
+
return extractTopLevelStringSetting(content, "model");
|
|
1435
1368
|
}
|
|
1436
|
-
function
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1369
|
+
function extractReasoningEffort(content) {
|
|
1370
|
+
return extractTopLevelStringSetting(content, "model_reasoning_effort");
|
|
1371
|
+
}
|
|
1372
|
+
function extractServiceTier(content) {
|
|
1373
|
+
return extractTopLevelStringSetting(content, "service_tier");
|
|
1374
|
+
}
|
|
1375
|
+
function extractTopLevelStringSetting(content, key) {
|
|
1376
|
+
for (const line of content.split(/\n/)) {
|
|
1377
|
+
if (isSectionHeader(line))
|
|
1378
|
+
return null;
|
|
1379
|
+
const rawValue = topLevelStringSettingRawValue(line, key);
|
|
1380
|
+
if (rawValue === undefined)
|
|
1381
|
+
continue;
|
|
1382
|
+
const parsed = parseJsonString(rawValue);
|
|
1383
|
+
if (parsed !== null)
|
|
1384
|
+
return parsed;
|
|
1440
1385
|
}
|
|
1441
|
-
return
|
|
1386
|
+
return null;
|
|
1442
1387
|
}
|
|
1443
|
-
function
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1388
|
+
function replaceTopLevelStringSetting(content, key, value, options) {
|
|
1389
|
+
const lines = content.split(/\n/);
|
|
1390
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
1391
|
+
const line = lines[index];
|
|
1392
|
+
if (line === undefined || isSectionHeader(line))
|
|
1393
|
+
break;
|
|
1394
|
+
if (topLevelStringSettingRawValue(line, key) === undefined)
|
|
1395
|
+
continue;
|
|
1396
|
+
if (value === null) {
|
|
1397
|
+
lines.splice(index, 1);
|
|
1398
|
+
return { content: lines.join(`
|
|
1399
|
+
`), replaced: true };
|
|
1400
|
+
}
|
|
1401
|
+
lines[index] = line.replace(/=\s*"(?:[^"\\]|\\.)*"/, `= ${JSON.stringify(value)}`);
|
|
1402
|
+
return { content: lines.join(`
|
|
1403
|
+
`), replaced: true };
|
|
1447
1404
|
}
|
|
1448
|
-
|
|
1405
|
+
if (value === null || !options.insertIfMissing)
|
|
1406
|
+
return { content, replaced: false };
|
|
1407
|
+
lines.splice(topLevelInsertionIndex(lines), 0, `${key} = ${JSON.stringify(value)}`);
|
|
1408
|
+
return { content: lines.join(`
|
|
1409
|
+
`), replaced: true };
|
|
1449
1410
|
}
|
|
1450
|
-
function
|
|
1451
|
-
|
|
1411
|
+
function topLevelStringSettingRawValue(line, key) {
|
|
1412
|
+
const match = line.match(/^\s*([A-Za-z0-9_]+)\s*=\s*("(?:[^"\\]|\\.)*")/);
|
|
1413
|
+
if (match === null)
|
|
1414
|
+
return;
|
|
1415
|
+
const settingKey = match[1];
|
|
1416
|
+
const rawValue = match[2];
|
|
1417
|
+
if (settingKey !== key || rawValue === undefined)
|
|
1418
|
+
return;
|
|
1419
|
+
return rawValue;
|
|
1452
1420
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
const escapedCodexHome = escapePosixDoubleQuoted(toPosixPath(codexHome));
|
|
1462
|
-
const escapedUlwLoopBin = escapePosixDoubleQuoted(ulwLoopBin);
|
|
1463
|
-
return [
|
|
1464
|
-
"#!/bin/sh",
|
|
1465
|
-
`# ${RUNTIME_WRAPPER_MARKER}`,
|
|
1466
|
-
`export CODEX_HOME="\${CODEX_HOME:-${escapedCodexHome}}"`,
|
|
1467
|
-
'if [ "$1" = "ulw-loop" ] && [ -x "' + escapedUlwLoopBin + '" ]; then',
|
|
1468
|
-
" shift",
|
|
1469
|
-
' exec "' + escapedUlwLoopBin + '" ulw-loop "$@"',
|
|
1470
|
-
"fi",
|
|
1471
|
-
`if [ "\${OMO_RUNTIME:-}" = "node" ] && [ -f "${nodeCli}" ]; then`,
|
|
1472
|
-
` exec node "${nodeCli}" "$@"`,
|
|
1473
|
-
"fi",
|
|
1474
|
-
'BUN_BINARY="${BUN_BINARY:-}"',
|
|
1475
|
-
'if [ -z "$BUN_BINARY" ] && command -v bun >/dev/null 2>&1; then',
|
|
1476
|
-
" BUN_BINARY=bun",
|
|
1477
|
-
"fi",
|
|
1478
|
-
'if [ -z "$BUN_BINARY" ]; then',
|
|
1479
|
-
' for omo_bun_candidate in "$HOME/.bun/bin/bun" /opt/homebrew/bin/bun /usr/local/bin/bun; do',
|
|
1480
|
-
' if [ -x "$omo_bun_candidate" ]; then',
|
|
1481
|
-
' BUN_BINARY="$omo_bun_candidate"',
|
|
1482
|
-
" break",
|
|
1483
|
-
" fi",
|
|
1484
|
-
" done",
|
|
1485
|
-
"fi",
|
|
1486
|
-
'if [ -z "$BUN_BINARY" ]; then',
|
|
1487
|
-
` if [ -f "${nodeCli}" ] && command -v node >/dev/null 2>&1; then`,
|
|
1488
|
-
` exec node "${nodeCli}" "$@"`,
|
|
1489
|
-
" fi",
|
|
1490
|
-
` echo "omo: bun runtime not found (checked PATH, ~/.bun/bin, /opt/homebrew/bin, /usr/local/bin) and the node fallback CLI is missing at ${nodeCli}; install bun from https://bun.sh, or reinstall omo and force the fallback with OMO_RUNTIME=node" >&2`,
|
|
1491
|
-
" exit 127",
|
|
1492
|
-
"fi",
|
|
1493
|
-
`if [ ! -f "${escapedCliPath}" ]; then`,
|
|
1494
|
-
` echo "omo: runtime target missing at ${escapedCliPath}; reinstall with: npx --yes lazycodex-ai@latest install --no-tui" >&2`,
|
|
1495
|
-
" exit 1",
|
|
1496
|
-
"fi",
|
|
1497
|
-
`exec "$BUN_BINARY" "${escapedCliPath}" "$@"`,
|
|
1498
|
-
""
|
|
1499
|
-
].join(`
|
|
1500
|
-
`);
|
|
1421
|
+
function topLevelInsertionIndex(lines) {
|
|
1422
|
+
const sectionIndex = lines.findIndex((line) => isSectionHeader(line));
|
|
1423
|
+
const topLevelEnd = sectionIndex === -1 ? lines.length : sectionIndex;
|
|
1424
|
+
let insertionIndex = topLevelEnd;
|
|
1425
|
+
while (insertionIndex > 0 && lines[insertionIndex - 1] === "") {
|
|
1426
|
+
insertionIndex -= 1;
|
|
1427
|
+
}
|
|
1428
|
+
return insertionIndex;
|
|
1501
1429
|
}
|
|
1502
|
-
function
|
|
1503
|
-
const
|
|
1504
|
-
return [
|
|
1505
|
-
"@echo off",
|
|
1506
|
-
`rem ${RUNTIME_WRAPPER_MARKER}`,
|
|
1507
|
-
`if not defined CODEX_HOME set "CODEX_HOME=${codexHome}"`,
|
|
1508
|
-
...windowsNodeDiscoveryLines(),
|
|
1509
|
-
`if "%~1"=="ulw-loop" if exist "${ulwLoopBin}" (`,
|
|
1510
|
-
" shift /1",
|
|
1511
|
-
` "${ulwLoopBin}" ulw-loop %*`,
|
|
1512
|
-
" exit /b %ERRORLEVEL%",
|
|
1513
|
-
")",
|
|
1514
|
-
`if "%OMO_RUNTIME%"=="node" if defined OMO_NODE_BINARY if exist "${nodeCliPath}" (`,
|
|
1515
|
-
` "%OMO_NODE_BINARY%" "${nodeCliPath}" %*`,
|
|
1516
|
-
" exit /b %ERRORLEVEL%",
|
|
1517
|
-
")",
|
|
1518
|
-
'if not defined BUN_BINARY where bun >nul 2>nul && set "BUN_BINARY=bun"',
|
|
1519
|
-
'if not defined BUN_BINARY if exist "%USERPROFILE%\\.bun\\bin\\bun.exe" set "BUN_BINARY=%USERPROFILE%\\.bun\\bin\\bun.exe"',
|
|
1520
|
-
"if not defined BUN_BINARY (",
|
|
1521
|
-
` if defined OMO_NODE_BINARY if exist "${nodeCliPath}" (`,
|
|
1522
|
-
` "%OMO_NODE_BINARY%" "${nodeCliPath}" %*`,
|
|
1523
|
-
" exit /b %ERRORLEVEL%",
|
|
1524
|
-
" )",
|
|
1525
|
-
` echo omo: bun runtime not found, no Node runtime was discovered from NODE_REPL_NODE_PATH or PATH, or the node fallback CLI is missing at ${nodeCliPath}; install bun from https://bun.sh or rerun LazyCodex install from Codex Desktop 1>&2`,
|
|
1526
|
-
" exit /b 127",
|
|
1527
|
-
")",
|
|
1528
|
-
`if not exist "${cliPath}" (`,
|
|
1529
|
-
` echo omo: runtime target missing at ${cliPath}; reinstall with: npx --yes lazycodex-ai@latest install --no-tui 1>&2`,
|
|
1530
|
-
" exit /b 1",
|
|
1531
|
-
")",
|
|
1532
|
-
`"%BUN_BINARY%" "${cliPath}" %*`,
|
|
1533
|
-
""
|
|
1534
|
-
].join(`\r
|
|
1535
|
-
`);
|
|
1430
|
+
function isSectionHeader(line) {
|
|
1431
|
+
const trimmed = line.trim();
|
|
1432
|
+
return trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
1536
1433
|
}
|
|
1537
|
-
function
|
|
1538
|
-
return
|
|
1539
|
-
}
|
|
1540
|
-
function escapePosixDoubleQuoted(value) {
|
|
1541
|
-
return value.replaceAll("\\", "\\\\").replaceAll('"', "\\\"").replaceAll("$", "\\$").replaceAll("`", "\\`");
|
|
1434
|
+
function agentNameFromToml(fileName) {
|
|
1435
|
+
return fileName.endsWith(".toml") ? fileName.slice(0, -".toml".length) : fileName;
|
|
1542
1436
|
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
await removeDanglingManagedComponentBins(input.binDir, platform, new Set(binLinks.map((link) => link.name)));
|
|
1552
|
-
const linked = [];
|
|
1553
|
-
for (const link of binLinks) {
|
|
1554
|
-
const linkPath = await linkCachedPluginBin(input.binDir, link, platform);
|
|
1555
|
-
linked.push({ name: link.name, path: linkPath, target: link.target });
|
|
1437
|
+
async function exists(path) {
|
|
1438
|
+
try {
|
|
1439
|
+
await lstat(path);
|
|
1440
|
+
return true;
|
|
1441
|
+
} catch (error) {
|
|
1442
|
+
if (nodeErrorCode(error) !== "ENOENT")
|
|
1443
|
+
throw error;
|
|
1444
|
+
return false;
|
|
1556
1445
|
}
|
|
1557
|
-
return linked;
|
|
1558
1446
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
if (!await isFile2(cliPath))
|
|
1447
|
+
function nodeErrorCode(error) {
|
|
1448
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
1562
1449
|
return null;
|
|
1563
|
-
|
|
1564
|
-
const platform = input.platform ?? process.platform;
|
|
1565
|
-
await mkdir5(input.binDir, { recursive: true });
|
|
1566
|
-
if (platform === "win32") {
|
|
1567
|
-
const linkPath2 = join14(input.binDir, "omo.cmd");
|
|
1568
|
-
await replaceRuntimeWrapper(linkPath2, windowsRuntimeWrapper(cliPath, input.codexHome, input.binDir, nodeCliPath));
|
|
1569
|
-
return { name: "omo", path: linkPath2, target: cliPath };
|
|
1570
|
-
}
|
|
1571
|
-
const linkPath = join14(input.binDir, "omo");
|
|
1572
|
-
await replaceRuntimeWrapper(linkPath, posixRuntimeWrapper(cliPath, input.codexHome, input.binDir, nodeCliPath));
|
|
1573
|
-
await chmod2(linkPath, 493);
|
|
1574
|
-
return { name: "omo", path: linkPath, target: cliPath };
|
|
1450
|
+
return typeof error.code === "string" ? error.code : null;
|
|
1575
1451
|
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1452
|
+
|
|
1453
|
+
// ../src/install/retired-managed-agent-purge.ts
|
|
1454
|
+
import { lstat as lstat2, readFile as readFile5, rm as rm5 } from "node:fs/promises";
|
|
1455
|
+
import { join as join9 } from "node:path";
|
|
1456
|
+
var RETIRED_MANAGED_AGENT_FILES = [
|
|
1457
|
+
{
|
|
1458
|
+
fileName: "codex-ultrawork-reviewer.toml",
|
|
1459
|
+
requiredMarkers: [
|
|
1460
|
+
'name = "codex-ultrawork-reviewer"',
|
|
1461
|
+
'description = "Strict ultrawork verification reviewer.',
|
|
1462
|
+
'developer_instructions = """You are the ultrawork verification reviewer.'
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
];
|
|
1466
|
+
async function purgeRetiredManagedAgentFiles(input) {
|
|
1467
|
+
const agentsDir = join9(input.codexHome, "agents");
|
|
1468
|
+
if (!await exists2(agentsDir))
|
|
1469
|
+
return;
|
|
1470
|
+
for (const retiredAgent of RETIRED_MANAGED_AGENT_FILES) {
|
|
1471
|
+
const agentPath = join9(agentsDir, retiredAgent.fileName);
|
|
1472
|
+
if (!await exists2(agentPath))
|
|
1473
|
+
continue;
|
|
1474
|
+
const agentStat = await lstat2(agentPath);
|
|
1475
|
+
if (agentStat.isDirectory() && !agentStat.isSymbolicLink())
|
|
1476
|
+
continue;
|
|
1477
|
+
const content = await readTextIfExists2(agentPath);
|
|
1478
|
+
if (content === null || !hasRequiredMarkers(content, retiredAgent.requiredMarkers))
|
|
1479
|
+
continue;
|
|
1480
|
+
await rm5(agentPath, { force: true });
|
|
1581
1481
|
}
|
|
1582
|
-
const linkPath = join14(binDir, link.name);
|
|
1583
|
-
await replaceSymlink(linkPath, link.target);
|
|
1584
|
-
return linkPath;
|
|
1585
1482
|
}
|
|
1586
|
-
|
|
1483
|
+
function hasRequiredMarkers(content, markers) {
|
|
1484
|
+
return markers.every((marker) => content.includes(marker));
|
|
1485
|
+
}
|
|
1486
|
+
async function readTextIfExists2(path) {
|
|
1587
1487
|
try {
|
|
1588
|
-
return
|
|
1488
|
+
return await readFile5(path, "utf8");
|
|
1589
1489
|
} catch (error) {
|
|
1590
|
-
if (
|
|
1591
|
-
return
|
|
1490
|
+
if (nodeErrorCode2(error) === "ENOENT")
|
|
1491
|
+
return null;
|
|
1592
1492
|
throw error;
|
|
1593
1493
|
}
|
|
1594
1494
|
}
|
|
1595
|
-
async function
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1495
|
+
async function exists2(path) {
|
|
1496
|
+
try {
|
|
1497
|
+
await lstat2(path);
|
|
1498
|
+
return true;
|
|
1499
|
+
} catch (error) {
|
|
1500
|
+
if (nodeErrorCode2(error) !== "ENOENT")
|
|
1501
|
+
throw error;
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1599
1504
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1505
|
+
function nodeErrorCode2(error) {
|
|
1506
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
1507
|
+
return null;
|
|
1508
|
+
return typeof error.code === "string" ? error.code : null;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// ../src/install/link-cached-plugin-agents.ts
|
|
1512
|
+
var MANIFEST_FILE = ".installed-agents.json";
|
|
1513
|
+
async function linkCachedPluginAgents(input) {
|
|
1514
|
+
const bundledAgents = await discoverBundledAgents(input.pluginRoot);
|
|
1515
|
+
await purgeRetiredManagedAgentFiles({ codexHome: input.codexHome });
|
|
1516
|
+
if (bundledAgents.length === 0) {
|
|
1517
|
+
await writeManifest(input.pluginRoot, []);
|
|
1518
|
+
return [];
|
|
1604
1519
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
await
|
|
1520
|
+
const agentsDir = join10(input.codexHome, "agents");
|
|
1521
|
+
await mkdir4(agentsDir, { recursive: true });
|
|
1522
|
+
const linked = [];
|
|
1523
|
+
for (const agentPath of bundledAgents) {
|
|
1524
|
+
const agentFileName = basename3(agentPath);
|
|
1525
|
+
const agentName = agentNameFromToml2(agentFileName);
|
|
1526
|
+
const linkPath = join10(agentsDir, agentFileName);
|
|
1527
|
+
await replaceWithCopy(linkPath, agentPath);
|
|
1528
|
+
await restorePreservedReasoning({
|
|
1529
|
+
agentName,
|
|
1530
|
+
linkPath,
|
|
1531
|
+
target: agentPath,
|
|
1532
|
+
value: input.preservedReasoning?.get(agentName)
|
|
1533
|
+
});
|
|
1534
|
+
await restorePreservedServiceTier({
|
|
1535
|
+
linkPath,
|
|
1536
|
+
preserved: input.preservedServiceTier?.has(agentName) ?? false,
|
|
1537
|
+
value: input.preservedServiceTier?.get(agentName) ?? null
|
|
1538
|
+
});
|
|
1539
|
+
linked.push({ name: agentFileName, path: linkPath, target: agentPath });
|
|
1614
1540
|
}
|
|
1541
|
+
await writeManifest(input.pluginRoot, linked.map((entry) => entry.path));
|
|
1542
|
+
return linked;
|
|
1615
1543
|
}
|
|
1616
|
-
async function
|
|
1617
|
-
const
|
|
1618
|
-
if (!
|
|
1619
|
-
return;
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
if (!isReservedNestedBinName(name, packageRoot, root)) {
|
|
1625
|
-
links.push({ name, target: resolvePackageBinTarget(packageRoot, packageBin) });
|
|
1626
|
-
}
|
|
1627
|
-
return;
|
|
1628
|
-
}
|
|
1629
|
-
if (!isPlainRecord(packageBin))
|
|
1630
|
-
return;
|
|
1631
|
-
for (const [name, target] of Object.entries(packageBin)) {
|
|
1632
|
-
if (typeof target !== "string")
|
|
1544
|
+
async function discoverBundledAgents(pluginRoot) {
|
|
1545
|
+
const componentsRoot = join10(pluginRoot, "components");
|
|
1546
|
+
if (!await exists3(componentsRoot))
|
|
1547
|
+
return [];
|
|
1548
|
+
const componentEntries = await readdir2(componentsRoot, { withFileTypes: true });
|
|
1549
|
+
const agents = [];
|
|
1550
|
+
for (const entry of componentEntries) {
|
|
1551
|
+
if (!entry.isDirectory())
|
|
1633
1552
|
continue;
|
|
1634
|
-
const
|
|
1635
|
-
if (
|
|
1553
|
+
const agentsRoot = join10(componentsRoot, entry.name, "agents");
|
|
1554
|
+
if (!await exists3(agentsRoot))
|
|
1636
1555
|
continue;
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1556
|
+
const agentEntries = await readdir2(agentsRoot, { withFileTypes: true });
|
|
1557
|
+
for (const file of agentEntries) {
|
|
1558
|
+
if (!file.isFile() || !file.name.endsWith(".toml"))
|
|
1559
|
+
continue;
|
|
1560
|
+
agents.push(join10(agentsRoot, file.name));
|
|
1561
|
+
}
|
|
1643
1562
|
}
|
|
1644
|
-
|
|
1563
|
+
agents.sort();
|
|
1564
|
+
return agents;
|
|
1645
1565
|
}
|
|
1646
|
-
function
|
|
1647
|
-
|
|
1566
|
+
async function replaceWithCopy(linkPath, target) {
|
|
1567
|
+
await prepareReplacement(linkPath);
|
|
1568
|
+
await copyFile(target, linkPath);
|
|
1648
1569
|
}
|
|
1649
|
-
function
|
|
1650
|
-
if (
|
|
1651
|
-
|
|
1652
|
-
const
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
if (relativeTarget === "" || relativeTarget !== ".." && !relativeTarget.startsWith(`..${sep}`) && !isAbsolute3(relativeTarget)) {
|
|
1656
|
-
return resolvedTarget;
|
|
1570
|
+
async function prepareReplacement(linkPath) {
|
|
1571
|
+
if (!await exists3(linkPath))
|
|
1572
|
+
return;
|
|
1573
|
+
const entryStat = await lstat3(linkPath);
|
|
1574
|
+
if (entryStat.isDirectory() && !entryStat.isSymbolicLink()) {
|
|
1575
|
+
throw new Error(`${linkPath} already exists and is a directory; refusing to replace`);
|
|
1657
1576
|
}
|
|
1658
|
-
|
|
1659
|
-
}
|
|
1660
|
-
async function replaceSymlink(linkPath, targetPath) {
|
|
1661
|
-
if (await existingNonSymlink(linkPath))
|
|
1662
|
-
throw new Error(`${linkPath} already exists and is not a symlink`);
|
|
1663
|
-
await rm9(linkPath, { force: true });
|
|
1664
|
-
await symlink(targetPath, linkPath);
|
|
1577
|
+
await rm6(linkPath, { force: true });
|
|
1665
1578
|
}
|
|
1666
|
-
async function
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
await
|
|
1579
|
+
async function writeManifest(pluginRoot, agentPaths) {
|
|
1580
|
+
const manifestPath = join10(pluginRoot, MANIFEST_FILE);
|
|
1581
|
+
const payload = { agents: [...agentPaths].sort() };
|
|
1582
|
+
await writeFile4(manifestPath, `${JSON.stringify(payload, null, "\t")}
|
|
1583
|
+
`);
|
|
1670
1584
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
|
|
1674
|
-
await rm9(linkPath, { force: true });
|
|
1675
|
-
await writeFile5(linkPath, content);
|
|
1585
|
+
function agentNameFromToml2(fileName) {
|
|
1586
|
+
return fileName.endsWith(".toml") ? fileName.slice(0, -".toml".length) : fileName;
|
|
1676
1587
|
}
|
|
1677
|
-
async function
|
|
1588
|
+
async function exists3(path) {
|
|
1678
1589
|
try {
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
return false;
|
|
1682
|
-
if (!stat5.isFile())
|
|
1683
|
-
return true;
|
|
1684
|
-
const content = await readFile8(path, "utf8");
|
|
1685
|
-
return !content.includes(RUNTIME_WRAPPER_MARKER);
|
|
1590
|
+
await lstat3(path);
|
|
1591
|
+
return true;
|
|
1686
1592
|
} catch (error) {
|
|
1687
|
-
if (
|
|
1688
|
-
|
|
1689
|
-
|
|
1593
|
+
if (nodeErrorCode3(error) !== "ENOENT")
|
|
1594
|
+
throw error;
|
|
1595
|
+
return false;
|
|
1690
1596
|
}
|
|
1691
1597
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
return true;
|
|
1697
|
-
const content = await readFile8(path, "utf8");
|
|
1698
|
-
if (content.includes(COMMAND_SHIM_MARKER))
|
|
1699
|
-
return false;
|
|
1700
|
-
throw new Error(`${path} already exists and is not a generated command shim`);
|
|
1701
|
-
} catch (error) {
|
|
1702
|
-
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1703
|
-
return false;
|
|
1704
|
-
throw error;
|
|
1705
|
-
}
|
|
1598
|
+
function nodeErrorCode3(error) {
|
|
1599
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
1600
|
+
return null;
|
|
1601
|
+
return typeof error.code === "string" ? error.code : null;
|
|
1706
1602
|
}
|
|
1707
|
-
|
|
1603
|
+
|
|
1604
|
+
// ../src/install/codex-cache-bins.ts
|
|
1605
|
+
import { chmod as chmod2, lstat as lstat7, mkdir as mkdir5, readFile as readFile8, readdir as readdir4, readlink as readlink3, rm as rm9, stat as stat4, symlink, writeFile as writeFile5 } from "node:fs/promises";
|
|
1606
|
+
import { basename as basename4, isAbsolute as isAbsolute3, join as join14, relative as relative2, resolve as resolve4, sep } from "node:path";
|
|
1607
|
+
|
|
1608
|
+
// ../src/install/codex-cache-command-shim.ts
|
|
1609
|
+
var COMMAND_SHIM_MARKER = ":: generated by oh-my-openagent Codex installer";
|
|
1610
|
+
function windowsNodeDiscoveryLines() {
|
|
1611
|
+
return [
|
|
1612
|
+
"setlocal EnableExtensions EnableDelayedExpansion",
|
|
1613
|
+
'set "OMO_NODE_BINARY="',
|
|
1614
|
+
'set "OMO_NODE_REPL_NODE_PATH=%NODE_REPL_NODE_PATH%"',
|
|
1615
|
+
'if exist "%CODEX_HOME%\\config.toml" (',
|
|
1616
|
+
` for /f "tokens=1,* delims==" %%A in ('findstr /R /C:"NODE_REPL_NODE_PATH[ ]*=" "%CODEX_HOME%\\config.toml" 2^>nul') do (`,
|
|
1617
|
+
' set "OMO_NODE_REPL_NODE_PATH=%%B"',
|
|
1618
|
+
" )",
|
|
1619
|
+
")",
|
|
1620
|
+
"if defined OMO_NODE_REPL_NODE_PATH (",
|
|
1621
|
+
' set "OMO_NODE_BINARY=!OMO_NODE_REPL_NODE_PATH!"',
|
|
1622
|
+
' for /f "tokens=* delims= " %%N in ("!OMO_NODE_BINARY!") do set "OMO_NODE_BINARY=%%N"',
|
|
1623
|
+
` if "!OMO_NODE_BINARY:~0,1!"=="'" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~1!"`,
|
|
1624
|
+
` if "!OMO_NODE_BINARY:~-1!"=="'" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~0,-1!"`,
|
|
1625
|
+
' if "!OMO_NODE_BINARY:~0,1!"=="^"" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~1!"',
|
|
1626
|
+
' if "!OMO_NODE_BINARY:~-1!"=="^"" set "OMO_NODE_BINARY=!OMO_NODE_BINARY:~0,-1!"',
|
|
1627
|
+
' if defined OMO_NODE_BINARY if not exist "!OMO_NODE_BINARY!" set "OMO_NODE_BINARY="',
|
|
1628
|
+
")",
|
|
1629
|
+
'if not defined OMO_NODE_BINARY where node >nul 2>nul && set "OMO_NODE_BINARY=node"'
|
|
1630
|
+
];
|
|
1631
|
+
}
|
|
1632
|
+
function windowsCommandShim(targetPath) {
|
|
1633
|
+
return [
|
|
1634
|
+
"@echo off",
|
|
1635
|
+
COMMAND_SHIM_MARKER,
|
|
1636
|
+
'if not defined CODEX_HOME set "CODEX_HOME=%USERPROFILE%\\.codex"',
|
|
1637
|
+
...windowsNodeDiscoveryLines(),
|
|
1638
|
+
"if not defined OMO_NODE_BINARY (",
|
|
1639
|
+
" echo omo: no Node runtime was discovered from NODE_REPL_NODE_PATH or PATH; rerun LazyCodex install from Codex Desktop 1>&2",
|
|
1640
|
+
" exit /b 127",
|
|
1641
|
+
")",
|
|
1642
|
+
`"%OMO_NODE_BINARY%" "${targetPath}" %*`,
|
|
1643
|
+
"exit /b %ERRORLEVEL%",
|
|
1644
|
+
""
|
|
1645
|
+
].join(`\r
|
|
1646
|
+
`);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
// ../src/install/codex-cache-dangling-bins.ts
|
|
1650
|
+
import { lstat as lstat5, readFile as readFile6, readdir as readdir3, readlink, rm as rm7, stat as stat3 } from "node:fs/promises";
|
|
1651
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join11, resolve as resolve3 } from "node:path";
|
|
1652
|
+
|
|
1653
|
+
// ../src/install/codex-cache-fs.ts
|
|
1654
|
+
import { lstat as lstat4 } from "node:fs/promises";
|
|
1655
|
+
async function fileExistsStrict(path) {
|
|
1708
1656
|
try {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
return true;
|
|
1712
|
-
await readlink3(path);
|
|
1713
|
-
return false;
|
|
1657
|
+
await lstat4(path);
|
|
1658
|
+
return true;
|
|
1714
1659
|
} catch (error) {
|
|
1715
1660
|
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1716
1661
|
return false;
|
|
1717
1662
|
throw error;
|
|
1718
1663
|
}
|
|
1719
1664
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
import { mkdir as mkdir6, readFile as readFile10 } from "node:fs/promises";
|
|
1723
|
-
import { dirname as dirname8 } from "node:path";
|
|
1724
|
-
|
|
1725
|
-
// ../src/install/toml-section-editor.ts
|
|
1726
|
-
function findTomlSection(config, header) {
|
|
1727
|
-
const headerLine = `[${header}]`;
|
|
1728
|
-
const targetHeaderPath = parseTomlDottedKey(header);
|
|
1729
|
-
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
1730
|
-
let offset = 0;
|
|
1731
|
-
let start = -1;
|
|
1732
|
-
for (const line of lines) {
|
|
1733
|
-
if (line.length === 0)
|
|
1734
|
-
break;
|
|
1735
|
-
const trimmed = line.trim();
|
|
1736
|
-
if (start === -1) {
|
|
1737
|
-
if (tomlTableHeaderMatches(trimmed, headerLine, targetHeaderPath))
|
|
1738
|
-
start = offset;
|
|
1739
|
-
} else if (isTomlTableHeaderLine(line)) {
|
|
1740
|
-
return { start, end: offset, text: config.slice(start, offset) };
|
|
1741
|
-
}
|
|
1742
|
-
offset += line.length;
|
|
1743
|
-
}
|
|
1744
|
-
if (start === -1)
|
|
1745
|
-
return null;
|
|
1746
|
-
return { start, end: config.length, text: config.slice(start) };
|
|
1747
|
-
}
|
|
1748
|
-
function replaceOrInsertSetting(config, section, key, value) {
|
|
1749
|
-
const linePattern = new RegExp(`^[ \\t]*${escapeRegExp(key)}[ \\t]*=.*$`, "m");
|
|
1750
|
-
const replacement = linePattern.test(section.text) ? section.text.replace(linePattern, `${key} = ${value}`) : insertSetting(section.text, key, value);
|
|
1751
|
-
return config.slice(0, section.start) + replacement + config.slice(section.end);
|
|
1665
|
+
function isPlainRecord(value) {
|
|
1666
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1752
1667
|
}
|
|
1753
|
-
function
|
|
1754
|
-
|
|
1755
|
-
const replacement = section.text.replace(linePattern, "");
|
|
1756
|
-
return config.slice(0, section.start) + replacement + config.slice(section.end);
|
|
1668
|
+
function isNodeErrorWithCode(error) {
|
|
1669
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
1757
1670
|
}
|
|
1758
|
-
function replaceOrInsertRootSetting(config, key, value) {
|
|
1759
|
-
const sectionStart = findFirstTableStart(config);
|
|
1760
|
-
const root = config.slice(0, sectionStart);
|
|
1761
|
-
const suffix = config.slice(sectionStart);
|
|
1762
|
-
const linePattern = new RegExp(`^[ \\t]*${escapeRegExp(key)}[ \\t]*=.*$`, "m");
|
|
1763
|
-
const replacement = linePattern.test(root) ? root.replace(linePattern, `${key} = ${value}`) : `${root.trimEnd()}${root.trimEnd().length > 0 ? `
|
|
1764
|
-
` : ""}${key} = ${value}
|
|
1765
|
-
`;
|
|
1766
|
-
if (suffix.length === 0)
|
|
1767
|
-
return replacement;
|
|
1768
|
-
return `${replacement.trimEnd()}
|
|
1769
1671
|
|
|
1770
|
-
|
|
1672
|
+
// ../src/install/codex-cache-dangling-bins.ts
|
|
1673
|
+
async function removeDanglingManagedComponentBins(binDir, platform, managedBinNames) {
|
|
1674
|
+
const entries = await readdir3(binDir, { withFileTypes: true });
|
|
1675
|
+
for (const entry of entries) {
|
|
1676
|
+
const binName = managedBinNameForEntry(entry.name, platform);
|
|
1677
|
+
if (binName === null || !managedBinNames.has(binName))
|
|
1678
|
+
continue;
|
|
1679
|
+
const linkPath = join11(binDir, entry.name);
|
|
1680
|
+
if (platform === "win32") {
|
|
1681
|
+
await removeDanglingGeneratedCommandShim(linkPath);
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
await removeDanglingManagedSymlink(linkPath);
|
|
1685
|
+
}
|
|
1771
1686
|
}
|
|
1772
|
-
function
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
` : ""}${block.trimEnd()}
|
|
1777
|
-
`;
|
|
1687
|
+
function managedBinNameForEntry(name, platform) {
|
|
1688
|
+
if (platform === "win32")
|
|
1689
|
+
return name.endsWith(".cmd") ? name.slice(0, -4) : null;
|
|
1690
|
+
return name;
|
|
1778
1691
|
}
|
|
1779
|
-
function
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1692
|
+
async function removeDanglingManagedSymlink(linkPath) {
|
|
1693
|
+
try {
|
|
1694
|
+
const linkStat = await lstat5(linkPath);
|
|
1695
|
+
if (!linkStat.isSymbolicLink())
|
|
1696
|
+
return;
|
|
1697
|
+
const linkTarget = await readlink(linkPath);
|
|
1698
|
+
const target = isAbsolute2(linkTarget) ? linkTarget : resolve3(dirname5(linkPath), linkTarget);
|
|
1699
|
+
if (!await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
|
|
1700
|
+
await rm7(linkPath, { force: true });
|
|
1701
|
+
} catch (error) {
|
|
1702
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1703
|
+
return;
|
|
1704
|
+
throw error;
|
|
1788
1705
|
}
|
|
1789
|
-
return config.length;
|
|
1790
|
-
}
|
|
1791
|
-
function insertSetting(sectionText, key, value) {
|
|
1792
|
-
const lines = sectionText.split(`
|
|
1793
|
-
`);
|
|
1794
|
-
lines.splice(1, 0, `${key} = ${value}`);
|
|
1795
|
-
return lines.join(`
|
|
1796
|
-
`);
|
|
1797
1706
|
}
|
|
1798
|
-
function
|
|
1799
|
-
|
|
1707
|
+
async function removeDanglingGeneratedCommandShim(linkPath) {
|
|
1708
|
+
try {
|
|
1709
|
+
const linkStat = await lstat5(linkPath);
|
|
1710
|
+
if (!linkStat.isFile())
|
|
1711
|
+
return;
|
|
1712
|
+
const content = await readFile6(linkPath, "utf8");
|
|
1713
|
+
if (!content.includes(COMMAND_SHIM_MARKER))
|
|
1714
|
+
return;
|
|
1715
|
+
const target = extractCommandShimTarget(content);
|
|
1716
|
+
if (target !== null && !await isFileSystemEntry(target) && isManagedComponentBinTarget(target))
|
|
1717
|
+
await rm7(linkPath, { force: true });
|
|
1718
|
+
} catch (error) {
|
|
1719
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1720
|
+
return;
|
|
1721
|
+
throw error;
|
|
1722
|
+
}
|
|
1800
1723
|
}
|
|
1801
|
-
function
|
|
1802
|
-
|
|
1803
|
-
|
|
1724
|
+
async function isFileSystemEntry(path) {
|
|
1725
|
+
try {
|
|
1726
|
+
await stat3(path);
|
|
1804
1727
|
return true;
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
return candidateHeaderPath.every((part, index) => part === targetHeaderPath[index]);
|
|
1728
|
+
} catch (error) {
|
|
1729
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1730
|
+
return false;
|
|
1731
|
+
throw error;
|
|
1732
|
+
}
|
|
1811
1733
|
}
|
|
1812
|
-
function
|
|
1813
|
-
const
|
|
1814
|
-
|
|
1815
|
-
return null;
|
|
1816
|
-
return parseTomlDottedKey(normalizedLine.slice(1, -1).trim());
|
|
1734
|
+
function extractCommandShimTarget(content) {
|
|
1735
|
+
const match = /"([^"\r\n]+components[\\/][^"\r\n]+[\\/]dist[\\/]cli\.js)" %\*/.exec(content);
|
|
1736
|
+
return match?.[1] ?? null;
|
|
1817
1737
|
}
|
|
1818
|
-
function
|
|
1819
|
-
const
|
|
1820
|
-
|
|
1738
|
+
function isManagedComponentBinTarget(target) {
|
|
1739
|
+
const parts = target.split(/[\\/]+/);
|
|
1740
|
+
const suffix = parts.slice(-4);
|
|
1741
|
+
return suffix[0] === "components" && suffix[2] === "dist" && suffix[3] === "cli.js" && (hasOmoPluginCachePrefix(parts, parts.length - 4) || hasOmoCodexPluginPrefix(parts, parts.length - 4));
|
|
1821
1742
|
}
|
|
1822
|
-
function
|
|
1823
|
-
let
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
const char = line[index];
|
|
1827
|
-
if (quote === '"') {
|
|
1828
|
-
if (char === "\\") {
|
|
1829
|
-
index += 2;
|
|
1830
|
-
continue;
|
|
1831
|
-
}
|
|
1832
|
-
if (char === '"')
|
|
1833
|
-
quote = null;
|
|
1834
|
-
index += 1;
|
|
1835
|
-
continue;
|
|
1836
|
-
}
|
|
1837
|
-
if (quote === "'") {
|
|
1838
|
-
if (char === "'")
|
|
1839
|
-
quote = null;
|
|
1840
|
-
index += 1;
|
|
1841
|
-
continue;
|
|
1842
|
-
}
|
|
1843
|
-
if (char === '"' || char === "'") {
|
|
1844
|
-
quote = char;
|
|
1845
|
-
index += 1;
|
|
1846
|
-
continue;
|
|
1743
|
+
function hasOmoPluginCachePrefix(parts, endExclusive) {
|
|
1744
|
+
for (let index = 0;index < endExclusive - 4; index += 1) {
|
|
1745
|
+
if (parts[index] === "plugins" && parts[index + 1] === "cache" && parts[index + 2] === "sisyphuslabs" && parts[index + 3] === "omo") {
|
|
1746
|
+
return index + 4 < endExclusive;
|
|
1847
1747
|
}
|
|
1848
|
-
if (char === "#")
|
|
1849
|
-
return line.slice(0, index);
|
|
1850
|
-
index += 1;
|
|
1851
1748
|
}
|
|
1852
|
-
return
|
|
1749
|
+
return false;
|
|
1853
1750
|
}
|
|
1854
|
-
function
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
index = skipWhitespace(input, index);
|
|
1859
|
-
const parsedKey = parseTomlKeyPart(input, index);
|
|
1860
|
-
if (!parsedKey)
|
|
1861
|
-
return null;
|
|
1862
|
-
parts.push(parsedKey.value);
|
|
1863
|
-
index = skipWhitespace(input, parsedKey.nextIndex);
|
|
1864
|
-
if (index === input.length)
|
|
1865
|
-
return parts;
|
|
1866
|
-
if (input[index] !== ".")
|
|
1867
|
-
return null;
|
|
1868
|
-
index += 1;
|
|
1751
|
+
function hasOmoCodexPluginPrefix(parts, endExclusive) {
|
|
1752
|
+
for (let index = 0;index <= endExclusive - 3; index += 1) {
|
|
1753
|
+
if (parts[index] === "packages" && parts[index + 1] === "omo-codex" && parts[index + 2] === "plugin")
|
|
1754
|
+
return true;
|
|
1869
1755
|
}
|
|
1870
|
-
return
|
|
1871
|
-
}
|
|
1872
|
-
function parseTomlKeyPart(input, startIndex) {
|
|
1873
|
-
const quote = input[startIndex];
|
|
1874
|
-
if (quote === "'")
|
|
1875
|
-
return parseLiteralTomlString(input, startIndex);
|
|
1876
|
-
if (quote === '"')
|
|
1877
|
-
return parseBasicTomlString(input, startIndex);
|
|
1878
|
-
return parseBareTomlKey(input, startIndex);
|
|
1756
|
+
return false;
|
|
1879
1757
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1758
|
+
|
|
1759
|
+
// ../src/install/codex-cache-legacy-bins.ts
|
|
1760
|
+
import { lstat as lstat6, readFile as readFile7, readlink as readlink2, rm as rm8 } from "node:fs/promises";
|
|
1761
|
+
import { join as join12 } from "node:path";
|
|
1762
|
+
var LEGACY_CODEX_COMPONENT_BINS = [
|
|
1763
|
+
{ name: "omo", component: "ulw-loop" },
|
|
1764
|
+
{ name: "codex-comment-checker", component: "comment-checker" },
|
|
1765
|
+
{ name: "codex-lsp", component: "lsp" },
|
|
1766
|
+
{ name: "codex-rules", component: "rules" },
|
|
1767
|
+
{ name: "codex-start-work-continuation", component: "start-work-continuation" },
|
|
1768
|
+
{ name: "codex-telemetry", component: "telemetry" },
|
|
1769
|
+
{ name: "codex-ultrawork", component: "ultrawork" }
|
|
1770
|
+
];
|
|
1771
|
+
async function removeLegacyCodexComponentBins(binDir, platform) {
|
|
1772
|
+
for (const entry of LEGACY_CODEX_COMPONENT_BINS) {
|
|
1773
|
+
const linkPath = join12(binDir, platform === "win32" ? `${entry.name}.cmd` : entry.name);
|
|
1774
|
+
await removeLegacyCodexComponentBin(linkPath, entry.component, platform);
|
|
1889
1775
|
}
|
|
1890
|
-
return null;
|
|
1891
1776
|
}
|
|
1892
|
-
function
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
continue;
|
|
1777
|
+
async function removeLegacyCodexComponentBin(linkPath, component, platform) {
|
|
1778
|
+
try {
|
|
1779
|
+
const stat4 = await lstat6(linkPath);
|
|
1780
|
+
if (platform !== "win32") {
|
|
1781
|
+
if (!stat4.isSymbolicLink())
|
|
1782
|
+
return;
|
|
1783
|
+
const target = await readlink2(linkPath);
|
|
1784
|
+
if (isManagedLegacyComponentTarget(target, component))
|
|
1785
|
+
await rm8(linkPath, { force: true });
|
|
1786
|
+
return;
|
|
1903
1787
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1788
|
+
if (!stat4.isFile())
|
|
1789
|
+
return;
|
|
1790
|
+
const content = await readFile7(linkPath, "utf8");
|
|
1791
|
+
if (content.includes(COMMAND_SHIM_MARKER))
|
|
1792
|
+
await rm8(linkPath, { force: true });
|
|
1793
|
+
} catch (error) {
|
|
1794
|
+
if (isNodeErrorWithCode2(error) && error.code === "ENOENT")
|
|
1795
|
+
return;
|
|
1796
|
+
throw error;
|
|
1909
1797
|
}
|
|
1910
|
-
return null;
|
|
1911
1798
|
}
|
|
1912
|
-
function
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
return { value: "\b", nextIndex: backslashIndex + 2 };
|
|
1918
|
-
if (escape === "t")
|
|
1919
|
-
return { value: "\t", nextIndex: backslashIndex + 2 };
|
|
1920
|
-
if (escape === "n")
|
|
1921
|
-
return { value: `
|
|
1922
|
-
`, nextIndex: backslashIndex + 2 };
|
|
1923
|
-
if (escape === "f")
|
|
1924
|
-
return { value: "\f", nextIndex: backslashIndex + 2 };
|
|
1925
|
-
if (escape === "r")
|
|
1926
|
-
return { value: "\r", nextIndex: backslashIndex + 2 };
|
|
1927
|
-
if (escape === '"')
|
|
1928
|
-
return { value: '"', nextIndex: backslashIndex + 2 };
|
|
1929
|
-
if (escape === "\\")
|
|
1930
|
-
return { value: "\\", nextIndex: backslashIndex + 2 };
|
|
1931
|
-
if (escape === "u")
|
|
1932
|
-
return parseUnicodeEscape(input, backslashIndex + 2, 4);
|
|
1933
|
-
if (escape === "U")
|
|
1934
|
-
return parseUnicodeEscape(input, backslashIndex + 2, 8);
|
|
1935
|
-
return null;
|
|
1799
|
+
function isManagedLegacyComponentTarget(target, component) {
|
|
1800
|
+
const parts = target.split(/[\\/]+/);
|
|
1801
|
+
const suffixStart = parts.length - 4;
|
|
1802
|
+
const suffix = parts.slice(-4);
|
|
1803
|
+
return suffix[0] === "components" && suffix[1] === component && suffix[2] === "dist" && suffix[3] === "cli.js" && (hasPluginCachePrefix(parts, suffixStart) || hasOmoCodexPluginPrefix2(parts, suffixStart));
|
|
1936
1804
|
}
|
|
1937
|
-
function
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1805
|
+
function hasPluginCachePrefix(parts, endExclusive) {
|
|
1806
|
+
for (let index = 0;index < endExclusive - 1; index += 1) {
|
|
1807
|
+
if (parts[index] === "plugins" && parts[index + 1] === "cache")
|
|
1808
|
+
return true;
|
|
1809
|
+
}
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
function hasOmoCodexPluginPrefix2(parts, endExclusive) {
|
|
1813
|
+
for (let index = 0;index <= endExclusive - 3; index += 1) {
|
|
1814
|
+
if (parts[index] === "packages" && parts[index + 1] === "omo-codex" && parts[index + 2] === "plugin")
|
|
1815
|
+
return true;
|
|
1816
|
+
}
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
function isNodeErrorWithCode2(error) {
|
|
1820
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
// ../src/install/codex-cache-runtime-wrapper.ts
|
|
1824
|
+
import { join as join13 } from "node:path";
|
|
1825
|
+
var RUNTIME_WRAPPER_MARKER = "OMO_GENERATED_RUNTIME_WRAPPER";
|
|
1826
|
+
function posixRuntimeWrapper(cliPath, codexHome, binDir, nodeCliPath) {
|
|
1827
|
+
const ulwLoopBin = toPosixPath(join13(binDir, "omo-ulw-loop"));
|
|
1828
|
+
const nodeCli = escapePosixDoubleQuoted(toPosixPath(nodeCliPath));
|
|
1829
|
+
const escapedCliPath = escapePosixDoubleQuoted(toPosixPath(cliPath));
|
|
1830
|
+
const escapedCodexHome = escapePosixDoubleQuoted(toPosixPath(codexHome));
|
|
1831
|
+
const escapedUlwLoopBin = escapePosixDoubleQuoted(ulwLoopBin);
|
|
1832
|
+
return [
|
|
1833
|
+
"#!/bin/sh",
|
|
1834
|
+
`# ${RUNTIME_WRAPPER_MARKER}`,
|
|
1835
|
+
`export CODEX_HOME="\${CODEX_HOME:-${escapedCodexHome}}"`,
|
|
1836
|
+
'if [ "$1" = "ulw-loop" ] && [ -x "' + escapedUlwLoopBin + '" ]; then',
|
|
1837
|
+
" shift",
|
|
1838
|
+
' exec "' + escapedUlwLoopBin + '" ulw-loop "$@"',
|
|
1839
|
+
"fi",
|
|
1840
|
+
`if [ "\${OMO_RUNTIME:-}" = "node" ] && [ -f "${nodeCli}" ]; then`,
|
|
1841
|
+
` exec node "${nodeCli}" "$@"`,
|
|
1842
|
+
"fi",
|
|
1843
|
+
'BUN_BINARY="${BUN_BINARY:-}"',
|
|
1844
|
+
'if [ -z "$BUN_BINARY" ] && command -v bun >/dev/null 2>&1; then',
|
|
1845
|
+
" BUN_BINARY=bun",
|
|
1846
|
+
"fi",
|
|
1847
|
+
'if [ -z "$BUN_BINARY" ]; then',
|
|
1848
|
+
' for omo_bun_candidate in "$HOME/.bun/bin/bun" /opt/homebrew/bin/bun /usr/local/bin/bun; do',
|
|
1849
|
+
' if [ -x "$omo_bun_candidate" ]; then',
|
|
1850
|
+
' BUN_BINARY="$omo_bun_candidate"',
|
|
1851
|
+
" break",
|
|
1852
|
+
" fi",
|
|
1853
|
+
" done",
|
|
1854
|
+
"fi",
|
|
1855
|
+
'if [ -z "$BUN_BINARY" ]; then',
|
|
1856
|
+
` if [ -f "${nodeCli}" ] && command -v node >/dev/null 2>&1; then`,
|
|
1857
|
+
` exec node "${nodeCli}" "$@"`,
|
|
1858
|
+
" fi",
|
|
1859
|
+
` echo "omo: bun runtime not found (checked PATH, ~/.bun/bin, /opt/homebrew/bin, /usr/local/bin) and the node fallback CLI is missing at ${nodeCli}; install bun from https://bun.sh, or reinstall omo and force the fallback with OMO_RUNTIME=node" >&2`,
|
|
1860
|
+
" exit 127",
|
|
1861
|
+
"fi",
|
|
1862
|
+
`if [ ! -f "${escapedCliPath}" ]; then`,
|
|
1863
|
+
` echo "omo: runtime target missing at ${escapedCliPath}; reinstall with: npx --yes lazycodex-ai@latest install --no-tui" >&2`,
|
|
1864
|
+
" exit 1",
|
|
1865
|
+
"fi",
|
|
1866
|
+
`exec "$BUN_BINARY" "${escapedCliPath}" "$@"`,
|
|
1867
|
+
""
|
|
1868
|
+
].join(`
|
|
1869
|
+
`);
|
|
1870
|
+
}
|
|
1871
|
+
function windowsRuntimeWrapper(cliPath, codexHome, binDir, nodeCliPath) {
|
|
1872
|
+
const ulwLoopBin = join13(binDir, "omo-ulw-loop.cmd");
|
|
1873
|
+
return [
|
|
1874
|
+
"@echo off",
|
|
1875
|
+
`rem ${RUNTIME_WRAPPER_MARKER}`,
|
|
1876
|
+
`if not defined CODEX_HOME set "CODEX_HOME=${codexHome}"`,
|
|
1877
|
+
...windowsNodeDiscoveryLines(),
|
|
1878
|
+
`if "%~1"=="ulw-loop" if exist "${ulwLoopBin}" (`,
|
|
1879
|
+
" shift /1",
|
|
1880
|
+
` "${ulwLoopBin}" ulw-loop %*`,
|
|
1881
|
+
" exit /b %ERRORLEVEL%",
|
|
1882
|
+
")",
|
|
1883
|
+
`if "%OMO_RUNTIME%"=="node" if defined OMO_NODE_BINARY if exist "${nodeCliPath}" (`,
|
|
1884
|
+
` "%OMO_NODE_BINARY%" "${nodeCliPath}" %*`,
|
|
1885
|
+
" exit /b %ERRORLEVEL%",
|
|
1886
|
+
")",
|
|
1887
|
+
'if not defined BUN_BINARY where bun >nul 2>nul && set "BUN_BINARY=bun"',
|
|
1888
|
+
'if not defined BUN_BINARY if exist "%USERPROFILE%\\.bun\\bin\\bun.exe" set "BUN_BINARY=%USERPROFILE%\\.bun\\bin\\bun.exe"',
|
|
1889
|
+
"if not defined BUN_BINARY (",
|
|
1890
|
+
` if defined OMO_NODE_BINARY if exist "${nodeCliPath}" (`,
|
|
1891
|
+
` "%OMO_NODE_BINARY%" "${nodeCliPath}" %*`,
|
|
1892
|
+
" exit /b %ERRORLEVEL%",
|
|
1893
|
+
" )",
|
|
1894
|
+
` echo omo: bun runtime not found, no Node runtime was discovered from NODE_REPL_NODE_PATH or PATH, or the node fallback CLI is missing at ${nodeCliPath}; install bun from https://bun.sh or rerun LazyCodex install from Codex Desktop 1>&2`,
|
|
1895
|
+
" exit /b 127",
|
|
1896
|
+
")",
|
|
1897
|
+
`if not exist "${cliPath}" (`,
|
|
1898
|
+
` echo omo: runtime target missing at ${cliPath}; reinstall with: npx --yes lazycodex-ai@latest install --no-tui 1>&2`,
|
|
1899
|
+
" exit /b 1",
|
|
1900
|
+
")",
|
|
1901
|
+
`"%BUN_BINARY%" "${cliPath}" %*`,
|
|
1902
|
+
""
|
|
1903
|
+
].join(`\r
|
|
1904
|
+
`);
|
|
1945
1905
|
}
|
|
1946
|
-
function
|
|
1947
|
-
|
|
1948
|
-
while (index < input.length && /[A-Za-z0-9_-]/.test(input[index]))
|
|
1949
|
-
index += 1;
|
|
1950
|
-
if (index === startIndex)
|
|
1951
|
-
return null;
|
|
1952
|
-
return { value: input.slice(startIndex, index), nextIndex: index };
|
|
1906
|
+
function toPosixPath(path) {
|
|
1907
|
+
return path.replaceAll("\\", "/");
|
|
1953
1908
|
}
|
|
1954
|
-
function
|
|
1955
|
-
|
|
1956
|
-
while (index < input.length && /\s/.test(input[index]))
|
|
1957
|
-
index += 1;
|
|
1958
|
-
return index;
|
|
1909
|
+
function escapePosixDoubleQuoted(value) {
|
|
1910
|
+
return value.replaceAll("\\", "\\\\").replaceAll('"', "\\\"").replaceAll("$", "\\$").replaceAll("`", "\\`");
|
|
1959
1911
|
}
|
|
1960
1912
|
|
|
1961
|
-
// ../src/install/codex-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
}
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
const
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
break;
|
|
1974
|
-
const header = parseTomlHeader2(line);
|
|
1975
|
-
if (header !== null) {
|
|
1976
|
-
if (current.text.length > 0)
|
|
1977
|
-
sections.push(current);
|
|
1978
|
-
current = { header, text: line };
|
|
1979
|
-
} else {
|
|
1980
|
-
current = { ...current, text: current.text + line };
|
|
1981
|
-
}
|
|
1913
|
+
// ../src/install/codex-cache-bins.ts
|
|
1914
|
+
var RESERVED_NESTED_BIN_NAMES = new Set(["omo", "lazycodex", "lazycodex-ai", "oh-my-opencode", "oh-my-openagent"]);
|
|
1915
|
+
async function linkCachedPluginBins(input) {
|
|
1916
|
+
const binLinks = await discoverPackageBins(input.pluginRoot);
|
|
1917
|
+
const platform = input.platform ?? process.platform;
|
|
1918
|
+
await mkdir5(input.binDir, { recursive: true });
|
|
1919
|
+
await removeLegacyCodexComponentBins(input.binDir, platform);
|
|
1920
|
+
await removeDanglingManagedComponentBins(input.binDir, platform, new Set(binLinks.map((link) => link.name)));
|
|
1921
|
+
const linked = [];
|
|
1922
|
+
for (const link of binLinks) {
|
|
1923
|
+
const linkPath = await linkCachedPluginBin(input.binDir, link, platform);
|
|
1924
|
+
linked.push({ name: link.name, path: linkPath, target: link.target });
|
|
1982
1925
|
}
|
|
1983
|
-
|
|
1984
|
-
sections.push(current);
|
|
1985
|
-
return sections;
|
|
1926
|
+
return linked;
|
|
1986
1927
|
}
|
|
1987
|
-
function
|
|
1988
|
-
const
|
|
1989
|
-
|
|
1928
|
+
async function linkRootRuntimeBin(input) {
|
|
1929
|
+
const cliPath = join14(input.repoRoot, "dist", "cli", "index.js");
|
|
1930
|
+
if (!await isFile2(cliPath))
|
|
1931
|
+
return null;
|
|
1932
|
+
const nodeCliPath = join14(input.repoRoot, "dist", "cli-node", "index.js");
|
|
1933
|
+
const platform = input.platform ?? process.platform;
|
|
1934
|
+
await mkdir5(input.binDir, { recursive: true });
|
|
1935
|
+
if (platform === "win32") {
|
|
1936
|
+
const linkPath2 = join14(input.binDir, "omo.cmd");
|
|
1937
|
+
await replaceRuntimeWrapper(linkPath2, windowsRuntimeWrapper(cliPath, input.codexHome, input.binDir, nodeCliPath));
|
|
1938
|
+
return { name: "omo", path: linkPath2, target: cliPath };
|
|
1939
|
+
}
|
|
1940
|
+
const linkPath = join14(input.binDir, "omo");
|
|
1941
|
+
await replaceRuntimeWrapper(linkPath, posixRuntimeWrapper(cliPath, input.codexHome, input.binDir, nodeCliPath));
|
|
1942
|
+
await chmod2(linkPath, 493);
|
|
1943
|
+
return { name: "omo", path: linkPath, target: cliPath };
|
|
1990
1944
|
}
|
|
1991
|
-
function
|
|
1992
|
-
|
|
1993
|
-
|
|
1945
|
+
async function linkCachedPluginBin(binDir, link, platform) {
|
|
1946
|
+
if (platform === "win32") {
|
|
1947
|
+
const linkPath2 = join14(binDir, `${link.name}.cmd`);
|
|
1948
|
+
await replaceCommandShim(linkPath2, link.target);
|
|
1949
|
+
return linkPath2;
|
|
1950
|
+
}
|
|
1951
|
+
const linkPath = join14(binDir, link.name);
|
|
1952
|
+
await replaceSymlink(linkPath, link.target);
|
|
1953
|
+
return linkPath;
|
|
1994
1954
|
}
|
|
1995
|
-
function
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
1955
|
+
async function isFile2(path) {
|
|
1956
|
+
try {
|
|
1957
|
+
return (await stat4(path)).isFile();
|
|
1958
|
+
} catch (error) {
|
|
1959
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
1960
|
+
return false;
|
|
1961
|
+
throw error;
|
|
1962
|
+
}
|
|
2000
1963
|
}
|
|
2001
|
-
function
|
|
2002
|
-
const
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
return trimmed.slice(1, -1);
|
|
1964
|
+
async function discoverPackageBins(root) {
|
|
1965
|
+
const links = [];
|
|
1966
|
+
await collectPackageBins(root, root, links);
|
|
1967
|
+
return links;
|
|
2006
1968
|
}
|
|
2007
|
-
function
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
index += 2;
|
|
2015
|
-
continue;
|
|
2016
|
-
}
|
|
2017
|
-
if (char === '"')
|
|
2018
|
-
quote = null;
|
|
2019
|
-
index += 1;
|
|
1969
|
+
async function collectPackageBins(directory, root, links) {
|
|
1970
|
+
const entries = await readdir4(directory, { withFileTypes: true });
|
|
1971
|
+
if (entries.some((entry) => entry.isFile() && entry.name === "package.json")) {
|
|
1972
|
+
await appendPackageBinLinks(join14(directory, "package.json"), directory, root, links);
|
|
1973
|
+
}
|
|
1974
|
+
for (const entry of entries) {
|
|
1975
|
+
if (!entry.isDirectory())
|
|
2020
1976
|
continue;
|
|
2021
|
-
|
|
2022
|
-
if (quote === "'") {
|
|
2023
|
-
if (char === "'")
|
|
2024
|
-
quote = null;
|
|
2025
|
-
index += 1;
|
|
1977
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")
|
|
2026
1978
|
continue;
|
|
2027
|
-
|
|
2028
|
-
if (
|
|
2029
|
-
quote = char;
|
|
2030
|
-
index += 1;
|
|
1979
|
+
const childPath = join14(directory, entry.name);
|
|
1980
|
+
if (!childPath.startsWith(root))
|
|
2031
1981
|
continue;
|
|
1982
|
+
await collectPackageBins(childPath, root, links);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
async function appendPackageBinLinks(packageJsonPath, packageRoot, root, links) {
|
|
1986
|
+
const packageJson = JSON.parse(await readFile8(packageJsonPath, "utf8"));
|
|
1987
|
+
if (!isPlainRecord(packageJson))
|
|
1988
|
+
return;
|
|
1989
|
+
const packageName = packageJson.name;
|
|
1990
|
+
const packageBin = packageJson.bin;
|
|
1991
|
+
if (typeof packageBin === "string" && typeof packageName === "string") {
|
|
1992
|
+
const name = assertSafeCommandName(basename4(packageName));
|
|
1993
|
+
if (!isReservedNestedBinName(name, packageRoot, root)) {
|
|
1994
|
+
links.push({ name, target: resolvePackageBinTarget(packageRoot, packageBin) });
|
|
2032
1995
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
if (!isPlainRecord(packageBin))
|
|
1999
|
+
return;
|
|
2000
|
+
for (const [name, target] of Object.entries(packageBin)) {
|
|
2001
|
+
if (typeof target !== "string")
|
|
2002
|
+
continue;
|
|
2003
|
+
const commandName = assertSafeCommandName(name);
|
|
2004
|
+
if (isReservedNestedBinName(commandName, packageRoot, root))
|
|
2005
|
+
continue;
|
|
2006
|
+
links.push({ name: commandName, target: resolvePackageBinTarget(packageRoot, target) });
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
function assertSafeCommandName(name) {
|
|
2010
|
+
if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\") || name.includes("\x00")) {
|
|
2011
|
+
throw new Error(`Invalid package bin command name: ${name}`);
|
|
2012
|
+
}
|
|
2013
|
+
return name;
|
|
2014
|
+
}
|
|
2015
|
+
function isReservedNestedBinName(name, packageRoot, root) {
|
|
2016
|
+
return packageRoot !== root && RESERVED_NESTED_BIN_NAMES.has(name);
|
|
2017
|
+
}
|
|
2018
|
+
function resolvePackageBinTarget(packageRoot, target) {
|
|
2019
|
+
if (target.includes("\x00"))
|
|
2020
|
+
throw new Error("Package bin target must stay inside package root");
|
|
2021
|
+
const root = resolve4(packageRoot);
|
|
2022
|
+
const resolvedTarget = resolve4(root, target);
|
|
2023
|
+
const relativeTarget = relative2(root, resolvedTarget);
|
|
2024
|
+
if (relativeTarget === "" || relativeTarget !== ".." && !relativeTarget.startsWith(`..${sep}`) && !isAbsolute3(relativeTarget)) {
|
|
2025
|
+
return resolvedTarget;
|
|
2026
|
+
}
|
|
2027
|
+
throw new Error("Package bin target must stay inside package root");
|
|
2028
|
+
}
|
|
2029
|
+
async function replaceSymlink(linkPath, targetPath) {
|
|
2030
|
+
if (await existingNonSymlink(linkPath))
|
|
2031
|
+
throw new Error(`${linkPath} already exists and is not a symlink`);
|
|
2032
|
+
await rm9(linkPath, { force: true });
|
|
2033
|
+
await symlink(targetPath, linkPath);
|
|
2034
|
+
}
|
|
2035
|
+
async function replaceCommandShim(linkPath, targetPath) {
|
|
2036
|
+
if (await existingNonShim(linkPath))
|
|
2037
|
+
throw new Error(`${linkPath} already exists and is not a command shim`);
|
|
2038
|
+
await writeFile5(linkPath, windowsCommandShim(targetPath));
|
|
2039
|
+
}
|
|
2040
|
+
async function replaceRuntimeWrapper(linkPath, content) {
|
|
2041
|
+
if (await existingNonRuntimeWrapper(linkPath))
|
|
2042
|
+
throw new Error(`${linkPath} already exists and is not a generated OMO runtime wrapper`);
|
|
2043
|
+
await rm9(linkPath, { force: true });
|
|
2044
|
+
await writeFile5(linkPath, content);
|
|
2045
|
+
}
|
|
2046
|
+
async function existingNonRuntimeWrapper(path) {
|
|
2047
|
+
try {
|
|
2048
|
+
const stat5 = await lstat7(path);
|
|
2049
|
+
if (stat5.isSymbolicLink())
|
|
2050
|
+
return false;
|
|
2051
|
+
if (!stat5.isFile())
|
|
2052
|
+
return true;
|
|
2053
|
+
const content = await readFile8(path, "utf8");
|
|
2054
|
+
return !content.includes(RUNTIME_WRAPPER_MARKER);
|
|
2055
|
+
} catch (error) {
|
|
2056
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
2057
|
+
return false;
|
|
2058
|
+
throw error;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
async function existingNonShim(path) {
|
|
2062
|
+
try {
|
|
2063
|
+
const stat5 = await lstat7(path);
|
|
2064
|
+
if (!stat5.isFile())
|
|
2065
|
+
return true;
|
|
2066
|
+
const content = await readFile8(path, "utf8");
|
|
2067
|
+
if (content.includes(COMMAND_SHIM_MARKER))
|
|
2068
|
+
return false;
|
|
2069
|
+
throw new Error(`${path} already exists and is not a generated command shim`);
|
|
2070
|
+
} catch (error) {
|
|
2071
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
2072
|
+
return false;
|
|
2073
|
+
throw error;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
async function existingNonSymlink(path) {
|
|
2077
|
+
try {
|
|
2078
|
+
const stat5 = await lstat7(path);
|
|
2079
|
+
if (!stat5.isSymbolicLink())
|
|
2080
|
+
return true;
|
|
2081
|
+
await readlink3(path);
|
|
2082
|
+
return false;
|
|
2083
|
+
} catch (error) {
|
|
2084
|
+
if (isNodeErrorWithCode(error) && error.code === "ENOENT")
|
|
2085
|
+
return false;
|
|
2086
|
+
throw error;
|
|
2036
2087
|
}
|
|
2037
|
-
return line;
|
|
2038
2088
|
}
|
|
2039
2089
|
|
|
2090
|
+
// ../src/install/codex-config-toml.ts
|
|
2091
|
+
import { mkdir as mkdir6, readFile as readFile10 } from "node:fs/promises";
|
|
2092
|
+
import { dirname as dirname8 } from "node:path";
|
|
2093
|
+
|
|
2040
2094
|
// ../src/install/codex-config-agents.ts
|
|
2041
2095
|
var LEGACY_MANAGED_CODEX_AGENT_NAMES_TO_PURGE = ["codex-ultrawork-reviewer"];
|
|
2042
2096
|
var CURRENT_MANAGED_CODEX_AGENT_NAMES = [
|
|
2043
2097
|
"explorer",
|
|
2098
|
+
"lazycodex-worker-high",
|
|
2099
|
+
"lazycodex-worker-low",
|
|
2100
|
+
"lazycodex-worker-medium",
|
|
2044
2101
|
"librarian",
|
|
2045
2102
|
"metis",
|
|
2046
2103
|
"momus",
|
|
@@ -2458,12 +2515,18 @@ import { readFile as readFile9 } from "node:fs/promises";
|
|
|
2458
2515
|
import { join as join16 } from "node:path";
|
|
2459
2516
|
var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
2460
2517
|
current: {
|
|
2461
|
-
model: "gpt-5.
|
|
2462
|
-
modelContextWindow:
|
|
2518
|
+
model: "gpt-5.6-sol",
|
|
2519
|
+
modelContextWindow: 372000,
|
|
2463
2520
|
modelReasoningEffort: "high",
|
|
2464
2521
|
planModeReasoningEffort: "xhigh"
|
|
2465
2522
|
},
|
|
2466
2523
|
managedProfiles: [
|
|
2524
|
+
{
|
|
2525
|
+
model: "gpt-5.5",
|
|
2526
|
+
modelContextWindow: 400000,
|
|
2527
|
+
modelReasoningEffort: "high",
|
|
2528
|
+
planModeReasoningEffort: "xhigh"
|
|
2529
|
+
},
|
|
2467
2530
|
{
|
|
2468
2531
|
model: "gpt-5.5",
|
|
2469
2532
|
modelContextWindow: 1e6,
|