Guard command.execute.before against injecting when parts already
contain auto-slash-command tags, preventing duplication when both
chat.message and command.execute.before fire for the same slash command.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Handle OpenCode session events that carry the session ID under properties.info.id or properties.info.sessionID so background tasks and continuation hooks do not miss idle/error/delete events.
Add regression coverage for nested session.idle events completing background tasks and waking continuation hooks.
mock.module('./executor') leaks across all files in the same batch because
Bun runs test files in a directory in parallel. The afterAll restore trick
doesn't work when other files load the module concurrently at startup.
Moving the leak test to its own subdirectory (leak/) ensures CI's batch
runner isolates it in a separate bun test invocation, preventing executor
mock contamination in executor-resolution.test.ts and index.test.ts.
mock.module('./executor') in auto-slash-command-leak.test.ts was leaking
into executor-resolution.test.ts in the same CI batch run, causing
executeSlashCommand to return the mock's raw replacement instead of the
real resolution result.
Fix: re-register the real executor exports via mock.module() in afterAll
so subsequent test files in the batch get the real implementation.
- Add afterAll(() => { mock.restore() }) to 52 test files missing cleanup
- Rewrite create-tool-guard-hooks.test.ts to use spyOn instead of barrel mock
- Fix skill-mcp-manager OAuth tests with missing mockTokens/mockLogin definitions
- Fix start-work hook: show worktree active block on resume with existing worktree_path
- Extract createWorktreeActiveBlock to worktree-block.ts to avoid circular import
- Replace 80-line isolated test runner CI config with single `bun test` command
Static slash-command discovery runs before agent registration, so /start-work regressed to Sisyphus even though config-time wiring still needed Atlas-aware fallback. Split builtin command resolution so discovery stays Atlas-first while command config remains availability-aware.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Use the plugin session directory instead of process.cwd() when resolving project slash commands. This restores project and opencode-project slashcommand behavior when the runtime cwd differs from the actual session workspace.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Add legacy plugin startup warning when oh-my-opencode config detected
- Update CLI installer and TUI installer for new package name
- Split monolithic config-manager.test.ts into focused test modules
- Add plugin config detection tests for legacy name fallback
- Update processed-command-store to use plugin-identity constants
- Add claude-code-plugin-loader discovery test for both config names
- Update chat-params and ultrawork-db tests for plugin identity
Part of #2823
Allow legitimate repeated slash commands in long sessions by replacing session-lifetime dedup with a short-lived TTL cache.
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
processedCommands and recentResults Sets grew infinitely because
Date.now() in dedup keys made deduplication impossible and no
session.deleted cleanup existed.
- Extract ProcessedCommandStore with maxSize cap and TTL-based eviction
- Add session cleanup on session.deleted event
- Remove Date.now() from dedup keys for effective deduplication
- Add dispose() for interval cleanup
Tests: 3 pass, 9 expects
Connect the existing plugin loader infrastructure to both slash command
dispatch paths (executor and slashcommand tool), enabling namespaced
commands like /daplug:run-prompt to resolve and execute.
- Add plugin discovery to executor.ts discoverAllCommands()
- Add plugin discovery to command-discovery.ts discoverCommandsSync()
- Add "plugin" to CommandScope type
- Remove blanket colon-rejection error (replaced with standard not-found)
- Update slash command regex to accept namespaced commands
- Thread claude_code.plugins config toggle through dispatch chain
- Add unit tests for plugin command discovery and dispatch
Closes#2019🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
Per reviewer feedback (code-yeongyu), keep the 'skill' tool as the main
tool and merge slashcommand functionality INTO it, rather than the reverse.
Changes:
- skill/tools.ts: Add command discovery (discoverCommandsSync) support;
handle both SKILL.md skills and .omo/commands/ slash commands in a single
tool; show combined listing in tool description
- skill/types.ts: Add 'commands' option to SkillLoadOptions
- skill/constants.ts: Update description to mention both skills and commands
- plugin/tool-registry.ts: Replace createSlashcommandTool with createSkillTool;
register tool as 'skill' instead of 'slashcommand'
- tools/index.ts: Export createSkillTool instead of createSlashcommandTool
- plugin/tool-execute-before.ts: Update tool name checks from 'slashcommand'
to 'skill'; update arg name from 'command' to 'name'
- agents/dynamic-agent-prompt-builder.ts: Categorize 'skill' tool as 'command'
- tools/skill-mcp/tools.ts: Update hint message to reference 'skill' tool
- hooks/auto-slash-command/executor.ts: Update error message
The slashcommand/ module files are kept (they provide shared utilities used
by the skill tool), but the slashcommand tool itself is no longer registered.
- Detect namespaced commands (containing ':') from Claude marketplace plugins
- Provide clear error message explaining marketplace plugins are not supported
- Point users to .claude/commands/ as alternative for custom commands
- Fixes issue where /daplug:run-prompt gave ambiguous 'command not found'
Closes#1682
Multiple files were hardcoding ~/.config/opencode paths instead of using
getOpenCodeConfigDir() which respects the OPENCODE_CONFIG_DIR env var.
This broke profile isolation features like OCX ghost mode, where users
set OPENCODE_CONFIG_DIR to a custom path but oh-my-opencode.json and
other configs weren't being read from that location.
Changes:
- plugin-config.ts: Use getOpenCodeConfigDir() directly
- cli/doctor/checks: Use getOpenCodeConfigDir() for auth and config checks
- tools/lsp/config.ts: Use getOpenCodeConfigDir() for LSP config paths
- command loaders: Use getOpenCodeConfigDir() for global command dirs
- hooks: Use getOpenCodeConfigDir() for hook config paths
- config-path.ts: Mark getUserConfigDir() as deprecated
- tests: Ensure OPENCODE_CONFIG_DIR is properly isolated in tests
- Remove all sync functions from command loader (async now default)
- Remove sync load functions from skill loader (async now default)
- Add resolveSymlinkAsync to file-utils.ts
- Update all callers to use async versions:
- config-handler.ts
- index.ts
- tools/slashcommand/tools.ts
- tools/skill/tools.ts
- hooks/auto-slash-command/executor.ts
- loader.test.ts
- All 607 tests pass, build succeeds
Generated with assistance of 🤖 [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
* feat(commands): add handoffs support for speckit compatibility
- Upgrade frontmatter parser to use js-yaml for complex YAML support
- Add HandoffDefinition interface for speckit-style workflow transitions
- Update CommandFrontmatter and CommandDefinition to include handoffs
- Add comprehensive tests for backward compatibility and complex YAML
- Fix type parameters in auto-slash-command and slashcommand tools
Closes#407
* fix(frontmatter): use JSON_SCHEMA for security and add extra fields tolerance tests
- Use JSON_SCHEMA in yaml.load() to prevent code execution via YAML tags
- Add tests to verify extra fields in frontmatter don't cause failures
- Address Greptile security review comment
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Replace mock.module() with spyOn() in auto-slash-command test to prevent shared module mocking from leaking to other test files. Remove unused mock.module() from think-mode test. This ensures test isolation so ralph-loop tests pass in both isolation and full suite runs.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This hook intercepts user messages starting with '/' and REPLACES them with the actual command template output instead of injecting instructions. The implementation includes:
- Slash command detection (detector.ts) - identifies messages starting with '/'
- Command discovery and execution (executor.ts) - loads templates from ~/.claude/commands/ or similar
- Hook integration (index.ts) - registers with chat.message event to replace output.parts
- Comprehensive test coverage - 37 tests covering detection, replacement, error handling, and command exclusions
- Configuration support in HookNameSchema
Key features:
- Supports excluded commands to skip processing
- Loads command templates from user's command directory
- Replaces user input before reaching the LLM
- Tests all edge cases including missing files, malformed templates, and special commands
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)