- P1: When allowedEnvVars is provided, PATH was missing from the base
restricted env, causing non-builtin commands to fail at exec time
- P2: Allowlisted HOME/CLAUDE_PROJECT_DIR could overwrite normalized
values from getHomeDirectory()/cwd with ambient process.env values
- P2: Test suite mutated shared pluginHooksState singleton without
resetting it in afterEach, causing cross-test state leaks
- Apply mcp_env_allowlist to plugin hooks: intersect HTTP allowedEnvVars
with MCP allowlist, set command allowedEnvVars to full MCP allowlist
- Scrub process.env in executeHookCommand when allowedEnvVars provided
- Add PluginHooksState class with per-directory Map storage
- Add PluginHooksConfig interface for typed boundary layer
- Pass directory context through hook-config-handler
- Add 16 tests across 4 files (40 assertions) covering allowlist
filtering, env scrubbing, directory isolation, and edge cases
- Remove unnecessary 'as' type assertions, use discriminated union
narrowing instead
Todo continuation could reinject with a lowercase built-in config key such as hephaestus when no registered alias was available. OpenCode prompt dispatch expects the prompt-facing agent name, so the continuation failed with an agent-not-found error.
Normalize the dispatch fallback through the existing prompt agent display-name resolver and pin the lowercase Hephaestus regression.
Gate idle ready notifications on the existing background-task continuation marker so cmux does not receive premature ready alerts while delegated work is still active.
Constraint: Reuse marker state from background task lifecycle without adding new notification config
Rejected: Patch cmux directly | notification readiness belongs upstream in OMO
Confidence: high
Scope-risk: narrow
- Drop the back-import of src/shared/logger so @oh-my-opencode/rules-core
stays free of host-adapter dependencies (ROADMAP package layering
invariant). Expose setSisyphusRuleDeprecationLogger(logger) for hosts to
inject their own logger; default is a noop.
- Wire the host injection in src/hooks/rules-injector/rule-file-finder.ts
as a module-level side effect so existing behavior is preserved.
- Add realpath boundary check to findRuleFilesRecursive and
validFileRealPath. Project rule scanners now refuse entries whose
realpath escapes the rule-source root, closing the symlink-escape
vector where a malicious repo could point .github/copilot-instructions.md
(or any .omo/rules/* entry) at ~/.ssh/id_rsa and have the rule injector
pull the secret into model context.
Accept apply_patch edits from nested result/metadata file lists and from raw patchText args when OpenCode does not provide direct metadata.files.
Forward tool args through the after-hook pipeline so comment-checker can inspect raw apply_patch inputs while preserving existing write, edit, and multiedit routing.
Tests: bun test src/hooks/comment-checker/hook.apply-patch.test.ts src/hooks/comment-checker/hook.before-after.test.ts src/plugin/tool-execute-after.test.ts
Tests: bun test src/hooks/comment-checker
Tests: bun run typecheck
Tests: bun run build
The full Bun suite can remove the shared rules-injector storage directory between a parent-directory check and the file write. Save operations now create the directory immediately before writing and retry once if ENOENT still wins the race.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ports the codex-rules transcript-aware dedup strategy: when a session cache is fresh (process restart or compaction-cleared cache), the injector now scans prior tool outputs for the `[Rule: <relativePath>]` banner and pre-populates the cache so duplicate rule injections are suppressed even when the persistent JSON has been lost. Hydration runs at most once per session per process, fails open on transport errors, and is short-circuited when the same banner reappears.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Previously, loadPluginHooksConfigs() loaded plugin hooks from marketplace
plugins (hookify, superpowers, zzcommon, zzfe, etc.) into
pluginComponents.hooksConfigs, but config-handler.ts never consumed them.
This meant plugin hooks were discovered but never merged into the runtime
hooks dispatch system.
Changes:
- Extend ClaudeHookEvent and ClaudeHooksConfig to support all 12 event
types (PostToolUseFailure, PermissionRequest, Notification,
SubagentStart, SubagentStop, SessionStart, SessionEnd) in addition to
the existing 5
- Add ALL_HOOK_EVENT_TYPES constant as single source of truth for event
type iteration
- Add mergePluginHooksConfigs() to unwrap plugin HooksConfig (with hooks
wrapper) into flat ClaudeHooksConfig, filtering out unsupported
prompt/agent hook types
- Add setPluginHooksConfigs() to store pending plugin configs and
invalidate the config cache
- Create applyHookConfig() handler following existing applyXxxConfig
pattern, wired into config-handler after loadPluginComponents()
- Extend DisabledHooksConfig and mergeDisabledHooks for all 12 events
Closes#4179
When OpenCode reports the original assistant error after a fallback retry has already been accepted, keep waiting for the pending fallback model instead of clearing the awaiting flag.
This prevents a duplicate stale session.error from advancing the fallback chain and dispatching a second assistant retry prompt.