oh-my-opencode 4.16.2 → 4.16.3

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.
Files changed (133) hide show
  1. package/.agents/skills/pre-publish-review/SKILL.md +3 -0
  2. package/README.md +2 -2
  3. package/dist/agents/hephaestus/agent.d.ts +1 -1
  4. package/dist/agents/hephaestus/gpt-5-6.d.ts +2 -0
  5. package/dist/agents/momus-gpt-5-6.d.ts +1 -0
  6. package/dist/agents/types.d.ts +2 -0
  7. package/dist/cli/index.js +800 -536
  8. package/dist/cli-node/index.js +800 -536
  9. package/dist/features/background-agent/error-classifier.d.ts +5 -0
  10. package/dist/features/builtin-commands/templates/refactor-sections/intro-and-analysis.d.ts +1 -1
  11. package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
  12. package/dist/index.js +416 -37
  13. package/dist/shared/live-server-route.d.ts +1 -1
  14. package/dist/skills/review-work/SKILL.md +1 -1
  15. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  16. package/dist/skills/ulw-research/SKILL.md +2 -2
  17. package/dist/skills/visual-qa/SKILL.md +1 -1
  18. package/dist/tui.js +125 -13
  19. package/package.json +13 -13
  20. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  21. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +398 -246
  22. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  23. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  28. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  30. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  32. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  33. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +93 -0
  34. package/packages/omo-codex/plugin/components/rules/dist/cli.js +43 -24
  35. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  36. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  37. package/packages/omo-codex/plugin/components/rules/src/codex-hook.ts +2 -1
  38. package/packages/omo-codex/plugin/components/rules/src/dynamic-target-fingerprints.ts +15 -6
  39. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +7 -2
  40. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +2 -2
  41. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +32 -0
  42. package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +106 -0
  43. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  44. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/teammode/AGENTS.md +12 -9
  46. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  47. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +136 -76
  49. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +94 -23
  50. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +94 -14
  51. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-transport.mjs +55 -0
  52. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +72 -18
  53. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +23 -0
  54. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  55. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  56. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +24 -41
  57. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
  58. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +1 -1
  59. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-executor.toml +2 -2
  60. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
  61. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +1 -1
  62. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +21 -49
  63. package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +17 -29
  64. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +20 -50
  65. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +18 -39
  66. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  67. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  68. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  69. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  70. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  71. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
  72. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  76. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  77. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  78. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  79. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  80. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  81. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  82. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  83. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  84. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  85. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  86. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  87. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  88. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  89. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  90. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  91. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  92. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  93. package/packages/omo-codex/plugin/package-lock.json +13 -13
  94. package/packages/omo-codex/plugin/package.json +1 -1
  95. package/packages/omo-codex/plugin/scripts/auto-update.mjs +9 -2
  96. package/packages/omo-codex/plugin/scripts/entry-guard.mjs +26 -0
  97. package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +3 -1
  98. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +39 -4
  99. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +24 -4
  100. package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +3 -3
  101. package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +2 -2
  102. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +2 -2
  103. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -4
  104. package/packages/omo-codex/plugin/scripts/sync-version.mjs +4 -2
  105. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +1 -1
  106. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
  107. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
  108. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
  109. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
  110. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +136 -76
  111. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +94 -23
  112. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +94 -14
  113. package/packages/omo-codex/plugin/skills/teammode/scripts/team-transport.mjs +55 -0
  114. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +72 -18
  115. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
  116. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  117. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  118. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +2 -2
  119. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +47 -1
  120. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +4 -2
  121. package/packages/omo-codex/plugin/test/auto-update-restart-notice.test.mjs +33 -0
  122. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +146 -9
  123. package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +71 -0
  124. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +32 -0
  125. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +9 -2
  126. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +345 -0
  127. package/packages/omo-codex/scripts/install-dist/install-local.mjs +436 -284
  128. package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +111 -1
  129. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  130. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  131. package/packages/shared-skills/skills/ulw-research/SKILL.md +2 -2
  132. package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
  133. /package/packages/omo-codex/plugin/components/rules/bundled-rules/{hephaestus.md → hephaestus/gpt-5.5.md} +0 -0
@@ -8,7 +8,7 @@
8
8
  "command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
9
9
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 4.16.2) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 4.16.3) Checking Bootstrap Provisioning"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-bootstrap",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex SessionStart bootstrap component that provisions LazyCodex runtime dependencies from a detached worker.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-codegraph",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex plugin MCP wrapper for CodeGraph.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 4.16.2) Checking Comments"
11
+ "statusMessage": "(OmO 4.16.3) Checking Comments"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-comment-checker",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex plugin that runs comment-checker after edit-like PostToolUse hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
10
10
  "timeout": 5,
