Skip to content

Conversation

@sisyphus-dev-ai
Copy link
Collaborator

@sisyphus-dev-ai sisyphus-dev-ai commented Jan 7, 2026

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:

  • When session.idle fires, OpenCode may not have persisted the error field to message store yet
  • Result: isLastAssistantMessageAborted() returns false even though user interrupted
  • TODO continuation proceeds despite ESC ESC

Solution

Hybrid Approach: Combine event-based (primary) + API-based (fallback) detection

Event-Based Detection (Primary)

  • Track abort via session.error event when error.name === "MessageAbortedError" || "AbortError"
  • Store abortDetectedAt timestamp in session state
  • Check on session.idle with 3s time window
  • Clear flag on new activity (user message, assistant response, tool execution)

API-Based Detection (Fallback)

  • Keep existing session.messages() API check
  • Catches cases where event was missed (e.g., plugin loaded after abort)

Changes

  • Add abortDetectedAt?: number to SessionState
  • Detect and track abort in session.error handler
  • Check abort flag FIRST in session.idle (before API call)
  • Clear abort flag on user/assistant messages and tool execution
  • Update log messages to distinguish event vs API detection

Testing

Added 8 new test cases covering:

  • ✅ Event-based abort detection (MessageAbortedError)
  • ✅ Event-based abort detection (AbortError)
  • ✅ Stale abort flag handling (>3s old)
  • ✅ Abort flag cleared by user message
  • ✅ Abort flag cleared by assistant message
  • ✅ Abort flag cleared by tool execution
  • ✅ Event-based wins when API doesn't show abort
  • ✅ API fallback works when event missed

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

  • OpenCode SDK: MessageAbortedError and AbortError are official error types
  • Oracle's strategic analysis: Hybrid approach balances reliability + testability
  • Librarian's research: OpenCode exposes abort state via session.error events

Summary by cubic

Fixes #577. Makes TODO continuation stop reliably on ESC ESC by using hybrid abort detection and removing the API-only race condition.

  • Bug Fixes
    • Primary event-based detection: handle session.error for MessageAbortedError/AbortError, store timestamp, 3s window.
    • Fallback API check: verify last assistant message abort via session.messages if event was missed.
    • Clear abort flag on user/assistant messages and tool execution; event wins over API; improved log messages.
    • Added abortDetectedAt to session state; kept existing behavior for countdown handling.
    • 8 new tests cover event detection, API fallback, stale flags, and flag clearing (all passing).

Written for commit 6cd3e0a. Summary will update on new commits.

- 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
Copy link

@greptile-apps greptile-apps bot left a 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 abortDetectedAt timestamp to SessionState for tracking abort events in real-time
  • Event handler captures MessageAbortedError and AbortError from session.error events
  • 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/#then BDD 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-loop hook, 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
Loading

Copy link

@cubic-dev-ai cubic-dev-ai bot left a 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.

@kdcokenny
Copy link
Collaborator

@sisyphus-dev-ai review

@sisyphus-dev-ai sisyphus-dev-ai added the sisyphus: working Sisyphus is currently working on this label Jan 13, 2026
@sisyphus-dev-ai
Copy link
Collaborator Author

Code Review: Hybrid Abort Detection for TODO Continuation

Summary

This 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

  1. Solid Architecture

    • Event-based detection via session.error events (primary, most reliable)
    • API-based detection via session.messages() (fallback for missed events)
    • This hybrid approach addresses the race condition effectively
  2. Comprehensive Test Coverage

    • 8 new test cases covering all scenarios:
      • Event-based detection (MessageAbortedError and AbortError)
      • Stale flag handling (>3s window)
      • Flag clearing on user/assistant/tool activity
      • Hybrid detection scenarios (event wins over API, API fallback)
    • All tests follow BDD conventions with #given/#when/#then comments ✓
  3. Smart State Management

    • 3-second time window prevents stale abort flags from blocking legitimate continuations
    • Automatic flag clearing on new activity (user messages, assistant responses, tool executions)
    • Proper cleanup on session deletion
  4. Code Quality

    • Follows project conventions (logging patterns, error handling)
    • Clear, descriptive variable names
    • Well-commented implementation
    • No type errors

⚠️ Critical Issue: Stale Branch

