-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix(todo-continuation): implement hybrid abort detection for reliable ESC ESC handling #578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add event-based abort detection as primary method - Keep API-based detection as fallback - Track abort events via session.error with 3s time window - Clear abort flag on user/assistant activity and tool execution - Add comprehensive tests for hybrid approach (8 new test cases) - All 663 tests pass Fixes #577
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Greptile Summary
Implements hybrid abort detection for the TODO continuation hook to fix race condition where ESC ESC interrupts weren't reliably detected. The solution combines event-based detection (primary) via session.error event with API-based detection (fallback) via session.messages() API call.
Key Changes:
- Added
abortDetectedAttimestamp toSessionStatefor tracking abort events in real-time - Event handler captures
MessageAbortedErrorandAbortErrorfromsession.errorevents - 3-second time window prevents stale abort flags from blocking legitimate continuations
- Abort flag automatically cleared on new user messages, assistant responses, and tool executions
- API-based detection retained as fallback for edge cases where event is missed
Testing:
- 8 new test cases cover event detection, stale flag handling, flag clearing, and hybrid scenarios
- All 663 tests pass (as mentioned in PR description)
- Tests align with existing TDD patterns using
#given/#when/#thenBDD comments
The implementation follows the established pattern from ralph-loop hook (line 336) and addresses a real reliability issue with a well-reasoned dual-detection approach.
Confidence Score: 5/5
- This PR is safe to merge with minimal risk
- Score reflects well-designed solution with comprehensive test coverage (8 new tests, all 663 pass), follows established patterns from
ralph-loophook, addresses real race condition issue, implements proper cleanup on state transitions, and includes both primary + fallback detection mechanisms - No files require special attention
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| src/hooks/todo-continuation-enforcer.ts | 5/5 | Implements hybrid abort detection with event-based primary detection and API fallback; adds abortDetectedAt timestamp tracking with 3s window and proper cleanup on user/assistant/tool activity |
| src/hooks/todo-continuation-enforcer.test.ts | 5/5 | Adds 8 comprehensive test cases covering event-based detection, stale flag handling, flag clearing on various activities, and hybrid detection scenarios |
Sequence Diagram
sequenceDiagram
participant User
participant OpenCode
participant Hook as TodoContinuationEnforcer
participant State as SessionState
participant API as OpenCode API
Note over User,API: Scenario 1: Event-Based Detection (Primary)
User->>OpenCode: Press ESC ESC (abort)
OpenCode->>Hook: session.error event<br/>(MessageAbortedError/AbortError)
Hook->>State: Store abortDetectedAt = Date.now()
Hook->>Hook: Cancel countdown
OpenCode->>Hook: session.idle event
Hook->>State: Check abortDetectedAt
State-->>Hook: timestamp < 3s old
Hook->>Hook: Skip todo continuation
Hook->>State: Clear abortDetectedAt
Note over User,API: Scenario 2: API Fallback Detection
User->>OpenCode: Press ESC ESC (abort)
Note over Hook: Event missed/not received
OpenCode->>Hook: session.idle event
Hook->>State: Check abortDetectedAt
State-->>Hook: undefined (no event received)
Hook->>API: session.messages() API call
API-->>Hook: Last message has error field
Hook->>Hook: Skip todo continuation
Note over User,API: Scenario 3: Abort Flag Cleared
User->>OpenCode: Press ESC ESC (abort)
OpenCode->>Hook: session.error event
Hook->>State: Store abortDetectedAt
User->>OpenCode: Send new message
OpenCode->>Hook: message.updated (role=user)
Hook->>State: Clear abortDetectedAt
Hook->>Hook: Cancel countdown
OpenCode->>Hook: session.idle event
Hook->>State: Check abortDetectedAt
State-->>Hook: undefined (cleared by user activity)
Hook->>API: session.messages() - no abort
Hook->>Hook: ✅ Start todo continuation countdown
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
|
@sisyphus-dev-ai review |
Code Review: Hybrid Abort Detection for TODO ContinuationSummaryThis PR implements a robust solution to fix race conditions in ESC ESC interrupt detection by combining event-based detection (primary) with API-based detection (fallback). The implementation is well-designed and thoroughly tested. ✅ Strengths
|
…#562) * fix: respect disabled_hooks for keyword-detector in claude-code-hooks The keyword detection in claude-code-hooks was running regardless of whether keyword-detector was in disabled_hooks. This caused analyze and search modes to trigger even when explicitly disabled. Pass keywordDetectorDisabled flag to createClaudeCodeHooksHook and skip keyword detection when the hook is disabled. Fixes #530 * refactor: restore keyword types in log output Add types array back to keyword detection log for better observability
* docs: update opencode-antigravity-auth version to 1.2.8 * docs: update opencode-antigravity-auth to 1.2.8 in localized READMEs --------- Co-authored-by: sisyphus-dev-ai <[email protected]>
… with automatic rotation (#579) * feat(auth): add multi-account types and storage layer Add foundation for multi-account Google Antigravity auth: - ModelFamily, AccountTier, RateLimitState types for rate limit tracking - AccountMetadata, AccountStorage, ManagedAccount interfaces - Cross-platform storage module with XDG_DATA_HOME/APPDATA support - Comprehensive test coverage for storage operations 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): implement AccountManager for multi-account rotation Add AccountManager class with automatic account rotation: - Per-family rate limit tracking (claude, gemini-flash, gemini-pro) - Paid tier prioritization in rotation logic - Round-robin account selection within tier pools - Account add/remove operations with index management - Storage persistence integration 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): add CLI prompts for multi-account setup Add @clack/prompts-based CLI utilities: - promptAddAnotherAccount() for multi-account flow - promptAccountTier() for free/paid tier selection - Non-TTY environment handling (graceful skip) 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): integrate multi-account OAuth flow into plugin Enhance OAuth flow for multi-account support: - Prompt for additional accounts after first OAuth (up to 10) - Collect email and tier for each account - Save accounts to storage via AccountManager - Load AccountManager in loader() from stored accounts - Toast notifications for account authentication success - Backward compatible with single-account flow 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): add rate limit rotation to fetch interceptor Integrate AccountManager into fetch for automatic rotation: - Model family detection from URL (claude/gemini-flash/gemini-pro) - Rate limit detection (429 with retry-after > 5s, 5xx errors) - Mark rate-limited accounts and rotate to next available - Recursive retry with new account on rotation - Lazy load accounts from storage on first request - Debug logging for account switches 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(cli): add auth account management commands Add CLI commands for managing Google Antigravity accounts: - `auth list`: Show all accounts with email, tier, rate limit status - `auth remove <index|email>`: Remove account by index or email - Help text with usage examples - Active account indicator and remaining rate limit display 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(auth): address review feedback - remove duplicate ManagedAccount and reuse fetch function - Remove unused ManagedAccount interface from types.ts (duplicate of accounts.ts) - Reuse fetchFn in rate limit retry instead of creating new fetch closure Preserves cachedTokens, cachedProjectId, fetchInstanceId, accountsLoaded state * fix(auth): address Cubic review feedback (8 issues) P1 fixes: - storage.ts: Use mode 0o600 for OAuth credentials file (security) - fetch.ts: Return original 5xx status instead of synthesized 429 - accounts.ts: Adjust activeIndex/currentIndex in removeAccount - plugin.ts: Fix multi-account migration to split on ||| not | P2 fixes: - cli.ts: Remove confusing cancel message when returning default - auth.ts: Use strict parseInt check to prevent partial matches - storage.test.ts: Use try/finally for env var cleanup * refactor(test): import ManagedAccount from accounts.ts instead of duplicating * fix(auth): address Oracle review findings (P1/P2) P1 fixes: - Clear cachedProjectId on account change to prevent stale project IDs - Continue endpoint fallback for single-account users on rate limit - Restore access/expires tokens from storage for non-active accounts - Re-throw non-ENOENT filesystem errors (keep returning null for parse errors) - Use atomic write (temp file + rename) for account storage P2 fixes: - Derive RateLimitState type from ModelFamily using mapped type - Add MODEL_FAMILIES constant and use dynamic iteration in clearExpiredRateLimits - Add missing else branch in storage.test.ts env cleanup - Handle open() errors gracefully with user-friendly toast message Tests updated to reflect correct behavior for token restoration. * fix(auth): address Cubic review round 2 (5 issues) P1: Return original 429/5xx response on last endpoint instead of generic 503 P2: Use unique temp filename (pid+timestamp) and cleanup on rename failure P2: Clear cachedProjectId when first account introduced (lastAccountIndex null) P3: Add console.error logging to open() catch block * test(auth): add AccountManager removeAccount index tests Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * test(auth): add storage layer security and atomicity tests Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * fix(auth): address Cubic review round 3 (4 issues) P1 Fixes: - plugin.ts: Validate refresh_token before constructing first account - plugin.ts: Validate additionalTokens.refresh_token before pushing accounts - fetch.ts: Reset cachedTokens when switching accounts during rotation P2 Fixes: - fetch.ts: Improve model-family detection (parse model from body, fallback to URL) * fix(auth): address Cubic review round 4 (3 issues) P1 Fixes: - plugin.ts: Close serverHandle before early return on missing refresh_token - plugin.ts: Close additionalServerHandle before continue on missing refresh_token P2 Fixes: - fetch.ts: Remove overly broad 'pro' matching in getModelFamilyFromModelName * fix(auth): address Cubic review round 5 (9 issues) P1 Fixes: - plugin.ts: Close additionalServerHandle after successful account auth - fetch.ts: Cancel response body on 429/5xx to prevent connection leaks P2 Fixes: - plugin.ts: Close additionalServerHandle on OAuth error/missing code - plugin.ts: Close additionalServerHandle on verifier mismatch - auth.ts: Set activeIndex to -1 when all accounts removed - storage.ts: Use shared getDataDir utility for consistent paths - fetch.ts: Catch loadAccounts IO errors with graceful fallback - storage.test.ts: Improve test assertions with proper error tracking * feat(antigravity): add system prompt and thinking config constants * feat(antigravity): add reasoning_effort and Gemini 3 thinkingLevel support * feat(antigravity): inject system prompt into all requests * feat(antigravity): integrate thinking config and system prompt in fetch layer * feat(auth): auto-open browser for OAuth login on all platforms * fix(auth): add alias2ModelName for Antigravity Claude models Root cause: Antigravity API expects 'claude-sonnet-4-5-thinking' but we were sending 'gemini-claude-sonnet-4-5-thinking'. Ported alias mapping from CLIProxyAPI antigravity_executor.go:1328-1347. Transforms: - gemini-claude-sonnet-4-5-thinking → claude-sonnet-4-5-thinking - gemini-claude-opus-4-5-thinking → claude-opus-4-5-thinking - gemini-3-pro-preview → gemini-3-pro-high - gemini-3-flash-preview → gemini-3-flash * fix(auth): add requestType and toolConfig for Antigravity API Missing required fields from CLIProxyAPI implementation: - requestType: 'agent' - request.toolConfig.functionCallingConfig.mode: 'VALIDATED' - Delete request.safetySettings Also strip 'antigravity-' prefix before alias transformation. * fix(auth): remove broken alias2ModelName transformations for Gemini 3 CLIProxyAPI's alias mappings don't work with public Antigravity API: - gemini-3-pro-preview → gemini-3-pro-high (404!) - gemini-3-flash-preview → gemini-3-flash (404!) Tested: -preview suffix names work, transformed names return 404. Keep only gemini-claude-* prefix stripping for future Claude support. * fix(auth): implement correct alias2ModelName transformations for Antigravity API Implements explicit switch-based model name mappings for Antigravity API. Updates SANDBOX endpoint constants to clarify quota/availability behavior. Fixes test expectations to match new transformation logic. 🤖 Generated with assistance of OhMyOpenCode --------- Co-authored-by: Sisyphus <[email protected]>
* feat(background-agent): add ConcurrencyManager for model-based limits 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * fix(background-agent): set default concurrency to 5 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(background-agent): support 0 as unlimited concurrency Setting concurrency to 0 means unlimited (Infinity). Works for defaultConcurrency, providerConcurrency, and modelConcurrency. 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): use auto flag for session resumption after compaction - executor.ts: Added `auto: true` to summarize body, removed subsequent prompt_async call - preemptive-compaction/index.ts: Added `auto: true` to summarize body, removed subsequent promptAsync call - executor.test.ts: Updated test expectation to include `auto: true` Instead of sending 'Continue' prompt after compaction, use SessionCompaction's `auto: true` feature which auto-resumes the session. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(agents): update sisyphus orchestrator Update Sisyphus agent orchestrator with latest changes. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(features): update background agent manager Update background agent manager with latest configuration changes. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(features): update init-deep template Update initialization template with latest configuration. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(hooks): update hook constants and configuration Update hook constants and configuration across agent-usage-reminder, keyword-detector, and claude-code-hooks. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(tools): remove background-task tool Remove background-task tool module completely: - src/tools/background-task/constants.ts - src/tools/background-task/index.ts - src/tools/background-task/tools.ts - src/tools/background-task/types.ts 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(tools): update tool exports and main plugin entry Update tool index exports and main plugin entry point after background-task tool removal. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): update constants to match CLIProxyAPI (50min buffer, 2 endpoints) - Changed ANTIGRAVITY_TOKEN_REFRESH_BUFFER_MS from 60,000ms (1min) to 3,000,000ms (50min) - Removed autopush endpoint from ANTIGRAVITY_ENDPOINT_FALLBACKS (now 2 endpoints: daily → prod) - Added comprehensive test suite with 6 tests covering all updated constants - Updated comments to reflect CLIProxyAPI parity 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(auth): remove PKCE to match CLIProxyAPI Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * feat(auth): implement port 51121 with OS fallback Add port fallback logic to OAuth callback server: - Try port 51121 (ANTIGRAVITY_CALLBACK_PORT) first - Fallback to OS-assigned port on EADDRINUSE - Add redirectUri property to CallbackServerHandle - Return actual bound port in handle.port Add comprehensive port handling tests (5 new tests): - Should prefer port 51121 - Should return actual bound port - Should fallback when port occupied - Should cleanup and release port on close - Should provide redirect URI with actual port All 16 tests passing (11 existing + 5 new). 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * test(auth): add token expiry tests for 50-min buffer Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * feat(agents): add Prometheus system prompt and planner methodology Add prometheus-prompt.ts with comprehensive planner agent system prompt. Update plan-prompt.ts with streamlined Prometheus workflow including: - Context gathering via explore/librarian agents - Metis integration for AI slop guardrails - Structured plan output format 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): add Metis plan consultant agent Add Metis agent for pre-planning analysis that identifies: - Hidden requirements and implicit constraints - AI failure points and common mistakes - Clarifying questions before planning begins 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): add Momus plan reviewer agent Add Momus agent for rigorous plan review against: - Clarity and verifiability standards - Completeness checks - AI slop detection 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): add Sisyphus-Junior focused executor agent Add Sisyphus-Junior agent for focused task execution: - Same discipline as Sisyphus, no delegation capability - Used for category-based task spawning via sisyphus_task tool 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): add orchestrator-sisyphus agent Add orchestrator-sisyphus agent for complex workflow orchestration: - Manages multi-agent workflows - Coordinates between specialized agents - Handles start-work command execution 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(skill-loader): add skill-content resolver for agent skills Add resolveMultipleSkills() for resolving skill content to prepend to agent prompts. Includes test coverage for resolution logic. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): add category and skills support to buildAgent Extend buildAgent() to support: - category: inherit model/temperature from DEFAULT_CATEGORIES - skills: prepend resolved skill content to agent prompt Includes comprehensive test coverage for new functionality. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): register new agents in index and types - Export Metis, Momus, orchestrator-sisyphus in builtinAgents - Add new agent names to BuiltinAgentName type - Update AGENTS.md documentation with new agents 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(features): add boulder-state persistence Add boulder-state feature for persisting workflow state: - storage.ts: File I/O operations for state persistence - types.ts: State interfaces - Includes test coverage 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(skills): add frontend-ui-ux builtin skill Add frontend-ui-ux skill for designer-turned-developer UI work: - SKILL.md with comprehensive design principles - skills.ts updated with skill template 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(tools): add sisyphus_task tool for category-based delegation Add sisyphus_task tool supporting: - Category-based task delegation (visual, business-logic, etc.) - Direct agent targeting - Background execution with resume capability - DEFAULT_CATEGORIES configuration Includes test coverage. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(background-agent): add resume capability and model field - Add resume() method for continuing existing agent sessions - Add model field to BackgroundTask and LaunchInput types - Update launch() to pass model to session.prompt() - Comprehensive test coverage for resume functionality 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add task-resume-info hook Add hook for injecting task resume information into tool outputs. Enables seamless continuation of background agent sessions. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add prometheus-md-only write restriction hook Add hook that restricts Prometheus planner to writing only .md files in the .sisyphus/ directory. Prevents planners from implementing. Includes test coverage. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add start-work hook for Sisyphus workflow Add hook for detecting /start-work command and triggering orchestrator-sisyphus agent for plan execution. Includes test coverage. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add sisyphus-orchestrator hook Add hook for orchestrating Sisyphus agent workflows: - Coordinates task execution between agents - Manages workflow state persistence - Handles agent handoffs Includes comprehensive test coverage. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): export new hooks in index Export new hooks: - createPrometheusMdOnlyHook - createTaskResumeInfoHook - createStartWorkHook - createSisyphusOrchestratorHook 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(todo-enforcer): add skipAgents option and improve permission check - Add skipAgents option to skip continuation for specified agents - Default skip: Prometheus (Planner) - Improve tool permission check to handle 'allow'/'deny' string values - Add agent name detection from session messages 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config): add categories, new agents and hooks to schema Update Zod schema with: - CategoryConfigSchema for task delegation categories - CategoriesConfigSchema for user category overrides - New agents: Metis (Plan Consultant) - New hooks: prometheus-md-only, start-work, sisyphus-orchestrator - New commands: start-work - Agent category and skills fields Includes schema test coverage. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(commands): add start-work command Add /start-work command for executing Prometheus plans: - start-work.ts: Command template for orchestrator-sisyphus - commands.ts: Register command with agent binding - types.ts: Add command name to type union 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(migration): add backup creation and category migration - Create timestamped backup before migration writes - Add migrateAgentConfigToCategory() for model→category migration - Add shouldDeleteAgentConfig() for cleanup when matching defaults - Add Prometheus and Metis to agent name map - Comprehensive test coverage for new functionality 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(config-handler): add Sisyphus-Junior and orchestrator support - Add Sisyphus-Junior agent creation - Add orchestrator-sisyphus tool restrictions - Rename Planner-Sisyphus to Prometheus (Planner) - Use PROMETHEUS_SYSTEM_PROMPT and PROMETHEUS_PERMISSION 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(cli): add categories config for Antigravity auth Add category model overrides for Gemini Antigravity authentication: - visual: gemini-3-pro-high - artistry: gemini-3-pro-high - writing: gemini-3-pro-high 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(sisyphus): update to use sisyphus_task and add resume docs - Update example code from background_task to sisyphus_task - Add 'Resume Previous Agent' documentation section - Remove model name from Oracle section heading - Disable call_omo_agent tool for Sisyphus 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor: update tool references from background_task to sisyphus_task Update all references across: - agent-usage-reminder: Update AGENT_TOOLS and REMINDER_MESSAGE - claude-code-hooks: Update comment - call-omo-agent: Update constants and tool restrictions - init-deep template: Update example code - tools/index.ts: Export sisyphus_task, remove background_task 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hook-message-injector): add ToolPermission type support Add ToolPermission type union: boolean | 'allow' | 'deny' | 'ask' Update StoredMessage and related interfaces for new permission format. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(main): wire up new tools, hooks and agents Wire up in main plugin entry: - Import and create sisyphus_task tool - Import and wire taskResumeInfo, startWork, sisyphusOrchestrator hooks - Update tool restrictions from background_task to sisyphus_task - Pass userCategories to createSisyphusTask 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * docs: update documentation for Prometheus and new features Update documentation across all language versions: - Rename Planner-Sisyphus to Prometheus (Planner) - Add Metis (Plan Consultant) agent documentation - Add Categories section with usage examples - Add sisyphus_task tool documentation - Update AGENTS.md with new structure and complexity hotspots - Update src/tools/AGENTS.md with sisyphus_task category 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * build: regenerate schema.json with new types Update JSON schema with: - New agents: Prometheus (Planner), Metis (Plan Consultant) - New hooks: prometheus-md-only, start-work, sisyphus-orchestrator - New commands: start-work - New skills: frontend-ui-ux - CategoryConfigSchema for task delegation - Agent category and skills fields 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * skill * feat: add toast notifications for task execution - Display toast when background task starts in BackgroundManager - Display toast when sisyphus_task sync task starts - Wire up prometheus-md-only hook initialization in main plugin This provides user feedback in OpenCode TUI where task TUI is not visible. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add read-only warning injection for Prometheus task delegation When Prometheus (Planner) spawns subagents via task tools (sisyphus_task, task, call_omo_agent), a system directive is injected into the prompt to ensure subagents understand they are in a planning consultation context and must NOT modify files. 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(hooks): add mandatory hands-on verification enforcement for orchestrated tasks - sisyphus-orchestrator: Add verification reminder with tool matrix (playwright/interactive_bash/curl) - start-work: Inject detailed verification workflow with deliverable-specific guidance 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) assistance * docs(agents): clarify oracle and metis agent descriptions emphasizing read-only consultation roles - Oracle: high-IQ reasoning specialist for debugging and architecture (read-only) - Metis: updated description to align with oracle's consultation-only model - Updated AGENTS.md with clarified agent responsibilities * docs(orchestrator): emphasize oracle as read-only consultation agent - Updated orchestrator-sisyphus agent descriptions - Updated sisyphus-prompt-builder to highlight oracle's read-only consultation role - Clarified that oracle provides high-IQ reasoning without write operations * docs(refactor,root): update oracle consultation model in feature templates and root docs - Updated refactor command template to emphasize oracle's read-only role - Updated root AGENTS.md with oracle agent description emphasizing high-IQ debugging and architecture consultation - Clarified oracle as non-write agent for design and debugging support * feat(features): add TaskToastManager for consolidated task notifications - Create task-toast-manager feature with singleton pattern - Show running task list (newest first) when new task starts - Track queued tasks status from ConcurrencyManager - Integrate with BackgroundManager and sisyphus-task tool 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) assistance * feat(hooks): add resume session_id to verification reminders for orchestrator subagent work When subagent work fails verification, show exact sisyphus_task(resume="...") command with session_id for immediate retry. Consolidates verification workflow across boulder and standalone modes. * refactor(hooks): remove duplicate verification enforcement from start-work hook Verification reminders are now centralized in sisyphus-orchestrator hook, eliminating redundant code in start-work. The orchestrator hook handles all verification messaging across both boulder and standalone modes. * test(hooks): update prometheus-md-only test assertions and formatting Updated test structure and assertions to match current output format. Improved test clarity while maintaining complete coverage of markdown validation and write restriction behavior. * orchestrator * feat(skills): add git-master skill for atomic commits and history management - Add comprehensive git-master skill for commit, rebase, and history operations - Implements atomic commit strategy with multi-file splitting rules - Includes style detection, branch analysis, and history search capabilities - Provides three modes: COMMIT, REBASE, HISTORY_SEARCH 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * docs(agents): add pre-delegation planning section to Sisyphus prompt - Add SISYPHUS_PRE_DELEGATION_PLANNING section with mandatory declaration rules - Implements 3-step decision tree: Identify → Select → Declare - Forces explicit category/agent/skill declaration before every sisyphus_task call - Includes mandatory 4-part format: Category/Agent, Reason, Skills, Expected Outcome - Provides examples (CORRECT vs WRONG) and enforcement rules - Follows prompt engineering best practices: Clear, CoT, Structured, Examples 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(tools): rename agent parameter to subagent_type in sisyphus_task - Update parameter name from 'agent' to 'subagent_type' for consistency with call_omo_agent - Update all references and error messages - Remove deprecated 'agent' field from SisyphusTaskArgs interface - Update git-master skill documentation to reflect parameter name change 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(agents): change orchestrator-sisyphus default model to claude-sonnet-4-5 - Update orchestrator-sisyphus model from opus-4-5 to sonnet-4-5 for better cost efficiency - Keep Prometheus using opus-4-5 for planning tasks 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * refactor(config): make Prometheus model independent from plan agent config - Prometheus no longer inherits model from plan agent configuration - Fallback chain: session default model -> claude-opus-4-5 - Removes coupling between Prometheus and legacy plan agent settings 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * fix(momus): allow system directives in input validation System directives (XML tags like <system-reminder>) are automatically injected and should be ignored during input validation. Only reject when there's actual user text besides the file path. 🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(prometheus): enhance high accuracy mode with mandatory Momus loop When user requests high accuracy: - Momus review loop is now mandatory until 'OKAY' - No excuses allowed - must fix ALL issues - No maximum retry limit - keep looping until approved - Added clear explanation of what 'OKAY' means 🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(prometheus): enhance reference section with detailed guidance References now include: - Pattern references (existing code to follow) - API/Type references (contracts to implement) - Test references (testing patterns) - Documentation references (specs and requirements) - External references (libraries and frameworks) - Explanation of WHY each reference matters The executor has no interview context - references are their only guide. 🤖 Generated with assistance of [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) * feat(git-master): add configurable commit footer and co-author options Add git_master config with commit_footer and include_co_authored_by flags. Users can disable Sisyphus attribution in commits via oh-my-opencode.json. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * feat(hooks): add single-task directive and system-reminder tags to orchestrator Inject SINGLE_TASK_DIRECTIVE when orchestrator calls sisyphus_task to enforce atomic task delegation. Wrap verification reminders in <system-reminder> tags for better LLM attention. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]> * refactor: use ContextCollector for hook injection and remove unused background tools Split changes: - Replace injectHookMessage with ContextCollector.register() pattern for improved hook content injection - Remove unused background task tools infrastructure (createBackgroundOutput, createBackgroundCancel) 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode) * chore(context-injector): add debug logging for context injection tracing Add DEBUG log statements to trace context injection flow: - Log message transform hook invocations - Log sessionID extraction from message info - Log hasPending checks for context collector - Log hook content registration to contextCollector 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) assistance * fix(context-injector): prepend to user message instead of separate synthetic message - Change from creating separate synthetic user message to prepending context directly to last user message's text part - Separate synthetic messages were ignored by model (treated as previous turn) - Prepending to clone ensures: UI shows original, model receives prepended content - Update tests to reflect new behavior * feat(prometheus): enforce mandatory todo registration on plan generation trigger * fix(sisyphus-task): add proper error handling for sync mode and implement BackgroundManager.resume() - Add try-catch for session.prompt() in sync mode with detailed error messages - Sort assistant messages by time to get the most recent response - Add 'No assistant response found' error handling - Implement BackgroundManager.resume() method for task resumption - Fix ConcurrencyManager type mismatch (model → concurrencyKey) * docs(sisyphus-task): clarify resume usage with session_id and add when-to-use guidance - Fix terminology: 'Task ID' → 'Session ID' in resume parameter docs - Add clear 'WHEN TO USE resume' section with concrete scenarios - Add example usage pattern in Sisyphus agent prompt - Emphasize token savings and context preservation benefits * fix(agents): block task/sisyphus_task/call_omo_agent from explore and librarian Exploration agents should not spawn other agents - they are leaf nodes in the agent hierarchy for codebase search only. * refactor(oracle): change default model from GPT-5.2 to Claude Opus 4.5 * feat(oracle): change default model to claude-opus-4-5 * fix(sisyphus-orchestrator): check boulder session_ids before filtering sessions Bug: continuation was not triggered even when boulder.json existed with session_ids because the session filter ran BEFORE reading boulder state. Fix: Read boulder state first, then include boulder sessions in the allowed sessions for continuation. * feat(task-toast): display skills and concurrency info in toast - Add skills field to TrackedTask and LaunchInput types - Show skills in task list message as [skill1, skill2] - Add concurrency slot info [running/limit] in Running header - Pass skills from sisyphus_task to toast manager (sync & background) - Add unit tests for new toast features * refactor(categories): rename high-iq to ultrabrain * feat(sisyphus-task): add skillContent support to background agent launching - Add optional skillContent field to LaunchInput type - Implement buildSystemContent utility to combine skill and category prompts - Update BackgroundManager to pass skillContent as system parameter - Add comprehensive tests for skillContent optionality and buildSystemContent logic 🤖 Generated with assistance of oh-my-opencode * Revert "refactor(tools): remove background-task tool" This reverts commit 6dbc4c095badd400e024510554a42a0dc018ae42. * refactor(sisyphus-task): rename background to run_in_background * fix(oracle): use gpt-5.2 as default model * test(sisyphus-task): add resume with background parameter tests * feat(start-work): auto-select single incomplete plan and use system-reminder format - Auto-select when only one incomplete plan exists among multiple - Wrap multiple plans message in <system-reminder> tag - Change prompt to 'ask user' style for agent guidance - Add 'All Plans Complete' state handling * feat(sisyphus-task): make skills parameter required - Add validation for skills parameter (must be provided, use [] if empty) - Update schema to remove .optional() - Update type definition to make skills non-optional - Fix existing tests to include skills parameter * fix: prevent session model change when sending notifications - background-agent: use only parentModel, remove prevMessage fallback - todo-continuation: don't pass model to preserve session's lastModel - Remove unused imports (findNearestMessageWithFields, fs, path) Root cause: session.prompt with model param changes session's lastModel * fix(sisyphus-orchestrator): register handler in event loop for boulder continuation * fix(sisyphus_task): use promptAsync for sync mode to preserve main session - session.prompt() changes the active session, causing UI model switch - Switch to promptAsync + polling to avoid main session state change - Matches background-agent pattern for consistency * fix(sisyphus-orchestrator): only trigger boulder continuation for orchestrator-sisyphus agent * feat(background-agent): add parentAgent tracking to preserve agent context in background tasks - Add parentAgent field to BackgroundTask, LaunchInput, and ResumeInput interfaces - Pass parentAgent through background task manager to preserve agent identity - Update sisyphus-orchestrator to set orchestrator-sisyphus agent context - Add session tracking for background agents to prevent context loss - Propagate agent context in background-task and sisyphus-task tools This ensures background/subagent spawned tasks maintain proper agent context for notifications and continuity. 🤖 Generated with assistance of oh-my-opencode * fix(antigravity): sync plugin.ts with PKCE-removed oauth.ts API Remove decodeState import and update OAuth flow to use simple state string comparison for CSRF protection instead of PKCE verifier. Update exchangeCode calls to match new signature (code, redirectUri, clientId, clientSecret). * fix(hook-message-injector): preserve agent info with two-pass message lookup findNearestMessageWithFields now has a fallback pass that returns messages with ANY useful field (agent OR model) instead of requiring ALL fields. This prevents parentAgent from being lost when stored messages don't have complete model info. * fix(sisyphus-task): use SDK session.messages API for parent agent lookup Background task notifications were showing 'build' agent instead of the actual parent agent (e.g., 'Sisyphus'). The hook-injected message storage only contains limited info; the actual agent name is in the SDK session. Changes: - Add getParentAgentFromSdk() to query SDK messages API - Look up agent from SDK first, fallback to hook-injected messages - Ensures background tasks correctly preserve parent agent context * fix(sisyphus-task): use ctx.agent directly for parentAgent The tool context already provides the agent name via ctx.agent. The previous SDK session.messages lookup was completely wrong - SDK messages don't store agent info per message. Removes useless getParentAgentFromSdk function. * feat(prometheus-md-only): allow .md files anywhere, only block code files Prometheus (Planner) can now write .md files anywhere, not just .sisyphus/. Still blocks non-.md files (code) to enforce read-only planning for code. This allows planners to write commentary and analysis in markdown format. * Revert "feat(prometheus-md-only): allow .md files anywhere, only block code files" This reverts commit c600111. * fix(momus): accept bracket-style system directives in input validation Momus was rejecting inputs with bracket-style directives like [analyze-mode] and [SYSTEM DIRECTIVE...] because it only recognized XML-style tags. Now accepts: - XML tags: <system-reminder>, <context>, etc. - Bracket blocks: [analyze-mode], [SYSTEM DIRECTIVE...], [SYSTEM REMINDER...], etc. * fix(sisyphus-orchestrator): inject delegation warning before Write/Edit outside .sisyphus - Add ORCHESTRATOR_DELEGATION_REQUIRED strong warning in tool.execute.before - Fix tool.execute.after filePath detection using pendingFilePaths Map - before stores filePath by callID, after retrieves and deletes it - Fixes bug where output.metadata.filePath was undefined * docs: add orchestration, category-skill, and CLI guides * fix(cli): correct category names in Antigravity migration (visual → visual-engineering) * fix(sisyphus-task): prevent infinite polling when session removed from status * fix(tests): update outdated test expectations - constants.test.ts: Update endpoint count (2→3) and token buffer (50min→60sec) - token.test.ts: Update expiry tests to use 60-second buffer - sisyphus-orchestrator: Add fallback to output.metadata.filePath when callID missing --------- Co-authored-by: Sisyphus <[email protected]>
Add missing agent names to Zod schema: - BuiltinAgentNameSchema - OverridableAgentNameSchema - AgentOverridesSchema This allows orchestrator-sisyphus and Momus (Plan Reviewer) to be properly validated in oh-my-opencode.json config files. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <[email protected]>
#615) * fix: prevent auto-update from downgrading prerelease/dist-tag versions The auto-update checker was incorrectly updating pinned prerelease versions (e.g., 3.0.0-beta.1) and dist-tags (e.g., @beta) to the stable latest version from npm, effectively downgrading users who opted into beta. Added isPrereleaseOrDistTag() check that skips auto-update when: - Version contains '-' (prerelease like 3.0.0-beta.1) - Version is a dist-tag (non-semver like beta, next, canary) Fixes #613 * refactor: export version helpers and import in tests Address review feedback: export isPrereleaseVersion, isDistTag, and isPrereleaseOrDistTag from index.ts and import them in tests instead of duplicating the logic.
…c investigation (#377)
Previously, orchestrator-sisyphus agent had hardcoded model and didn't accept model parameter, making config overrides ineffective. - Add model param to OrchestratorContext interface - Use ctx?.model ?? DEFAULT_MODEL pattern (consistent with Sisyphus) - Pass model override from config to createOrchestratorSisyphusAgent
Convert static agent exports to factory functions for consistency: - Metis: add createMetisAgent(model) factory function - Update agentSources to use createMetisAgent, createMomusAgent This ensures model overrides work consistently across all agents.
When user has a prerelease version (e.g., 3.0.0-beta.1) installed without pinning the version in config (just 'oh-my-opencode' without @Version), auto-update was incorrectly downgrading to the latest stable version. Now checks if currentVersion is a prerelease before auto-updating, preventing unintended downgrades regardless of pinning status.
npm requires --tag flag when publishing prerelease versions. Extracts tag from version string (e.g., 'beta' from '3.0.0-beta.2').
…tifications When parentAgent is undefined, omit the agent field entirely from session.prompt body instead of passing undefined. This prevents the OpenCode SDK from falling back to defaultAgent(), which would change the parent session's agent context. Changes: - manager.ts: Build prompt body conditionally, only include agent/model when defined - background-task/tools.ts: Use ctx.agent as primary source for parentAgent (consistent with sisyphus-task) - registerExternalTask: Add parentAgent parameter support - Added tests for agent context preservation scenarios
- Add test for starting new loop while previous loop active (different session) - Add test for restarting loop in same session - Verifies startLoop properly overwrites state and resets iteration
- Extract body during initial parseFrontmatter call - Rename lazyContent → eagerLoader with rationale comment - Eliminates redundant file read and race condition
…gent response The implementation preserves original subagent responses for debugging failed tasks. Updated test assertion from .not.toContain() to .toContain() to match this behavior.
Allow optional model variant config for agents and categories. Propagate category variants into task model payloads so category-driven runs inherit provider-specific variants. Closes: #647
Previously, the install command would delete the entire 'agents' object from the user's oh-my-opencode config before merging new install settings. This caused all user customizations to be lost on reinstall. Fixed by removing the 'delete existing.agents' line and relying on the existing deepMerge function to properly merge configs, preserving user customizations while updating only the fields specified by the installer. Fixes #556
Allow Sisyphus and orchestrator-sisyphus agents to use OpenCode's question tool for interactive user prompts. OpenCode defaults question permission to "deny" for all agents except build/plan.
- Root: Add Prometheus/Metis/Momus agents, MCP architecture, 82 test files - agents/: Document 7-section delegation and wisdom notepad - auth/: Multi-account load balancing (10 accounts), endpoint fallback - features/: Update background-agent 825 lines, builtin-skills 1230 lines - hooks/: 22+ hooks with event timing details - tools/: sisyphus-task 583 lines, LSP client 632 lines - cli/: config-manager 725 lines, 17+ doctor checks - shared/: Cross-cutting utilities with usage patterns
…ncy release - manager.ts: Release concurrency key immediately on task completion, not after retention - call-omo-agent: Add polling loop for sync agent completion detection - sisyphus-task: Add abort handling, improve poll logging for debugging
…theus Restrict question tool to primary agents only: - Remove from orchestrator-sisyphus (subagent orchestration) - Add to prometheus (planner needs to ask clarifying questions)
…ent deny Use version-aware permission system instead of hardcoded tools object. This ensures call_omo_agent is properly denied on both old (tools) and new (permission) OpenCode versions.
…l_omo_agent deny" This reverts commit 9011111eb0575fcdc630fd33043e5524640adfe0.
…cting recursive calls - Enable call_omo_agent tool for skill execution in BackgroundManager - Enable call_omo_agent tool for agent execution in BackgroundManager - Enable call_omo_agent tool for sisyphus_task resume operations - Enable call_omo_agent tool for sisyphus_task category-based delegation - Restrict recursive task and sisyphus_task calls to prevent loops - Allows background agents to delegate to other agents cleanly 🤖 Generated with OhMyOpenCode assistance
Allow Sisyphus-Junior (category-based tasks) to spawn explore/librarian agents via call_omo_agent for research capabilities. Changes: - Remove call_omo_agent from BLOCKED_TOOLS in sisyphus-junior.ts - Update prompt to show ALLOWED status for call_omo_agent - Remove global call_omo_agent blocking in config-handler.ts - Keep blocking for orchestrator-sisyphus (use sisyphus_task instead) - Keep runtime recursion prevention in index.ts for explore/librarian Co-authored-by: Sisyphus <[email protected]>
Add comprehensive unit tests for the deep-merge.ts utility functions: - isPlainObject: 11 test cases covering null, undefined, primitives, Array, Date, RegExp, and plain objects - deepMerge: 15 test cases covering: - Basic object merging - Deep nested object merging - Edge cases (undefined handling) - Array replacement behavior - Prototype pollution protection (DANGEROUS_KEYS) - MAX_DEPTH limit handling
When merging user and project configs, categories were simply spread instead of deep merged. This caused user-level category model settings to be completely overwritten by project-level configs, even when the project config only specified partial overrides like temperature. Add deepMerge for categories field and comprehensive tests.
|
my goodness.. that rebase failed spectacularly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
18 issues found across 168 files (changes from recent commits).
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="package.json">
<violation number="1" location="package.json:3">
P2: Version should not be bumped manually in package.json; CI handles versioning per project deployment rules.</violation>
</file>
<file name="src/features/context-injector/injector.ts">
<violation number="1" location="src/features/context-injector/injector.ts:137">
P2: Returning early when no text part exists drops the pending context because it was already consumed, so context injection never happens for file-only user messages.</violation>
</file>
<file name="src/features/builtin-commands/templates/init-deep.ts">
<violation number="1" location="src/features/builtin-commands/templates/init-deep.ts:48">
P2: All six initial explore-agent calls switched to `sisyphus_task` but omit the required `run_in_background` and `skills` arguments, so the documented workflow now errors whenever executed.</violation>
<violation number="2" location="src/features/builtin-commands/templates/init-deep.ts:79">
P2: The dynamic-agent example now shows `sisyphus_task` invocations that are missing mandatory `run_in_background` and `skills` arguments, so the documented scaling recipe cannot run.</violation>
<violation number="3" location="src/features/builtin-commands/templates/init-deep.ts:243">
P2: Launching document-writer agents via `sisyphus_task` now lacks the required `run_in_background` and `skills` arguments, so the generation step fails instead of creating subdirectory AGENTS.md files.</violation>
</file>
<file name="src/cli/config-manager.ts">
<violation number="1" location="src/cli/config-manager.ts:316">
P2: Use Antigravity-prefixed Gemini model names so category overrides route through the intended quota.</violation>
</file>
<file name="src/agents/AGENTS.md">
<violation number="1" location="src/agents/AGENTS.md:35">
P2: The agent table now uses the non-existent name `frontend-ui-ux`; it should match the actual `frontend-ui-ux-engineer` key so readers configure the correct agent.</violation>
</file>
<file name="src/features/background-agent/manager.ts">
<violation number="1" location="src/features/background-agent/manager.ts:395">
P2: Race condition: Missing status re-check after async validation. The task status could change between the initial check and when this callback executes, potentially causing double notifications or status corruption.</violation>
</file>
<file name="src/features/builtin-skills/git-master/SKILL.md">
<violation number="1" location="src/features/builtin-skills/git-master/SKILL.md:228">
P2: The minimum-commit formula contradicts the earlier “NO EXCEPTIONS” rule, so agents get incompatible instructions.</violation>
<violation number="2" location="src/features/builtin-skills/git-master/SKILL.md:663">
P2: The final file-count checklist repeats the conflicting ceil(N/3) limits, so the document gives mutually exclusive commit-splitting requirements.</violation>
</file>
<file name="src/features/AGENTS.md">
<violation number="1" location="src/features/AGENTS.md:23">
P3: `context-injector/` is listed twice in the structure tree, making the documented directory layout inaccurate.</violation>
</file>
<file name="src/config/schema.ts">
<violation number="1" location="src/config/schema.ts:44">
P2: `Prometheus (Planner)` was added to the overridable-agent list but not to `BuiltinAgentNameSchema`, so the new agent name is still invalid anywhere `AgentName`/`BuiltinAgentNameSchema` is used (e.g., `disabled_agents`). Add the same literal to `BuiltinAgentNameSchema` to keep the schemas in sync.</violation>
</file>
<file name="src/auth/antigravity/thinking.ts">
<violation number="1" location="src/auth/antigravity/thinking.ts:744">
P2: Honor the includeThoughts flag instead of forcing include_thoughts to true so user-provided thinkingConfig settings are respected.</violation>
</file>
<file name="src/features/boulder-state/storage.ts">
<violation number="1" location="src/features/boulder-state/storage.ts:114">
P2: `getPlanProgress` ignores indented checklist items because the regex requires column‑0 bullets, so nested tasks are never counted. Allow optional leading whitespace so nested markdown checkboxes contribute to progress.</violation>
</file>
<file name="src/auth/antigravity/oauth.ts">
<violation number="1" location="src/auth/antigravity/oauth.ts:47">
P2: buildAuthURL() now ignores projectId entirely (it’s no longer encoded/preserved across the redirect). This can break flows that relied on projectId being recovered after callback. Either remove projectId from the API, or include it in the state mechanism again (and validate it on callback).</violation>
<violation number="2" location="src/auth/antigravity/oauth.ts:56">
P0: PKCE was removed from the OAuth authorization-code flow (no code_challenge in the auth URL and no code_verifier in the token exchange). For a localhost/CLI-style “public client” flow this weakens protection against authorization-code interception and is a regression in the existing security posture. Reintroduce PKCE (S256) and persist the verifier alongside state (in-memory map keyed by state, or encoded state) so exchangeCode includes code_verifier again.</violation>
<violation number="3" location="src/auth/antigravity/oauth.ts:213">
P2: The Bun.serve fallback catches all errors and silently retries on a random port, which can hide real server-startup problems (not just “port in use”). Narrow the fallback to address-in-use errors and rethrow anything else so startup failures aren’t masked.</violation>
<violation number="4" location="src/auth/antigravity/oauth.ts:276">
P2: Use serverHandle.redirectUri instead of rebuilding the redirect URI string manually, to ensure the token exchange uses the exact same redirect URI the callback server is bound to.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| url.searchParams.set("state", encodeState(state)) | ||
| url.searchParams.set("code_challenge", pkce.challenge) | ||
| url.searchParams.set("code_challenge_method", "S256") | ||
| url.searchParams.set("state", state) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P0: PKCE was removed from the OAuth authorization-code flow (no code_challenge in the auth URL and no code_verifier in the token exchange). For a localhost/CLI-style “public client” flow this weakens protection against authorization-code interception and is a regression in the existing security posture. Reintroduce PKCE (S256) and persist the verifier alongside state (in-memory map keyed by state, or encoded state) so exchangeCode includes code_verifier again.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/auth/antigravity/oauth.ts, line 56:
<comment>PKCE was removed from the OAuth authorization-code flow (no code_challenge in the auth URL and no code_verifier in the token exchange). For a localhost/CLI-style “public client” flow this weakens protection against authorization-code interception and is a regression in the existing security posture. Reintroduce PKCE (S256) and persist the verifier alongside state (in-memory map keyed by state, or encoded state) so exchangeCode includes code_verifier again.</comment>
<file context>
@@ -136,42 +53,37 @@ export async function buildAuthURL(
- url.searchParams.set("state", encodeState(state))
- url.searchParams.set("code_challenge", pkce.challenge)
- url.searchParams.set("code_challenge_method", "S256")
+ url.searchParams.set("state", state)
url.searchParams.set("access_type", "offline")
url.searchParams.set("prompt", "consent")
</file context>
| { | ||
| "name": "oh-my-opencode", | ||
| "version": "2.14.0", | ||
| "version": "3.0.0-beta.5", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Version should not be bumped manually in package.json; CI handles versioning per project deployment rules.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 3:
<comment>Version should not be bumped manually in package.json; CI handles versioning per project deployment rules.</comment>
<file context>
@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode",
- "version": "2.14.0",
+ "version": "3.0.0-beta.5",
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
"main": "dist/index.js",
</file context>
| time: { start: now, end: now }, | ||
| } as Part, | ||
| ], | ||
| if (textPartIndex === -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Returning early when no text part exists drops the pending context because it was already consumed, so context injection never happens for file-only user messages.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/context-injector/injector.ts, line 137:
<comment>Returning early when no text part exists drops the pending context because it was already consumed, so context injection never happens for file-only user messages.</comment>
<file context>
@@ -109,47 +130,26 @@ export function createContextInjectorMessagesTransformHook(
- time: { start: now, end: now },
- } as Part,
- ],
+ if (textPartIndex === -1) {
+ log("[context-injector] No text part found in last user message, skipping injection", {
+ sessionID,
</file context>
| \`\`\` | ||
| for loc in AGENTS_LOCATIONS (except root): | ||
| background_task(agent="document-writer", prompt=\\\` | ||
| sisyphus_task(agent="document-writer", prompt=\\\` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Launching document-writer agents via sisyphus_task now lacks the required run_in_background and skills arguments, so the generation step fails instead of creating subdirectory AGENTS.md files.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/builtin-commands/templates/init-deep.ts, line 243:
<comment>Launching document-writer agents via `sisyphus_task` now lacks the required `run_in_background` and `skills` arguments, so the generation step fails instead of creating subdirectory AGENTS.md files.</comment>
<file context>
@@ -240,7 +240,7 @@ Launch document-writer agents for each location:
\`\`\`
for loc in AGENTS_LOCATIONS (except root):
- background_task(agent="document-writer", prompt=\\\`
+ sisyphus_task(agent="document-writer", prompt=\\\`
Generate AGENTS.md for: \${loc.path}
- Reason: \${loc.reason}
</file context>
| sisyphus_task(agent="document-writer", prompt=\\\` | |
| sisyphus_task(agent="document-writer", run_in_background=true, skills=[], prompt=\\\` |
| sisyphus_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots") | ||
| sisyphus_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions") | ||
| sisyphus_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The dynamic-agent example now shows sisyphus_task invocations that are missing mandatory run_in_background and skills arguments, so the documented scaling recipe cannot run.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/builtin-commands/templates/init-deep.ts, line 79:
<comment>The dynamic-agent example now shows `sisyphus_task` invocations that are missing mandatory `run_in_background` and `skills` arguments, so the documented scaling recipe cannot run.</comment>
<file context>
@@ -76,9 +76,9 @@ max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' |
-background_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
-background_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
-background_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories")
+sisyphus_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
+sisyphus_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
+sisyphus_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories")
</file context>
| sisyphus_task(agent="explore", prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots") | |
| sisyphus_task(agent="explore", prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions") | |
| sisyphus_task(agent="explore", prompt="Cross-cutting concerns: FIND shared utilities across directories") | |
| sisyphus_task(agent="explore", run_in_background=true, skills=[], prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots") | |
| sisyphus_task(agent="explore", run_in_background=true, skills=[], prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions") | |
| sisyphus_task(agent="explore", run_in_background=true, skills=[], prompt="Cross-cutting concerns: FIND shared utilities across directories") |
| const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || [] | ||
| const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: getPlanProgress ignores indented checklist items because the regex requires column‑0 bullets, so nested tasks are never counted. Allow optional leading whitespace so nested markdown checkboxes contribute to progress.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/boulder-state/storage.ts, line 114:
<comment>`getPlanProgress` ignores indented checklist items because the regex requires column‑0 bullets, so nested tasks are never counted. Allow optional leading whitespace so nested markdown checkboxes contribute to progress.</comment>
<file context>
@@ -0,0 +1,150 @@
+ const content = readFileSync(planPath, "utf-8")
+
+ // Match markdown checkboxes: - [ ] or - [x] or - [X]
+ const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || []
+ const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || []
+
</file context>
| const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || [] | |
| const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || [] | |
| const uncheckedMatches = content.match(/^\s*[-*]\s*\[\s*\]/gm) || [] | |
| const checkedMatches = content.match(/^\s*[-*]\s*\[[xX]\]/gm) || [] |
| } | ||
|
|
||
| const tokens = await exchangeCode(callback.code, auth.verifier, clientId, clientSecret, serverHandle.port) | ||
| const redirectUri = `http://localhost:${serverHandle.port}/oauth-callback` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Use serverHandle.redirectUri instead of rebuilding the redirect URI string manually, to ensure the token exchange uses the exact same redirect URI the callback server is bound to.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/auth/antigravity/oauth.ts, line 276:
<comment>Use serverHandle.redirectUri instead of rebuilding the redirect URI string manually, to ensure the token exchange uses the exact same redirect URI the callback server is bound to.</comment>
<file context>
@@ -345,15 +269,15 @@ export async function performOAuthFlow(
}
- const tokens = await exchangeCode(callback.code, auth.verifier, clientId, clientSecret, serverHandle.port)
+ const redirectUri = `http://localhost:${serverHandle.port}/oauth-callback`
+ const tokens = await exchangeCode(callback.code, redirectUri, clientId, clientSecret)
const userInfo = await fetchUserInfo(tokens.access_token)
</file context>
| const redirectUri = `http://localhost:${serverHandle.port}/oauth-callback` | |
| const redirectUri = serverHandle.redirectUri |
| } catch (error) { | ||
| server = Bun.serve({ | ||
| port: 0, | ||
| fetch: fetchHandler, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The Bun.serve fallback catches all errors and silently retries on a random port, which can hide real server-startup problems (not just “port in use”). Narrow the fallback to address-in-use errors and rethrow anything else so startup failures aren’t masked.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/auth/antigravity/oauth.ts, line 213:
<comment>The Bun.serve fallback catches all errors and silently retries on a random port, which can hide real server-startup problems (not just “port in use”). Narrow the fallback to address-in-use errors and rethrow anything else so startup failures aren’t masked.</comment>
<file context>
@@ -259,43 +172,53 @@ export function startCallbackServer(
+ port: ANTIGRAVITY_CALLBACK_PORT,
+ fetch: fetchHandler,
+ })
+ } catch (error) {
+ server = Bun.serve({
+ port: 0,
</file context>
| } catch (error) { | |
| server = Bun.serve({ | |
| port: 0, | |
| fetch: fetchHandler, | |
| }) | |
| } | |
| } catch (error) { | |
| const message = error instanceof Error ? error.message : String(error) | |
| if (!message.includes("EADDRINUSE")) { | |
| throw error | |
| } | |
| server = Bun.serve({ | |
| port: 0, | |
| fetch: fetchHandler, | |
| }) | |
| } |
| verifier: pkce.verifier, | ||
| projectId, | ||
| } | ||
| const state = crypto.randomUUID().replace(/-/g, "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: buildAuthURL() now ignores projectId entirely (it’s no longer encoded/preserved across the redirect). This can break flows that relied on projectId being recovered after callback. Either remove projectId from the API, or include it in the state mechanism again (and validate it on callback).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/auth/antigravity/oauth.ts, line 47:
<comment>buildAuthURL() now ignores projectId entirely (it’s no longer encoded/preserved across the redirect). This can break flows that relied on projectId being recovered after callback. Either remove projectId from the API, or include it in the state mechanism again (and validate it on callback).</comment>
<file context>
@@ -64,70 +39,12 @@ export interface CallbackResult {
- verifier: pkce.verifier,
- projectId,
- }
+ const state = crypto.randomUUID().replace(/-/g, "")
const redirectUri = `http://localhost:${port}/oauth-callback`
</file context>
| ├── claude-code-plugin-loader/ # installed_plugins.json (484 lines) | ||
| ├── claude-code-plugin-loader/ # installed_plugins.json | ||
| ├── claude-code-session-state/ # Session state persistence | ||
| ├── context-injector/ # Context collection and injection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: context-injector/ is listed twice in the structure tree, making the documented directory layout inaccurate.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/AGENTS.md, line 23:
<comment>`context-injector/` is listed twice in the structure tree, making the documented directory layout inaccurate.</comment>
<file context>
@@ -1,29 +1,34 @@
-├── claude-code-plugin-loader/ # installed_plugins.json (484 lines)
+├── claude-code-plugin-loader/ # installed_plugins.json
├── claude-code-session-state/ # Session state persistence
+├── context-injector/ # Context collection and injection
├── opencode-skill-loader/ # Skills from OpenCode + Claude paths
├── skill-mcp-manager/ # MCP servers in skill YAML
</file context>
|
Replaced by #753 - the original PR was contaminated by a bad rebase that included 101 upstream commits. |
Summary
Fixes #577 - TODO continuation hook now reliably stops when users interrupt with ESC ESC.
Problem
The current API-based abort detection has a race condition:
session.idlefires, OpenCode may not have persisted the error field to message store yetisLastAssistantMessageAborted()returns false even though user interruptedSolution
Hybrid Approach: Combine event-based (primary) + API-based (fallback) detection
Event-Based Detection (Primary)
session.errorevent whenerror.name === "MessageAbortedError" || "AbortError"abortDetectedAttimestamp in session statesession.idlewith 3s time windowAPI-Based Detection (Fallback)
session.messages()API checkChanges
abortDetectedAt?: numbertoSessionStatesession.errorhandlersession.idle(before API call)Testing
Added 8 new test cases covering:
All 663 tests pass ✅
Why This Works
The ralph-loop hook already uses event-based detection successfully (line 336). The previous event-based implementation was removed due to "unreliable tests", but the approach itself is sound—it's the most reliable way to detect real-time aborts.
References
MessageAbortedErrorandAbortErrorare official error typessession.erroreventsSummary by cubic
Fixes #577. Makes TODO continuation stop reliably on ESC ESC by using hybrid abort detection and removing the API-only race condition.
Written for commit 6cd3e0a. Summary will update on new commits.