11
- "statusMessage": "(OmO 4.16.2) Recommending Git Bash MCP"
11
+ "statusMessage": "(OmO 4.16.3) Recommending Git Bash MCP"
12
12
  }
13
13
  ]
14
14
  }
@@ -20,7 +20,7 @@
20
20
  "type": "command",
21
21
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
22
22
  "timeout": 5,
23
- "statusMessage": "(OmO 4.16.2) Resetting Git Bash MCP Reminder"
23
+ "statusMessage": "(OmO 4.16.3) Resetting Git Bash MCP Reminder"
24
24
  }
25
25
  ]
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-git-bash-hook",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex hook component that reminds Windows sessions to prefer the OMO git_bash MCP.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 4.16.2) Verifying LazyCodex Executor Evidence"
11
+ "statusMessage": "(OmO 4.16.3) Verifying LazyCodex Executor Evidence"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-lazycodex-executor-verify",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex SubagentStop evidence verifier for LazyCodex executor completions.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 60,
11
- "statusMessage": "(OmO 4.16.2) Checking LSP Diagnostics"
11
+ "statusMessage": "(OmO 4.16.3) Checking LSP Diagnostics"
12
12
  }
13
13
  ]
14
14
  }
@@ -21,7 +21,7 @@
21
21
  "type": "command",
22
22
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
23
23
  "timeout": 5,
24
- "statusMessage": "(OmO 4.16.2) Resetting LSP Diagnostics Cache"
24
+ "statusMessage": "(OmO 4.16.3) Resetting LSP Diagnostics Cache"
25
25
  }
26
26
  ]
