- Add afterAll(() => { mock.restore() }) to 52 test files missing cleanup
- Rewrite create-tool-guard-hooks.test.ts to use spyOn instead of barrel mock
- Fix skill-mcp-manager OAuth tests with missing mockTokens/mockLogin definitions
- Fix start-work hook: show worktree active block on resume with existing worktree_path
- Extract createWorktreeActiveBlock to worktree-block.ts to avoid circular import
- Replace 80-line isolated test runner CI config with single `bun test` command
When a user cancels a generation (ESC x2), all three idle hooks could
enter a permanently broken state:
1. **todo-continuation-enforcer**: consecutiveFailures accumulated from
abort-caused promptAsync failures, eventually hitting MAX_CONSECUTIVE_FAILURES
and permanently stopping continuation injection.
2. **unstable-agent-babysitter**: no abort awareness at all — would keep
firing reminders after user cancelled the session.
3. **runtime-fallback**: retry dedupe keys and pending fallback state
persisted across cancellation, blocking legitimate error recovery.
Fix:
- Add shared `isAbortError()` utility for consistent abort detection
- Reset consecutiveFailures and clear stale state on AbortError in all hooks
- Track `lastCancelledAt` in todo-continuation-enforcer for abort window
- Add abort-awareness to unstable-agent-babysitter (skip if recently cancelled)
- Clear runtime-fallback retry state on abort errors
Tests: 61 pass, 0 fail across all 3 affected hook test suites.
Closes#2984
Validate tar and zip entries before extraction to prevent path traversal:
- Reject absolute paths in archives
- Reject .. traversal paths
- Reject symlinks pointing outside extraction dir
- New archive-entry-validator module with comprehensive tests
Addresses: security audit finding for unsafe archive extraction.
Deep category now uses gpt-5.4 as its default model across all providers
(openai, github-copilot, venice, opencode), matching Hephaestus's GPT 5.4
upgrade. The requiresModel constraint is removed since gpt-5.4 is widely
available. Adds openai/gpt-5.3-codex -> openai/gpt-5.4 config migration
for existing user configs. Deep category prompt optimized for GPT 5.4's
stronger native capabilities (leaner, less verbose).
3 failures in fallback.cliproxyapi-matrix.test.ts:
- Root cause: leaked spyOn(getMainSessionID) in
tool-execute-before-session-notification.test.ts was never restored,
poisoning module state for subsequent tests in the same worker
- Added mockRestore() call and _resetModelFallbackForTesting in afterEach
3 failures in background-agent/manager.test.ts:
- Root cause: connected-providers-cache memConnected/memProviderModels
persisted across test files, making isReachable() skip fallback
candidates in retry tests
- Added mock.module for connected-providers-cache at file level
- Added _resetMemCacheForTesting export and global beforeEach cleanup
Full suite: 4638/4638 pass, 0 fail
- background_output: snapshot read cursor before consuming, restore on
/undo message removal so re-reads return data (fixes#2915)
- MCP loader: preserve oauth field in transformMcpServer, add scope/
projectPath filtering so local-scoped MCPs only load in matching
directories (fixes#2917)
- runtime-fallback: add 'reached your usage limit' to retryable error
patterns so quota exhaustion triggers model fallback (fixes#2918)
Verified: bun test (4606 pass / 0 fail), tsc --noEmit clean
model_not_supported errors from providers (e.g. OpenAI returning
{"error": {"code": "model_not_supported"}}) were not recognized as
retryable. Subagents would silently fail with no response, hanging the
parent session.
Fix:
- Add "model_not_supported", "model not supported", "model is not
supported" to RETRYABLE_MESSAGE_PATTERNS in model-error-classifier.ts
- Add regex patterns to RETRYABLE_ERROR_PATTERNS in
runtime-fallback/constants.ts to match "model ... is ... not ...
supported" with flexible spacing
- Add regression test covering all three variations
Now model_not_supported errors trigger the normal fallback chain instead
of silent failure.
When opencode-skills plugin is registered alongside oh-my-openagent,
all user skills are loaded twice, causing 'Duplicate tool names detected'
warnings and HTTP 400 errors.
This fix:
1. Detects if opencode-skills plugin is loaded in opencode.json
2. Emits a startup warning explaining the conflict
3. Suggests fixes: either remove opencode-skills or disable skills in oh-my-openagent
Fixes#2881
resolveSkillPathReferences: add looksLikeFilePath() guard that requires
a file extension or trailing slash before resolving @scope/package
references. npm packages like @mycom/my_mcp_tools@beta were incorrectly
being rewritten to absolute paths in skill templates.
2 new tests.
- logLegacyPluginStartupWarning now emits console.warn (visible to user,
not just log file) when oh-my-opencode is detected in opencode.json
- Auto-migrates opencode.json plugin entry from oh-my-opencode to
oh-my-openagent (with backup)
- plugin-config.ts: add console.warn when loading legacy config filename
- test: 10 tests covering migration, console output, edge cases
The server-health module used module-level state for inProcessServerRunning,
which doesn't survive when Bun loads separate module instances in the same
process. Fix: use globalThis with Symbol.for key so the flag is truly
process-global.
- server-health.ts: replace module-level boolean with globalThis[Symbol.for()]
- export markServerRunningInProcess from tmux-utils barrel
- test: verify flag skips HTTP fetch, verify globalThis persistence
- fix(switcher): use lastIndexOf for multi-slash model IDs (e.g. aws/anthropic/claude-sonnet-4)
- fix(model-resolution): same lastIndexOf fix in doctor parseProviderModel
- fix(call-omo-agent): resolve model from agent config and forward to both
background and sync executors via DelegatedModelConfig
- fix(subagent-resolver): inherit category model/variant when agent uses
category reference without explicit model override
- test: add model override forwarding tests for call-omo-agent
- test: add multi-slash model ID test for switcher
- fix(context-limit): check modelContextLimitsCache for all Anthropic
models, not just GA-model set; user config/cache wins over 200K default
(fixes#2836)
- fix(agent-key-remapper): preserve config key aliases alongside display
names so `opencode run --agent sisyphus` resolves correctly
(fixes#2858)
- fix(tool-config): respect host permission.skill=deny by disabling
skill/skill_mcp tools when host denies them (fixes#2873)
- test: update context-limit and agent-key-remapper tests to match new
behavior