feat(hooks): auto-disable directory-agents-injector for OpenCode 1.1.37+ native support (#1204)
* feat(delegate-task): add prometheus self-delegation block and delegate_task permission - Block prometheus from delegating to itself via delegate_task - Grant delegate_task permission to prometheus when called as subagent - Other subagents still have delegate_task disabled * feat(version): add OPENCODE_NATIVE_AGENTS_INJECTION_VERSION constant * docs: add deprecation notes for directory-agents-injector * feat(hooks): auto-disable directory-agents-injector for OpenCode 1.1.37+ --------- Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
This commit is contained in:
@@ -768,6 +768,8 @@ Disable specific built-in hooks via `disabled_hooks` in `~/.config/opencode/oh-m
|
||||
|
||||
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `preemptive-compaction`
|
||||
|
||||
**Note on `directory-agents-injector`**: This hook is **automatically disabled** when running on OpenCode 1.1.37+ because OpenCode now has native support for dynamically resolving AGENTS.md files from subdirectories (PR #10678). This prevents duplicate AGENTS.md injection. For older OpenCode versions, the hook remains active to provide the same functionality.
|
||||
|
||||
**Note on `auto-update-checker` and `startup-toast`**: The `startup-toast` hook is a sub-feature of `auto-update-checker`. To disable only the startup toast notification while keeping update checking enabled, add `"startup-toast"` to `disabled_hooks`. To disable all update checking features (including the toast), add `"auto-update-checker"` to `disabled_hooks`.
|
||||
|
||||
## MCPs
|
||||
|
||||
@@ -320,7 +320,7 @@ Hooks intercept and modify behavior at key points in the agent lifecycle.
|
||||
|
||||
| Hook | Event | Description |
|
||||
|------|-------|-------------|
|
||||
| **directory-agents-injector** | PostToolUse | Auto-injects AGENTS.md when reading files. Walks from file to project root, collecting all AGENTS.md files. |
|
||||
| **directory-agents-injector** | PostToolUse | Auto-injects AGENTS.md when reading files. Walks from file to project root, collecting all AGENTS.md files. **Deprecated for OpenCode 1.1.37+** - Auto-disabled when native AGENTS.md injection is available. |
|
||||
| **directory-readme-injector** | PostToolUse | Auto-injects README.md for directory context. |
|
||||
| **rules-injector** | PostToolUse | Injects rules from `.claude/rules/` when conditions match. Supports globs and alwaysApply. |
|
||||
| **compaction-context-injector** | Stop | Preserves critical context during session compaction. |
|
||||
|
||||
25
src/index.ts
25
src/index.ts
@@ -78,7 +78,7 @@ import { SkillMcpManager } from "./features/skill-mcp-manager";
|
||||
import { initTaskToastManager } from "./features/task-toast-manager";
|
||||
import { TmuxSessionManager } from "./features/tmux-subagent";
|
||||
import { type HookName } from "./config";
|
||||
import { log, detectExternalNotificationPlugin, getNotificationConflictWarning, resetMessageCursor, includesCaseInsensitive, hasConnectedProvidersCache } from "./shared";
|
||||
import { log, detectExternalNotificationPlugin, getNotificationConflictWarning, resetMessageCursor, includesCaseInsensitive, hasConnectedProvidersCache, getOpenCodeVersion, isOpenCodeVersionAtLeast, OPENCODE_NATIVE_AGENTS_INJECTION_VERSION } from "./shared";
|
||||
import { loadPluginConfig } from "./plugin-config";
|
||||
import { createModelCacheState, getModelLimit } from "./plugin-state";
|
||||
import { createConfigHandler } from "./plugin-handlers";
|
||||
@@ -136,9 +136,26 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
||||
experimental: pluginConfig.experimental,
|
||||
})
|
||||
: null;
|
||||
const directoryAgentsInjector = isHookEnabled("directory-agents-injector")
|
||||
? createDirectoryAgentsInjectorHook(ctx)
|
||||
: null;
|
||||
// Check for native OpenCode AGENTS.md injection support before creating hook
|
||||
let directoryAgentsInjector = null;
|
||||
if (isHookEnabled("directory-agents-injector")) {
|
||||
const currentVersion = getOpenCodeVersion();
|
||||
const hasNativeSupport = currentVersion !== null &&
|
||||
isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION);
|
||||
|
||||
if (hasNativeSupport) {
|
||||
console.warn(
|
||||
`[oh-my-opencode] directory-agents-injector hook auto-disabled: ` +
|
||||
`OpenCode ${currentVersion} has native AGENTS.md support (>= ${OPENCODE_NATIVE_AGENTS_INJECTION_VERSION})`
|
||||
);
|
||||
log("directory-agents-injector auto-disabled due to native OpenCode support", {
|
||||
currentVersion,
|
||||
nativeVersion: OPENCODE_NATIVE_AGENTS_INJECTION_VERSION,
|
||||
});
|
||||
} else {
|
||||
directoryAgentsInjector = createDirectoryAgentsInjectorHook(ctx);
|
||||
}
|
||||
}
|
||||
const directoryReadmeInjector = isHookEnabled("directory-readme-injector")
|
||||
? createDirectoryReadmeInjectorHook(ctx)
|
||||
: null;
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
resetVersionCache,
|
||||
setVersionCache,
|
||||
MINIMUM_OPENCODE_VERSION,
|
||||
OPENCODE_NATIVE_AGENTS_INJECTION_VERSION,
|
||||
} from "./opencode-version"
|
||||
|
||||
describe("opencode-version", () => {
|
||||
@@ -220,4 +221,46 @@ describe("opencode-version", () => {
|
||||
expect(MINIMUM_OPENCODE_VERSION).toBe("1.1.1")
|
||||
})
|
||||
})
|
||||
|
||||
describe("OPENCODE_NATIVE_AGENTS_INJECTION_VERSION", () => {
|
||||
test("is set to 1.1.37", () => {
|
||||
// #given the native agents injection version constant
|
||||
// #when exported
|
||||
// #then it should be 1.1.37 (PR #10678)
|
||||
expect(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION).toBe("1.1.37")
|
||||
})
|
||||
|
||||
test("version detection works correctly with native agents version", () => {
|
||||
// #given OpenCode version at or above native agents injection version
|
||||
setVersionCache("1.1.37")
|
||||
|
||||
// #when checking against native agents version
|
||||
const result = isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION)
|
||||
|
||||
// #then returns true (native support available)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
test("version detection returns false for older versions", () => {
|
||||
// #given OpenCode version below native agents injection version
|
||||
setVersionCache("1.1.36")
|
||||
|
||||
// #when checking against native agents version
|
||||
const result = isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION)
|
||||
|
||||
// #then returns false (no native support)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
test("returns true when version detection fails (fail-safe)", () => {
|
||||
// #given version cannot be detected
|
||||
setVersionCache(null)
|
||||
|
||||
// #when checking against native agents version
|
||||
const result = isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION)
|
||||
|
||||
// #then returns true (assume latest, enable native support)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,6 +6,15 @@ import { execSync } from "child_process"
|
||||
*/
|
||||
export const MINIMUM_OPENCODE_VERSION = "1.1.1"
|
||||
|
||||
/**
|
||||
* OpenCode version that introduced native AGENTS.md injection.
|
||||
* PR #10678 merged on Jan 26, 2026 - OpenCode now dynamically resolves
|
||||
* AGENTS.md files from subdirectories as the agent explores them.
|
||||
* When this version is detected, the directory-agents-injector hook
|
||||
* is auto-disabled to prevent duplicate AGENTS.md loading.
|
||||
*/
|
||||
export const OPENCODE_NATIVE_AGENTS_INJECTION_VERSION = "1.1.37"
|
||||
|
||||
const NOT_CACHED = Symbol("NOT_CACHED")
|
||||
let cachedVersion: string | null | typeof NOT_CACHED = NOT_CACHED
|
||||
|
||||
|
||||
Reference in New Issue
Block a user