- Create src/shared/opencode-storage-paths.ts with all 4 constants
- Update 4 previous declaration sites to import from shared file
- Update additional OPENCODE_STORAGE usages for consistency
- Re-export from src/shared/index.ts
- No duplicate constant declarations remain
- When deleting tasks, prefer matching by id if present
- Fall back to content matching only when todo has no id
- Prevents deleting unrelated todos with same subject
- Add content-based fallback matching for todos without ids
- Add TODO comment for exported but unused SDK functions
- Add resetStorageClient() for test isolation
- Fixes todo duplication risk on beta (SQLite backend)
- Add src/shared/opencode-storage-paths.ts with consolidated constants
- Update imports in hook-message-injector and session-manager
- Add src/shared/opencode-storage-detection.ts with isSqliteBackend()
- Add OPENCODE_SQLITE_VERSION constant
- Export all from shared/index.ts
- Make id field optional in all Todo interfaces (TodoInfo, Todo, TodoItem)
- Fix null-unsafe comparisons in todo-sync.ts to handle missing ids
- Add test case for todos without id field preservation
- All tests pass and typecheck clean
The polling loop in executeUnstableAgentTask only checked session status
and message stability, never checking if the background task itself had
been interrupted. This caused the tool call to hang until MAX_POLL_TIME_MS
(10 minutes) when a task was interrupted by prompt errors.
Add manager.getTask() check at each poll iteration to break immediately
on terminal statuses (interrupt, error, cancelled), returning a clear
failure message instead of hanging.
Pass parentTools from session-tools-store through the background task
lifecycle (launch → task → notify) so that when notifyParentSession
sends promptAsync, the original tool restrictions (e.g., question: false)
are preserved. This prevents the Question tool from re-enabling after
call_omo_agent background tasks complete.
Call setSessionTools(sessionID, tools) before every prompt dispatch so
the tools object is captured and available for later retrieval when
background tasks complete.
LLMs sometimes pass load_skills as a serialized JSON string instead
of an array. Add defensive JSON.parse before validation to handle
this gracefully.
Fixes#1701
Community-reported-by: @omarmciver
The isBinaryAvailableOnWindows() function used spawnSync("where")
which fails even when the binary IS on PATH, causing false negatives.
Removed the redundant pre-check and let nodeSpawn handle binary
resolution naturally with proper OS-level error messages.
Fixes#1805
Replace PreToolUse hook-based question tool blocking with the existing
tools parameter approach (tools: { question: false }) which physically
removes the tool from the LLM's toolset before inference.
The hook was redundant because every session.prompt() call already passes
question: false via the tools parameter. OpenCode converts this to a
PermissionNext deny rule and deletes the tool from the toolset, preventing
the LLM from even seeing it. The hook only fired after the LLM already
called the tool, wasting tokens.
Changes:
- Remove subagent-question-blocker hook invocation from PreToolUse chain
- Remove hook registration from create-session-hooks.ts
- Delete src/hooks/subagent-question-blocker/ directory (dead code)
- Remove hook from HookNameSchema and barrel export
- Fix sync-executor.ts missing question: false in tools parameter
- Add regression tests for both the removal and the tools parameter
Extends the process.cwd() fix to cover all project-level loaders. In the desktop app, process.cwd() points to the app installation directory instead of the project directory, causing project-level agents, commands, and slash commands to not be discovered. Each function now accepts an optional directory parameter (defaulting to process.cwd() for backward compatibility) and callers pass ctx.directory from the plugin context.
When delegate-task resumes a session via session_id, the response
task_metadata now includes a subagent field identifying which agent
was running in the resumed session. This allows the parent agent to
know what type of subagent it is continuing.
- sync-continuation: uses resumeAgent extracted from session messages
- background-continuation: uses task.agent from BackgroundTask object
- Gracefully omits subagent when agent info is unavailable
- Detect namespaced commands (containing ':') from Claude marketplace plugins
- Provide clear error message explaining marketplace plugins are not supported
- Point users to .claude/commands/ as alternative for custom commands
- Fixes issue where /daplug:run-prompt gave ambiguous 'command not found'
Closes#1682
Allow individual categories to be disabled via `disable: true` in
config. Introduce shared `mergeCategories()` utility to centralize
category merging and disabled filtering across all 7 consumption sites.
Child session creation was injecting permission: { question: 'deny' } which
conflicted with OpenCode's child session permission handling, causing subagent
sessions to hang with 0 messages after creation (zombie state).
Remove the permission override from all session creators (BackgroundManager,
sync-session-creator, call-omo-agent) and rely on prompt-level tool restrictions
(tools.question=false) to maintain the intended policy.
Closes#1711
df0b9f76 regressed look_at from synchronous prompt (session.prompt) to
async prompt (session.promptAsync) + pollSessionUntilIdle polling. This
introduced a race condition where the poller fires before the server
registers the session as busy, causing it to return immediately with no
messages available.
Fix: restore promptSyncWithModelSuggestionRetry (blocking HTTP call) and
remove polling entirely. Catch prompt errors gracefully and still attempt
to fetch messages, since session.prompt may throw even on success.
- fix(background): include "interrupt" status in all terminal status checks (3 files)
- fix(background): display "INTERRUPTED" instead of "CANCELLED" for interrupted tasks
- fix(cli): add error recovery grace period in poll-for-completion
- fix(lsp): use JSONC parser for config loading to support comments
All changes verified with tests and typecheck.
- fix(delegate-task): return error on poll timeout instead of silent null
- fix(delegate-task): ensure toast and session cleanup on all error paths with try/finally
- fix(delegate-task): apply agent tool restrictions in sync-prompt-sender
- fix(plugin): add symmetric idle dedup to prevent double hook triggers
- fix(cli): replace regex-based JSONC editing with jsonc-parser in auth-plugins
- fix(cli): abort event stream after completion and restore no-timeout default
All changes verified with tests and typecheck.
- Add comprehensive TODO SYNC section documenting automatic
bidirectional sync between tasks and OpenCode todo system
- Improve sync-continuation.test.ts with proper mock modules
for pollSyncSession and fetchSyncResult dependencies
Replace unified 'task' tool documentation with 4 individual tools:
- task_create: Create task with auto-generated T-{uuid} ID
- task_list: List active tasks with summary
- task_get: Retrieve full task object by ID
- task_update: Update task fields with dependency support
Add detailed TASK TOOLS section with args tables and usage examples.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Add tests for sync-continuation error paths and toast cleanup
- Add tests for sync-result-fetcher with anchor message support
- Expand sync-session-poller tests for edge cases and completion detection
- Add bulk cleanup test for recent-synthetic-idles
- Add proper error handling in executeSyncContinuation with try-catch blocks
- Ensure toast cleanup happens in all error paths via finally block
- Add anchorMessageCount tracking for accurate result fetching after continuation
- Improve fetchSyncResult to filter messages after anchor point
- Add silent failure detection when no new response is generated
OpenCode SDK does not expose client.model.list API. This caused the
provider-models cache to always be empty (models: {}), which in turn
caused delegate-task categories with requiresModel (e.g., 'deep',
'artistry') to fail with misleading 'Unknown category' errors.
Changes:
- connected-providers-cache.ts: Extract models from provider.list()
response's .all array instead of calling non-existent client.model.list
- category-resolver.ts: Distinguish between 'unknown category' and
'model not available' errors with clearer error messages
- Add comprehensive tests for both fixes
Bug chain:
client.model?.list is undefined -> empty cache -> isModelAvailable
returns false for requiresModel categories -> null returned from
resolveCategoryConfig -> 'Unknown category' error (wrong message)
Update notification systems to display INTERRUPTED status.
Add interrupt handling to background_output tool (terminal status).
Add interrupt-specific status note to formatTaskStatus.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Category-based delegation should always route to sisyphus-junior even if
subagent_type is mistakenly provided, matching the original behavior and
preventing accidental bypass of category routing.