opencode 1.3.16 bundles zod v3 internally and accesses _zod.def in
toJsonSchema. When oh-my-openagent installed zod v4, schemas from our
plugin caused a TypeError crash on any tool execution.
We only use basic z.* APIs with no v4-specific features, so pinning
to ^3.24.0 is safe and restores full compatibility.
These agents should only be usable as primary session agents, not as
subagent targets via call_omo_agent/task(). Previously MODE was 'all'
which allowed them to be spawned as subagents, leading to confusing
behavior (e.g. Atlas delegating to Hephaestus as a subagent).
Subagent-callable agents remain: oracle, explore, librarian,
multimodal-looker, metis, momus, sisyphus-junior.
Note: Prometheus is not a BuiltinAgentName and is only invoked via
slash commands, so no change needed there.
- Remove leading ./ from bin entry (npm strips invalid paths)
- Write schema to dist/ for export map compatibility (keep assets/ for GitHub URL)
- Remove unused codex dep + bump @modelcontextprotocol/sdk to ^1.25.2
- Fix broken relative link in configuration.md (../guide/installation.md)
🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
Add discoverProjectAgentsSkills() for project-level .agents/skills/ and
discoverGlobalAgentsSkills() for ~/.agents/skills/ — matching OpenCode's
native skill discovery paths (https://opencode.ai/docs/skills/).
Updated discoverAllSkills(), discoverSkills(), and createSkillContext()
to include these new sources with correct priority ordering.
Co-authored-by: dtateks <dtateks@users.noreply.github.com>
Closes#1818
The SSE event stream subscription was missing the directory parameter,
causing the OpenCode server to only emit global events (heartbeat,
connected, toast) but not session-scoped events (session.idle,
session.status, tool.execute, message.updated, message.part.updated).
Without session events:
- hasReceivedMeaningfulWork stays false (no message/tool events)
- mainSessionIdle never updates (no session.idle/status events)
- pollForCompletion either hangs or exits for unrelated reasons
Fix: Pass { directory } to client.event.subscribe(), matching the
pattern already used by client.session.promptAsync().
Also adds a stabilization period (10s) after first meaningful work
as defense-in-depth against early exit race conditions.
The ralph-loop hook calls promptAsync in the implementation, but the
test mock only defined prompt(). Added promptAsync with identical
behavior to make tests pass.
- All 38 ralph-loop tests now pass
- Total test suite: 2361 pass, 3 fail (unrelated to this change)
- Added port-utils module with isPortAvailable, findAvailablePort, getAvailableServerPort
- Modified runner.ts to automatically find available port if preferred port is busy
- Shows warning message when using auto-selected port
- Eliminates need for manual OPENCODE_SERVER_PORT workaround
The auto-update-checker was operating on the wrong directory:
- CACHE_DIR (~/.cache/opencode) was used for node_modules, package.json, and bun.lock
- But plugins are installed in USER_CONFIG_DIR (~/.config/opencode)
This caused auto-updates to fail silently:
1. Update detected correctly (3.x.x -> 3.y.y)
2. invalidatePackage() tried to delete from ~/.cache/opencode (wrong!)
3. bun install ran but respected existing lockfile
4. Old version remained installed
Fix: Use USER_CONFIG_DIR consistently for all invalidation operations.
Also moves INSTALLED_PACKAGE_JSON constant to use USER_CONFIG_DIR for consistency.
- Replace setMainSession(undefined) with _resetForTesting() in keyword-detector tests
- Add _resetForTesting() to afterEach hooks for proper cleanup
- Un-skip the previously flaky mainSessionID test in state.test.ts
Fixes#848
Co-authored-by: 배지훈 <new0126@naver.com>
* refactor(lsp): migrate to vscode-jsonrpc for improved stability
Replace custom JSON-RPC implementation with vscode-jsonrpc library.
Use MessageConnection with StreamMessageReader/Writer.
Implement Bun↔Node stream bridges for compatibility.
Preserve all existing functionality (warmup, cleanup, capabilities).
Net reduction of ~60 lines while improving protocol handling.
* fix(lsp): clear timeout on successful response to prevent unhandled rejections
---------
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
- Remove mandatory model requirement from plugin initialization
- Allow OpenCode to use its built-in model fallback when user doesn't specify
- Update model-resolver to handle undefined systemDefaultModel
- Remove throw errors in config-handler, utils, atlas, delegate-task
- Add tests for optional model scenarios
Closes#1129
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
Skip all keyword detection for background task sessions to prevent mode
injection (e.g., [analyze-mode], [search-mode]) which incorrectly triggers
Prometheus planner restrictions on Sisyphus sessions.
This aligns with the existing pattern used in:
- sisyphus-orchestrator (line 504)
- todo-continuation-enforcer (line 303)
- session-notification (line 278)
Closes#713
* 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 <clio-agent@sisyphuslabs.ai>
* test(auth): add storage layer security and atomicity tests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* 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 <clio-agent@sisyphuslabs.ai>