Adds .sisyphus/rules/test-discipline.md, auto-injected by
rulesInjector hook whenever an agent reads or edits a test file
(**/*.test.ts, __tests__/**, src/testing/**, test-setup.ts,
script/run-ci-tests.ts).
Rules enforced:
- 'bun test' must pass in one process, one run, no isolation flags
- no setTimeout/sleep in test bodies unless time is the SUT
- event tests must subscribe-before-trigger with explicit timeout
- no .only/.skip/process-isolation to mask state leaks
- prompt-builder tests must assert behavior, not text snapshots
Also un-ignores .sisyphus/rules/ so project-scope rules can be
checked in while keeping .sisyphus/{draft,run-continuation,...}
ignored.
Keep prompt reservations briefly after successful dispatch so rapid idle/message/error transitions cannot inject the same follow-up twice.
Route all production session prompt calls through the shared gate, restore skipped background resume state, release holds after abort/recovery paths, and preserve Ralph/ULW loop state when a dispatch is deferred.
Add regression coverage for session routing, static prompt route auditing, team-mode live messaging, model suggestion retries, call-omo-agent reuse, background parent wakes, runtime fallback, compaction recovery, Atlas, and Ralph/ULW loops.
Adds an opt-in `disabled_providers` config field plus the `shared/disabled-providers`
helper (`isProviderDisabled`, `filterDisabledProviderModels`, `applyDisabledProviders`)
that the plugin-config layer applies to resolved providers.
The routing changes in team-mode (team-runtime, tools/lifecycle, plugin/tool-registry)
are NOT in this PR — those are entangled with the `MemberSelectionMode` /
`ShutdownActor` refactors from the closed PR #3871 and need their own extraction
once those refactors land independently. This PR isolates the parts that are
cleanly independent: schema, helper, and config-layer wiring.
Companion to #4024 (live-tail tailer), both extracted from the closed PR #3871.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Guard the tool-pair validator when transformed assistant messages belong to a tracked subagent session, while keeping normal main-session orphaned tool_use repair intact.
Constraint: code-yeongyu/oh-my-openagent#3996 reports background Oracle sessions hanging after synthetic placeholder tool_result insertion.
Rejected: disable tool-pair-validator globally | would regress main-session compaction/orphaned tool_use repair.
Confidence: high
Scope-risk: narrow
Directive: Keep subagent skip coverage and normal repair coverage together when changing tool-pair validation.
Tested: bun test src/hooks/tool-pair-validator/hook.test.ts src/plugin/messages-transform.test.ts
Tested: bun run typecheck
Not-tested: live Oracle background task e2e; no remote push or PR comment performed.
scheduleForcedExit was called without exitAfterCleanup=true for SIGTERM/SIGINT.
After cleanup completed, timeout cleared but process.exit() never called.
Process stayed alive waiting for event loop to drain.
Benchmark (systemctl stop):
- Before: 10s+ timeout (systemd had to SIGKILL)
- After: ~30ms instant shutdown
Test results (3 runs):
- Test 1: 30ms
- Test 2: 28ms
- Test 3: 27ms
The sort shim always placed core agents (sisyphus, hephaestus, prometheus,
atlas) before any custom agent, ignoring the user's configured default_agent
in opencode.json. This caused the TUI to always show Sisyphus as the selected
agent on startup regardless of default_agent.
Add setDefaultAgentForSort() which inserts the configured default_agent at
rank 0 in the sort shim's rank map. Called from applyAgentConfig after
resolving the effective default_agent value.
Fixes#3900
Bun's --frozen-lockfile failed on origin/dev because v4.1.2 (c75deee54)
bumped the platform binary versions in package.json without refreshing
bun.lock. Regenerated via `bun install` to unblock CI on dev-based PRs.
Required for `bun install --frozen-lockfile` (used by ci.yml test +
typecheck jobs) to succeed.
When many background tasks complete in rapid succession while the parent
session is idle, each completion fired its own promptAsync call, stacking
N consecutive `<system-reminder>` user messages with no assistant turn
between. Hyperplan + many parallel explore subagents made this very
visible to the user.
Route the idle-path through the existing pendingParentWakes queue with a
100ms debounce window. Notifications arriving during the debounce join
the same batch, the 150ms settle window also coalesces newcomers, and a
single batched prompt fires to the parent. Busy-path semantics are
unchanged (still 1s retry).
Prior attempts (1c05c60dc, ea55c385b, a337635e3) all coalesced only the
busy-defer path, leaving the idle-immediate-send path uncoalesced.
Reframe the skill's Lifecycle section so the lead treats teams as
ephemeral, one-per-phase units. The moment a phase ends or the shape
no longer fits, call team_delete and spawn a fresh team. Restructure
through delete-then-create, never in place.
Also fixes a misframing in old step 5: team_shutdown_request is a
per-session self-shutdown signal, not a 'wind down the team' command.
team_delete is what tears the whole team down.
- Add src/locales/ with en baseline and zh overrides (Partial<Record> fallback)
- Add src/shared/i18n.ts with initI18n/t/setLocale/getLocale (LANG env auto-detect)
- Add I18nConfigSchema with locale field to plugin config
- Internationalize 13 hardcoded strings in task-toast-manager
- Add 18 unit tests for i18n module
- Pin manager tests to en locale for determinism