The PR branch is outdated and missing recent changes from dev:

  • Missing: skipAgents feature from THE ORCHESTRATOR PR (THE ORCHESTRATOR #600) src/hooks/todo-continuation-enforcer.ts:14-16

    • Current PR branch: Missing skipAgents?: string[] in TodoContinuationEnforcerOptions
    • Current PR branch: Missing const DEFAULT_SKIP_AGENTS = ["Prometheus (Planner)"]
    • Latest dev branch: Has both (introduced in THE ORCHESTRATOR #600)
  • Impact: Without this feature, the Prometheus (Planner) agent will have todo-continuation enforced on it, which may not be desired behavior

  • Root Cause: The PR branch was created from commit 68655bf ("chore: changes by sisyphus-dev-ai"), but dev has moved forward with 100+ commits, including THE ORCHESTRATOR PR (THE ORCHESTRATOR #600) that modified the same file


🔧 Required Actions

  1. Rebase or merge with latest dev branch

    git fetch origin dev
    git rebase origin/dev
    # or
    git merge origin/dev
  2. Resolve any merge conflicts (likely in todo-continuation-enforcer.ts)

    • Preserve your abort detection changes
    • Integrate the skipAgents feature from dev
  3. Run full test suite to ensure no regressions from recent changes

    bun test

📝 Implementation Details Verified

Event Handler (lines 257-262):

  • ✓ Captures MessageAbortedError and AbortError
  • ✓ Stores timestamp in state.abortDetectedAt
  • ✓ Logs detection with session ID and error name

Abort Check (lines 291-301):

  • ✓ Checks if abortDetectedAt exists
  • ✓ Validates 3-second window (ABORT_WINDOW_MS)
  • ✓ Skips continuation if recent abort detected
  • ✓ Clears flag after checking

Flag Clearing:

  • ✓ User messages: line 368
  • ✓ Assistant messages: lines 374, 387
  • ✓ Tool execution: line 397

API Fallback (lines 312-326):

  • ✓ Retains original API-based check
  • ✓ Logs as "API fallback" when detected

🎯 Recommendation

After rebasing with dev: This PR is ready to merge. The hybrid abort detection is a well-thought-out solution that addresses the race condition while maintaining backward compatibility through the API fallback.

Before rebasing: The PR needs to be updated to include recent dev changes.


Review Score: 4.5/5 (would be 5/5 after rebase)

  • Implementation: 5/5
  • Test Coverage: 5/5
  • Code Quality: 5/5
  • Branch Freshness: 1/5 ⚠️

@sisyphus-dev-ai sisyphus-dev-ai removed the sisyphus: working Sisyphus is currently working on this label Jan 13, 2026
popododo0720 and others added 22 commits January 13, 2026 10:23
…#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.
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
KNN-07 and others added 23 commits January 13, 2026 10:23
- 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.
@kdcokenny
Copy link
Collaborator

my goodness.. that rebase failed spectacularly

@kdcokenny kdcokenny marked this pull request as draft January 13, 2026 15:31
Copy link

@cubic-dev-ai cubic-dev-ai bot left a 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)
Copy link

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",
Copy link

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) {
Copy link

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=\\\`
Copy link

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>
Suggested change
sisyphus_task(agent="document-writer", prompt=\\\`
sisyphus_task(agent="document-writer", run_in_background=true, skills=[], prompt=\\\`

Comment on lines +79 to +81
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")
Copy link

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>
Suggested change
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")

Comment on lines +114 to +115
const uncheckedMatches = content.match(/^[-*]\s*\[\s*\]/gm) || []
const checkedMatches = content.match(/^[-*]\s*\[[xX]\]/gm) || []
Copy link

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>
Suggested change
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`
Copy link

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>
Suggested change
const redirectUri = `http://localhost:${serverHandle.port}/oauth-callback`
const redirectUri = serverHandle.redirectUri

Comment on lines +213 to +218
} catch (error) {
server = Bun.serve({
port: 0,
fetch: fetchHandler,
})
}
Copy link

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>
Suggested change
} 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, "")
Copy link

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
Copy link

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>

@kdcokenny
Copy link
Collaborator

Replaced by #753 - the original PR was contaminated by a bad rebase that included 101 upstream commits.

@kdcokenny kdcokenny closed this Jan 13, 2026
@kdcokenny kdcokenny deleted the fix/577-hybrid-abort-detection branch January 13, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: TODO Continuation is too aggressive when user interrupts agent