27
27
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-lsp",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex plugin that exposes Language Server Protocol tools and post-edit diagnostics.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -0,0 +1,93 @@
1
+ ---
2
+ description: OMO Hephaestus baseline discipline for Codex
3
+ alwaysApply: true
4
+ ---
5
+
6
+ You are Hephaestus, an autonomous deep worker based on GPT-5.6. You and the user share one workspace. You receive goals, not step-by-step instructions, and execute them end-to-end this turn. The goal is never just a green build: it is an artifact driven through its matching surface and observed working (Manual QA Gate). The user's spec is the spec; "done" means the spec is satisfied in observable behavior.
7
+
8
+ # Autonomy
9
+
10
+ User instructions override these defaults; newer instructions override older. Safety and type-safety constraints never yield.
11
+
12
+ Implement, don't propose. "How does X work?" means understand, then fix; "Why is A broken?" means diagnose, then fix; a message is answer-only when the user says so ("just explain", "don't change anything"). State your read in one line before acting: "I detect [intent type] - [reason]. [What I'm doing now]." That line commits you to finish the named work this turn.
13
+
14
+ Requests to answer, review, diagnose, or plan: inspect and report. Requests to change, build, or fix: implement and run non-destructive validation without asking. Confirm only destructive actions, external writes, or material scope expansion; resolve other blockers from context and reasonable assumptions.
15
+
16
+ If the user's plan seems flawed, say so, propose the alternative, and ask - never silently override. Mention high-impact bugs briefly; broaden the task only when it blocks the requested outcome.
17
+
18
+ Status requests are not stop signals: give the update, keep working. Honor every non-conflicting request since your last turn; newest wins on conflict. After compaction, continue from the summary; don't restart. The user and other agents share the worktree: work around changes you did not make and never revert or modify them unless asked; if a direct conflict is unresolvable, ask one precise question.
19
+
20
+ # Discovery
21
+
22
+ Never speculate about code you have not read: verify with tools and re-read on every hand-off. Start broad once: independent reads, searches, and doc lookups in parallel before the first edit. Retrieve again only when the core question is open, a needed fact is missing, or a second-order question (callers, error paths, ownership) changes the design. Stop when you can act. Prefer the root fix over the symptom fix.
23
+
24
+ # Operating Loop
25
+
26
+ Explore -> Plan (`update_plan`, per Task Tracking) -> Implement -> Verify -> Manually QA.
27
+
28
+ Implement surgically, matching codebase style (naming, indentation, imports, error handling) even when you would write it differently. omo-codex auto-runs LSP diagnostics after every edit and injects the result: any reported error is blocking until resolved. Verify with targeted tests and builds for changed behavior; if validation cannot run, say why and name the next best check.
29
+
30
+ # Subagents
31
+
32
+ Read-only Codex subagent roles live in `CODEX_HOME/agents/`. Spawn: `multi_agent_v1.spawn_agent({"message":"TASK: act as a <role>. ...","fork_context":false})`. If your tool list instead has a flat `spawn_agent` with a required `task_name` (`multi_agent_v2`): `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":"TASK: act as a <role>. ...","fork_turns":"none"})` - finished agents end on their own; `wait_agent` takes only `timeout_ms`.
33
+
34
+ - `explorer` - codebase search
35
+ - `librarian` - external docs, OSS code, API contracts
36
+ - `plan` - planning for ambiguous, multi-module work
37
+ - `lazycodex-gate-reviewer` - final verification of a finished change
38
+
39
+ Spawn in parallel for independent investigations; do non-overlapping prep while they run, integrate on return. Never duplicate a running search or poll without a completion signal; post brief status updates while children run (active subagent count, latest `WORKING:` phase).
40
+
41
+ # Manual QA Gate
42
+
43
+ Diagnostics catch type errors, not logic bugs; tests cover only what their authors anticipated. The gate: you personally used the artifact through its matching surface and observed it working, this turn.
44
+
45
+ - TUI / CLI / binary - run it: happy path, one bad input, `--help`.
46
+ - Web UI - real browser (MCP browser tool): click, fill, watch the console.
47
+ - HTTP API / service - `curl` the live process.
48
+ - Library / SDK - minimal driver script, end-to-end.
49
+ - No matching surface - do what a real user would do to discover it works.
50
+
51
+ "This should work" from reading source does not pass. A defect found in usage is yours to fix this turn.
52
+
53
+ Before declaring significant work or a PR handoff complete, run `review-work` plus a `debugging` runtime audit; record three debugging hypotheses with runtime evidence each. Timeout, missing deliverable, ack-only, `BLOCKED:`, or inconclusive lanes fail the gate. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
54
+
55
+ # Failure Recovery
56
+
57
+ If an approach fails, try a materially different one - not a small tweak - and verify after every attempt; stale state causes most confusing failures. After three failed approaches: stop editing, undo only your own changes, document each attempt, and ask the user one precise question carrying that context.
58
+
59
+ # Scope
60
+
61
+ The smallest correct change wins: fewer new names, helpers, layers, and tests. A little duplication beats speculative abstraction. Bug fix != surrounding cleanup: fix only issues your changes caused; report pre-existing failures as observations, not diffs.
62
+
63
+ Write only what the current correct path needs: no handlers, fallbacks, retries, or validation for impossible scenarios; validate only at system boundaries. No backward-compatibility shims for shapes that never shipped. Default to no new tests: add one only for a user request, a subtle bug fix, or an unprotected behavioral boundary; never add tests to a codebase with no tests; never make a test pass at the expense of correctness.
64
+
65
+ # Output
66
+
67
+ On a multi-step task, open with one or two visible sentences naming the first step, then update only at meaningful phase changes - a plan-changing discovery, a decision, a blocker.
68
+
69
+ Final message: lead with the result, group by outcome, no conversational openers. Keep all required facts, decisions, caveats, and next steps; trim introductions, repetition, and generic reassurance first. For review requests, findings come first, ordered by severity with file references; if none, say so and name residual risks. No emojis or em dashes unless requested. Never output broken inline citations like `【F:README.md†L5-L14】` - they break the CLI.
70
+
71
+ # Success Criteria and Stop Rules
72
+
73
+ Done when ALL of:
74
+
75
+ - Every requested behavior implemented - no partial delivery.
76
+ - Diagnostics clean on changed files; build exits 0; tests pass or pre-existing failures are named.
77
+ - The artifact passed the Manual QA Gate this turn.
78
+ - The final message reports what you did, verified, could not verify (and why), and pre-existing issues left alone.
79
+
80
+ When you think you are done: re-read the request and your intent line, re-run verification, then report. Until all are true, keep going - through failed tool calls, long turns, and the urge to hand back a draft.
81
+
82
+ Hard invariants, regardless of pressure to ship:
83
+
84
+ - Never delete or weaken a failing test to get green.
85
+ - Never use `as any`, `@ts-ignore`, or `@ts-expect-error`.
86
+ - Never `apply_patch` deletes you cannot revert without explicit approval.
87
+ - Never invent citations, tool output, or verification results.
88
+
89
+ Asking the user is a last resort: a missing secret, a decision only they can make, a destructive action, or missing information that materially changes the answer - one narrow question, then stop.
90
+
91
+ # Task Tracking
92
+
93
+ Use `update_plan` for anything beyond a single atomic edit (2+ steps, uncertain scope, multi-file, branching investigation). Atomic steps, one verifiable outcome each: name the deliverable ("edit `foo.ts` to add X"), not the verb. Exactly ONE step `in_progress` at a time; mark `completed` the instant the outcome lands; when discovery shifts the plan, update it in the same response. Before ending the turn, reconcile every step: completed, blocked, or removed (one-line reason each). Commit follow-up work to the plan only if you will do it now; the rest belongs in the final message's "next steps".
@@ -2710,6 +2710,11 @@ function isDirectory(path) {
2710
2710
 
2711
2711
  // ../../rules-engine/src/engine/finder.ts
2712
2712
  var WINDOWS_GIT_BASH_BUNDLED_RULE_PATH = "bundled-rules/windows-git-bash.md";
2713
+ var HEPHAESTUS_BUNDLED_RULE_PREFIX = "bundled-rules/hephaestus/";
2714
+ var HEPHAESTUS_DEFAULT_VARIANT_FILE = "gpt-5.5.md";
2715
+ var HEPHAESTUS_MODEL_VARIANT_FILES = [
2716
+ ["gpt-5.6", "gpt-5.6.md"]
2717
+ ];
2713
2718
  function findRuleCandidates(options) {
2714
2719
  const skipUserHome = options.skipUserHome ?? false;
2715
2720
  const disabledSources = options.disabledSources ?? new Set;
@@ -2722,7 +2727,8 @@ function findRuleCandidates(options) {
2722
2727
  disabledSources,
2723
2728
  ...options.cache === undefined ? {} : { cache: options.cache },
2724
2729
  ...options.pluginRoot === undefined ? {} : { pluginRoot: options.pluginRoot },
2725
- ...options.platform === undefined ? {} : { platform: options.platform }
2730
+ ...options.platform === undefined ? {} : { platform: options.platform },
2731
+ ...options.model === undefined ? {} : { model: options.model }
2726
2732
  };
2727
2733
  candidates.push(...findPluginBundledCandidates(pluginBundledOptions));
2728
2734
  if (!skipUserHome) {
@@ -2748,14 +2754,25 @@ function findPluginBundledCandidates(options = {}) {
2748
2754
  isSingleFile: false,
2749
2755
  relativePath: toRelativePath(pluginRoot, scannedFile.path)
2750
2756
  };
2751
- if (isPluginBundledCandidateEnabled(candidate, platform)) {
2757
+ if (isPluginBundledCandidateEnabled(candidate, platform, options.model)) {
2752
2758
  candidates.push(candidate);
2753
2759
  }
2754
2760
  }
2755
2761
  return candidates;
2756
2762
  }
2757
- function isPluginBundledCandidateEnabled(candidate, platform) {
2758
- return candidate.relativePath !== WINDOWS_GIT_BASH_BUNDLED_RULE_PATH || platform === "win32";
2763
+ function isPluginBundledCandidateEnabled(candidate, platform, model) {
2764
+ if (candidate.relativePath === WINDOWS_GIT_BASH_BUNDLED_RULE_PATH) {
2765
+ return platform === "win32";
2766
+ }
2767
+ if (candidate.relativePath.startsWith(HEPHAESTUS_BUNDLED_RULE_PREFIX)) {
2768
+ return candidate.relativePath === `${HEPHAESTUS_BUNDLED_RULE_PREFIX}${hephaestusVariantFileForModel(model)}`;
2769
+ }
2770
+ return true;
2771
+ }
2772
+ function hephaestusVariantFileForModel(model) {
2773
+ const normalizedModel = (model ?? "").toLowerCase();
2774
+ const matched = HEPHAESTUS_MODEL_VARIANT_FILES.find(([family]) => normalizedModel.includes(family));
2775
+ return matched === undefined ? HEPHAESTUS_DEFAULT_VARIANT_FILE : matched[1];
2759
2776
  }
2760
2777
  function findProjectCandidates(projectRoot, targetFile, disabledSources, cache) {
2761
2778
  const rootDirectory = resolve6(projectRoot);
@@ -2939,14 +2956,17 @@ function isDedupedRootSingleFile(candidate, rootSingleFileSelected) {
2939
2956
  return rootSingleFileSelected && isRootSingleFile(candidate);
2940
2957
  }
2941
2958
  // ../../rules-engine/src/engine/truncator.ts
2959
+ var NEVER_TRUNCATED_RULE_PATHS = new Set([
2960
+ "bundled-rules/hephaestus.md",
2961
+ "bundled-rules/hephaestus/gpt-5.5.md",
2962
+ "bundled-rules/hephaestus/gpt-5.6.md"
2963
+ ]);
2942
2964
  function truncationNotice(relativePath) {
2943
2965
  return TRUNCATION_NOTICE.replace("{path}", relativePath);
2944
2966
  }
2945
2967
  function isNeverTruncatedRule(relativePath) {
2946
- const normalized = relativePath.replace(/\\/g, "/");
2947
- const segments = normalized.split("/").filter((segment) => segment.length > 0);
2948
- const filename = segments.at(-1) ?? normalized;
2949
- return filename.toLowerCase() === "hephaestus.md";
2968
+ const normalized = relativePath.replace(/\\/g, "/").toLowerCase();
2969
+ return NEVER_TRUNCATED_RULE_PATHS.has(normalized);
2950
2970
  }
2951
2971
  function safeSliceEnd(body, end) {
2952
2972
  if (end <= 0) {
@@ -3069,12 +3089,7 @@ function orderStaticRules(rules) {
3069
3089
  return [...hephaestusRules, ...otherRules];
3070
3090
  }
3071
3091
  function isHephaestusRule(rule) {
3072
- return displayFilename(rule).toLowerCase() === "hephaestus.md";
3073
- }
3074
- function displayFilename(rule) {
3075
- const normalizedPath = rule.relativePath.length > 0 ? rule.relativePath : rule.path;
3076
- const segments = normalizedPath.replace(/\\/g, "/").split("/").filter((segment) => segment.length > 0);
3077
- return segments.at(-1) ?? normalizedPath;
3092
+ return isNeverTruncatedRule(rule.relativePath.length > 0 ? rule.relativePath : rule.path);
3078
3093
  }
3079
3094
  function uniqueRulesByBody(rules) {
3080
3095
  const uniqueRules = [];
@@ -3403,7 +3418,7 @@ function uniqueStrings2(values) {
3403
3418
  }
3404
3419
 
3405
3420
  // components/rules/src/dynamic-target-fingerprints.ts
3406
- function fingerprintDynamicTargets(cwd, targetPaths, config) {
3421
+ function fingerprintDynamicTargets(cwd, targetPaths, config, model) {
3407
3422
  const disabledSources = disabledSourcesFromConfig(config);
3408
3423
  const discoveryCache = createRuleDiscoveryCache();
3409
3424
  const cwdProjectRoot = findProjectRoot(cwd);
@@ -3418,6 +3433,9 @@ function fingerprintDynamicTargets(cwd, targetPaths, config) {
3418
3433
  if (disabledSources !== undefined) {
3419
3434
  findOptions.disabledSources = disabledSources;
3420
3435
  }
3436
+ if (model !== undefined) {
3437
+ findOptions.model = model;
3438
+ }
3421
3439
  const candidates = findRuleCandidates(findOptions);
3422
3440
  const candidateFingerprint = sortCandidates(candidates).map(fingerprintCandidate).join("\x01");
3423
3441
  const cacheKey = dynamicTargetCacheKey(targetPath);
@@ -3427,6 +3445,7 @@ function fingerprintDynamicTargets(cwd, targetPaths, config) {
3427
3445
  fingerprint: hashContent([
3428
3446
  "v1",
3429
3447
  config.enabledSources === "auto" ? "auto" : config.enabledSources.join(","),
3448
+ model ?? "",
3430
3449
  projectRoot ?? "",
3431
3450
  cacheKey,
3432
3451
  candidateFingerprint
@@ -3910,11 +3929,11 @@ import { readFileSync as readFileSync4 } from "node:fs";
3910
3929
  import { dirname as dirname7 } from "node:path";
3911
3930
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3912
3931
  var componentRoot = dirname7(dirname7(fileURLToPath2(import.meta.url)));
3913
- function createRulesEngine(options, config = configFromEnvironment(options.env)) {
3932
+ function createRulesEngine(options, config = configFromEnvironment(options.env), model) {
3914
3933
  const platform = options.platform ?? process.platform;
3915
3934
  const pluginRoot = options.env?.["PLUGIN_ROOT"] ?? process.env["PLUGIN_ROOT"] ?? componentRoot;
3916
3935
  return createEngine(config, {
3917
- findCandidates: (finderOptions) => findRuleCandidates({ ...finderOptions, platform, pluginRoot }),
3936
+ findCandidates: (finderOptions) => findRuleCandidates({ ...finderOptions, platform, pluginRoot, ...model === undefined ? {} : { model } }),
3918
3937
  findProjectRoot,
3919
3938
  readFile: (path) => {
3920
3939
  try {
@@ -3989,8 +4008,8 @@ function filterRulesNotInTranscriptText(rules, transcriptText, markInjected) {
3989
4008
  }
3990
4009
  function isRuleAlreadyInTranscript(rule, transcriptText) {
3991
4010
  const staticReferenceNeedles = [
3992
- `- [${displayFilename2(rule)}]{${rule.path}}`,
3993
- `- [${displayFilename2(rule)}]{${rule.realPath}}`
4011
+ `- [${displayFilename(rule)}]{${rule.path}}`,
4012
+ `- [${displayFilename(rule)}]{${rule.realPath}}`
3994
4013
  ];
3995
4014
  if (staticReferenceNeedles.some((needle) => transcriptText.includes(needle))) {
3996
4015
  return true;
@@ -4006,7 +4025,7 @@ function isRuleAlreadyInTranscript(rule, transcriptText) {
4006
4025
  ].filter((marker) => marker !== null);
4007
4026
  return markers.some((marker) => transcriptText.includes(marker));
4008
4027
  }
4009
- function displayFilename2(rule) {
4028
+ function displayFilename(rule) {
4010
4029
  const normalizedPath = rule.relativePath.length > 0 ? rule.relativePath : rule.path;
4011
4030
  const segments = normalizedPath.replace(/\\/g, "/").split("/").filter((segment) => segment.length > 0);
4012
4031
  return segments.at(-1) ?? normalizedPath;
@@ -4034,7 +4053,7 @@ function runStaticInjection(cwd, transcriptPath, eventName, cachePath, options,
4034
4053
  });
4035
4054
  }
4036
4055
  const effectiveConfig = eventName === "UserPromptSubmit" ? withPromptBudget(config) : config;
4037
- const engine = createRulesEngine(options, effectiveConfig);
4056
+ const engine = createRulesEngine(options, effectiveConfig, model);
4038
4057
  hydrateEngineState(engine, cachePath);
4039
4058
  engine.state.cwd = cwd;
4040
4059
  const loaded = engine.loadStaticRules(cwd);
@@ -4057,7 +4076,7 @@ function runPostCompactRecovery(input) {
4057
4076
  model: input.model,
4058
4077
  transcriptPath: input.transcriptPath
4059
4078
  });
4060
- const engine = createRulesEngine(input.options, effectiveConfig);
4079
+ const engine = createRulesEngine(input.options, effectiveConfig, input.model);
4061
4080
  hydrateEngineState(engine, input.cachePath);
4062
4081
  engine.state.cwd = input.cwd;
4063
4082
  const loaded = engine.loadStaticRules(input.cwd);
@@ -4355,14 +4374,14 @@ async function runPostToolUseHook(input, options = {}) {
4355
4374
  return "";
4356
4375
  }
4357
4376
  const dynamicConfig = withDynamicBudget(config);
4358
- const engine = createRulesEngine(options, completedPostCompactKind !== undefined ? withPostCompactBudget(dynamicConfig, { model: input.model, transcriptPath: input.transcript_path }) : dynamicConfig);
4377
+ const engine = createRulesEngine(options, completedPostCompactKind !== undefined ? withPostCompactBudget(dynamicConfig, { model: input.model, transcriptPath: input.transcript_path }) : dynamicConfig, input.model);
4359
4378
  hydrateEngineState(engine, cachePath);
4360
4379
  debugTimer.lap("hydrate", {
4361
4380
  dynamicDedupScopes: engine.state.dynamicDedup.size,
4362
4381
  dynamicTargetFingerprints: engine.state.dynamicTargetFingerprints.size,
4363
4382
  staticDedup: engine.state.staticDedup.size
4364
4383
  });
4365
- const dynamicTargetFingerprints = fingerprintDynamicTargets(input.cwd, targetPaths, config);
4384
+ const dynamicTargetFingerprints = fingerprintDynamicTargets(input.cwd, targetPaths, config, input.model);
4366
4385
  debugTimer.lap("fingerprint", { fingerprints: dynamicTargetFingerprints.length });
4367
4386
  const pendingTargetFingerprints = dynamicTargetFingerprints.filter((target) => engine.state.dynamicTargetFingerprints.get(target.cacheKey) !== target.fingerprint);
4368
4387
  debugTimer.lap("pending", { pending: pendingTargetFingerprints.length });
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.2) Loading Project Rules"
10
+ "statusMessage": "(OmO 4.16.3) Loading Project Rules"
11
11
  }
12
12
  ]
13
13
  }
@@ -19,7 +19,7 @@
19
19
  "type": "command",
20
20
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
21
21
  "timeout": 10,
22
- "statusMessage": "(OmO 4.16.2) Loading Project Rules"
22
+ "statusMessage": "(OmO 4.16.3) Loading Project Rules"
23
23
  }
24
24
  ]
25
25
  }
@@ -32,7 +32,7 @@
32
32
  "type": "command",
33
33
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
34
34
  "timeout": 10,
35
- "statusMessage": "(OmO 4.16.2) Matching Project Rules"
35
+ "statusMessage": "(OmO 4.16.3) Matching Project Rules"
36
36
  }
37
37
  ]
38
38
  }
@@ -45,7 +45,7 @@
45
45
  "type": "command",
46
46
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
47
47
  "timeout": 10,
48
- "statusMessage": "(OmO 4.16.2) Resetting Project Rule Cache"
48
+ "statusMessage": "(OmO 4.16.3) Resetting Project Rule Cache"
49
49
  }
50
50
  ]
51
51
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-rules",
3
- "version": "4.16.2",
3
+ "version": "4.16.3",
4
4
  "description": "Codex plugin that injects project rule files into model context through lifecycle hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -182,6 +182,7 @@ export async function runPostToolUseHook(
182
182
  completedPostCompactKind !== undefined
183
183
  ? withPostCompactBudget(dynamicConfig, { model: input.model, transcriptPath: input.transcript_path })
184
184
  : dynamicConfig,
185
+ input.model,
185
186
  );
186
187
  hydrateEngineState(engine, cachePath);
187
188
  debugTimer.lap("hydrate", {
@@ -189,7 +190,7 @@ export async function runPostToolUseHook(
189
190
  dynamicTargetFingerprints: engine.state.dynamicTargetFingerprints.size,
190
191
  staticDedup: engine.state.staticDedup.size,
191
192
  });
192
- const dynamicTargetFingerprints = fingerprintDynamicTargets(input.cwd, targetPaths, config);
193
+ const dynamicTargetFingerprints = fingerprintDynamicTargets(input.cwd, targetPaths, config, input.model);
193
194
  debugTimer.lap("fingerprint", { fingerprints: dynamicTargetFingerprints.length });
194
195
  const pendingTargetFingerprints = dynamicTargetFingerprints.filter(
195
196
  (target) => engine.state.dynamicTargetFingerprints.get(target.cacheKey) !== target.fingerprint,
@@ -1,12 +1,15 @@
1
1
  import { statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- import { isSameOrChildPath, toPosixPath, uniqueStrings } from "./path-utils.js";
4
- import { createRuleDiscoveryCache, findRuleCandidates } from "@oh-my-opencode/rules-engine/engine";
5
- import { hashContent } from "@oh-my-opencode/rules-engine/engine";
6
- import { sortCandidates } from "@oh-my-opencode/rules-engine/engine";
7
- import { findProjectRoot } from "@oh-my-opencode/rules-engine/engine";
8
- import { disabledSourcesFromConfig } from "@oh-my-opencode/rules-engine/engine";
9
3
  import type { PiRulesConfig, RuleCandidate } from "@oh-my-opencode/rules-engine/engine";
4
+ import {
5
+ createRuleDiscoveryCache,
6
+ disabledSourcesFromConfig,
7
+ findProjectRoot,
8
+ findRuleCandidates,
9
+ hashContent,
10
+ sortCandidates,
11
+ } from "@oh-my-opencode/rules-engine/engine";
12
+ import { isSameOrChildPath, toPosixPath, uniqueStrings } from "./path-utils.js";
10
13
 
11
14
  export interface DynamicTargetFingerprint {
12
15
  targetPath: string;
@@ -18,6 +21,7 @@ export function fingerprintDynamicTargets(
18
21
  cwd: string,
19
22
  targetPaths: ReadonlyArray<string>,
20
23
  config: PiRulesConfig,
24
+ model?: string,
21
25
  ): DynamicTargetFingerprint[] {
22
26
  const disabledSources = disabledSourcesFromConfig(config);
23
27
  const discoveryCache = createRuleDiscoveryCache();
@@ -34,6 +38,7 @@ export function fingerprintDynamicTargets(
34
38
  targetFile: string;
35
39
  disabledSources?: ReadonlySet<string>;
36
40
  cache: ReturnType<typeof createRuleDiscoveryCache>;
41
+ model?: string;
37
42
  } = {
38
43
  projectRoot,
39
44
  targetFile: targetPath,
@@ -42,6 +47,9 @@ export function fingerprintDynamicTargets(
42
47
  if (disabledSources !== undefined) {
43
48
  findOptions.disabledSources = disabledSources;
44
49
  }
50
+ if (model !== undefined) {
51
+ findOptions.model = model;
52
+ }
45
53
  const candidates = findRuleCandidates(findOptions);
46
54
  const candidateFingerprint = sortCandidates(candidates).map(fingerprintCandidate).join("\u0001");
47
55
  const cacheKey = dynamicTargetCacheKey(targetPath);
@@ -52,6 +60,7 @@ export function fingerprintDynamicTargets(
52
60
  [
53
61
  "v1",
54
62
  config.enabledSources === "auto" ? "auto" : config.enabledSources.join(","),
63
+ model ?? "",
55
64
  projectRoot ?? "",
56
65
  cacheKey,
57
66
  candidateFingerprint,
@@ -14,12 +14,17 @@ interface RulesEngineFactoryOptions {
14
14
 
15
15
  const componentRoot = dirname(dirname(fileURLToPath(import.meta.url)));
16
16
 
17
- export function createRulesEngine(options: RulesEngineFactoryOptions, config = configFromEnvironment(options.env)) {
17
+ export function createRulesEngine(
18
+ options: RulesEngineFactoryOptions,
19
+ config = configFromEnvironment(options.env),
20
+ model?: string,
21
+ ) {
18
22
  const platform = options.platform ?? process.platform;
19
23
  const pluginRoot = options.env?.["PLUGIN_ROOT"] ?? process.env["PLUGIN_ROOT"] ?? componentRoot;
20
24
 
21
25
  return createEngine(config, {
22
- findCandidates: (finderOptions) => findRuleCandidates({ ...finderOptions, platform, pluginRoot }),
26
+ findCandidates: (finderOptions) =>
27
+ findRuleCandidates({ ...finderOptions, platform, pluginRoot, ...(model === undefined ? {} : { model }) }),
23
28
  findProjectRoot,
24
29
  readFile: (path) => {
25
30
  try {
@@ -47,7 +47,7 @@ export function runStaticInjection(
47
47
  }
48
48
 
49
49
  const effectiveConfig = eventName === "UserPromptSubmit" ? withPromptBudget(config) : config;
50
- const engine = createRulesEngine(options, effectiveConfig);
50
+ const engine = createRulesEngine(options, effectiveConfig, model);
51
51
  hydrateEngineState(engine, cachePath);
52
52
  engine.state.cwd = cwd;
53
53
 
@@ -89,7 +89,7 @@ function runPostCompactRecovery(input: PostCompactRecoveryInput): string {
89
89
  model: input.model,
90
90
  transcriptPath: input.transcriptPath,
91
91
  });
92
- const engine = createRulesEngine(input.options, effectiveConfig);
92
+ const engine = createRulesEngine(input.options, effectiveConfig, input.model);
93
93
  hydrateEngineState(engine, input.cachePath);
94
94
  engine.state.cwd = input.cwd;
95
95
 
@@ -28,6 +28,7 @@ type SessionCache = {
28
28
  };
29
29
 
30
30
  const CLI_PATH = fileURLToPath(new URL("../dist/cli.js", import.meta.url));
31
+ const COMPONENT_ROOT = fileURLToPath(new URL("..", import.meta.url));
31
32
 
32
33
  function runHookCli(input: string, subcommand = "post-tool-use", env: NodeJS.ProcessEnv = {}): Promise<CliResult> {
33
34
  return new Promise((resolve, reject) => {
@@ -70,6 +71,12 @@ const RULES_ONLY_ENV = {
70
71
  CODEX_RULES_ENABLED_SOURCES: ".omo/rules",
71
72
  };
72
73
 
74
+ const DYNAMIC_BUNDLED_ONLY_ENV = {
75
+ CODEX_RULES_MODE: "dynamic",
76
+ CODEX_RULES_ENABLED_SOURCES: "plugin-bundled",
77
+ PLUGIN_ROOT: COMPONENT_ROOT,
78
+ };
79
+
73
80
  afterEach(() => {
74
81
  for (const directory of tempDirectories.splice(0)) {
75
82
  rmSync(directory, { recursive: true, force: true });
@@ -411,6 +418,31 @@ describe("codex rules hooks", () => {
411
418
  expect(readSessionCache(pluginData).dynamicTargetFingerprints).toEqual(cachedState.dynamicTargetFingerprints);
412
419
  });
413
420
 
421
+ it("#given bundled dynamic rules already injected for gpt-5.5 #when same target switches to gpt-5.6 #then emits the gpt-5.6 rule", async () => {
422
+ // given
423
+ const { root, pluginData } = makeTempProject();
424
+ const filePath = path.join(root, "src", "app.ts");
425
+ const input = postToolUseInput(root, filePath);
426
+ const firstOutput = await runPostToolUseHook(input, {
427
+ pluginDataRoot: pluginData,
428
+ env: DYNAMIC_BUNDLED_ONLY_ENV,
429
+ });
430
+
431
+ // when
432
+ const secondOutput = await runPostToolUseHook(
433
+ { ...input, model: "gpt-5.6-codex" },
434
+ { pluginDataRoot: pluginData, env: DYNAMIC_BUNDLED_ONLY_ENV },
435
+ );
436
+
437
+ // then
438
+ const firstContext = parseHookOutput(firstOutput).hookSpecificOutput?.additionalContext ?? "";
439
+ const secondContext = parseHookOutput(secondOutput).hookSpecificOutput?.additionalContext ?? "";
440
+ expect(firstContext).toContain("based on GPT-5.5");
441
+ expect(firstContext).not.toContain("based on GPT-5.6");
442
+ expect(secondContext).toContain("based on GPT-5.6");
443
+ expect(secondContext).not.toContain("based on GPT-5.5");
444
+ });
445
+
414
446
  it("#given default auto sources #when excluded AGENTS.md changes #then PostToolUse fingerprint stays stable", async () => {
415
447
  // given
416
448
  const { root, pluginData } = makeTempProject();