The keyword-detector was using ctx.client.session.get() to check parentID for
determining subagent sessions, but this API didn't reliably return parentID.
This caused non-ultrawork keywords (search, analyze) to be injected in subagent
sessions when they should only work in main sessions.
Changed to use getMainSessionID() comparison, consistent with other hooks like
session-notification and todo-continuation-enforcer.
- Replace unreliable parentID API check with mainSessionID comparison
- Add comprehensive test coverage for session filtering behavior
- Remove unnecessary session.get API call
- Fix#542: slashcommand tool returns empty content for skills
- Add lazyContentLoader to CommandInfo type
- Load skill content in formatLoadedCommand when content is empty
- Filter non-ultrawork keywords in subagent sessions
Replace Bun shell template literals (ctx.$) with node:child_process.spawn
to work around Bun's ShellInterpreter garbage collection bug on Windows.
This bug causes segmentation faults in deinitFromFinalizer during heap
sweeping when shell operations are used repeatedly over time.
Bug references:
- oven-sh/bun#23177 (closed incomplete)
- oven-sh/bun#24368 (still open)
- Pending fix: oven-sh/bun#24093
The fix applies to all platforms for consistency and safety.
Added comprehensive VERIFICATION GUARANTEE section to ultrawork prompt to enforce proof-based task completion. Includes:
- Pre-implementation success criteria definition (Functional, Observable, Pass/Fail)
- Mandatory Test Plan template for non-trivial tasks
- Execution & Evidence requirements table (Build, Test, Manual Verify, Regression)
- TDD workflow with evidence requirements
- Verification anti-patterns and blocking violations
This enhancement ensures agents must provide PROOF that something works before claiming completion - eliminating vague "it should work now" claims without evidence.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Restore [CODE RED] maximum precision requirement
- Restore YOU MUST LEVERAGE ALL AVAILABLE AGENTS directive
- Restore TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW
- Restore explicit parallel exploration/librarian spawn workflow
- Keep mandatory ULTRAWORK MODE ENABLED! message
- Simplify constants structure for better maintainability
This addresses the issue where explore/librarian agents were being called less frequently after recent prompt changes.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
Wire agent information through keyword detector hooks:
- Pass input.agent to detectKeywordsWithType in keyword-detector hook
- Pass input.agent to detectKeywordsWithType in claude-code-hooks
- Enables agent-aware ultrawork message generation
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
Restructure ultrawork message generation to support agent-specific instructions.
- Extract ultrawork message components into modular constants
- Add getUltraworkMessage(agentName) function that adapts instructions based on agent type
- Support planner-specific vs default agent execution patterns
- Pass agentName parameter through detector.ts for message resolution
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- 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)
Move keyword detection from experimental.chat.messages.transform to claude-code-hooks
chat.message handler. Uses proven injectHookMessage file system approach for reliable
context injection.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Add MockMessage interface to match new message structure
- Update client mock to include messages() method
- Remove abort error detection tests that were unreliable
- Simplify error handling logic for better testability
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
- Add ContextCollector class for managing and merging context entries across sessions
- Add types and interfaces for context management (ContextEntry, ContextPriority, PendingContext)
- Create context-injector hook for injection coordination
- Refactor keyword-detector to use context-injector instead of hook-message-injector
- Update src/index.ts to initialize context-injector infrastructure
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
When using custom providers with model ID prefixes (e.g., vertex_ai/claude-sonnet-4-5),
the think mode switcher was stripping the prefix when mapping to high variants,
causing routing failures in custom LLM proxies.
Changes:
- Add extractModelPrefix() to parse and preserve prefixes like vertex_ai/, openai/, etc.
- Update getHighVariant() to preserve prefix when mapping to -high variants
- Update isAlreadyHighVariant() to check base model name (without prefix)
- Update getThinkingConfig() to check capability using base model name
- Add comprehensive tests for custom provider prefix scenarios
This fix ensures backward compatibility while supporting custom providers
that use prefixed model IDs for routing.
Fixes issue where think mode would break custom providers with prefixed models
by stripping the routing prefix during model variant switching.
- Update preemptive-compaction hook to use 1M limit when env vars set
- Update dynamic-truncator to use 1M limit for output truncation
- Update context-window-monitor to use 1M limit for usage tracking
Previously hardcoded 200k limits caused compaction at 140k tokens even
with 1M context enabled. Now respects env vars consistently with base
opencode implementation.
Fixes compaction triggering too early with Claude Sonnet 4.5 1M context.
Related to anomalyco/opencode#6660
Previous `VAR=val cmd` format only applied to first command in chains.
New `export VAR=val; cmd` format ensures variables persist for all commands.
Also increased test timeouts for todo-continuation-enforcer stability.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
* fix(ralph-loop): clear orphaned state when original session no longer exists
When a session with an active ralph-loop terminates abnormally (abort, window close),
the state file remains with active: true. Previously, when a new session started,
the hook would skip the orphaned state without cleaning it up.
This fix adds session existence validation:
- Before skipping a loop owned by a different session, check if that session still exists
- If the original session no longer exists, clear the orphan state and log
- If the original session still exists, skip as before (it's another active session's loop)
Changes:
- Add checkSessionExists option to RalphLoopOptions for dependency injection
- Wire up sessionExists from session-manager as the default implementation
- Add tests for orphan state cleanup and active session preservation
* fix(ralph-loop): add error handling around checkSessionExists call
Wraps the async checkSessionExists call in try/catch for consistency
with other async operations in this file. If the check throws, logs
the error and falls back to the original behavior (not clearing state).
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
- Restructure ultrawork mode message with clearer priorities
- Add TODO IS YOUR LIFELINE section emphasizing TodoWrite usage
- Enhance agent utilization principles and execution rules
- Improve clarity of zero tolerance failure policies
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
Root cause: DEFAULT_TARGET_MAX_TOKENS (50k tokens ~200k chars) was too high
for webfetch outputs. Web pages can be large but most content doesn't exceed
this limit, so truncation rarely triggered.
Changes:
- Add WEBFETCH_MAX_TOKENS = 10k tokens (~40k chars) for web content
- Introduce TOOL_SPECIFIC_MAX_TOKENS map for per-tool limits
- webfetch/WebFetch now use aggressive 10k token limit
- Other tools continue using default 50k token limit
- Add comprehensive tests for truncation behavior
Fixes#195
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Improves readability by placing the git command on its own line instead of concatenating it directly after environment variables. The VAR=value prefix now continues to the next line with proper shell escaping.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
OpenCode's bash tool ignores args.env and uses hardcoded process.env in spawn().
Work around this by prepending GIT_EDITOR, EDITOR, VISUAL, and PAGER env vars
directly to the command string. Only applies to git commands to avoid bloating
non-git commands.
Added shellEscape() and buildEnvPrefix() helper functions to properly escape
env var values and construct the prefix string.
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
The prompt_async method expects path parameter named 'id' (not 'sessionID').
This bug prevented the 'Continue' message from being sent after compaction,
causing the recovery process to fail silently due to silent error swallowing
in the empty catch block.
Fixes:
- Type definition: changed path: { sessionID: string } to path: { id: string }
- Implementation: changed path: { sessionID } to path: { id: sessionID } at 2 locations (lines 411, 509)
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Detects Edit tool errors (oldString/newString mismatches)
- Injects system reminder forcing AI to read file, verify state, apologize
- Includes comprehensive test suite (8 tests)
- Integrates with hook system and configuration schema
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Allow UserPromptSubmit hooks to run on first message (used for title generation)
- For first message: prepend hook content directly to message parts
- For subsequent messages: use file system injection as before
- Preserves hook injection integrity while enabling title generation hooks
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
- Removed 'invalid_request_error' from TOKEN_LIMIT_KEYWORDS (too broad)
- Added THINKING_BLOCK_ERROR_PATTERNS to explicitly detect thinking block structure errors
- Added isThinkingBlockError() function to filter these out before token limit checks
- Prevents 'thinking block order' errors from triggering compaction instead of session-recovery
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
When injecting continuation prompts, extract and pass the model field
(providerID + modelID) from the nearest stored message, matching the
pattern used in background-agent/manager.ts and session-recovery.
Also updated tests to capture the model field for verification.
* fix(ralph-loop): detect completion promise from session messages API
The completion promise (e.g., <promise>DONE</promise>) was not being detected
because assistant text messages were never recorded to the transcript file.
Only user messages, tool uses, and tool results were recorded.
This fix adds a new detection method that fetches session messages via the
OpenCode API and checks assistant text messages for the completion promise.
The transcript file check is kept as a fallback.
Fixes#412
* refactor(ralph-loop): address review feedback
- Simplify response parsing to use response.data consistently (greptile)
- Add session ID tracking to messages mock for better test coverage (cubic)
- Add assertion to verify correct session ID is passed to API
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Previously, the hook only set NON_INTERACTIVE_ENV without inheriting the parent process environment, causing subprocess to run without proper PATH and other env vars. Now it properly inherits process.env first, then applies GIT_EDITOR=":" and EDITOR=":" to prevent interactive editors from spawning.
🤖 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>
* fix: Windows auto-update path detection and add install function support
- Fix Windows path inconsistency: check ~/.config first, then %APPDATA%
- Add actual update installation via runBunInstall when autoUpdate=true
- Check both Windows config locations for comprehensive detection
Closes#402
* fix: address review feedback on error logging and message clarity
- Update misleading log message to clarify fallback behavior
- Serialize error object before logging to prevent {} serialization
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Replace the time-based ERROR_COOLDOWN_MS mechanism with an event-order based
lastEventWasAbortError flag. This fixes the bug where abort errors permanently
block todo continuation since session.idle only fires once during the cooldown.
Now abort errors only skip continuation when they occur IMMEDIATELY before
session.idle event. Any intervening event (message, tool execution) clears the
abort state, allowing normal continuation flow on the next idle.
Comprehensive tests added to verify:
- Abort detection correctly blocks continuation when immediately before idle
- Intervening events (assistant message, tool execution) clear abort state
- Non-abort errors don't block continuation
- Multiple abort events (only last one matters)
- No time-based throttle preventing consecutive injections
🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
- Changed GIT_EDITOR, EDITOR, GIT_SEQUENCE_EDITOR from 'true' to ':' (shell no-op builtin)
- Changed VISUAL from 'true' to '' (empty string to prevent fallback issues)
- Added GIT_MERGE_AUTOEDIT: 'no' to prevent merge editor prompts
Fixes SIGTERM issues when git tries to open editors in non-interactive environments.
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
Fixes critical v2.10.0 compaction regression where truncation ALWAYS returned early
without checking if it was sufficient, causing PHASE 3 (Summarize) to be skipped.
This led to "history disappears" symptom where all context was lost after compaction.
Changes:
- Restored aggressiveResult.sufficient check before early return in executor
- Only return from Truncate phase if truncation successfully reduced tokens below limit
- Otherwise fall through to Summarize phase when truncation is insufficient
- Restored conservative charsPerToken=4 (was changed to 2, too aggressive)
- Added 2 regression tests:
* Test 1: Verify Summarize is called when truncation is insufficient
* Test 2: Verify Summarize is skipped when truncation is sufficient
Regression details:
- v2.10.0 changed charsPerToken from 4 to 2, making truncation too aggressive
- Early return removed sufficient check, skipping fallback to Summarize
- Users reported complete loss of conversation history after compaction
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
- Regenerated root AGENTS.md with overview, structure, and complexity hotspots
- Regenerated all 7 subdirectory AGENTS.md files: hooks, tools, features, agents, cli, auth, shared
- Used 11 background explore agents for comprehensive feature and architecture analysis
- All files within size limits (root: 112 lines, subdirs: 57-68 lines)
- Includes where-to-look guide, conventions, anti-patterns, and agent model information
🤖 Generated with assistance of oh-my-opencode
* feat(rules-injector): add GitHub Copilot instructions format support
- Add .github/instructions/ directory to rule discovery paths
- Add applyTo as alias for globs field in frontmatter parser
- Support .github/copilot-instructions.md single-file format (always-apply)
- Filter .github/instructions/ to only accept *.instructions.md files
- Add comprehensive tests for parser and finder
Closes#397
* fix(rules-injector): use cross-platform path separator in calculateDistance
path.relative() returns OS-native separators (backslashes on Windows),
but the code was splitting by forward slash only, causing incorrect
distance calculations on Windows.
Use regex /[/\]/ to handle both separator types.
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
- Add skill_mcp and webfetch to TRUNCATABLE_TOOLS list
- Add grep parameter for regex filtering of output lines
- Prevents token overflow from large MCP responses
🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
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)