lazycodex-ai 4.16.3 → 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/README.ja.md +4 -4
- package/README.ko.md +4 -4
- package/README.md +2 -2
- package/README.ru.md +4 -4
- package/README.zh-cn.md +4 -4
- package/dist/cli/index.js +179 -63
- package/dist/cli-node/index.js +179 -63
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +84 -19
- 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 +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +6 -6
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +6 -4
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +4 -4
- 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/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/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +8 -2
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +8 -2
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +5 -2
- 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/scripts/scaffold-plan.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +2 -2
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +76 -16
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +14 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +11 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -2
- 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-dist/install-local.mjs +91 -21
- package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
- package/packages/shared-skills/skills/start-work/SKILL.md +5 -2
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
- 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
|
@@ -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
|
});
|
|
@@ -235,6 +235,15 @@ test("#given synced aggregate Codex skills #when they describe background orches
|
|
|
235
235
|
}
|
|
236
236
|
});
|
|
237
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
|
+
|
|
238
247
|
test("#given review-work skill #when some lanes do not finish #then aggregate result remains bounded", async () => {
|
|
239
248
|
const content = await readSkill("review-work");
|
|
240
249
|
|
|
@@ -245,6 +254,8 @@ test("#given review-work skill #when some lanes do not finish #then aggregate re
|
|
|
245
254
|
assert.match(content, /Overall Verdict: PASSED \/ FAILED \/ INCONCLUSIVE/);
|
|
246
255
|
assert.match(content, /PASS\/FAIL\/INCONCLUSIVE \| HIGH\/MED\/LOW/);
|
|
247
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/);
|
|
248
259
|
assert.match(content, /Do not use `multi_agent_v1\.send_input` as an interrupt/);
|
|
249
260
|
});
|
|
250
261
|
|
|
@@ -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/],
|
|
@@ -6,47 +6,16 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
|
|
7
7
|
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
8
|
|
|
9
|
-
async
|
|
9
|
+
test("#given ulw-plan skill copies #when component source and packaged copy are compared #then they are byte-identical and expose the loader-parsed name", async () => {
|
|
10
|
+
// given
|
|
10
11
|
const componentPath = join(root, "components", "ultrawork", "skills", "ulw-plan", "SKILL.md");
|
|
11
12
|
const packagedPath = join(root, "skills", "ulw-plan", "SKILL.md");
|
|
12
|
-
return [
|
|
13
|
-
{ label: "component", path: componentPath, content: await readFile(componentPath, "utf8") },
|
|
14
|
-
{ label: "packaged", path: packagedPath, content: await readFile(packagedPath, "utf8") },
|
|
15
|
-
];
|
|
16
|
-
}
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`${copy.label}: must preserve independent spawn waves`,
|
|
26
|
-
);
|
|
27
|
-
assert.match(
|
|
28
|
-
copy.content,
|
|
29
|
-
/After the wave\s+is launched[\s\S]{0,240}multi_agent_v1\.wait_agent[\s\S]{0,240}terminal status/i,
|
|
30
|
-
`${copy.label}: must wait after the wave is launched`,
|
|
31
|
-
);
|
|
32
|
-
assert.doesNotMatch(
|
|
33
|
-
copy.content,
|
|
34
|
-
/Immediately after any `multi_agent_v1\.spawn_agent`/i,
|
|
35
|
-
`${copy.label}: must not serialize independent spawns`,
|
|
36
|
-
);
|
|
37
|
-
assert.match(copy.content, /terminal status/i, `${copy.label}: must wait until terminal status`);
|
|
38
|
-
assert.match(copy.content, /WORKING:/, `${copy.label}: must keep progress liveness guidance`);
|
|
39
|
-
assert.match(copy.content, /BLOCKED:/, `${copy.label}: must keep blocked liveness guidance`);
|
|
40
|
-
assert.match(
|
|
41
|
-
copy.content,
|
|
42
|
-
/timeout only means no new mailbox update arrived/i,
|
|
43
|
-
`${copy.label}: must frame wait timeouts as mailbox silence`,
|
|
44
|
-
);
|
|
45
|
-
assert.match(copy.content, /Fallback only when/, `${copy.label}: must keep explicit fallback conditions`);
|
|
46
|
-
assert.match(
|
|
47
|
-
copy.content,
|
|
48
|
-
/do not start dependent planning, drafting, approval-gate work, or final handoff/i,
|
|
49
|
-
`${copy.label}: must block dependent planning work before child results are integrated`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
14
|
+
// when
|
|
15
|
+
const component = await readFile(componentPath, "utf8");
|
|
16
|
+
const packaged = await readFile(packagedPath, "utf8");
|
|
17
|
+
|
|
18
|
+
// then
|
|
19
|
+
assert.equal(packaged, component);
|
|
20
|
+
assert.match(component, /^name: ulw-plan$/m);
|
|
52
21
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
// allow: SIZE_OK - ULW research skill contract tests inspect one bundled prompt protocol; this release introduces the contract and future additions should split by protocol phase.
|
|
2
|
-
|
|
3
1
|
import assert from "node:assert/strict";
|
|
4
2
|
import { readFile } from "node:fs/promises";
|
|
5
3
|
import { dirname, join } from "node:path";
|
|
6
4
|
import test from "node:test";
|
|
7
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
8
7
|
import { sharedSkillsRootPath } from "@oh-my-opencode/shared-skills";
|
|
9
8
|
|
|
10
9
|
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
@@ -18,286 +17,14 @@ async function readUlwResearchCopies() {
|
|
|
18
17
|
];
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
const match = content.match(/^---\r?\n[\s\S]*?\bdescription:\s*"([\s\S]*?)"\r?\n[\s\S]*?---/);
|
|
23
|
-
assert.notEqual(match, null, "SKILL.md frontmatter description not found");
|
|
24
|
-
return match[1];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function escapeRegExp(value) {
|
|
28
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function markdownSection(content, heading, nextHeading) {
|
|
32
|
-
const headingPattern = new RegExp(`^${escapeRegExp(heading)}\\r?$`, "m");
|
|
33
|
-
const headingMatch = content.match(headingPattern);
|
|
34
|
-
assert.notEqual(headingMatch, null, `SKILL.md section not found: ${heading}`);
|
|
35
|
-
assert.notEqual(headingMatch.index, undefined, `SKILL.md section index not found: ${heading}`);
|
|
36
|
-
const bodyStart = headingMatch.index + headingMatch[0].length;
|
|
37
|
-
if (nextHeading === undefined) {
|
|
38
|
-
return content.slice(bodyStart);
|
|
39
|
-
}
|
|
40
|
-
const nextHeadingIndex = content.indexOf(`\n${nextHeading}`, bodyStart);
|
|
41
|
-
assert.notEqual(nextHeadingIndex, -1, `SKILL.md next section not found: ${nextHeading}`);
|
|
42
|
-
return content.slice(bodyStart, nextHeadingIndex);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
test("#given renamed research skill #when frontmatter is inspected #then ulw-research is the canonical name", async () => {
|
|
20
|
+
test("#given ulw-research skill copies #when frontmatter is inspected #then the loader-parsed name is ulw-research", async () => {
|
|
46
21
|
for (const copy of await readUlwResearchCopies()) {
|
|
47
22
|
assert.match(copy.content, /^name: ulw-research$/m, `${copy.label}: frontmatter must expose ulw-research`);
|
|
48
23
|
}
|
|
49
24
|
});
|
|
50
25
|
|
|
51
|
-
test("#given
|
|
52
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
53
|
-
assert.match(
|
|
54
|
-
copy.content,
|
|
55
|
-
/`ULW-RESEARCH MODE ENABLED!`/,
|
|
56
|
-
`${copy.label}: body must expose the ulw-research activation marker`,
|
|
57
|
-
);
|
|
58
|
-
assert.doesNotMatch(
|
|
59
|
-
copy.content,
|
|
60
|
-
/`ULTRARESEARCH MODE ENABLED!`/,
|
|
61
|
-
`${copy.label}: body must not expose the old ultraresearch activation marker`,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("#given ulw-research skill #when scanned for non-English content #then it contains no Hangul", async () => {
|
|
67
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
68
|
-
assert.doesNotMatch(
|
|
69
|
-
copy.content,
|
|
70
|
-
/[ᄀ-ᇿ-가-힣]/,
|
|
71
|
-
`${copy.label} copy contains Hangul characters`,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("#given ulw-research description #when activation policy is inspected #then it gates on explicit research demands only", async () => {
|
|
77
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
78
|
-
const description = frontmatterDescription(copy.content);
|
|
79
|
-
assert.match(description, /ulw-research/i, `${copy.label}: description must name the ulw-research trigger`);
|
|
80
|
-
if (copy.label === "shared") {
|
|
81
|
-
assert.match(description, /ultraresearch/i, `${copy.label}: description must preserve ultraresearch discoverability`);
|
|
82
|
-
} else {
|
|
83
|
-
assert.doesNotMatch(description, /ultraresearch/i, `${copy.label}: description must not expose ultraresearch`);
|
|
84
|
-
}
|
|
85
|
-
assert.match(description, /\bulw\b/i, `${copy.label}: description must preserve ulw discoverability`);
|
|
86
|
-
assert.match(description, /explicit/i, `${copy.label}: description must gate activation on explicit demand`);
|
|
87
|
-
assert.match(
|
|
88
|
-
description,
|
|
89
|
-
/ultra-precise investigation/i,
|
|
90
|
-
`${copy.label}: description must name the ultra-precise investigation trigger`,
|
|
91
|
-
);
|
|
92
|
-
assert.match(description, /\bresearch\b/i, `${copy.label}: description must name the research trigger`);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("#given packaged ulw-research skill #when scanned for legacy aliases #then ultraresearch is not exposed", async () => {
|
|
97
|
-
const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
|
|
98
|
-
assert.notEqual(packaged, undefined, "packaged copy not found");
|
|
99
|
-
assert.doesNotMatch(packaged.content, /ultraresearch/i, "packaged ulw-research must not expose ultraresearch");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("#given packaged ulw-research skill #when Codex guidance is inspected #then compatibility guidance is preserved", async () => {
|
|
103
|
-
const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
|
|
104
|
-
assert.notEqual(packaged, undefined, "packaged copy not found");
|
|
105
|
-
assert.match(packaged.content, /## Codex Harness Tool Compatibility/);
|
|
106
|
-
assert.match(packaged.content, /multi_agent_v1\.spawn_agent/);
|
|
107
|
-
assert.match(packaged.content, /multi_agent_v1\.wait_agent/);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("#given ulw-research body #when authority is inspected #then it takes precedence over exploration-bounding instructions", async () => {
|
|
111
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
112
|
-
assert.match(
|
|
113
|
-
copy.content,
|
|
114
|
-
/exploration-bounding|exploration (?:caps|budgets|limits)/i,
|
|
115
|
-
`${copy.label}: body must name the exploration-bounding instructions it overrides`,
|
|
116
|
-
);
|
|
117
|
-
assert.match(
|
|
118
|
-
copy.content,
|
|
119
|
-
/supersede|override|do(?:es)? not (?:bind|apply)/i,
|
|
120
|
-
`${copy.label}: body must state precedence while the mode is active`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("#given ulw-research worker protocol #when EXPAND flow is inspected #then markers travel as message text and workers never write files", async () => {
|
|
126
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
127
|
-
assert.match(copy.content, /EXPAND/, `${copy.label}: body must keep the EXPAND marker protocol`);
|
|
128
|
-
assert.match(
|
|
129
|
-
copy.content,
|
|
130
|
-
/(?:reply|message|response) text|end (?:its|the|your) (?:reply|response|final message)/i,
|
|
131
|
-
`${copy.label}: EXPAND markers must be returned as message text`,
|
|
132
|
-
);
|
|
133
|
-
assert.match(
|
|
134
|
-
copy.content,
|
|
135
|
-
/read-only|cannot write files|never ask (?:a )?worker(?:s)? to write/i,
|
|
136
|
-
`${copy.label}: body must state the read-only worker constraint`,
|
|
137
|
-
);
|
|
138
|
-
assert.doesNotMatch(
|
|
139
|
-
copy.content,
|
|
140
|
-
/APPEND (?:your )?findings to \$SESSION_DIR/i,
|
|
141
|
-
`${copy.label}: workers must not be instructed to append session-dir files`,
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test("#given ulw-research journaling #when ownership is inspected #then the orchestrator owns the session journal", async () => {
|
|
147
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
148
|
-
assert.match(
|
|
149
|
-
copy.content,
|
|
150
|
-
/orchestrator[\s\S]{0,200}journal|journal[\s\S]{0,200}orchestrator/i,
|
|
151
|
-
`${copy.label}: body must assign session-journal writes to the orchestrator`,
|
|
152
|
-
);
|
|
153
|
-
assert.match(copy.content, /SESSION_DIR/, `${copy.label}: body must keep the session directory protocol`);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("#given ulw-research expansion loop #when stop rules are inspected #then convergence rules and a depth cap are stated", async () => {
|
|
158
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
159
|
-
assert.match(copy.content, /converg/i, `${copy.label}: body must define convergence`);
|
|
160
|
-
assert.match(copy.content, /depth/i, `${copy.label}: body must define an expansion depth cap`);
|
|
161
|
-
assert.match(
|
|
162
|
-
copy.content,
|
|
163
|
-
/minimum (?:of )?(?:2|two) expansion waves|at least (?:2|two) expansion waves/i,
|
|
164
|
-
`${copy.label}: body must require a minimum of two expansion waves before convergence`,
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("#given ulw-research under ultrawork #when coexistence is inspected #then marker and done-definition conflicts are resolved", async () => {
|
|
170
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
171
|
-
assert.match(copy.content, /ultrawork|\bulw\b/i, `${copy.label}: body must address ultrawork coexistence`);
|
|
172
|
-
assert.match(
|
|
173
|
-
copy.content,
|
|
174
|
-
/first(?:-| )line/i,
|
|
175
|
-
`${copy.label}: body must resolve the first-line activation marker conflict`,
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test("#given ulw-research worker sizing #when spawn guidance is inspected #then capable-model and high-effort routing is stated", async () => {
|
|
181
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
182
|
-
assert.match(
|
|
183
|
-
copy.content,
|
|
184
|
-
/capable model|high(?:est)? (?:reasoning )?effort/i,
|
|
185
|
-
`${copy.label}: body must route research workers to a capable model or high effort`,
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
test("#given ulw-research execution substrate #when team usage is inspected #then it prefers a cooperating team with harness-native team tools", async () => {
|
|
191
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
192
|
-
assert.match(
|
|
193
|
-
copy.content,
|
|
194
|
-
/cooperating team/i,
|
|
195
|
-
`${copy.label}: body must encourage running the swarm as a cooperating team`,
|
|
196
|
-
);
|
|
197
|
-
assert.match(copy.content, /\bteammode\b/i, `${copy.label}: body must name the Codex teammode skill`);
|
|
198
|
-
assert.match(copy.content, /team_mode/i, `${copy.label}: body must name the OpenCode team_mode path`);
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
test("#given ulw-research team composition #when member slicing is inspected #then members map to part/ownership/perspective, never job titles", async () => {
|
|
203
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
204
|
-
assert.match(
|
|
205
|
-
copy.content,
|
|
206
|
-
/by part, ownership, or perspective/i,
|
|
207
|
-
`${copy.label}: body must compose members by part, ownership, or perspective`,
|
|
208
|
-
);
|
|
209
|
-
assert.match(
|
|
210
|
-
copy.content,
|
|
211
|
-
/never a job title|not (?:a |by )?job title/i,
|
|
212
|
-
`${copy.label}: body must forbid vague job-title members`,
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
test("#given ulw-research team communication #when the raise law is inspected #then members broadcast every lead immediately rather than hoarding", async () => {
|
|
218
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
219
|
-
assert.match(
|
|
220
|
-
copy.content,
|
|
221
|
-
/raise law|broadcast every lead/i,
|
|
222
|
-
`${copy.label}: body must state the raise/broadcast law`,
|
|
223
|
-
);
|
|
224
|
-
assert.match(copy.content, /over-communicate/i, `${copy.label}: body must demand over-communication`);
|
|
225
|
-
assert.match(
|
|
226
|
-
copy.content,
|
|
227
|
-
/the (?:moment|instant) it (?:surfaces|appears|lands)/i,
|
|
228
|
-
`${copy.label}: body must require raising leads the moment they surface`,
|
|
229
|
-
);
|
|
230
|
-
assert.match(
|
|
231
|
-
copy.content,
|
|
232
|
-
/hoard/i,
|
|
233
|
-
`${copy.label}: body must reject hoarding leads for a final dump`,
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
test("#given ulw-research default swarm #when team guidance is inspected #then teammode, many teammates, and hyperdebate are defaulted", async () => {
|
|
239
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
240
|
-
const teamSection = markdownSection(copy.content, "## Run the swarm as a cooperating team", "## Worker ground rules");
|
|
241
|
-
assert.match(teamSection, /default(?:s)? to teammode|teammode by default/i, `${copy.label}: teammode must be the default`);
|
|
242
|
-
assert.match(teamSection, /many teammates|larger roster|5-8 teammates|5\+ teammates/i, `${copy.label}: body must prefer many teammates`);
|
|
243
|
-
assert.match(teamSection, /hyperdebate|ultradebate/i, `${copy.label}: body must require adversarial debate`);
|
|
244
|
-
assert.match(teamSection, /skeptic|red-team|cross-critique/i, `${copy.label}: body must include a critique perspective`);
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("#given ulw-research non-code verification #when the gate is inspected #then a claim graph / verified-claims data-flow-lock exists", async () => {
|
|
249
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
250
|
-
assert.match(
|
|
251
|
-
copy.content,
|
|
252
|
-
/claim graph|verified-claims/i,
|
|
253
|
-
`${copy.label}: body must define the non-code claim-graph verification gate`,
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
test("#given ulw-research claim graph #when ownership is inspected #then workers never write the graph / verified-claims artifact", async () => {
|
|
259
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
260
|
-
assert.doesNotMatch(
|
|
261
|
-
copy.content,
|
|
262
|
-
/worker[^.]*\b(?:write|append|create)s?\b[^.]*(?:claim[- ]graph|verified-claims)/i,
|
|
263
|
-
`${copy.label}: workers must not be instructed to write/append/create the claim graph or verified-claims`,
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test("#given ulw-research report output #when defaults are inspected #then HTML/PDF reports go through frontend, visual QA, and reviewer approval", async () => {
|
|
269
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
270
|
-
const phase0 = markdownSection(copy.content, "## Phase 0 — Decompose and open the journal", "## Phase 1 — Saturation wave");
|
|
271
|
-
const phase4 = markdownSection(copy.content, "## Phase 4 — Synthesize", "## Phase 5 — Final materials");
|
|
272
|
-
const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
|
|
273
|
-
assert.match(phase0, /Final material format:\s*<HTML\/PDF default \| explicit format \| markdown only>/, `${copy.label}: Phase 0 must track the default final-material contract`);
|
|
274
|
-
assert.match(phase4, /citation source of truth/i, `${copy.label}: Phase 4 synthesis must be a source of truth, not the default final artifact`);
|
|
275
|
-
assert.doesNotMatch(phase4, /When no report was requested, this is the deliverable/i, `${copy.label}: Phase 4 must not contradict default HTML/PDF final materials`);
|
|
276
|
-
assert.match(phase5, /Default final materials to HTML\/PDF unless the user explicitly asks/i, `${copy.label}: Phase 5 must default final materials to HTML/PDF`);
|
|
277
|
-
assert.match(phase5, /HTML first[\s\S]{0,120}PDF default/i, `${copy.label}: report output must default to HTML with PDF availability`);
|
|
278
|
-
assert.match(phase5, /\bfrontend\b/i, `${copy.label}: report assembly must load the frontend skill`);
|
|
279
|
-
assert.match(phase5, /visual-qa/i, `${copy.label}: report assembly must require visual-qa`);
|
|
280
|
-
assert.match(phase5, /ulw-loop|ULW loop/i, `${copy.label}: report QA must run under the ULW loop`);
|
|
281
|
-
assert.match(phase5, /reviewer[\s\S]{0,120}(?:approve|says no broken parts|no broken parts)/i, `${copy.label}: report completion must wait for reviewer approval`);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
test("#given ulw-research final materials #when visual artifact guidance is inspected #then charts Mermaid graphs and imagegen are strongly required", async () => {
|
|
286
|
-
for (const copy of await readUlwResearchCopies()) {
|
|
287
|
-
const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
|
|
288
|
-
assert.match(phase5, /actively use charts/i, `${copy.label}: reports must strongly require charts`);
|
|
289
|
-
assert.match(phase5, /Mermaid graphs/i, `${copy.label}: reports must require Mermaid graphs`);
|
|
290
|
-
assert.match(phase5, /imagegen skill/i, `${copy.label}: reports must require imagegen visuals`);
|
|
291
|
-
assert.match(phase5, /generated (?:diagrams|visuals)|generated diagrams or editorial visuals/i, `${copy.label}: report assets must include generated visual guidance`);
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test("#given ulw-research blocked sources #when escalation is inspected #then it routes through the ultimate-browsing skill", async () => {
|
|
26
|
+
test("#given ulw-research skill copies #when scanned for non-English content #then they contain no Hangul", async () => {
|
|
296
27
|
for (const copy of await readUlwResearchCopies()) {
|
|
297
|
-
assert.
|
|
298
|
-
copy.content,
|
|
299
|
-
/ultimate-browsing/,
|
|
300
|
-
`${copy.label}: body must escalate blocked sources via the ultimate-browsing skill`,
|
|
301
|
-
);
|
|
28
|
+
assert.doesNotMatch(copy.content, /[ᄀ-ᇿ-가-힣]/, `${copy.label} copy contains Hangul characters`);
|
|
302
29
|
}
|
|
303
30
|
});
|
|
@@ -5903,7 +5903,7 @@ var package_default;
|
|
|
5903
5903
|
var init_package = __esm(() => {
|
|
5904
5904
|
package_default = {
|
|
5905
5905
|
name: "@oh-my-opencode/omo-codex",
|
|
5906
|
-
version: "4.16.
|
|
5906
|
+
version: "4.16.3",
|
|
5907
5907
|
type: "module",
|
|
5908
5908
|
private: true,
|
|
5909
5909
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -7612,7 +7612,12 @@ function shouldCopyPluginPath(path, root) {
|
|
|
7612
7612
|
if (relative4 === "")
|
|
7613
7613
|
return true;
|
|
7614
7614
|
const parts = relative4.split(sep5);
|
|
7615
|
-
|
|
7615
|
+
if (parts.some((part) => part === ".git" || part === "node_modules"))
|
|
7616
|
+
return false;
|
|
7617
|
+
return !isNestedComponentMcpManifest(parts);
|
|
7618
|
+
}
|
|
7619
|
+
function isNestedComponentMcpManifest(parts) {
|
|
7620
|
+
return parts.length > 1 && parts.at(-1) === ".mcp.json";
|
|
7616
7621
|
}
|
|
7617
7622
|
var removedSparkshellReferencePattern = /\b(?:sparkshell|spark[-_\s]+shell)\b/i;
|
|
7618
7623
|
var removedSparkshellPromptSurfaceDirs = new Set([".codex-plugin", "agents", "bundled-rules", "hooks", "skills"]);
|
|
@@ -8139,6 +8144,9 @@ function stripTomlLineComment(line) {
|
|
|
8139
8144
|
var LEGACY_MANAGED_CODEX_AGENT_NAMES_TO_PURGE = ["codex-ultrawork-reviewer"];
|
|
8140
8145
|
var CURRENT_MANAGED_CODEX_AGENT_NAMES = [
|
|
8141
8146
|
"explorer",
|
|
8147
|
+
"lazycodex-worker-high",
|
|
8148
|
+
"lazycodex-worker-low",
|
|
8149
|
+
"lazycodex-worker-medium",
|
|
8142
8150
|
"librarian",
|
|
8143
8151
|
"metis",
|
|
8144
8152
|
"momus",
|
|
@@ -8556,12 +8564,18 @@ import { readFile as readFile10 } from "node:fs/promises";
|
|
|
8556
8564
|
import { join as join17 } from "node:path";
|
|
8557
8565
|
var FALLBACK_CODEX_MODEL_CATALOG = {
|
|
8558
8566
|
current: {
|
|
8559
|
-
model: "gpt-5.
|
|
8560
|
-
modelContextWindow:
|
|
8567
|
+
model: "gpt-5.6-sol",
|
|
8568
|
+
modelContextWindow: 372000,
|
|
8561
8569
|
modelReasoningEffort: "high",
|
|
8562
8570
|
planModeReasoningEffort: "xhigh"
|
|
8563
8571
|
},
|
|
8564
8572
|
managedProfiles: [
|
|
8573
|
+
{
|
|
8574
|
+
model: "gpt-5.5",
|
|
8575
|
+
modelContextWindow: 400000,
|
|
8576
|
+
modelReasoningEffort: "high",
|
|
8577
|
+
planModeReasoningEffort: "xhigh"
|
|
8578
|
+
},
|
|
8565
8579
|
{
|
|
8566
8580
|
model: "gpt-5.5",
|
|
8567
8581
|
modelContextWindow: 1e6,
|
|
@@ -9004,32 +9018,88 @@ import { join as join20 } from "node:path";
|
|
|
9004
9018
|
var MANAGED_REASONING_DEFAULT_UPGRADES = new Map([
|
|
9005
9019
|
[
|
|
9006
9020
|
"explorer",
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9021
|
+
[
|
|
9022
|
+
{
|
|
9023
|
+
previous: { model: "gpt-5.4-mini", effort: "low" },
|
|
9024
|
+
current: { model: "gpt-5.6-terra", effort: "medium" }
|
|
9025
|
+
},
|
|
9026
|
+
{
|
|
9027
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
9028
|
+
current: { model: "gpt-5.6-luna", effort: "low" }
|
|
9029
|
+
}
|
|
9030
|
+
]
|
|
9011
9031
|
],
|
|
9012
9032
|
[
|
|
9013
9033
|
"librarian",
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9034
|
+
[
|
|
9035
|
+
{
|
|
9036
|
+
previous: { model: "gpt-5.4-mini", effort: "low" },
|
|
9037
|
+
current: { model: "gpt-5.6-terra", effort: "medium" }
|
|
9038
|
+
},
|
|
9039
|
+
{
|
|
9040
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
9041
|
+
current: { model: "gpt-5.6-luna", effort: "low" }
|
|
9042
|
+
}
|
|
9043
|
+
]
|
|
9018
9044
|
],
|
|
9019
9045
|
[
|
|
9020
9046
|
"momus",
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9047
|
+
[
|
|
9048
|
+
{
|
|
9049
|
+
previous: { model: "gpt-5.5", effort: "xhigh" },
|
|
9050
|
+
current: { model: "gpt-5.6-sol", effort: "ultra" }
|
|
9051
|
+
}
|
|
9052
|
+
]
|
|
9053
|
+
],
|
|
9054
|
+
[
|
|
9055
|
+
"plan",
|
|
9056
|
+
[
|
|
9057
|
+
{
|
|
9058
|
+
previous: { model: "gpt-5.6-sol", effort: "xhigh" },
|
|
9059
|
+
current: { model: "gpt-5.6-sol", effort: "max" }
|
|
9060
|
+
}
|
|
9061
|
+
]
|
|
9062
|
+
],
|
|
9063
|
+
[
|
|
9064
|
+
"lazycodex-worker-medium",
|
|
9065
|
+
[
|
|
9066
|
+
{
|
|
9067
|
+
previous: { model: "gpt-5.6-sol", effort: "high" },
|
|
9068
|
+
current: { model: "gpt-5.6-luna", effort: "max" }
|
|
9069
|
+
}
|
|
9070
|
+
]
|
|
9071
|
+
],
|
|
9072
|
+
[
|
|
9073
|
+
"lazycodex-qa-executor",
|
|
9074
|
+
[
|
|
9075
|
+
{
|
|
9076
|
+
previous: { model: "gpt-5.6-terra", effort: "medium" },
|
|
9077
|
+
current: { model: "gpt-5.6-luna", effort: "high" }
|
|
9078
|
+
}
|
|
9079
|
+
]
|
|
9080
|
+
],
|
|
9081
|
+
[
|
|
9082
|
+
"lazycodex-gate-reviewer",
|
|
9083
|
+
[
|
|
9084
|
+
{
|
|
9085
|
+
previous: { model: "gpt-5.6-sol", effort: "xhigh" },
|
|
9086
|
+
current: { model: "gpt-5.6-sol", effort: "high" }
|
|
9087
|
+
}
|
|
9088
|
+
]
|
|
9025
9089
|
]
|
|
9026
9090
|
]);
|
|
9027
9091
|
function resolveManagedAgentReasoning(input) {
|
|
9028
|
-
const
|
|
9029
|
-
if (
|
|
9030
|
-
return
|
|
9031
|
-
|
|
9032
|
-
|
|
9092
|
+
const steps = MANAGED_REASONING_DEFAULT_UPGRADES.get(input.agentName);
|
|
9093
|
+
if (steps === undefined)
|
|
9094
|
+
return input.preserved.effort;
|
|
9095
|
+
const latest = steps[steps.length - 1];
|
|
9096
|
+
if (latest === undefined)
|
|
9097
|
+
return input.preserved.effort;
|
|
9098
|
+
if (input.bundledModel !== latest.current.model || input.bundledEffort !== latest.current.effort) {
|
|
9099
|
+
return input.preserved.effort;
|
|
9100
|
+
}
|
|
9101
|
+
const preservedMatchesAnyStep = steps.some((step) => input.preserved.model === step.previous.model && input.preserved.effort === step.previous.effort);
|
|
9102
|
+
return preservedMatchesAnyStep ? latest.current.effort : input.preserved.effort;
|
|
9033
9103
|
}
|
|
9034
9104
|
|
|
9035
9105
|
// packages/omo-codex/src/install/preserved-agent-settings.ts
|