oh-my-opencode 4.5.12 → 4.7.0
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/skills/opencode-qa/SKILL.md +194 -0
- package/.agents/skills/opencode-qa/references/cli-commands.md +188 -0
- package/.agents/skills/opencode-qa/references/db-investigation.md +197 -0
- package/.agents/skills/opencode-qa/references/events-hooks.md +110 -0
- package/.agents/skills/opencode-qa/references/sdk.md +96 -0
- package/.agents/skills/opencode-qa/references/server-api.md +200 -0
- package/.agents/skills/opencode-qa/references/testing-harness.md +218 -0
- package/.agents/skills/opencode-qa/references/tui-tmux.md +52 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-id.sh +53 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-name.sh +57 -0
- package/.agents/skills/opencode-qa/scripts/db-session-by-text.sh +158 -0
- package/.agents/skills/opencode-qa/scripts/export-roundtrip.sh +57 -0
- package/.agents/skills/opencode-qa/scripts/lib/common.sh +216 -0
- package/.agents/skills/opencode-qa/scripts/server-smoke.sh +64 -0
- package/.agents/skills/opencode-qa/scripts/sse-hook-probe.sh +106 -0
- package/.agents/skills/opencode-qa/scripts/tui-smoke.sh +89 -0
- package/README.ja.md +13 -3
- package/README.ko.md +13 -3
- package/README.md +24 -14
- package/README.ru.md +13 -3
- package/README.zh-cn.md +13 -3
- package/bin/oh-my-opencode.js +4 -3
- package/bin/oh-my-opencode.test.ts +35 -7
- package/bin/platform.d.ts +1 -1
- package/bin/platform.js +4 -4
- package/bin/platform.test.ts +31 -9
- package/bin/version-mismatch.js +47 -0
- package/bin/version-mismatch.test.ts +120 -0
- package/dist/cli/cleanup-command.d.ts +4 -0
- package/dist/cli/cleanup.d.ts +11 -0
- package/dist/cli/cli-program.d.ts +2 -1
- package/dist/cli/codex-ulw-loop.d.ts +12 -0
- package/dist/cli/doctor/checks/tui-plugin-config.d.ts +2 -0
- package/dist/cli/index.js +2189 -529
- package/dist/cli/install-codex/codex-cache.d.ts +1 -0
- package/dist/cli/install-codex/codex-cleanup-config.d.ts +6 -0
- package/dist/cli/install-codex/codex-cleanup.d.ts +21 -0
- package/dist/cli/install-codex/codex-config-permissions.d.ts +1 -0
- package/dist/cli/install-codex/codex-config-reasoning.d.ts +2 -0
- package/dist/cli/install-codex/codex-config-toml.d.ts +2 -1
- package/dist/cli/install-codex/codex-installation-detection.d.ts +36 -0
- package/dist/cli/install-codex/codex-model-catalog.d.ts +13 -0
- package/dist/cli/install-codex/codex-package-layout.d.ts +1 -0
- package/dist/cli/install-codex/codex-project-local-cleanup-best-effort.d.ts +7 -0
- package/dist/cli/install-codex/codex-project-local-cleanup.d.ts +35 -0
- package/dist/cli/install-codex/git-bash.d.ts +35 -0
- package/dist/cli/install-codex/index.d.ts +4 -0
- package/dist/cli/install-codex/toml-section-editor.d.ts +2 -0
- package/dist/cli/install-codex/types.d.ts +20 -0
- package/dist/cli/run/event-state.d.ts +1 -0
- package/dist/cli/run/poll-for-completion.d.ts +1 -0
- package/dist/cli/run/prompt-start.d.ts +7 -0
- package/dist/cli/star-request.d.ts +9 -0
- package/dist/config/schema/hooks.d.ts +0 -1
- package/dist/create-hooks.d.ts +0 -1
- package/dist/features/background-agent/concurrency.d.ts +1 -0
- package/dist/features/background-agent/process-cleanup.d.ts +6 -0
- package/dist/features/builtin-skills/skills/debugging.d.ts +2 -0
- package/dist/features/builtin-skills/skills/index.d.ts +1 -0
- package/dist/features/claude-code-session-state/state.d.ts +1 -0
- package/dist/features/opencode-skill-loader/index.d.ts +1 -0
- package/dist/features/opencode-skill-loader/opencode-config-skills-reader.d.ts +5 -0
- package/dist/features/tmux-subagent/attachable-session-status.d.ts +1 -1
- package/dist/features/tmux-subagent/session-status-parser.d.ts +1 -0
- package/dist/hooks/comment-checker/cli.d.ts +1 -0
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/tasks-todowrite-disabler/constants.d.ts +1 -1
- package/dist/index.js +1077 -563
- package/dist/plugin/hooks/create-core-hooks.d.ts +0 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +1 -2
- package/dist/plugin/messages-transform.d.ts +8 -1
- package/dist/plugin/user-abort-interrupted-recovery-guard.d.ts +6 -0
- package/dist/shared/command-executor/execute-hook-command.d.ts +2 -0
- package/dist/shared/prompt-async-gate/recent-dispatches.d.ts +14 -0
- package/dist/shared/prompt-async-gate/semantic-dedupe.d.ts +7 -0
- package/dist/shared/prompt-async-gate/session-idle-dispatch.d.ts +1 -0
- package/dist/shared/prompt-async-gate/timing.d.ts +1 -0
- package/dist/shared/prompt-async-gate/types.d.ts +2 -0
- package/dist/shared/prompt-async-gate.d.ts +1 -1
- package/dist/tools/skill/description-formatter.d.ts +5 -1
- package/dist/tools/skill/types.d.ts +1 -0
- package/package.json +22 -18
- package/packages/ast-grep-mcp/dist/cli.js +53 -9
- package/packages/git-bash-mcp/dist/cli.js +367 -0
- package/packages/lsp-tools-mcp/dist/lsp/process.js +1 -1
- package/packages/omo-codex/plugin/.mcp.json +11 -0
- package/packages/omo-codex/plugin/components/comment-checker/README.md +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +29 -0
- package/packages/omo-codex/plugin/components/git-bash/package.json +23 -0
- package/packages/omo-codex/plugin/components/git-bash/src/cli.ts +33 -0
- package/packages/omo-codex/plugin/components/git-bash/src/codex-hook.ts +180 -0
- package/packages/omo-codex/plugin/components/git-bash/src/index.ts +10 -0
- package/packages/omo-codex/plugin/components/git-bash/test/codex-hook.test.ts +195 -0
- package/packages/omo-codex/plugin/components/git-bash/tsconfig.build.json +13 -0
- package/packages/omo-codex/plugin/components/git-bash/tsconfig.json +25 -0
- package/packages/omo-codex/plugin/components/lsp/README.md +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/cli.ts +5 -5
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +33 -0
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +19 -27
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-cli.test.ts +28 -0
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-errors.test.ts +55 -0
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +7 -5
- package/packages/omo-codex/plugin/components/rules/README.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +6 -4
- package/packages/omo-codex/plugin/components/rules/bundled-rules/windows-git-bash.md +10 -0
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +0 -2
- package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +3 -1
- package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +97 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +6 -5
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +22 -0
- package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/agents/codex-ultrawork-reviewer.toml +4 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +8 -7
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +9 -8
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +32 -6
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +27 -4
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +25 -0
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +28 -205
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +231 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +12 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +19 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +102 -5
- package/packages/omo-codex/plugin/hooks/hooks.json +35 -2
- package/packages/omo-codex/plugin/model-catalog.json +49 -0
- package/packages/omo-codex/plugin/package-lock.json +19 -0
- package/packages/omo-codex/plugin/package.json +3 -1
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +159 -0
- package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +16 -1
- package/packages/omo-codex/plugin/scripts/build-components.mjs +2 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +269 -0
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +89 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -6
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +127 -0
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +9 -0
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +6 -6
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +33 -8
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +25 -5
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +28 -205
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +231 -0
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +17 -17
- package/packages/omo-codex/plugin/test/aggregate.test.mjs +188 -20
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +129 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +58 -11
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +34 -0
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +21 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +146 -0
- package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +48 -0
- package/packages/omo-codex/plugin/test/subagent-guidance.test.mjs +76 -0
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +67 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +54 -2
- package/packages/omo-codex/scripts/install/cache.mjs +5 -3
- package/packages/omo-codex/scripts/install/cli-args.mjs +112 -0
- package/packages/omo-codex/scripts/install/config.mjs +23 -1
- package/packages/omo-codex/scripts/install/delegated-command.mjs +25 -0
- package/packages/omo-codex/scripts/install/git-bash.mjs +99 -0
- package/packages/omo-codex/scripts/install/git-bash.test.mjs +174 -0
- package/packages/omo-codex/scripts/install/legacy-bins.mjs +1 -0
- package/packages/omo-codex/scripts/install/mcp-runtime-cache.mjs +5 -1
- package/packages/omo-codex/scripts/install/model-catalog.mjs +66 -0
- package/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +7 -1
- package/packages/omo-codex/scripts/install/permissions.d.mts +1 -0
- package/packages/omo-codex/scripts/install/permissions.mjs +26 -0
- package/packages/omo-codex/scripts/install/project-local-cleanup.mjs +229 -0
- package/packages/omo-codex/scripts/install/reasoning-config.mjs +72 -0
- package/packages/omo-codex/scripts/install/source-package-build.mjs +20 -0
- package/packages/omo-codex/scripts/install/toml-editor.mjs +19 -2
- package/packages/omo-codex/scripts/install-bin-links.test.mjs +23 -0
- package/packages/omo-codex/scripts/install-cli-args.test.mjs +146 -0
- package/packages/omo-codex/scripts/install-config-autonomous.test.mjs +48 -0
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +141 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +205 -0
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +157 -0
- package/packages/omo-codex/scripts/install-local-git-bash-preflight.test.mjs +145 -0
- package/packages/omo-codex/scripts/install-local.mjs +91 -8
- package/packages/omo-codex/scripts/install-local.test.mjs +15 -0
- package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +60 -0
- package/packages/omo-codex/scripts/install-packaged-local.test.mjs +67 -0
- package/packages/omo-codex/scripts/install-project-local-cleanup.test.mjs +277 -0
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +127 -0
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +9 -0
- package/packages/shared-skills/skills/review-work/SKILL.md +33 -8
- package/packages/shared-skills/skills/start-work/SKILL.md +25 -5
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -11
- package/postinstall.mjs +36 -3
- package/dist/hooks/context-window-monitor.d.ts +0 -19
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const CODEX_ONLY_ERROR = "lazycodex-ai installs the Codex Light edition only. Use the omo installer for OpenCode or both-platform installs.";
|
|
2
|
+
const PASSTHROUGH_COMMANDS = new Set(["doctor", "cleanup", "get-local-version", "boulder", "refresh-model-capabilities", "run", "ulw-loop"]);
|
|
3
|
+
|
|
4
|
+
export function parseLazyCodexInstallCliArgs(argv) {
|
|
5
|
+
const args = [...argv];
|
|
6
|
+
if (args.length === 0) return { kind: "install", autonomousPermissions: undefined, repoRoot: undefined };
|
|
7
|
+
|
|
8
|
+
let repoRoot;
|
|
9
|
+
let command;
|
|
10
|
+
let dryRun = false;
|
|
11
|
+
let noTui = false;
|
|
12
|
+
let skipAuth = false;
|
|
13
|
+
let autonomousPermissions;
|
|
14
|
+
let index = 0;
|
|
15
|
+
while (index < args.length) {
|
|
16
|
+
const arg = args[index];
|
|
17
|
+
if (arg === "--help" || arg === "-h" || arg === "help") return { kind: "help" };
|
|
18
|
+
if (arg === "--version" || arg === "-v" || arg === "version") return { kind: "version" };
|
|
19
|
+
if (arg === "--dry-run") {
|
|
20
|
+
dryRun = true;
|
|
21
|
+
index += 1;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (arg === "--no-tui") {
|
|
25
|
+
noTui = true;
|
|
26
|
+
index += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (arg === "--skip-auth") {
|
|
30
|
+
skipAuth = true;
|
|
31
|
+
index += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (arg === "--codex-autonomous") {
|
|
35
|
+
autonomousPermissions = true;
|
|
36
|
+
index += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (arg === "--no-codex-autonomous") {
|
|
40
|
+
autonomousPermissions = false;
|
|
41
|
+
index += 1;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg === "--platform") {
|
|
45
|
+
const platform = readOptionValue(args, index, "--platform");
|
|
46
|
+
if (platform !== "codex") throw new Error(CODEX_ONLY_ERROR);
|
|
47
|
+
index += 2;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (typeof arg === "string" && arg.startsWith("--platform=")) {
|
|
51
|
+
const platform = arg.slice("--platform=".length);
|
|
52
|
+
if (platform.trim().length === 0) throw new Error("--platform requires a value");
|
|
53
|
+
if (platform !== "codex") throw new Error(CODEX_ONLY_ERROR);
|
|
54
|
+
index += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (arg === "--repo-root") {
|
|
58
|
+
repoRoot = readOptionValue(args, index, "--repo-root");
|
|
59
|
+
index += 2;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (typeof arg === "string" && arg.startsWith("--repo-root=")) {
|
|
63
|
+
const value = arg.slice("--repo-root=".length);
|
|
64
|
+
if (value.trim().length === 0) throw new Error("--repo-root requires a path");
|
|
65
|
+
repoRoot = value;
|
|
66
|
+
index += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === "install" || arg === "setup") {
|
|
70
|
+
if (command !== undefined) throw new Error(`Unsupported lazycodex-ai install option: ${String(arg)}`);
|
|
71
|
+
command = "install";
|
|
72
|
+
index += 1;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (PASSTHROUGH_COMMANDS.has(arg)) {
|
|
76
|
+
return { kind: "command", command: arg, dryRun, args: args.slice(index + 1) };
|
|
77
|
+
}
|
|
78
|
+
if (command === undefined && typeof arg === "string" && !arg.startsWith("-")) {
|
|
79
|
+
throw new Error(`Unsupported lazycodex-ai command: ${String(arg)}`);
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`Unsupported lazycodex-ai install option: ${String(arg)}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!dryRun) return { kind: "install", autonomousPermissions, repoRoot };
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
kind: "command",
|
|
88
|
+
command: command ?? "install",
|
|
89
|
+
dryRun,
|
|
90
|
+
noTui,
|
|
91
|
+
skipAuth,
|
|
92
|
+
autonomousPermissions,
|
|
93
|
+
repoRoot,
|
|
94
|
+
args: [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function readOptionValue(args, index, option) {
|
|
99
|
+
const value = args[index + 1];
|
|
100
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
101
|
+
throw new Error(`${option} requires a value`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function formatLazyCodexInstallHelp() {
|
|
107
|
+
return [
|
|
108
|
+
"Usage: lazycodex-ai install [--no-tui] [--codex-autonomous|--no-codex-autonomous] [--repo-root <path>]",
|
|
109
|
+
"",
|
|
110
|
+
"Installs the Codex Light edition into ~/.codex using Node/npm.",
|
|
111
|
+
].join("\n");
|
|
112
|
+
}
|
|
@@ -2,6 +2,9 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { ensureCodexMultiAgentV2Config } from "./multi-agent-v2-config.mjs";
|
|
5
|
+
import { readCodexModelCatalog } from "./model-catalog.mjs";
|
|
6
|
+
import { ensureCodexReasoningConfig } from "./reasoning-config.mjs";
|
|
7
|
+
import { ensureAutonomousPermissions } from "./permissions.mjs";
|
|
5
8
|
import { appendBlock, findTomlSection, replaceOrInsertSetting } from "./toml-editor.mjs";
|
|
6
9
|
import { exists } from "./utils.mjs";
|
|
7
10
|
|
|
@@ -22,8 +25,10 @@ export async function updateCodexConfig({
|
|
|
22
25
|
marketplaceName,
|
|
23
26
|
marketplaceSource = defaultMarketplaceSource(marketplaceName, repoRoot),
|
|
24
27
|
pluginNames,
|
|
28
|
+
platform = process.platform,
|
|
25
29
|
trustedHookStates = [],
|
|
26
30
|
agentConfigs = [],
|
|
31
|
+
autonomousPermissions = false,
|
|
27
32
|
}) {
|
|
28
33
|
await mkdir(dirname(configPath), { recursive: true });
|
|
29
34
|
let config = "";
|
|
@@ -39,11 +44,14 @@ export async function updateCodexConfig({
|
|
|
39
44
|
config = removeStaleManagedAgentBlocks(config, new Set(agentConfigs.map((agentConfig) => agentConfig.name)));
|
|
40
45
|
config = ensureFeatureEnabled(config, "plugins");
|
|
41
46
|
config = ensureFeatureEnabled(config, "plugin_hooks");
|
|
47
|
+
config = ensureCodexReasoningConfig(config, await readCodexModelCatalog(repoRoot));
|
|
42
48
|
config = ensureCodexMultiAgentV2Config(config);
|
|
49
|
+
if (autonomousPermissions === true) config = ensureAutonomousPermissions(config);
|
|
43
50
|
config = ensureMarketplaceBlock(config, marketplaceName, marketplaceSource);
|
|
44
51
|
for (const pluginName of pluginNames) {
|
|
45
52
|
config = ensurePluginEnabled(config, `${pluginName}@${marketplaceName}`);
|
|
46
53
|
}
|
|
54
|
+
config = ensureOmoGitBashMcpPolicy(config, { marketplaceName, pluginNames, platform });
|
|
47
55
|
for (const state of trustedHookStates) {
|
|
48
56
|
config = ensureHookTrusted(config, state.key, state.trustedHash);
|
|
49
57
|
}
|
|
@@ -136,6 +144,19 @@ function ensurePluginEnabled(config, pluginKey) {
|
|
|
136
144
|
return replaceOrInsertSetting(config, section, "enabled", "true");
|
|
137
145
|
}
|
|
138
146
|
|
|
147
|
+
function ensurePluginMcpEnabled(config, pluginKey, serverName, enabled) {
|
|
148
|
+
const header = `plugins.${JSON.stringify(pluginKey)}.mcp_servers.${serverName}`;
|
|
149
|
+
const section = findTomlSection(config, header);
|
|
150
|
+
const enabledValue = enabled ? "true" : "false";
|
|
151
|
+
if (!section) return appendBlock(config, `[${header}]\nenabled = ${enabledValue}\n`);
|
|
152
|
+
return replaceOrInsertSetting(config, section, "enabled", enabledValue);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function ensureOmoGitBashMcpPolicy(config, { marketplaceName, pluginNames, platform }) {
|
|
156
|
+
if (marketplaceName !== "sisyphuslabs" || !pluginNames.includes("omo")) return config;
|
|
157
|
+
return ensurePluginMcpEnabled(config, "omo@sisyphuslabs", "git_bash", platform === "win32");
|
|
158
|
+
}
|
|
159
|
+
|
|
139
160
|
function ensureHookTrusted(config, key, trustedHash) {
|
|
140
161
|
const header = `hooks.state.${JSON.stringify(key)}`;
|
|
141
162
|
const section = findTomlSection(config, header);
|
|
@@ -223,7 +244,8 @@ function parseJsonString(value) {
|
|
|
223
244
|
try {
|
|
224
245
|
const parsed = JSON.parse(value);
|
|
225
246
|
return typeof parsed === "string" ? parsed : null;
|
|
226
|
-
} catch {
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (error instanceof Error) return null;
|
|
227
249
|
return null;
|
|
228
250
|
}
|
|
229
251
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export async function runDelegatedOmoCommand(parsed, options) {
|
|
2
|
+
const invocation = buildDelegatedOmoInvocation(parsed);
|
|
3
|
+
if (parsed.dryRun) {
|
|
4
|
+
options.log(`${invocation.command} ${invocation.args.join(" ")}`);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
await options.runCommand(invocation.command, invocation.args, { cwd: options.cwd });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function buildDelegatedOmoInvocation(parsed) {
|
|
11
|
+
const args = ["--yes", "--package", "oh-my-openagent", "omo", parsed.command];
|
|
12
|
+
if (parsed.command === "install") {
|
|
13
|
+
args.push("--platform=codex");
|
|
14
|
+
if (parsed.noTui) args.push("--no-tui");
|
|
15
|
+
if (parsed.skipAuth) args.push("--skip-auth");
|
|
16
|
+
if (parsed.autonomousPermissions !== false) args.push("--codex-autonomous");
|
|
17
|
+
if (parsed.autonomousPermissions === false) args.push("--no-codex-autonomous");
|
|
18
|
+
if (parsed.repoRoot) args.push(`--repo-root=${parsed.repoRoot}`);
|
|
19
|
+
} else if (parsed.command === "cleanup") {
|
|
20
|
+
args.push("--platform=codex", ...parsed.args);
|
|
21
|
+
} else {
|
|
22
|
+
args.push(...parsed.args);
|
|
23
|
+
}
|
|
24
|
+
return { command: "npx", args };
|
|
25
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
const GIT_BASH_ENV_KEY = "OMO_CODEX_GIT_BASH_PATH";
|
|
5
|
+
const SKIP_GIT_BASH_AUTO_INSTALL_ENV_KEY = "OMO_CODEX_SKIP_GIT_BASH_AUTO_INSTALL";
|
|
6
|
+
const PROGRAM_FILES_GIT_BASH = "C:\\Program Files\\Git\\bin\\bash.exe";
|
|
7
|
+
const PROGRAM_FILES_X86_GIT_BASH = "C:\\Program Files (x86)\\Git\\bin\\bash.exe";
|
|
8
|
+
const WINGET_INSTALL_ARGS = ["install", "--id", "Git.Git", "-e", "--source", "winget"];
|
|
9
|
+
|
|
10
|
+
export function resolveGitBash({ platform, env, exists, where }) {
|
|
11
|
+
if (platform !== "win32") return { found: true, path: null, source: "not-required" };
|
|
12
|
+
|
|
13
|
+
const checkedPaths = [];
|
|
14
|
+
const envPath = nonEmptyEnvValue(env, GIT_BASH_ENV_KEY);
|
|
15
|
+
if (envPath !== undefined) {
|
|
16
|
+
checkedPaths.push(envPath);
|
|
17
|
+
if (isBashExePath(envPath) && exists(envPath)) return { found: true, path: envPath, source: "env" };
|
|
18
|
+
return missingGitBash(checkedPaths);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const candidate of [
|
|
22
|
+
{ path: PROGRAM_FILES_GIT_BASH, source: "program-files" },
|
|
23
|
+
{ path: PROGRAM_FILES_X86_GIT_BASH, source: "program-files-x86" },
|
|
24
|
+
]) {
|
|
25
|
+
checkedPaths.push(candidate.path);
|
|
26
|
+
if (exists(candidate.path)) return { found: true, path: candidate.path, source: candidate.source };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const pathCandidate of where("bash")) {
|
|
30
|
+
const candidate = pathCandidate.trim();
|
|
31
|
+
if (candidate.length === 0) continue;
|
|
32
|
+
checkedPaths.push(candidate);
|
|
33
|
+
if (isBashExePath(candidate) && exists(candidate)) return { found: true, path: candidate, source: "path" };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return missingGitBash(checkedPaths);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveGitBashForCurrentProcess(options = {}) {
|
|
40
|
+
return resolveGitBash({
|
|
41
|
+
platform: options.platform ?? process.platform,
|
|
42
|
+
env: options.env ?? process.env,
|
|
43
|
+
exists: existsSync,
|
|
44
|
+
where: whereCommand,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function prepareGitBashForInstall(options) {
|
|
49
|
+
const resolveGitBashWithDefaults = options.resolveGitBash
|
|
50
|
+
?? (() => resolveGitBashForCurrentProcess({ platform: options.platform, env: options.env }));
|
|
51
|
+
const initialResolution = resolveGitBashWithDefaults();
|
|
52
|
+
if (options.platform !== "win32" || initialResolution.found) return initialResolution;
|
|
53
|
+
if (options.env[SKIP_GIT_BASH_AUTO_INSTALL_ENV_KEY] === "1") return initialResolution;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await options.runCommand("winget", WINGET_INSTALL_ARGS, { cwd: options.cwd });
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (!(error instanceof Error)) throw error;
|
|
59
|
+
return initialResolution;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return resolveGitBashWithDefaults();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function missingGitBash(checkedPaths) {
|
|
66
|
+
return {
|
|
67
|
+
found: false,
|
|
68
|
+
checkedPaths,
|
|
69
|
+
installHint: [
|
|
70
|
+
"Git Bash is required for native Windows Codex profile installs.",
|
|
71
|
+
"Install it with: winget install --id Git.Git -e --source winget",
|
|
72
|
+
`For a custom install, set ${GIT_BASH_ENV_KEY}=C:\\path\\to\\bash.exe`,
|
|
73
|
+
"Then rerun `npx lazycodex-ai install`.",
|
|
74
|
+
].join("\n"),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function nonEmptyEnvValue(env, key) {
|
|
79
|
+
const value = env[key];
|
|
80
|
+
if (typeof value !== "string") return undefined;
|
|
81
|
+
const trimmed = value.trim();
|
|
82
|
+
return trimmed.length === 0 ? undefined : trimmed;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isBashExePath(path) {
|
|
86
|
+
return path.toLowerCase().endsWith("bash.exe");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function whereCommand(command) {
|
|
90
|
+
try {
|
|
91
|
+
return execFileSync("where", [command], { encoding: "utf8" })
|
|
92
|
+
.split(/\r?\n/)
|
|
93
|
+
.map((line) => line.trim())
|
|
94
|
+
.filter((line) => line.length > 0);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof Error) return [];
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { prepareGitBashForInstall, resolveGitBash } from "./git-bash.mjs";
|
|
5
|
+
|
|
6
|
+
const programFilesGitBash = "C:\\Program Files\\Git\\bin\\bash.exe";
|
|
7
|
+
const programFilesX86GitBash = "C:\\Program Files (x86)\\Git\\bin\\bash.exe";
|
|
8
|
+
|
|
9
|
+
test("#given non-Windows platform #when resolving Git Bash #then no preflight is required", () => {
|
|
10
|
+
const result = resolveGitBash({
|
|
11
|
+
platform: "linux",
|
|
12
|
+
env: {},
|
|
13
|
+
exists: () => false,
|
|
14
|
+
where: () => [],
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
assert.deepEqual(result, { found: true, path: null, source: "not-required" });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("#given Windows env override to bash.exe #when the file exists #then env path wins", () => {
|
|
21
|
+
const overridePath = "D:\\Tools\\Git\\bin\\bash.exe";
|
|
22
|
+
const result = resolveGitBash({
|
|
23
|
+
platform: "win32",
|
|
24
|
+
env: { OMO_CODEX_GIT_BASH_PATH: overridePath },
|
|
25
|
+
exists: (path) => path === overridePath,
|
|
26
|
+
where: () => [programFilesGitBash],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
assert.deepEqual(result, { found: true, path: overridePath, source: "env" });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("#given Windows standard paths are absent and PATH contains bash #when resolving #then uses where bash candidate", () => {
|
|
33
|
+
const pathCandidate = "E:\\Git\\bin\\bash.exe";
|
|
34
|
+
const result = resolveGitBash({
|
|
35
|
+
platform: "win32",
|
|
36
|
+
env: {},
|
|
37
|
+
exists: (path) => path === pathCandidate,
|
|
38
|
+
where: () => ["C:\\Windows\\System32\\bash.exe", pathCandidate],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
assert.deepEqual(result, { found: true, path: pathCandidate, source: "path" });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("#given Windows invalid env override #when resolving #then returns guidance without falling through", () => {
|
|
45
|
+
const overridePath = "D:\\Tools\\Git\\bin\\git.exe";
|
|
46
|
+
const result = resolveGitBash({
|
|
47
|
+
platform: "win32",
|
|
48
|
+
env: { OMO_CODEX_GIT_BASH_PATH: overridePath },
|
|
49
|
+
exists: () => true,
|
|
50
|
+
where: () => [programFilesGitBash],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
assert.equal(result.found, false);
|
|
54
|
+
assert.deepEqual(result.checkedPaths, [overridePath]);
|
|
55
|
+
assert.match(result.installHint, /OMO_CODEX_GIT_BASH_PATH=C:\\path\\to\\bash\.exe/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("#given Windows without Git Bash #when resolving #then returns install guidance", () => {
|
|
59
|
+
const result = resolveGitBash({
|
|
60
|
+
platform: "win32",
|
|
61
|
+
env: {},
|
|
62
|
+
exists: () => false,
|
|
63
|
+
where: () => [],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
assert.equal(result.found, false);
|
|
67
|
+
assert.deepEqual(result.checkedPaths, [programFilesGitBash, programFilesX86GitBash]);
|
|
68
|
+
assert.match(result.installHint, /winget install --id Git\.Git -e --source winget/);
|
|
69
|
+
assert.match(result.installHint, /rerun `npx lazycodex-ai install`/);
|
|
70
|
+
assert.doesNotMatch(result.installHint, /bunx/);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("#given Windows without Git Bash and winget is allowed #when preparing #then winget runs and resolver retries", async () => {
|
|
74
|
+
const runCalls = [];
|
|
75
|
+
const resolutions = [
|
|
76
|
+
{ found: false, checkedPaths: [programFilesGitBash], installHint: "install hint" },
|
|
77
|
+
{ found: true, path: programFilesGitBash, source: "program-files" },
|
|
78
|
+
];
|
|
79
|
+
let resolveCallCount = 0;
|
|
80
|
+
|
|
81
|
+
const result = await prepareGitBashForInstall({
|
|
82
|
+
platform: "win32",
|
|
83
|
+
env: {},
|
|
84
|
+
cwd: "C:\\repo",
|
|
85
|
+
resolveGitBash: () => resolutions[resolveCallCount++] ?? resolutions[resolutions.length - 1],
|
|
86
|
+
runCommand: async (command, args, options) => {
|
|
87
|
+
runCalls.push([command, ...args, options.cwd].join(" "));
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
assert.deepEqual(runCalls, ["winget install --id Git.Git -e --source winget C:\\repo"]);
|
|
92
|
+
assert.equal(resolveCallCount, 2);
|
|
93
|
+
assert.deepEqual(result, { found: true, path: programFilesGitBash, source: "program-files" });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("#given Windows without Git Bash and skip env is set #when preparing #then winget is not run and install hint remains", async () => {
|
|
97
|
+
const runCalls = [];
|
|
98
|
+
const missingResolution = {
|
|
99
|
+
found: false,
|
|
100
|
+
checkedPaths: [programFilesGitBash, programFilesX86GitBash],
|
|
101
|
+
installHint: "install hint",
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const result = await prepareGitBashForInstall({
|
|
105
|
+
platform: "win32",
|
|
106
|
+
env: { OMO_CODEX_SKIP_GIT_BASH_AUTO_INSTALL: "1" },
|
|
107
|
+
cwd: "C:\\repo",
|
|
108
|
+
resolveGitBash: () => missingResolution,
|
|
109
|
+
runCommand: async (command, args, options) => {
|
|
110
|
+
runCalls.push([command, ...args, options.cwd].join(" "));
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
assert.deepEqual(runCalls, []);
|
|
115
|
+
assert.deepEqual(result, missingResolution);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("#given non-Windows platform #when preparing #then winget is never called", async () => {
|
|
119
|
+
const runCalls = [];
|
|
120
|
+
const result = await prepareGitBashForInstall({
|
|
121
|
+
platform: "linux",
|
|
122
|
+
env: {},
|
|
123
|
+
cwd: "/repo",
|
|
124
|
+
runCommand: async (command, args, options) => {
|
|
125
|
+
runCalls.push([command, ...args, options.cwd].join(" "));
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
assert.deepEqual(runCalls, []);
|
|
130
|
+
assert.deepEqual(result, { found: true, path: null, source: "not-required" });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("#given Windows without Git Bash and winget fails #when preparing #then original install hint is preserved", async () => {
|
|
134
|
+
const missingResolution = {
|
|
135
|
+
found: false,
|
|
136
|
+
checkedPaths: [programFilesGitBash, programFilesX86GitBash],
|
|
137
|
+
installHint: "install hint",
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = await prepareGitBashForInstall({
|
|
141
|
+
platform: "win32",
|
|
142
|
+
env: {},
|
|
143
|
+
cwd: "C:\\repo",
|
|
144
|
+
resolveGitBash: () => missingResolution,
|
|
145
|
+
runCommand: async () => {
|
|
146
|
+
throw new Error("winget unavailable");
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
assert.deepEqual(result, missingResolution);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("#given Windows without Git Bash and winget succeeds but bash is still missing #when preparing #then install hint remains", async () => {
|
|
154
|
+
const missingResolution = {
|
|
155
|
+
found: false,
|
|
156
|
+
checkedPaths: [programFilesGitBash, programFilesX86GitBash],
|
|
157
|
+
installHint: "install hint",
|
|
158
|
+
};
|
|
159
|
+
let resolveCallCount = 0;
|
|
160
|
+
|
|
161
|
+
const result = await prepareGitBashForInstall({
|
|
162
|
+
platform: "win32",
|
|
163
|
+
env: {},
|
|
164
|
+
cwd: "C:\\repo",
|
|
165
|
+
resolveGitBash: () => {
|
|
166
|
+
resolveCallCount += 1;
|
|
167
|
+
return missingResolution;
|
|
168
|
+
},
|
|
169
|
+
runCommand: async () => {},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
assert.equal(resolveCallCount, 2);
|
|
173
|
+
assert.deepEqual(result, missingResolution);
|
|
174
|
+
});
|
|
@@ -5,6 +5,7 @@ import { COMMAND_SHIM_MARKER } from "./command-shim.mjs";
|
|
|
5
5
|
|
|
6
6
|
const LEGACY_CODEX_COMPONENT_BINS = [
|
|
7
7
|
{ name: "codex-comment-checker", component: "comment-checker" },
|
|
8
|
+
{ name: "codex-lsp", component: "lsp" },
|
|
8
9
|
{ name: "codex-rules", component: "rules" },
|
|
9
10
|
{ name: "codex-start-work-continuation", component: "start-work-continuation" },
|
|
10
11
|
{ name: "codex-telemetry", component: "telemetry" },
|
|
@@ -40,7 +40,7 @@ function resolveExternalMcpPackageRoot(runtimePath, sourceRoot) {
|
|
|
40
40
|
if (!isPathInside(runtimePath, packagesRoot)) return undefined;
|
|
41
41
|
let packageRoot = dirname(runtimePath);
|
|
42
42
|
while (packageRoot !== packagesRoot) {
|
|
43
|
-
if (
|
|
43
|
+
if (isPathInside(runtimePath, join(packageRoot, "dist")) && isRuntimePackageRoot(packageRoot)) {
|
|
44
44
|
return packageRoot;
|
|
45
45
|
}
|
|
46
46
|
const parent = dirname(packageRoot);
|
|
@@ -50,6 +50,10 @@ function resolveExternalMcpPackageRoot(runtimePath, sourceRoot) {
|
|
|
50
50
|
return undefined;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
function isRuntimePackageRoot(packageRoot) {
|
|
54
|
+
return existsSync(join(packageRoot, "package.json")) || existsSync(join(packageRoot, "dist"));
|
|
55
|
+
}
|
|
56
|
+
|
|
53
57
|
function findPackagesRoot(path) {
|
|
54
58
|
let current = resolve(path);
|
|
55
59
|
for (let index = 0; index < 8; index++) {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const FALLBACK_CODEX_MODEL_CATALOG = {
|
|
5
|
+
current: {
|
|
6
|
+
model: "gpt-5.5",
|
|
7
|
+
modelContextWindow: 400_000,
|
|
8
|
+
modelReasoningEffort: "high",
|
|
9
|
+
planModeReasoningEffort: "xhigh",
|
|
10
|
+
},
|
|
11
|
+
managedProfiles: [{ model: "gpt-5.2" }],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function readCodexModelCatalog(codexPackageRoot) {
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(await readFile(join(codexPackageRoot, "plugin", "model-catalog.json"), "utf8"));
|
|
17
|
+
return parseCodexModelCatalog(parsed) ?? FALLBACK_CODEX_MODEL_CATALOG;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (!(error instanceof Error)) throw error;
|
|
20
|
+
return FALLBACK_CODEX_MODEL_CATALOG;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function readCodexReasoningProfile(codexPackageRoot) {
|
|
25
|
+
return (await readCodexModelCatalog(codexPackageRoot)).current;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function parseCodexModelCatalog(value) {
|
|
29
|
+
if (!isRecord(value) || !isRecord(value.current) || !Array.isArray(value.managedProfiles)) return null;
|
|
30
|
+
const { current } = value;
|
|
31
|
+
if (
|
|
32
|
+
typeof current.model !== "string" ||
|
|
33
|
+
typeof current.model_context_window !== "number" ||
|
|
34
|
+
typeof current.model_reasoning_effort !== "string" ||
|
|
35
|
+
typeof current.plan_mode_reasoning_effort !== "string"
|
|
36
|
+
) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const managedProfiles = [];
|
|
40
|
+
for (const profile of value.managedProfiles) {
|
|
41
|
+
if (!isRecord(profile) || !isRecord(profile.match)) return null;
|
|
42
|
+
managedProfiles.push(parseProfileMatch(profile.match));
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
current: {
|
|
46
|
+
model: current.model,
|
|
47
|
+
modelContextWindow: current.model_context_window,
|
|
48
|
+
modelReasoningEffort: current.model_reasoning_effort,
|
|
49
|
+
planModeReasoningEffort: current.plan_mode_reasoning_effort,
|
|
50
|
+
},
|
|
51
|
+
managedProfiles,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseProfileMatch(match) {
|
|
56
|
+
const profile = {};
|
|
57
|
+
if (typeof match.model === "string") profile.model = match.model;
|
|
58
|
+
if (typeof match.model_context_window === "number") profile.modelContextWindow = match.model_context_window;
|
|
59
|
+
if (typeof match.model_reasoning_effort === "string") profile.modelReasoningEffort = match.model_reasoning_effort;
|
|
60
|
+
if (typeof match.plan_mode_reasoning_effort === "string") profile.planModeReasoningEffort = match.plan_mode_reasoning_effort;
|
|
61
|
+
return profile;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isRecord(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
+
}
|
|
@@ -4,7 +4,7 @@ const CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
|
|
|
4
4
|
const CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION = 10000;
|
|
5
5
|
|
|
6
6
|
export function ensureCodexMultiAgentV2Config(config) {
|
|
7
|
-
const normalizedConfig = removeFeatureFlagSetting(config, "multi_agent_v2");
|
|
7
|
+
const normalizedConfig = removeLegacyAgentsMaxThreadsSetting(removeFeatureFlagSetting(config, "multi_agent_v2"));
|
|
8
8
|
const section = findTomlSection(normalizedConfig, CODEX_MULTI_AGENT_V2_HEADER);
|
|
9
9
|
const maxThreadsValue = CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION.toString();
|
|
10
10
|
if (!section) {
|
|
@@ -30,3 +30,9 @@ function removeFeatureFlagSetting(config, featureName) {
|
|
|
30
30
|
if (!section) return config;
|
|
31
31
|
return removeSetting(config, section, featureName);
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
function removeLegacyAgentsMaxThreadsSetting(config) {
|
|
35
|
+
const section = findTomlSection(config, "agents");
|
|
36
|
+
if (!section) return config;
|
|
37
|
+
return removeSetting(config, section, "max_threads");
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function ensureAutonomousPermissions(config: string): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { appendBlock, findTomlSection, removeSetting, replaceOrInsertRootSetting, replaceOrInsertSetting } from "./toml-editor.mjs";
|
|
2
|
+
|
|
3
|
+
export function ensureAutonomousPermissions(config) {
|
|
4
|
+
let next = replaceOrInsertRootSetting(config, "approval_policy", JSON.stringify("never"));
|
|
5
|
+
next = replaceOrInsertRootSetting(next, "sandbox_mode", JSON.stringify("danger-full-access"));
|
|
6
|
+
next = replaceOrInsertRootSetting(next, "network_access", JSON.stringify("enabled"));
|
|
7
|
+
next = removeWindowsSandboxSetting(next);
|
|
8
|
+
next = ensureNoticeEnabled(next, "hide_full_access_warning");
|
|
9
|
+
return ensureNoticeEnabled(next, "hide_world_writable_warning");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function removeWindowsSandboxSetting(config) {
|
|
13
|
+
const section = findTomlSection(config, "windows");
|
|
14
|
+
if (!section) return config;
|
|
15
|
+
return removeSetting(config, section, "sandbox");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function ensureNoticeEnabled(config, key) {
|
|
19
|
+
const section = findTomlSection(config, "notice");
|
|
20
|
+
if (!section) return appendNoticeBlock(config, key);
|
|
21
|
+
return replaceOrInsertSetting(config, section, key, "true");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function appendNoticeBlock(config, key) {
|
|
25
|
+
return appendBlock(config, `[notice]\n${key} = true\n`);
|
|
26
|
+
}
|