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
|
@@ -17,15 +17,73 @@ const agentSchemaKeys = new Set([
|
|
|
17
17
|
|
|
18
18
|
const lazycodexAgentInvariants = new Map([
|
|
19
19
|
[
|
|
20
|
-
"
|
|
20
|
+
"explorer.toml",
|
|
21
|
+
{
|
|
22
|
+
model: "gpt-5.6-luna",
|
|
23
|
+
effort: "low",
|
|
24
|
+
includes: [/Read-only/, /working tree/, /rg/],
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"librarian.toml",
|
|
29
|
+
{
|
|
30
|
+
model: "gpt-5.6-luna",
|
|
31
|
+
effort: "low",
|
|
32
|
+
includes: [/Read-only/, /SHA-pinned GitHub permalink/, /external/],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"metis.toml",
|
|
37
|
+
{
|
|
38
|
+
model: "gpt-5.6-sol",
|
|
39
|
+
effort: "high",
|
|
40
|
+
includes: [/pre-planning analyst/i, /contradictions/, /Read-only/],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
"momus.toml",
|
|
45
|
+
{
|
|
46
|
+
model: "gpt-5.6-sol",
|
|
47
|
+
effort: "ultra",
|
|
48
|
+
includes: [/plan reviewer/i, /OKAY, ITERATE, or REJECT/, /Read-only/],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
"plan.toml",
|
|
53
|
+
{
|
|
54
|
+
model: "gpt-5.6-sol",
|
|
55
|
+
effort: "max",
|
|
56
|
+
includes: [/strategic planning consultant/i, /\.omo\/plans\/<slug>\.md/, /never implements/i],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"lazycodex-worker-low.toml",
|
|
21
61
|
{
|
|
62
|
+
model: "gpt-5.6-luna",
|
|
22
63
|
effort: "high",
|
|
23
|
-
includes: [/EVIDENCE_RECORDED: <path>/, /
|
|
64
|
+
includes: [/EVIDENCE_RECORDED: <path>/, /low-difficulty/i, /smallest correct change/i],
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
[
|
|
68
|
+
"lazycodex-worker-medium.toml",
|
|
69
|
+
{
|
|
70
|
+
model: "gpt-5.6-luna",
|
|
71
|
+
effort: "max",
|
|
72
|
+
includes: [/EVIDENCE_RECORDED: <path>/, /medium-difficulty/i, /smallest correct change/i],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"lazycodex-worker-high.toml",
|
|
77
|
+
{
|
|
78
|
+
model: "gpt-5.6-sol",
|
|
79
|
+
effort: "max",
|
|
80
|
+
includes: [/EVIDENCE_RECORDED: <path>/, /high-difficulty/i, /smallest correct change/i],
|
|
24
81
|
},
|
|
25
82
|
],
|
|
26
83
|
[
|
|
27
84
|
"lazycodex-clone-fidelity-reviewer.toml",
|
|
28
85
|
{
|
|
86
|
+
model: "gpt-5.6-sol",
|
|
29
87
|
effort: "xhigh",
|
|
30
88
|
includes: [/recommendation/, /blockers/, /\.omo\/evidence\/<goal>-clone-fidelity\.md/],
|
|
31
89
|
},
|
|
@@ -33,22 +91,25 @@ const lazycodexAgentInvariants = new Map([
|
|
|
33
91
|
[
|
|
34
92
|
"lazycodex-code-reviewer.toml",
|
|
35
93
|
{
|
|
94
|
+
model: "gpt-5.6-sol",
|
|
36
95
|
effort: "xhigh",
|
|
37
|
-
includes: [/codeQualityStatus/, /recommendation/,
|
|
96
|
+
includes: [/codeQualityStatus/, /recommendation/, /<attemptDir>\/<goalId>-code-review\.md/, /currentAttemptDir/],
|
|
38
97
|
},
|
|
39
98
|
],
|
|
40
99
|
[
|
|
41
100
|
"lazycodex-qa-executor.toml",
|
|
42
101
|
{
|
|
43
|
-
|
|
44
|
-
|
|
102
|
+
model: "gpt-5.6-luna",
|
|
103
|
+
effort: "high",
|
|
104
|
+
includes: [/not_applicable/, /surfaceEvidence/, /adversarialCases/, /<attemptDir>\/<goalId>-manual-qa\.md/],
|
|
45
105
|
},
|
|
46
106
|
],
|
|
47
107
|
[
|
|
48
108
|
"lazycodex-gate-reviewer.toml",
|
|
49
109
|
{
|
|
50
|
-
|
|
51
|
-
|
|
110
|
+
model: "gpt-5.6-sol",
|
|
111
|
+
effort: "high",
|
|
112
|
+
includes: [/APPROVE\/REJECT/, /blockers/, /<attemptDir>\/<goalId>-gate-review\.md/, /currentAttemptDir/],
|
|
52
113
|
},
|
|
53
114
|
],
|
|
54
115
|
]);
|
|
@@ -69,9 +130,11 @@ test("#given bundled Codex agents #when components/ultrawork/agents directory is
|
|
|
69
130
|
"explorer.toml",
|
|
70
131
|
"lazycodex-clone-fidelity-reviewer.toml",
|
|
71
132
|
"lazycodex-code-reviewer.toml",
|
|
72
|
-
"lazycodex-executor.toml",
|
|
73
133
|
"lazycodex-gate-reviewer.toml",
|
|
74
134
|
"lazycodex-qa-executor.toml",
|
|
135
|
+
"lazycodex-worker-high.toml",
|
|
136
|
+
"lazycodex-worker-low.toml",
|
|
137
|
+
"lazycodex-worker-medium.toml",
|
|
75
138
|
"librarian.toml",
|
|
76
139
|
"metis.toml",
|
|
77
140
|
"momus.toml",
|
|
@@ -94,11 +157,29 @@ test("#given bundled Codex agents #when components/ultrawork/agents directory is
|
|
|
94
157
|
}
|
|
95
158
|
});
|
|
96
159
|
|
|
160
|
+
test("#given bundled agent TOMLs #when nickname_candidates are inspected #then they use only the codex-accepted charset", async () => {
|
|
161
|
+
// given: codex_app_server ignores a role whose nickname has characters outside
|
|
162
|
+
// ASCII letters, digits, spaces, hyphens, underscores (observed live in task-15 QA)
|
|
163
|
+
const agentsDir = join(root, "components", "ultrawork", "agents");
|
|
164
|
+
const files = (await readdir(agentsDir)).filter((name) => name.endsWith(".toml"));
|
|
165
|
+
|
|
166
|
+
// when/then
|
|
167
|
+
for (const file of files) {
|
|
168
|
+
const text = await readFile(join(agentsDir, file), "utf8");
|
|
169
|
+
for (const match of text.matchAll(/nickname_candidates\s*=\s*\[([^\]]*)\]/g)) {
|
|
170
|
+
for (const nickname of match[1].matchAll(/"([^"]*)"/g)) {
|
|
171
|
+
assert.match(nickname[1], /^[A-Za-z0-9 _-]+$/, `${file}: nickname "${nickname[1]}"`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
97
177
|
test("#given planner agent prompt #when inspected #then generated artifacts stay under .omo", async () => {
|
|
98
178
|
const prompt = await readFile(join(root, "components", "ultrawork", "agents", "plan.toml"), "utf8");
|
|
99
179
|
|
|
100
180
|
assert.match(prompt, /\.omo\/plans\/<slug>\.md/);
|
|
101
|
-
assert.match(prompt,
|
|
181
|
+
assert.match(prompt, /<attemptDir>\/task-<N>-<slug>\.<ext>/);
|
|
182
|
+
assert.match(prompt, /\.omo\/evidence\/ulw\/<session>\/<goalId>\/a<attempt>/);
|
|
102
183
|
assert.doesNotMatch(prompt, /(?<!\.omo\/)plans\/<slug>\.md/);
|
|
103
184
|
assert.doesNotMatch(prompt, /(?<!\.omo\/)evidence\/task-/);
|
|
104
185
|
});
|
|
@@ -109,7 +190,8 @@ test("#given lazycodex agent prompts #when inspected #then each role pins model
|
|
|
109
190
|
for (const [fileName, invariant] of lazycodexAgentInvariants) {
|
|
110
191
|
const prompt = await readFile(join(agentsDir, fileName), "utf8");
|
|
111
192
|
|
|
112
|
-
|
|
193
|
+
const escapedModel = invariant.model.replace(/\./g, "\\.");
|
|
194
|
+
assert.match(prompt, new RegExp(`^model\\s*=\\s*"${escapedModel}"$`, "m"));
|
|
113
195
|
assert.match(prompt, new RegExp(`^model_reasoning_effort\\s*=\\s*"${invariant.effort}"$`, "m"));
|
|
114
196
|
assert.doesNotMatch(prompt, /^tools\s*=/m);
|
|
115
197
|
assert.doesNotMatch(prompt, /^blocking\s*=/m);
|
|
@@ -161,3 +243,27 @@ test("#given LazyCodex reviewer prompts #when inspected #then anti-slop review c
|
|
|
161
243
|
"gate reviewer must perform the overfit/slop pass directly before checking report coverage",
|
|
162
244
|
);
|
|
163
245
|
});
|
|
246
|
+
|
|
247
|
+
test("#given done-gate reviewer prompts #when inspected #then burden of proof is approve-unless-cited and reject priors are gone", async () => {
|
|
248
|
+
const agentsDir = join(root, "components", "ultrawork", "agents");
|
|
249
|
+
const gateReviewer = await readFile(join(agentsDir, "lazycodex-gate-reviewer.toml"), "utf8");
|
|
250
|
+
const qaExecutor = await readFile(join(agentsDir, "lazycodex-qa-executor.toml"), "utf8");
|
|
251
|
+
const codeReviewer = await readFile(join(agentsDir, "lazycodex-code-reviewer.toml"), "utf8");
|
|
252
|
+
|
|
253
|
+
assert.match(gateReviewer, /APPROVE unless you can cite/);
|
|
254
|
+
assert.match(gateReviewer, /violatedCriterion/);
|
|
255
|
+
assert.match(gateReviewer, /evidencePointer/);
|
|
256
|
+
assert.match(gateReviewer, /top blockers inline/);
|
|
257
|
+
assert.match(gateReviewer, /is a NOTE, not a blocker/);
|
|
258
|
+
assert.match(gateReviewer, /You do NOT check/);
|
|
259
|
+
assert.doesNotMatch(gateReviewer, /Assume the work has already failed/);
|
|
260
|
+
assert.doesNotMatch(gateReviewer, /Return exactly one recommendation: APPROVE\/REJECT\./);
|
|
261
|
+
|
|
262
|
+
assert.match(qaExecutor, /one-line reason/);
|
|
263
|
+
assert.match(qaExecutor, /rejecting a legitimately untriggered class is itself an error/);
|
|
264
|
+
assert.doesNotMatch(qaExecutor, /Trust nothing\./);
|
|
265
|
+
|
|
266
|
+
assert.match(codeReviewer, /MEDIUM by default/);
|
|
267
|
+
assert.doesNotMatch(codeReviewer, /Treat useless tests or needless production complexity as CRITICAL\/HIGH/);
|
|
268
|
+
});
|
|
269
|
+
|
|
@@ -48,6 +48,22 @@ test("#given isolated components #when hooks are inspected #then commands stay i
|
|
|
48
48
|
assert.equal(await exists("scripts/migrate-codex-config.mjs"), true);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
test("#given aggregate Stop hooks #when inspected #then start-work continuation and ulw-loop resume are separate groups", async () => {
|
|
52
|
+
// given
|
|
53
|
+
const manifests = await readAggregateHookManifests();
|
|
54
|
+
|
|
55
|
+
// when
|
|
56
|
+
const stopCommands = manifests
|
|
57
|
+
.filter(({ hooks }) => hooks.hooks.Stop)
|
|
58
|
+
.flatMap(({ hooks }) => hooks.hooks.Stop)
|
|
59
|
+
.flatMap((group) => group.hooks.map((handler) => handler.command));
|
|
60
|
+
|
|
61
|
+
// then
|
|
62
|
+
assert.equal(stopCommands.length, 2);
|
|
63
|
+
assert.ok(stopCommands.some((command) => command.includes("start-work-continuation/dist/cli.js")));
|
|
64
|
+
assert.ok(stopCommands.some((command) => command.includes("ulw-loop/dist/cli.js\" hook stop")));
|
|
65
|
+
});
|
|
66
|
+
|
|
51
67
|
test("#given aggregate SubagentStop hooks #when inspected #then start-work and LazyCodex executor verifier are separate groups", async () => {
|
|
52
68
|
// given
|
|
53
69
|
const manifests = await readAggregateHookManifests();
|
|
@@ -64,7 +80,7 @@ test("#given aggregate SubagentStop hooks #when inspected #then start-work and L
|
|
|
64
80
|
// then
|
|
65
81
|
assert.equal(subagentStopGroups.length, 2);
|
|
66
82
|
assert.equal(subagentStopGroups[0]?.matcher, undefined);
|
|
67
|
-
assert.equal(subagentStopGroups[1]?.matcher, "^lazycodex-
|
|
83
|
+
assert.equal(subagentStopGroups[1]?.matcher, "^lazycodex-worker-(low|medium|high)$");
|
|
68
84
|
assert.equal(verifierGroups.length, 1);
|
|
69
85
|
assert.equal(verifierGroups[0]?.groupIndex, 0);
|
|
70
86
|
assert.equal(verifierGroups[0]?.handler.timeout, 10);
|
|
@@ -158,7 +174,12 @@ test("#given aggregate OMO plugin is enabled #when hooks are inspected #then she
|
|
|
158
174
|
assert.match(text, /Resetting Git Bash MCP Reminder/);
|
|
159
175
|
assert.match(text, /components\/ulw-loop\/dist\/cli\.js/);
|
|
160
176
|
assert.match(text, /hook pre-tool-use/);
|
|
161
|
-
assert.deepEqual(preToolUseGroups.map((group) => group.matcher), [
|
|
177
|
+
assert.deepEqual(preToolUseGroups.map((group) => group.matcher), [
|
|
178
|
+
"^Bash$",
|
|
179
|
+
"^create_goal$",
|
|
180
|
+
"^(spawn_agent|collaborationspawn_agent|collaboration\\.spawn_agent)$",
|
|
181
|
+
]);
|
|
182
|
+
assert.match(text, /hook pre-tool-use-spawn/);
|
|
162
183
|
});
|
|
163
184
|
|
|
164
185
|
test("#given aggregate OMO plugin has a dedicated ultrawork trigger #when hooks are inspected #then ulw-loop does not duplicate ultrawork injection", async () => {
|
|
@@ -17,7 +17,7 @@ test("#given aggregate plugin manifest #when inspected #then it owns the omo nam
|
|
|
17
17
|
// then
|
|
18
18
|
assert.equal(manifest.name, "omo");
|
|
19
19
|
assert(Array.isArray(hookPaths));
|
|
20
|
-
assert.equal(hookPaths.length,
|
|
20
|
+
assert.equal(hookPaths.length, 23);
|
|
21
21
|
assert(hookPaths.every((hookPath) => typeof hookPath === "string" && hookPath.startsWith("./hooks/")));
|
|
22
22
|
assert(!hookPaths.includes("./hooks/hooks.json"));
|
|
23
23
|
assert(!hookPaths.includes("./hooks/user-prompt-submit-selecting-lazycodex-workflow.json"));
|
|
@@ -8,17 +8,17 @@ import { root } from "./aggregate-plugin-fixture.mjs";
|
|
|
8
8
|
test("#given bundled model catalog #when inspected #then default verifier and worker roles are pinned", async () => {
|
|
9
9
|
const catalog = JSON.parse(await readFile(join(root, "model-catalog.json"), "utf8"));
|
|
10
10
|
|
|
11
|
-
assert.equal(catalog.current.model, "gpt-5.
|
|
12
|
-
assert.equal(catalog.current.model_context_window,
|
|
11
|
+
assert.equal(catalog.current.model, "gpt-5.6-sol");
|
|
12
|
+
assert.equal(catalog.current.model_context_window, 372000);
|
|
13
13
|
assert.equal(catalog.current.model_reasoning_effort, "high");
|
|
14
14
|
assert.equal(catalog.current.plan_mode_reasoning_effort, "xhigh");
|
|
15
15
|
assert.deepEqual(catalog.roles.default, catalog.current);
|
|
16
16
|
assert.deepEqual(catalog.roles.verifier, {
|
|
17
|
-
model: "gpt-5.
|
|
17
|
+
model: "gpt-5.6-sol",
|
|
18
18
|
model_reasoning_effort: "high",
|
|
19
19
|
});
|
|
20
20
|
assert.deepEqual(catalog.roles.worker, {
|
|
21
|
-
model: "gpt-5.
|
|
21
|
+
model: "gpt-5.6-sol",
|
|
22
22
|
model_reasoning_effort: "high",
|
|
23
23
|
});
|
|
24
24
|
});
|
|
@@ -34,7 +34,8 @@ test('#given synced skills and bundled rules #when role-specific agents are spaw
|
|
|
34
34
|
const promptFiles = skillEntries
|
|
35
35
|
.filter((entry) => entry.isDirectory())
|
|
36
36
|
.map((entry) => join(skillsDir, entry.name, "SKILL.md"));
|
|
37
|
-
promptFiles.push(join(root, "components", "rules", "bundled-rules", "hephaestus.md"));
|
|
37
|
+
promptFiles.push(join(root, "components", "rules", "bundled-rules", "hephaestus", "gpt-5.5.md"));
|
|
38
|
+
promptFiles.push(join(root, "components", "rules", "bundled-rules", "hephaestus", "gpt-5.6.md"));
|
|
38
39
|
|
|
39
40
|
const missingForkContext = [];
|
|
40
41
|
for (const promptPath of promptFiles) {
|
|
@@ -53,7 +54,8 @@ test("#given long-running orchestration prompts #when waiting on child agents #t
|
|
|
53
54
|
join(root, "skills", "ulw-loop", "references", "full-workflow.md"),
|
|
54
55
|
join(root, "skills", "review-work", "SKILL.md"),
|
|
55
56
|
join(root, "skills", "start-work", "SKILL.md"),
|
|
56
|
-
join(root, "components", "rules", "bundled-rules", "hephaestus.md"),
|
|
57
|
+
join(root, "components", "rules", "bundled-rules", "hephaestus", "gpt-5.5.md"),
|
|
58
|
+
join(root, "components", "rules", "bundled-rules", "hephaestus", "gpt-5.6.md"),
|
|
57
59
|
];
|
|
58
60
|
|
|
59
61
|
const missingLivenessGuidance = [];
|
|
@@ -224,3 +224,36 @@ test("#given completed pending update #when hook session-start runs as CLI #then
|
|
|
224
224
|
assert.equal(repeat.status, 0);
|
|
225
225
|
assert.equal(repeat.stdout, "");
|
|
226
226
|
});
|
|
227
|
+
|
|
228
|
+
test("#given the script reached through a symlinked directory #when hook session-start runs as CLI #then the entry guard still fires", async () => {
|
|
229
|
+
const root = await mkdtemp(join(tmpdir(), "lazycodex-restart-notice-symlink-"));
|
|
230
|
+
const env = autoUpdateEnv(root, {
|
|
231
|
+
LAZYCODEX_CURRENT_VERSION: "1.0.1",
|
|
232
|
+
LAZYCODEX_LATEST_VERSION: "1.0.1",
|
|
233
|
+
LAZYCODEX_CONFIG_MIGRATION_DISABLED: "1",
|
|
234
|
+
});
|
|
235
|
+
await writeFile(env.LAZYCODEX_AUTO_UPDATE_STATE_PATH, JSON.stringify({
|
|
236
|
+
lastCheckedAt: Date.now() - 1_000,
|
|
237
|
+
lastStatus: "success",
|
|
238
|
+
pendingNotice: { fromVersion: "1.0.0", toVersion: "1.0.1", startedAt: 1 },
|
|
239
|
+
}));
|
|
240
|
+
// Simulate a symlinked plugin cache dir: argv[1] spells the symlink, while
|
|
241
|
+
// import.meta.url resolves to the real path. Seen in the wild; the old
|
|
242
|
+
// `pathToFileURL(process.argv[1])` guard never matched and the hook was a
|
|
243
|
+
// silent no-op.
|
|
244
|
+
const { symlink } = await import("node:fs/promises");
|
|
245
|
+
const { dirname } = await import("node:path");
|
|
246
|
+
const linkDir = join(root, "linked-scripts");
|
|
247
|
+
await symlink(dirname(SCRIPT_PATH), linkDir, "dir");
|
|
248
|
+
const linkedScript = join(linkDir, "auto-update.mjs");
|
|
249
|
+
|
|
250
|
+
const result = spawnSync(process.execPath, [linkedScript, "hook", "session-start"], {
|
|
251
|
+
encoding: "utf8",
|
|
252
|
+
env: { ...process.env, ...env },
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
assert.equal(result.status, 0);
|
|
256
|
+
const lines = result.stdout.split("\n").filter((line) => line.length > 0);
|
|
257
|
+
assert.equal(lines.length, 1, `expected one SessionStart JSON line, got stdout=${JSON.stringify(result.stdout)} stderr=${JSON.stringify(result.stderr)}`);
|
|
258
|
+
assert.equal(JSON.parse(lines[0]).hookSpecificOutput.hookEventName, "SessionStart");
|
|
259
|
+
});
|
|
@@ -225,7 +225,7 @@ test("#given test command override #when running check #then records state and l
|
|
|
225
225
|
toVersion: "1.0.1",
|
|
226
226
|
},
|
|
227
227
|
]);
|
|
228
|
-
assert.match(await readFile(join(env.CODEX_HOME, "config.toml"), "utf8"), /model = "gpt-5\.
|
|
228
|
+
assert.match(await readFile(join(env.CODEX_HOME, "config.toml"), "utf8"), /model = "gpt-5\.6-sol"/);
|
|
229
229
|
});
|
|
230
230
|
|
|
231
231
|
test("#given failed waited update #when retry window passes #then next update is not blocked by success throttle", async () => {
|
|
@@ -279,7 +279,7 @@ test("#given active lock #when running check #then skips concurrent update", asy
|
|
|
279
279
|
|
|
280
280
|
assert.equal(result.started, false);
|
|
281
281
|
assert.equal(result.reason, "locked");
|
|
282
|
-
assert.match(await readFile(join(root, "codex-home", "config.toml"), "utf8"), /model_context_window =
|
|
282
|
+
assert.match(await readFile(join(root, "codex-home", "config.toml"), "utf8"), /model_context_window = 372000/);
|
|
283
283
|
});
|
|
284
284
|
|
|
285
285
|
test("#given stale lock #when running check #then removes lock and runs update", async () => {
|
|
@@ -645,8 +645,8 @@ test("#given throttled updater and stale Codex config #when running check #then
|
|
|
645
645
|
const content = await readFile(join(codexHome, "config.toml"), "utf8");
|
|
646
646
|
assert.equal(result.started, false);
|
|
647
647
|
assert.equal(result.reason, "throttled");
|
|
648
|
-
assert.match(content, /model = "gpt-5\.
|
|
649
|
-
assert.match(content, /model_context_window =
|
|
648
|
+
assert.match(content, /model = "gpt-5\.6-sol"/);
|
|
649
|
+
assert.match(content, /model_context_window = 372000/);
|
|
650
650
|
assert.match(content, /model_reasoning_effort = "high"/);
|
|
651
651
|
assert.match(content, /plan_mode_reasoning_effort = "xhigh"/);
|
|
652
652
|
assert.doesNotMatch(content, /gpt-5\.2/);
|
|
@@ -180,12 +180,12 @@ export function componentHookContractCases(tempRoot) {
|
|
|
180
180
|
},
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
|
-
name: "lazycodex
|
|
183
|
+
name: "lazycodex worker verifier subagent-stop blocks missing evidence",
|
|
184
184
|
component: "lazycodex-executor-verify",
|
|
185
185
|
event: "subagent-stop",
|
|
186
186
|
payload: {
|
|
187
187
|
hook_event_name: "SubagentStop",
|
|
188
|
-
agent_type: "lazycodex-
|
|
188
|
+
agent_type: "lazycodex-worker-medium",
|
|
189
189
|
agent_id: "agent-task12",
|
|
190
190
|
session_id: "s-task12",
|
|
191
191
|
transcript_path: join(tempRoot, "transcript.jsonl"),
|
|
@@ -7,109 +7,12 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
8
|
const sharedSkillsRoot = join(pluginRoot, "..", "..", "shared-skills");
|
|
9
9
|
|
|
10
|
-
async
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
test("#given synced lcx-report-bug skill #when inspected #then it files LazyCodex bug issues with generated labels", async () => {
|
|
15
|
-
// given
|
|
16
|
-
const skillRoot = join(sharedSkillsRoot, "skills", "lcx-report-bug");
|
|
17
|
-
|
|
18
|
-
// when
|
|
19
|
-
const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
|
|
20
|
-
const interfaceMetadata = await readFile(join(skillRoot, "agents", "openai.yaml"), "utf8");
|
|
21
|
-
|
|
22
|
-
// then
|
|
23
|
-
assert.match(skill, /^---\r?\nname: lcx-report-bug\r?\n/m);
|
|
24
|
-
assert.match(skill, /Never create a PR or push a branch against `code-yeongyu\/lazycodex`/);
|
|
25
|
-
assert.match(skill, /gh pr create --repo openai\/codex/);
|
|
26
|
-
assert.doesNotMatch(skill, /gh pr create --repo "\$TARGET_REPO"/);
|
|
27
|
-
assert.doesNotMatch(skill, /gh pr create --repo code-yeongyu\/lazycodex/);
|
|
28
|
-
assert.match(interfaceMetadata, /display_name: "lcx-report-bug \(omo\)"/);
|
|
29
|
-
assert.match(interfaceMetadata, /- "lazycodex bug"/);
|
|
30
|
-
assert.match(interfaceMetadata, /- "openai codex bug"/);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("#given synced lcx-contribute-bug-fix skill #when inspected #then it delivers LazyCodex fixes as issues and upstream fixes as fork PRs", async () => {
|
|
34
|
-
// given
|
|
35
|
-
const skillRoot = join(sharedSkillsRoot, "skills", "lcx-contribute-bug-fix");
|
|
36
|
-
|
|
37
|
-
// when
|
|
38
|
-
const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
|
|
39
|
-
const interfaceMetadata = await readFile(join(skillRoot, "agents", "openai.yaml"), "utf8");
|
|
40
|
-
|
|
41
|
-
// then
|
|
42
|
-
assert.match(skill, /^---\r?\nname: lcx-contribute-bug-fix\r?\n/m);
|
|
43
|
-
assert.match(skill, /NEVER open a PR or push a branch against this repo/);
|
|
44
|
-
assert.match(skill, /gh issue create --repo code-yeongyu\/lazycodex/);
|
|
45
|
-
assert.match(skill, /gh pr create --repo openai\/codex/);
|
|
46
|
-
assert.doesNotMatch(skill, /gh pr create --repo "\$TARGET_REPO"/);
|
|
47
|
-
assert.doesNotMatch(skill, /gh pr create --repo code-yeongyu\/lazycodex/);
|
|
48
|
-
assert.match(interfaceMetadata, /display_name: "lcx-contribute-bug-fix \(omo\)"/);
|
|
49
|
-
assert.match(interfaceMetadata, /- "contribute a bug fix"/);
|
|
50
|
-
assert.match(interfaceMetadata, /- "fix bug pr"/);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test("#given synced lcx-doctor skill #when inspected #then it diagnoses installs against latest temp-root sources without mutating them", async () => {
|
|
54
|
-
// given
|
|
55
|
-
const skillRoot = join(sharedSkillsRoot, "skills", "lcx-doctor");
|
|
56
|
-
|
|
57
|
-
// when
|
|
58
|
-
const skill = await readFile(join(skillRoot, "SKILL.md"), "utf8");
|
|
59
|
-
const interfaceMetadata = await readFile(join(skillRoot, "agents", "openai.yaml"), "utf8");
|
|
60
|
-
|
|
61
|
-
// then
|
|
62
|
-
assert.match(skill, /^---\r?\nname: lcx-doctor\r?\n/m);
|
|
63
|
-
assert.match(interfaceMetadata, /display_name: "lcx-doctor \(omo\)"/);
|
|
64
|
-
assert.match(interfaceMetadata, /- "lazycodex doctor"/);
|
|
65
|
-
assert.match(interfaceMetadata, /- "lazycodex health check"/);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("#given lcx source-sync skills #when inspected #then source caches are validated before reuse", async () => {
|
|
69
|
-
// given
|
|
70
|
-
const skillNames = ["lcx-doctor", "lcx-report-bug", "lcx-contribute-bug-fix"];
|
|
71
|
-
|
|
72
|
-
for (const skillName of skillNames) {
|
|
10
|
+
test("#given lcx skills #when frontmatter is inspected #then each exposes the loader-parsed skill name", async () => {
|
|
11
|
+
for (const skillName of ["lcx-report-bug", "lcx-contribute-bug-fix", "lcx-doctor"]) {
|
|
73
12
|
// when
|
|
74
|
-
const skill = await
|
|
13
|
+
const skill = await readFile(join(sharedSkillsRoot, "skills", skillName, "SKILL.md"), "utf8");
|
|
75
14
|
|
|
76
15
|
// then
|
|
77
|
-
assert.match(skill,
|
|
78
|
-
assert.match(skill, /git -C "\$DEST" rev-parse --is-inside-work-tree/);
|
|
79
|
-
assert.match(skill, /git -C "\$DEST" config --get remote\.origin\.url/);
|
|
80
|
-
assert.match(skill, /DEST\.corrupt\.\$\(date \+%Y%m%d%H%M%S\)/);
|
|
81
|
-
assert.doesNotMatch(skill, /if \[ ! -d "\$DEST\/\.git" \]; then/);
|
|
82
|
-
assert.doesNotMatch(skill, /sync_latest_source code-yeongyu\/lazycodex \/tmp\/lazycodex-source/);
|
|
83
|
-
assert.doesNotMatch(skill, /sync_latest_source openai\/codex \/tmp\/openai-codex-source/);
|
|
16
|
+
assert.match(skill, new RegExp(`^name: ${skillName}$`, "m"), `${skillName}: frontmatter must expose ${skillName}`);
|
|
84
17
|
}
|
|
85
18
|
});
|
|
86
|
-
|
|
87
|
-
test("#given lcx-doctor skill #when inspected #then aggregate hook validation follows the current manifest", async () => {
|
|
88
|
-
// given
|
|
89
|
-
const skill = await readSkill("lcx-doctor");
|
|
90
|
-
|
|
91
|
-
// then
|
|
92
|
-
assert.match(skill, /\.codex-plugin\/plugin\.json/);
|
|
93
|
-
assert.match(skill, /manifest declares a `hooks` array/);
|
|
94
|
-
assert.match(skill, /validate every direct hook path declared by the manifest/);
|
|
95
|
-
assert.match(skill, /`hooks\/hooks\.json` only when the manifest declares it/);
|
|
96
|
-
assert.match(skill, /do not require retired paths such as `components\/workflow-selector`/);
|
|
97
|
-
assert.match(skill, /`hooks\/user-prompt-submit-selecting-lazycodex-workflow\.json` unless the current manifest declares them/);
|
|
98
|
-
assert.doesNotMatch(skill, /Plugin payload present and non-empty: `hooks\/hooks\.json`/);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
test("#given lcx-doctor skill #when inspected #then runtime probes and materialized payloads distinguish expected rewrites from missing files", async () => {
|
|
102
|
-
// given
|
|
103
|
-
const skill = await readSkill("lcx-doctor");
|
|
104
|
-
|
|
105
|
-
// then
|
|
106
|
-
assert.match(skill, /manifest-declared runtime payload/);
|
|
107
|
-
assert.match(skill, /`dist\/cli\/index\.js` and `dist\/cli-node\/index\.js`/);
|
|
108
|
-
assert.match(skill, /install-time materialization rewrites as expected/);
|
|
109
|
-
assert.match(skill, /absolute `\.mcp\.json` runtime paths/);
|
|
110
|
-
assert.match(skill, /Missing or zero-byte rewritten targets are FAIL/);
|
|
111
|
-
assert.match(skill, /Use the configured Codex default model/);
|
|
112
|
-
assert.match(skill, /unless the user explicitly passed a model override/);
|
|
113
|
-
assert.match(skill, /never force a guessed\/rejected model such as `gpt-5\.5-codex-mini`/);
|
|
114
|
-
assert.doesNotMatch(skill, /--model gpt-5\.5-codex-mini/);
|
|
115
|
-
});
|