oh-my-opencode 4.16.2 → 4.17.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/command/omomomo.md +1 -1
- package/.agents/skills/hyperplan/SKILL.md +3 -3
- package/.agents/skills/omomomo/SKILL.md +1 -1
- package/.agents/skills/pre-publish-review/SKILL.md +3 -0
- package/.opencode/command/omomomo.md +1 -1
- package/.opencode/skills/hyperplan/SKILL.md +3 -3
- package/.opencode/skills/pre-publish-review/SKILL.md +3 -0
- package/README.ja.md +4 -4
- package/README.ko.md +4 -4
- package/README.md +4 -4
- package/README.ru.md +4 -4
- package/README.zh-cn.md +4 -4
- package/dist/agents/hephaestus/agent.d.ts +1 -1
- package/dist/agents/hephaestus/gpt-5-6.d.ts +2 -0
- package/dist/agents/momus-gpt-5-6.d.ts +1 -0
- package/dist/agents/types.d.ts +2 -0
- package/dist/cli/index.js +947 -567
- package/dist/cli-node/index.js +947 -567
- package/dist/features/background-agent/error-classifier.d.ts +5 -0
- package/dist/features/builtin-commands/templates/refactor-sections/intro-and-analysis.d.ts +1 -1
- package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
- package/dist/features/team-mode/test-support/async-test-helpers.d.ts +2 -2
- package/dist/index.js +523 -81
- 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/shared/live-server-route.d.ts +1 -1
- package/dist/skills/remove-ai-slops/SKILL.md +2 -2
- package/dist/skills/review-work/SKILL.md +1 -1
- package/dist/skills/start-work/SKILL.md +5 -2
- package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/dist/skills/ulw-research/SKILL.md +2 -2
- package/dist/skills/visual-qa/SKILL.md +1 -1
- package/dist/tui.js +195 -41
- package/package.json +15 -14
- package/packages/git-bash-mcp/package.json +27 -0
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +465 -248
- 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/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.6.md +93 -0
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +43 -24
- 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/rules/src/codex-hook.ts +2 -1
- package/packages/omo-codex/plugin/components/rules/src/dynamic-target-fingerprints.ts +15 -6
- package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +7 -2
- package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +2 -2
- package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +32 -0
- package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +106 -0
- 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 +12 -9
- 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 +136 -76
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +94 -23
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +94 -14
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-transport.mjs +55 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +72 -18
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +23 -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 +23 -40
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +7 -7
- 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} +7 -5
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +20 -48
- package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +17 -29
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +20 -50
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +22 -43
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +55 -28
- 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 +55 -28
- 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/scripts/scaffold-plan.mjs +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -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 +55 -28
- 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 +29 -27
- 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/auto-update.mjs +9 -2
- package/packages/omo-codex/plugin/scripts/entry-guard.mjs +26 -0
- package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +3 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +39 -4
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +24 -4
- package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +3 -3
- package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +2 -2
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +2 -2
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +14 -6
- package/packages/omo-codex/plugin/scripts/sync-version.mjs +4 -2
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +3 -3
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +3 -3
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +5 -5
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +9 -3
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +6 -3
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +136 -76
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +94 -23
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +94 -14
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-transport.mjs +55 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +72 -18
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +55 -28
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +29 -27
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +4 -4
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +116 -10
- 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/aggregate-skills.test.mjs +4 -2
- package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +33 -0
- 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 +160 -23
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +71 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +32 -0
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +20 -2
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -2
- package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +345 -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 +508 -286
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +111 -1
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
- package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
- package/packages/shared-skills/skills/start-work/SKILL.md +5 -2
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
- package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
- 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
- /package/packages/omo-codex/plugin/components/rules/bundled-rules/{hephaestus.md → hephaestus/gpt-5.5.md} +0 -0
|
@@ -54,8 +54,8 @@ test("#given stale root reasoning config #when ensuring config #then replaces st
|
|
|
54
54
|
assert.equal(result.match(/^model_context_window\s*=/gm)?.length, 1);
|
|
55
55
|
assert.equal(result.match(/^model_reasoning_effort\s*=/gm)?.length, 1);
|
|
56
56
|
assert.equal(result.match(/^plan_mode_reasoning_effort\s*=/gm)?.length, 1);
|
|
57
|
-
assert.match(result, /model = "gpt-5\.
|
|
58
|
-
assert.match(result, /model_context_window =
|
|
57
|
+
assert.match(result, /model = "gpt-5\.6-sol"/);
|
|
58
|
+
assert.match(result, /model_context_window = 372000/);
|
|
59
59
|
assert.match(result, /model_reasoning_effort = "high"/);
|
|
60
60
|
assert.match(result, /plan_mode_reasoning_effort = "xhigh"/);
|
|
61
61
|
assert.doesNotMatch(result, /gpt-5\.2/);
|
|
@@ -79,8 +79,8 @@ test("#given section settings reuse managed root keys #when ensuring config #the
|
|
|
79
79
|
].join("\n"),
|
|
80
80
|
);
|
|
81
81
|
|
|
82
|
-
assert.match(result, /^model = "gpt-5\.
|
|
83
|
-
assert.match(result, /^model_context_window =
|
|
82
|
+
assert.match(result, /^model = "gpt-5\.6-sol"$/m);
|
|
83
|
+
assert.match(result, /^model_context_window = 372000$/m);
|
|
84
84
|
assert.match(result, /\[model_providers\.openai\]\nmodel = "provider-scoped-value"\nmodel_context_window = 123456/);
|
|
85
85
|
assert.match(result, /\[profiles\.review\]\nmodel_reasoning_effort = "medium"\nplan_mode_reasoning_effort = "medium"/);
|
|
86
86
|
});
|
|
@@ -161,8 +161,8 @@ test("#given global and project-local stale Codex configs #when migrating #then
|
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
assert.deepEqual(result.changed.sort(), [join(codexHome, "config.toml"), projectConfig].sort());
|
|
164
|
-
assert.match(await readFile(join(codexHome, "config.toml"), "utf8"), /model = "gpt-5\.
|
|
165
|
-
assert.match(await readFile(projectConfig, "utf8"), /model_context_window =
|
|
164
|
+
assert.match(await readFile(join(codexHome, "config.toml"), "utf8"), /model = "gpt-5\.6-sol"/);
|
|
165
|
+
assert.match(await readFile(projectConfig, "utf8"), /model_context_window = 372000/);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
168
|
test("#given model catalog is unavailable and stale 272k config #when migrating #then fallback catalog still upgrades it", async () => {
|
|
@@ -183,8 +183,8 @@ test("#given model catalog is unavailable and stale 272k config #when migrating
|
|
|
183
183
|
|
|
184
184
|
const content = await readFile(join(codexHome, "config.toml"), "utf8");
|
|
185
185
|
assert.deepEqual(result.changed, [join(codexHome, "config.toml")]);
|
|
186
|
-
assert.match(content, /model = "gpt-5\.
|
|
187
|
-
assert.match(content, /model_context_window =
|
|
186
|
+
assert.match(content, /model = "gpt-5\.6-sol"/);
|
|
187
|
+
assert.match(content, /model_context_window = 372000/);
|
|
188
188
|
});
|
|
189
189
|
|
|
190
190
|
test("#given model catalog is malformed and stale config #when migrating #then fallback catalog still upgrades it", async () => {
|
|
@@ -206,8 +206,8 @@ test("#given model catalog is malformed and stale config #when migrating #then f
|
|
|
206
206
|
|
|
207
207
|
const content = await readFile(join(codexHome, "config.toml"), "utf8");
|
|
208
208
|
assert.deepEqual(result.changed, [join(codexHome, "config.toml")]);
|
|
209
|
-
assert.match(content, /model = "gpt-5\.
|
|
210
|
-
assert.match(content, /model_context_window =
|
|
209
|
+
assert.match(content, /model = "gpt-5\.6-sol"/);
|
|
210
|
+
assert.match(content, /model_context_window = 372000/);
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
test("#given user-customized Codex model config #when migrating #then user values are preserved without root multi-agent mode", async () => {
|
|
@@ -262,7 +262,7 @@ test("#given managed config state is malformed #when migrating #then migration i
|
|
|
262
262
|
const content = await readFile(join(codexHome, "config.toml"), "utf8");
|
|
263
263
|
const state = JSON.parse(await readFile(statePath, "utf8"));
|
|
264
264
|
assert.deepEqual(result.changed, [join(codexHome, "config.toml")]);
|
|
265
|
-
assert.match(content, /model_context_window =
|
|
265
|
+
assert.match(content, /model_context_window = 372000/);
|
|
266
266
|
assert.equal(state.files[join(codexHome, "config.toml")].managed, true);
|
|
267
267
|
});
|
|
268
268
|
|
|
@@ -670,15 +670,15 @@ test("#given global config starts with inline-comment features table #when full
|
|
|
670
670
|
const content = await readFile(configPath, "utf8");
|
|
671
671
|
const parsed = parseTomlWithPython(content);
|
|
672
672
|
assert.equal("multi_agent_mode" in parsed, false);
|
|
673
|
-
assert.equal(parsed.model, "gpt-5.
|
|
674
|
-
assert.equal(parsed.model_context_window,
|
|
673
|
+
assert.equal(parsed.model, "gpt-5.6-sol");
|
|
674
|
+
assert.equal(parsed.model_context_window, 372000);
|
|
675
675
|
assert.equal(parsed.model_reasoning_effort, "high");
|
|
676
676
|
assert.equal(parsed.plan_mode_reasoning_effort, "xhigh");
|
|
677
677
|
assert.equal(parsed.features.plugins, true);
|
|
678
678
|
assert.equal("multi_agent_mode" in parsed.features, false);
|
|
679
679
|
assert.equal("model" in parsed.features, false);
|
|
680
680
|
assert.equal("model_context_window" in parsed.features, false);
|
|
681
|
-
assert.match(content, /^model = "gpt-5\.
|
|
681
|
+
assert.match(content, /^model = "gpt-5\.6-sol"\nmodel_context_window = 372000/m);
|
|
682
682
|
assert.doesNotMatch(content, /^\s*multi_agent_mode\s*=/m);
|
|
683
683
|
assert.match(content, /\[features\] # keep comment\nplugins = true/);
|
|
684
684
|
});
|
|
@@ -756,7 +756,7 @@ test("#given global config with forced multi_agent_v2 #when full migration runs
|
|
|
756
756
|
test("#given enabled = true with an inline comment #when forcing disable #then flips to false and preserves the comment", () => {
|
|
757
757
|
const config = ["[features.multi_agent_v2]", "enabled = true # tuned by me", ""].join("\n");
|
|
758
758
|
|
|
759
|
-
const result = forceDisableMultiAgentV2(config, { multiAgentVersion:
|
|
759
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: "v1" });
|
|
760
760
|
|
|
761
761
|
assert.match(result, /^enabled = false # tuned by me$/m);
|
|
762
762
|
assert.doesNotMatch(result, /enabled = true/);
|
|
@@ -767,7 +767,7 @@ test("#given enabled = true with an inline comment #when forcing disable #then f
|
|
|
767
767
|
test("#given a section header with an inline comment #when forcing disable #then patches in place without duplicating the table", () => {
|
|
768
768
|
const config = ["[features.multi_agent_v2] # pinned by me", "enabled = true", ""].join("\n");
|
|
769
769
|
|
|
770
|
-
const result = forceDisableMultiAgentV2(config, { multiAgentVersion:
|
|
770
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: "v1" });
|
|
771
771
|
|
|
772
772
|
assert.equal((result.match(/\[features\.multi_agent_v2\]/g) ?? []).length, 1);
|
|
773
773
|
assert.match(result, /enabled = false/);
|
|
@@ -779,19 +779,19 @@ test("#given an already-guarded commented config #when re-running #then output i
|
|
|
779
779
|
const configA = ["[features.multi_agent_v2]", "enabled = true # tuned by me", ""].join("\n");
|
|
780
780
|
const configB = ["[features.multi_agent_v2] # pinned by me", "enabled = true", ""].join("\n");
|
|
781
781
|
|
|
782
|
-
const firstA = forceDisableMultiAgentV2(configA, { multiAgentVersion:
|
|
783
|
-
const rerunA = forceDisableMultiAgentV2(firstA, { multiAgentVersion:
|
|
782
|
+
const firstA = forceDisableMultiAgentV2(configA, { multiAgentVersion: "v1" });
|
|
783
|
+
const rerunA = forceDisableMultiAgentV2(firstA, { multiAgentVersion: "v1" });
|
|
784
784
|
assert.equal(rerunA, firstA);
|
|
785
785
|
|
|
786
|
-
const firstB = forceDisableMultiAgentV2(configB, { multiAgentVersion:
|
|
787
|
-
const rerunB = forceDisableMultiAgentV2(firstB, { multiAgentVersion:
|
|
786
|
+
const firstB = forceDisableMultiAgentV2(configB, { multiAgentVersion: "v1" });
|
|
787
|
+
const rerunB = forceDisableMultiAgentV2(firstB, { multiAgentVersion: "v1" });
|
|
788
788
|
assert.equal(rerunB, firstB);
|
|
789
789
|
});
|
|
790
790
|
|
|
791
791
|
test("#given user-disabled with an inline comment #when forcing disable #then returns config unchanged", () => {
|
|
792
792
|
const config = ["[features.multi_agent_v2]", "enabled = false # I turned this off myself", ""].join("\n");
|
|
793
793
|
|
|
794
|
-
const result = forceDisableMultiAgentV2(config, { multiAgentVersion:
|
|
794
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: "v1" });
|
|
795
795
|
|
|
796
796
|
assert.equal(result, config);
|
|
797
797
|
});
|
|
@@ -799,7 +799,7 @@ test("#given user-disabled with an inline comment #when forcing disable #then re
|
|
|
799
799
|
test("#given [features] shorthand true with an inline comment #when forcing disable #then removes the shorthand and appends one disabled table", () => {
|
|
800
800
|
const config = ["[features]", "plugins = true", "multi_agent_v2 = true # legacy", ""].join("\n");
|
|
801
801
|
|
|
802
|
-
const result = forceDisableMultiAgentV2(config, { multiAgentVersion:
|
|
802
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: "v1" });
|
|
803
803
|
|
|
804
804
|
assert.doesNotMatch(result, /^\s*multi_agent_v2\s*=/m);
|
|
805
805
|
assert.equal((result.match(/\[features\.multi_agent_v2\]/g) ?? []).length, 1);
|
|
@@ -816,7 +816,7 @@ test("#given a following section header with an inline comment #when inserting e
|
|
|
816
816
|
"",
|
|
817
817
|
].join("\n");
|
|
818
818
|
|
|
819
|
-
const result = forceDisableMultiAgentV2(config, { multiAgentVersion:
|
|
819
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: "v1" });
|
|
820
820
|
|
|
821
821
|
assert.match(result, /\[features\.multi_agent_v2\]\nenabled = false\n/);
|
|
822
822
|
assert.match(result, /\[mcp_servers\.x\][^\n]*\nenabled = true/);
|
|
@@ -1034,6 +1034,41 @@ test("#given legacy shorthand and no session model on hook path #when full migra
|
|
|
1034
1034
|
assert.equal("enabled" in parsed.features.multi_agent_v2, false);
|
|
1035
1035
|
});
|
|
1036
1036
|
|
|
1037
|
+
test("#given SoT migration failure #when hook migration runs #then config.toml repair still happens", async () => {
|
|
1038
|
+
const { runAutoUpdateCheck } = await import("../scripts/auto-update.mjs");
|
|
1039
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-sot-isolation-"));
|
|
1040
|
+
const codexHome = join(root, "codex-home");
|
|
1041
|
+
await mkdir(codexHome, { recursive: true });
|
|
1042
|
+
const configPath = join(codexHome, "config.toml");
|
|
1043
|
+
await writeFile(
|
|
1044
|
+
configPath,
|
|
1045
|
+
['model = "gpt-5.6-sol"', "", "[features.multi_agent_v2]", "enabled = false", ""].join("\n"),
|
|
1046
|
+
);
|
|
1047
|
+
await writeFile(
|
|
1048
|
+
join(codexHome, "models_cache.json"),
|
|
1049
|
+
JSON.stringify({ models: [{ slug: "gpt-5.6-sol", multi_agent_version: "v2" }] }),
|
|
1050
|
+
);
|
|
1051
|
+
// HOME pointing at a FILE makes migrateOmoSotConfig's mkdir(~/.omo) throw.
|
|
1052
|
+
const brokenHome = join(root, "not-a-dir");
|
|
1053
|
+
await writeFile(brokenHome, "");
|
|
1054
|
+
|
|
1055
|
+
await runAutoUpdateCheck({
|
|
1056
|
+
env: {
|
|
1057
|
+
CODEX_HOME: codexHome,
|
|
1058
|
+
HOME: brokenHome,
|
|
1059
|
+
USERPROFILE: brokenHome,
|
|
1060
|
+
LAZYCODEX_AUTO_UPDATE_DISABLED: "1",
|
|
1061
|
+
LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json"),
|
|
1062
|
+
LAZYCODEX_AUTO_UPDATE_STATE_PATH: join(root, "state.json"),
|
|
1063
|
+
},
|
|
1064
|
+
sessionModel: "gpt-5.6-sol",
|
|
1065
|
+
requireSessionModel: true,
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
const content = await readFile(configPath, "utf8");
|
|
1069
|
+
assert.doesNotMatch(content, /^\s*enabled\s*=\s*false/m);
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1037
1072
|
test("#given config default gpt-5.5 #when full migration gets SessionStart gpt-5.6-terra #then clears disable using session model", async () => {
|
|
1038
1073
|
const root = await mkdtemp(join(tmpdir(), "lazycodex-multi-agent-v2-session-model-"));
|
|
1039
1074
|
const codexHome = join(root, "codex-home");
|
|
@@ -1078,6 +1113,47 @@ test("#given config default gpt-5.5 #when full migration gets SessionStart gpt-5
|
|
|
1078
1113
|
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
1079
1114
|
});
|
|
1080
1115
|
|
|
1116
|
+
test("#given no session model and no root model #when forcing disable #then leaves the enable state untouched", () => {
|
|
1117
|
+
const config = ["[features]", "plugins = true", "", "[features.multi_agent_v2]", "enabled = true", ""].join("\n");
|
|
1118
|
+
|
|
1119
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: null, sessionModel: null });
|
|
1120
|
+
|
|
1121
|
+
assert.match(result, /enabled = true/);
|
|
1122
|
+
assert.doesNotMatch(result, /enabled = false/);
|
|
1123
|
+
assert.doesNotMatch(result, /openai\/codex#26753/);
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
test("#given no session model and no root model #when config has no multi_agent_v2 section #then does not append a disable", () => {
|
|
1127
|
+
const config = ["[features]", "plugins = true", ""].join("\n");
|
|
1128
|
+
|
|
1129
|
+
const result = forceDisableMultiAgentV2(config, { multiAgentVersion: null, sessionModel: null });
|
|
1130
|
+
|
|
1131
|
+
assert.equal(result, config);
|
|
1132
|
+
assert.doesNotMatch(result, /\[features\.multi_agent_v2\]/);
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
test("#given user-modified config without root model #when full non-hook migration runs #then writes no disable and no new agents.max_threads", async () => {
|
|
1136
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-multi-agent-v2-desktop-no-model-"));
|
|
1137
|
+
const codexHome = join(root, "codex-home");
|
|
1138
|
+
await mkdir(codexHome, { recursive: true });
|
|
1139
|
+
const configPath = join(codexHome, "config.toml");
|
|
1140
|
+
// Codex Desktop sessions select the model in the UI; config.toml has no root
|
|
1141
|
+
// `model`, so migration cannot prove the session is not a GPT-5.6
|
|
1142
|
+
// reserved-schema model (#6002).
|
|
1143
|
+
await writeFile(configPath, ['model_reasoning_effort = "high"', "", "[features]", "plugins = true", ""].join("\n"));
|
|
1144
|
+
|
|
1145
|
+
await migrateCodexConfig({
|
|
1146
|
+
env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
|
|
1147
|
+
cwd: root,
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
const content = await readFile(configPath, "utf8");
|
|
1151
|
+
assert.doesNotMatch(content, /^\s*enabled\s*=\s*false/m);
|
|
1152
|
+
assert.doesNotMatch(content, /openai\/codex#26753/);
|
|
1153
|
+
assert.doesNotMatch(content, /^\s*max_threads\s*=/m);
|
|
1154
|
+
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1081
1157
|
async function canCreateSymlink(type) {
|
|
1082
1158
|
const root = await mkdtemp(join(tmpdir(), "lazycodex-symlink-capability-"));
|
|
1083
1159
|
const target = join(root, "target");
|
|
@@ -1103,3 +1179,64 @@ async function canCreateSymlink(type) {
|
|
|
1103
1179
|
return false;
|
|
1104
1180
|
}
|
|
1105
1181
|
}
|
|
1182
|
+
|
|
1183
|
+
test("#given model_catalog_json declares a v2 model as v1 #when full migration runs #then keeps the managed disable and max_threads", async () => {
|
|
1184
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-multi-agent-v2-catalog-override-"));
|
|
1185
|
+
const codexHome = join(root, "codex-home");
|
|
1186
|
+
await mkdir(codexHome, { recursive: true });
|
|
1187
|
+
const configPath = join(codexHome, "config.toml");
|
|
1188
|
+
const catalogPath = join(root, "custom-catalog.json");
|
|
1189
|
+
// Codex Desktop user forces gpt-5.6-sol to v1 via an explicit replacement catalog.
|
|
1190
|
+
await writeFile(configPath, [
|
|
1191
|
+
'model = "gpt-5.6-sol"',
|
|
1192
|
+
`model_catalog_json = "${catalogPath}"`,
|
|
1193
|
+
"",
|
|
1194
|
+
"[agents]",
|
|
1195
|
+
"max_threads = 1000",
|
|
1196
|
+
"max_depth = 2",
|
|
1197
|
+
"",
|
|
1198
|
+
"[features.multi_agent_v2]",
|
|
1199
|
+
"enabled = false",
|
|
1200
|
+
"max_concurrent_threads_per_session = 1000",
|
|
1201
|
+
"",
|
|
1202
|
+
].join("\n"));
|
|
1203
|
+
// models_cache.json STILL says v2 (stale), but the explicit catalog wins and says v1.
|
|
1204
|
+
await writeFile(join(codexHome, "models_cache.json"), JSON.stringify({ models: [{ slug: "gpt-5.6-sol", multi_agent_version: "v2" }] }));
|
|
1205
|
+
await writeFile(catalogPath, JSON.stringify({ models: [{ slug: "gpt-5.6-sol", multi_agent_version: "v1" }] }));
|
|
1206
|
+
|
|
1207
|
+
await migrateCodexConfig({
|
|
1208
|
+
env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
|
|
1209
|
+
cwd: root,
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
const content = await readFile(configPath, "utf8");
|
|
1213
|
+
assert.match(content, /enabled = false/, "explicit v1 catalog must keep the managed disable");
|
|
1214
|
+
assert.match(content, /max_threads = 1000/, "explicit v1 catalog must keep agents.max_threads");
|
|
1215
|
+
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
1216
|
+
assert.match(content, /max_depth = 2/);
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
test("#given model_catalog_json declares a model as v2 #when full migration runs #then clears the managed disable", async () => {
|
|
1220
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-multi-agent-v2-catalog-v2-"));
|
|
1221
|
+
const codexHome = join(root, "codex-home");
|
|
1222
|
+
await mkdir(codexHome, { recursive: true });
|
|
1223
|
+
const configPath = join(codexHome, "config.toml");
|
|
1224
|
+
const catalogPath = join(root, "custom-catalog.json");
|
|
1225
|
+
await writeFile(configPath, [
|
|
1226
|
+
'model = "custom-model"',
|
|
1227
|
+
`model_catalog_json = "${catalogPath}"`,
|
|
1228
|
+
"",
|
|
1229
|
+
"[features.multi_agent_v2]",
|
|
1230
|
+
"enabled = false",
|
|
1231
|
+
"",
|
|
1232
|
+
].join("\n"));
|
|
1233
|
+
await writeFile(catalogPath, JSON.stringify({ models: [{ slug: "custom-model", multi_agent_version: "v2" }] }));
|
|
1234
|
+
|
|
1235
|
+
await migrateCodexConfig({
|
|
1236
|
+
env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
|
|
1237
|
+
cwd: root,
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
const content = await readFile(configPath, "utf8");
|
|
1241
|
+
assert.doesNotMatch(content, /^\s*enabled\s*=\s*false/m, "explicit v2 catalog must clear the disable");
|
|
1242
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import { migrateCodexConfig } from "../scripts/migrate-codex-config.mjs";
|
|
8
|
+
|
|
9
|
+
test("#given relative model_catalog_json declares gpt-5.6 model as v1 #when migrating #then resolves catalog from config directory", async () => {
|
|
10
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-v2-relative-catalog-"));
|
|
11
|
+
const codexHome = join(root, "codex-home");
|
|
12
|
+
await mkdir(codexHome, { recursive: true });
|
|
13
|
+
const configPath = join(codexHome, "config.toml");
|
|
14
|
+
await writeFile(
|
|
15
|
+
configPath,
|
|
16
|
+
[
|
|
17
|
+
'model = "gpt-5.6-sol"',
|
|
18
|
+
'model_catalog_json = "custom-catalog.json"',
|
|
19
|
+
"",
|
|
20
|
+
"[agents]",
|
|
21
|
+
"max_threads = 1000",
|
|
22
|
+
"",
|
|
23
|
+
"[features.multi_agent_v2]",
|
|
24
|
+
"enabled = false",
|
|
25
|
+
"max_concurrent_threads_per_session = 1000",
|
|
26
|
+
"",
|
|
27
|
+
].join("\n"),
|
|
28
|
+
);
|
|
29
|
+
await writeFile(join(codexHome, "models_cache.json"), JSON.stringify({ models: [{ slug: "gpt-5.6-sol", multi_agent_version: "v2" }] }));
|
|
30
|
+
await writeFile(join(codexHome, "custom-catalog.json"), JSON.stringify({ models: [{ slug: "gpt-5.6-sol", multi_agent_version: "v1" }] }));
|
|
31
|
+
|
|
32
|
+
await migrateCodexConfig({
|
|
33
|
+
env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
|
|
34
|
+
cwd: root,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const content = await readFile(configPath, "utf8");
|
|
38
|
+
assert.match(content, /enabled = false/);
|
|
39
|
+
assert.match(content, /max_threads = 1000/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("#given no SessionStart model and root gpt-5.6 model without catalog #when migrating #then clears stale V2 disable", async () => {
|
|
43
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-v2-root-gpt56-nocache-"));
|
|
44
|
+
const codexHome = join(root, "codex-home");
|
|
45
|
+
await mkdir(codexHome, { recursive: true });
|
|
46
|
+
const configPath = join(codexHome, "config.toml");
|
|
47
|
+
await writeFile(
|
|
48
|
+
configPath,
|
|
49
|
+
[
|
|
50
|
+
'model = "gpt-5.6-terra"',
|
|
51
|
+
"",
|
|
52
|
+
"[agents]",
|
|
53
|
+
"max_threads = 1000",
|
|
54
|
+
"",
|
|
55
|
+
"[features.multi_agent_v2]",
|
|
56
|
+
"enabled = false",
|
|
57
|
+
"max_concurrent_threads_per_session = 1000",
|
|
58
|
+
"",
|
|
59
|
+
].join("\n"),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await migrateCodexConfig({
|
|
63
|
+
env: { CODEX_HOME: codexHome, LAZYCODEX_MODEL_CATALOG_STATE_PATH: join(root, "model-state.json") },
|
|
64
|
+
cwd: root,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const content = await readFile(configPath, "utf8");
|
|
68
|
+
assert.doesNotMatch(content, /^\s*enabled\s*=\s*false/m);
|
|
69
|
+
assert.doesNotMatch(content, /^\s*max_threads\s*=/m);
|
|
70
|
+
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
71
|
+
});
|
|
@@ -75,3 +75,35 @@ test("#given gpt-5.6 session model with no models_cache #when migrating #then do
|
|
|
75
75
|
assert.match(content, /max_depth = 4/);
|
|
76
76
|
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
77
77
|
});
|
|
78
|
+
|
|
79
|
+
test("#given config without any model #when migrating #then does not introduce agents.max_threads", async () => {
|
|
80
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-subagent-limit-no-model-"));
|
|
81
|
+
const configPath = join(root, "config.toml");
|
|
82
|
+
await writeFile(
|
|
83
|
+
configPath,
|
|
84
|
+
['model_reasoning_effort = "high"', "", "[agents]", "max_depth = 4", ""].join("\n"),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
await migrateConfigFile(configPath, { env: { CODEX_HOME: root } });
|
|
88
|
+
|
|
89
|
+
const content = await readFile(configPath, "utf8");
|
|
90
|
+
assert.doesNotMatch(content, /^\s*max_threads\s*=/m);
|
|
91
|
+
assert.match(content, /max_depth = 4/);
|
|
92
|
+
assert.match(content, /max_concurrent_threads_per_session = 1000/);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("#given config without any model but an existing low cap #when migrating #then still raises the existing cap", async () => {
|
|
96
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-subagent-limit-no-model-raise-"));
|
|
97
|
+
const configPath = join(root, "config.toml");
|
|
98
|
+
await writeFile(
|
|
99
|
+
configPath,
|
|
100
|
+
['model_reasoning_effort = "high"', "", "[agents]", "max_threads = 6", "max_depth = 4", ""].join("\n"),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
await migrateConfigFile(configPath, { env: { CODEX_HOME: root } });
|
|
104
|
+
|
|
105
|
+
const content = await readFile(configPath, "utf8");
|
|
106
|
+
assert.match(content, /max_threads = 1000/);
|
|
107
|
+
assert.doesNotMatch(content, /max_threads = 6/);
|
|
108
|
+
assert.match(content, /max_depth = 4/);
|
|
109
|
+
});
|
|
@@ -3,7 +3,7 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import test from "node:test";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { insertCodexCompatibilityGuidance } from "../scripts/sync-skills.mjs";
|
|
6
|
+
import { codexHarnessToolCompatibility, insertCodexCompatibilityGuidance } from "../scripts/sync-skills.mjs";
|
|
7
7
|
|
|
8
8
|
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
9
9
|
|
|
@@ -207,7 +207,8 @@ test("#given synced aggregate Codex skills #when they describe background orches
|
|
|
207
207
|
["working progress message", /WORKING:/],
|
|
208
208
|
["blocked progress message", /BLOCKED:/],
|
|
209
209
|
["mailbox timeout framing", /timeout only means no new mailbox update arrived/],
|
|
210
|
-
|
|
210
|
+
// Skills route by session tool surface: the namespaced V1 tool or the flat V2 tool both count.
|
|
211
|
+
["wait-agent tool ref", /multi_agent_v1\.wait_agent|`wait_agent`/],
|
|
211
212
|
["explicit fallback conditions", /Fallback only when|Mark a file for retry only when/],
|
|
212
213
|
];
|
|
213
214
|
const bannedPatterns = [
|
|
@@ -234,6 +235,15 @@ test("#given synced aggregate Codex skills #when they describe background orches
|
|
|
234
235
|
}
|
|
235
236
|
});
|
|
236
237
|
|
|
238
|
+
test("#given start-work skill #when synced for Codex #then the difficulty-tier delegation guidance survives the overlay", async () => {
|
|
239
|
+
const content = await readSkill("start-work");
|
|
240
|
+
|
|
241
|
+
assert.match(content, /lazycodex-worker-medium/);
|
|
242
|
+
assert.match(content, /Delegation by difficulty/);
|
|
243
|
+
assert.match(content, /Global Review and Debugging Gate/);
|
|
244
|
+
assert.doesNotMatch(content, /works the same on both surfaces/);
|
|
245
|
+
});
|
|
246
|
+
|
|
237
247
|
test("#given review-work skill #when some lanes do not finish #then aggregate result remains bounded", async () => {
|
|
238
248
|
const content = await readSkill("review-work");
|
|
239
249
|
|
|
@@ -244,6 +254,8 @@ test("#given review-work skill #when some lanes do not finish #then aggregate re
|
|
|
244
254
|
assert.match(content, /Overall Verdict: PASSED \/ FAILED \/ INCONCLUSIVE/);
|
|
245
255
|
assert.match(content, /PASS\/FAIL\/INCONCLUSIVE \| HIGH\/MED\/LOW/);
|
|
246
256
|
assert.match(content, /Do not spin in repeated/);
|
|
257
|
+
assert.match(content, /bare REJECT\/FAIL token without findings is not a verdict/);
|
|
258
|
+
assert.match(content, /cites the violated goal criterion/);
|
|
247
259
|
assert.match(content, /Do not use `multi_agent_v1\.send_input` as an interrupt/);
|
|
248
260
|
});
|
|
249
261
|
|
|
@@ -265,3 +277,9 @@ test("#given PR and review skills #when synced for Codex #then worktree lifecycl
|
|
|
265
277
|
assert.match(reviewWork, /dedicated review worktree attached to that branch/);
|
|
266
278
|
assert.match(reviewWork, /Never\s+checkout, test, or edit the review branch in the main worktree/);
|
|
267
279
|
});
|
|
280
|
+
|
|
281
|
+
test("#given generated Codex compatibility guidance #when multi-agent lifecycle tools are mentioned #then optional tools are guarded by the active tools list", () => {
|
|
282
|
+
assert.match(codexHarnessToolCompatibility, /when exposed in the active tools list/, "send_input/close_agent must be marked optional (lazycodex#116)");
|
|
283
|
+
assert.match(codexHarnessToolCompatibility, /multi_agent_v1\.spawn_agent/);
|
|
284
|
+
assert.match(codexHarnessToolCompatibility, /multi_agent_v1\.wait_agent/);
|
|
285
|
+
});
|
|
@@ -92,7 +92,7 @@ const startWorkOriginalHardRule = "- No completion claim while an applicable ult
|
|
|
92
92
|
const startWorkCodexHardRule = "- No completion claim while an applicable ultraqa adversarial class was never probed. Each applicable class needs a captured observable result; each skipped class needs a one-line not-applicable reason in the ledger.\n- No `ORCHESTRATION COMPLETE`, final response, PR creation, PR handoff, or merge before the Global Review and Debugging Gate passes with recorded evidence.\n- No PR/branch implementation or review in the main worktree; create or use a task-owned git worktree first.\n- No unprefixed session ids in Boulder state. Codex sessions are always `codex:<session_id>`.";
|
|
93
93
|
|
|
94
94
|
const reviewWorkCodexGatePattern =
|
|
95
|
-
/\nWhen `review-work` is used as a final implementation, PR, or `\$start-work`\ngate, it is blocking\. A timeout, missing deliverable, ack-only response,\nexplicit `BLOCKED:`, or inconclusive lane is not a pass\. Treat that lane as\nfailed, investigate the underlying uncertainty with the `debugging` skill when\nruntime behavior may be wrong, fix with evidence, and rerun the affected lane\nbefore claiming completion, creating or handing off a PR, or merging\.\n\nWhen reviewing a PR or branch, collect diff, file contents, and verification\nresults from a dedicated review worktree attached to that branch\. Never\ncheckout, test, or edit the review branch in the main worktree\.\n\nReview evidence must be safe to share\. Redact or mask secrets and sensitive\nuser data before including evidence in logs, PR bodies, or handoffs\. Never\ninclude raw tokens, credentials, auth headers, cookies, API keys, env dumps,\nprivate logs, or PII; summarize with lengths, hashes, and short non-sensitive\nprefixes when identity is needed\.\n/;
|
|
95
|
+
/\nWhen `review-work` is used as a final implementation, PR, or `\$start-work`\ngate, it is blocking\. A timeout, missing deliverable, ack-only response,\nexplicit `BLOCKED:`, or inconclusive lane is not a pass\. Treat that lane as\nfailed, investigate the underlying uncertainty with the `debugging` skill when\nruntime behavior may be wrong, fix with evidence, and rerun the affected lane\nbefore claiming completion, creating or handing off a PR, or merging\.\n\nA rejecting lane must name its blockers inline in its final message — each\nblocker cites the violated goal criterion or requirement plus an evidence\npointer\. A bare REJECT\/FAIL token without findings is not a verdict; treat it\nas an inconclusive lane \(one bounded respawn, then record it inconclusive with\nthat reason\)\.\n\nWhen reviewing a PR or branch, collect diff, file contents, and verification\nresults from a dedicated review worktree attached to that branch\. Never\ncheckout, test, or edit the review branch in the main worktree\.\n\nReview evidence must be safe to share\. Redact or mask secrets and sensitive\nuser data before including evidence in logs, PR bodies, or handoffs\. Never\ninclude raw tokens, credentials, auth headers, cookies, API keys, env dumps,\nprivate logs, or PII; summarize with lengths, hashes, and short non-sensitive\nprefixes when identity is needed\.\n/;
|
|
96
96
|
|
|
97
97
|
export function removeCodexSkillOverlays(skillName, content) {
|
|
98
98
|
if (skillName === "ulw-research") {
|
|
@@ -252,13 +252,15 @@ test("#given synced ulw-loop skill #when worker guidance is inspected #then cont
|
|
|
252
252
|
);
|
|
253
253
|
const syncedSkill = await readFile(join(root, "skills", "ulw-loop", "SKILL.md"), "utf8");
|
|
254
254
|
const syncedWorkflow = await readFile(join(root, "skills", "ulw-loop", "references", "full-workflow.md"), "utf8");
|
|
255
|
+
// ulw-loop is V2-primary (gpt-5.6 sol/terra use the flat `wait_agent`); the `multi_agent_v1.*`
|
|
256
|
+
// namespace is documented only as the v1 fallback, so the wait_agent refs accept the bare token.
|
|
255
257
|
const requiredPatterns = [
|
|
256
|
-
["
|
|
258
|
+
["wait_agent ref", /\bwait_agent\b/],
|
|
257
259
|
["local spawned-name tracking", /Track spawned agent names locally/],
|
|
258
260
|
["wait_agent mailbox path", /wait_agent.*mailbox signals/],
|
|
259
261
|
["progress status contract", /WORKING:/],
|
|
260
262
|
["long-running plan/reviewer background guidance", /Plan and reviewer agents may run for a long time/],
|
|
261
|
-
["bounded plan/reviewer polling", /
|
|
263
|
+
["bounded plan/reviewer polling", /wait_agent.*cycles/],
|
|
262
264
|
["single long wait guard", /single long blocking wait/],
|
|
263
265
|
["git-master checkpointing", /git-master/],
|
|
264
266
|
["touched-path commit-style probe", /touched-path commit history/],
|