Commit Graph

5227 Commits

Author SHA1 Message Date
MoerAI fbf130ec3a fix(test): update integration tests to expect fallback on quota exhaustion 2026-04-21 18:30:04 +09:00
MoerAI 7488c527df fix(runtime-fallback): trigger fallback on quota/credit exhaustion (fixes #3519) 2026-04-21 18:17:22 +09:00
YeonGyu-Kim 93dc103092 Merge pull request #3552 from code-yeongyu/feature/explore-librarian-gpt-5-4-mini-fast-primary
feat(agents): route explore + librarian primary to openai/gpt-5.4-mini-fast
2026-04-21 14:29:13 +09:00
YeonGyu-Kim 993fe20a12 docs(orchestration): reindent explore/librarian mermaid nodes
Align with sibling Junior/Oracle/Frontend nodes in the Worker Layer subgraph.
2026-04-21 14:23:39 +09:00
YeonGyu-Kim 3a6bd93252 fix(cli): keep mini-fast primary in openai-only install catalog
OPENAI_ONLY_AGENT_OVERRIDES was rewriting explore and librarian back to
gpt-5.4 medium for OpenAI-only installs. Match the runtime primary so the
install default stays on gpt-5.4-mini-fast.
2026-04-21 14:23:39 +09:00
YeonGyu-Kim 6914b44957 docs(configuration): restore vercel aliases in explore/librarian rows
Align documented fallback provider lists with the runtime chain in
model-requirements.ts so operators see the same providers that resolve at runtime.
2026-04-21 13:38:23 +09:00
YeonGyu-Kim fe44363bf8 fix(model-capabilities): drop pdf modality from gpt-5.4-mini-fast
OpenAI's mini-fast variant only accepts text and image input; advertising
pdf risks unsupported requests hitting runtime errors.
2026-04-21 13:38:23 +09:00
YeonGyu-Kim 02e4de865e docs(model): sync explorer and librarian guidance
Document the new primary chain and install-time fallback behavior for explorer and librarian.\nKeep the user-facing guidance aligned with the runtime and CLI model selection.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-21 13:30:11 +09:00
YeonGyu-Kim ceadf4bdbc fix(cli): prefer mini-fast for install fallback
Default the install-time fallback chain to gpt-5.4-mini-fast for librarian and explore when OpenAI is available.\nKeep the snapshot and catalog tests aligned with the new resolution path.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-21 13:30:02 +09:00
YeonGyu-Kim d2e5ddd73d fix(model-requirements): route primary agents to mini-fast
Use gpt-5.4-mini-fast as the primary runtime model for librarian and explore.\nKeep the fallback chain intact so older providers still resolve.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-21 13:29:55 +09:00
YeonGyu-Kim 680dd161b4 fix(model-capabilities): bundle gpt-5.4-mini-fast caps
Keep the supplemental OpenAI model available when the bundled snapshot omits it.\nMerge its capabilities at runtime so downstream model resolution can use it.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-21 13:29:49 +09:00
YeonGyu-Kim 064dcc844e fix(delegate-task): remove deprecated sync continuation fallback
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:56:05 +09:00
YeonGyu-Kim a17ba1673e chore(delegate-task): remove unused metadata model export
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:51:19 +09:00
YeonGyu-Kim 54e48de7f8 refactor(delegate-task): extract background session registration helpers
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:50:28 +09:00
YeonGyu-Kim 2585031f54 refactor(delegate-task): extract sync continuation resume context
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:48:58 +09:00
YeonGyu-Kim 4810d0f1bd fix(delegate-task): apply load_skills content to continuation prompts
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:36:24 +09:00
YeonGyu-Kim d0a3cb3936 fix(delegate-task): align background-continuation title with args.description
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:33:45 +09:00
YeonGyu-Kim 83c8ffbe01 fix(delegate-task): include category in continuation task_metadata blocks
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:33:05 +09:00
YeonGyu-Kim b5bc4cd404 fix(delegate-task): preserve variant in sync-continuation metadata model
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:32:16 +09:00
YeonGyu-Kim 54cc9b7ca4 test(delegate-task): lock Oracle-found gaps with TDD
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 15:29:32 +09:00
YeonGyu-Kim 3f28e42483 refactor(delegate-task): remove AI slop from supporting files
Tighten resolve-metadata-model runtime guards, tidy tool-argument-preparation
subagent-type override logging, and trim a redundant literal in the
metadata-model-unification test. Behavior preserved (328 tests pass).
2026-04-20 15:20:45 +09:00
YeonGyu-Kim bcf95112ca refactor(delegate-task): remove AI slop from executor metadata paths
Strip obvious comments, over-defensive guards, and dead branches across
the five delegate-task executor files while preserving all metadata
propagation behavior added in prior commits. Regression tests remain
green (328 pass / 0 fail).
2026-04-20 15:16:48 +09:00
YeonGyu-Kim 271068d871 chore(delegate-task): remove unused execute field from DelegateTaskArgs
The execute field with { task_id, task_dir } was defined but never referenced anywhere in the codebase. Removing dead code simplifies the type surface and prevents accidental future misuse.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:53:44 +09:00
YeonGyu-Kim cd0c98e54d fix(delegate-task): preserve model variant in metadata resolution
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:53:31 +09:00
YeonGyu-Kim a82f0560cc test(delegate-task): add failing tests for model variant preservation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:53:31 +09:00
YeonGyu-Kim f486df71ae feat(delegate-task): preserve raw subagent_type across metadata
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:50:40 +09:00
YeonGyu-Kim 8a2a11b210 fix(delegate-task): propagate category in background continuation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:50:18 +09:00
YeonGyu-Kim 9bd5829a76 fix(delegate-task): propagate agent and category in sync continuation
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:50:11 +09:00
YeonGyu-Kim 9bf89deee3 test(delegate-task): add failing tests for metadata continuation gaps
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-20 14:49:35 +09:00
github-actions[bot] 869accd11b @CoderLuii has signed the CLA in code-yeongyu/oh-my-openagent#3518 2026-04-19 03:28:31 +00:00
Sisyphus 017e4ef1c7 Merge pull request #3514 from andomeder/fix/cli-attach-auth 2026-04-19 02:38:19 +09:00
William Obino 69315fcad7 fix(cli): restrict attach auth injection to loopback URLs 2026-04-18 18:12:58 +03:00
github-actions[bot] ad0ee7abcd @andomeder has signed the CLA in code-yeongyu/oh-my-openagent#3514 2026-04-18 14:55:59 +00:00
William Obino ef5c74e972 fix(cli): inject server auth for attach clients 2026-04-18 17:49:05 +03:00
YeonGyu-Kim 64b49b465d Merge pull request #3510 from code-yeongyu/fix/tmux-stale-session-sweep
feat(tmux): sweep stale omo-agents-<pid> sessions on first spawn
2026-04-18 21:05:59 +09:00
YeonGyu-Kim e35ac38bbf test(tmux): rewrite stale-sweep tests via DI to eliminate cross-file mock leak
Oracle flagged that the previous test file monkey-patched process.kill
and relied on mock.module for 5 modules. Running it after manager.test.ts
in the same Bun process reproduced 2 failures - the test resolution of
`./session-kill` specifier interacted badly with manager.test.ts's
`../../shared/tmux` barrel mock.

Solution: refactor stale-session-sweep.ts to expose
`sweepStaleOmoAgentSessionsWith(deps)` that accepts a SweepDeps record
(isInsideTmux, getTmuxPath, listCandidateSessions, killSession,
processAlive, currentPid, log). The public `sweepStaleOmoAgentSessions()`
still uses runtime-built deps so call sites are unchanged.

The test file now imports the pure function directly and constructs a
fixture with fake deps. Zero mock.module calls, zero process.kill
patching, zero cache-bust dynamic imports. 8 tests (up from 6) run
deterministically in any order with any neighbor.

Before: combined run with manager.test.ts = 2 fail, 50 pass.
After:  combined run with manager.test.ts = 0 fail, 54 pass.
2026-04-18 21:00:34 +09:00
YeonGyu-Kim d1fc46da42 test(tmux): restore process.kill in afterEach to prevent cross-file leak
Oracle noted that loadSweeper() monkey-patches process.kill without
ever restoring it. Added afterEach hook to set process.kill back to the
captured original. Individual file runs already passed, and
script/run-ci-tests.ts confirms the full CI suite - 4781 pass, 0 fail
across 491 files - but this makes the test file safe under non-isolated
local runs as well.
2026-04-18 20:51:24 +09:00
YeonGyu-Kim 913fac05f5 fix(tmux-subagent): retry stale sweep if first attempt throws
Oracle flagged: staleSweepCompleted was set to true BEFORE
sweepStaleOmoAgentSessions() ran, so any throw from the first
invocation would permanently disable stale cleanup for the rest
of the process lifetime.

Fix:
- Move staleSweepCompleted=true into the try-block success branch.
- Add staleSweepInProgress guard so concurrent onSessionCreated calls
  do not invoke sweep twice in parallel (sweep is idempotent, but the
  guard prevents doubled log noise).
- finally{} clears the inProgress flag regardless of outcome.
- cleanup() resets both flags.

Two new tests cover: retry after a thrown first attempt, and single
invocation when subsequent spawns follow a successful first sweep.
2026-04-18 20:45:21 +09:00
YeonGyu-Kim 859d67f41e fix(tmux-subagent): revert session.error cleanup (recoverable-error regression)
Oracle flagged a regression introduced in PR #3507 commit 21554be8:
event.ts routed session.error through tmux pane cleanup BEFORE the
existing session-recovery / model-fallback logic ran.

Problem: when session.error was recoverable (context window limit,
quota rate limit, provider fallback), the recovery/fallback code would
successfully continue the SAME session - but by then its tmux pane had
already been destroyed. User-visible symptom is exactly the original
complaint - 'screen appears but streaming stops working' after an
auto-retry.

Fix is the minimal revert: remove the onSessionError funnel from
event.ts and drop onSessionError from the manager. Fatal errors that
actually end a session still fire session.deleted, which continues to
trigger cleanup correctly. Non-fatal error streams stay attached to
the surviving pane.
2026-04-18 20:37:49 +09:00
YeonGyu-Kim 3dce19d173 fix(tmux-subagent): move 'cleanup complete' log back to cleanup() method
The log line was misplaced at the end of sweepStaleIsolatedSessionsOnce
where it said 'cleanup complete' after the stale sweep, which was
misleading. Per Oracle review.
2026-04-18 20:27:48 +09:00
YeonGyu-Kim 104523051d feat(tmux): sweep stale omo-agents-<pid> sessions on first spawn
Follow-up to PR #3507 addressing the Oracle-noted operational limitation:
per-PID isolated session names (getIsolatedSessionName(process.pid)) mean
that when an opencode process is SIGKILL'd (or the machine hard-reboots),
the old omo-agents-<old-pid> tmux session survives forever because nothing
is around to kill it.

Added sweepStaleOmoAgentSessions() that:
1. Lists tmux sessions matching /^omo-agents-(\d+)$/
2. For each, checks process.kill(pid, 0) to detect a dead PID
3. Skips our own PID
4. Calls killTmuxSessionIfExists for every session whose owner process is gone

Wired into TmuxSessionManager.onSessionCreated() as a one-shot (guarded by
staleSweepCompleted flag) so it runs lazily on the first subagent spawn when
isolation="session". The flag is reset in cleanup() so subsequent process
restarts re-run the sweep.

6 new tests cover: outside-tmux no-op, no matching sessions, multiple dead
PIDs, current PID skip, live PID skip, list-sessions failure.

Manual E2E verified on real tmux:
- Created omo-agents-99999, sweep killed it
- Spawned our own omo-agents-<pid>, closeTmuxPane returned true even after
  pane auto-destroy from Ctrl+C
- Final tmux list-sessions shows zero omo-agents-* orphans
2026-04-18 20:22:00 +09:00
YeonGyu-Kim a503989a52 Merge pull request #3507 from code-yeongyu/fix/tmux-serve-attach-cleanup
fix(tmux): repair serve/attach cleanup so panes and isolated sessions tear down reliably
2026-04-18 20:01:55 +09:00
YeonGyu-Kim aa79284dc5 fix(background-agent): reset process.exitCode to 0 between cleanup tests
CI test suite exited 1 despite 0 failing tests because process-cleanup.test.ts
assertions left process.exitCode=1 in place. The afterEach hook only reset to
originalExitCode (which starts undefined), not 0, so Bun picked up exitCode=1
on shutdown and reported the shared batch as failing.

Explicitly set process.exitCode = 0 in beforeEach and afterEach so each test
starts and ends with a clean exit state.
2026-04-18 19:57:26 +09:00
YeonGyu-Kim 257b6cf951 fix(tmux): scope isolated session name per plugin instance (Oracle review)
Oracle flagged the previous commit: "omo-agents" was a shared constant,
so when two plugin instances ran in the same tmux server they wrote into
the same session. One instance's cleanup would then kill-session on the
shared name and tear down the other instance's live attached panes.

Replace the const ISOLATED_SESSION_NAME with getIsolatedSessionName(pid)
which defaults to process.pid, so every opencode process owns its own
"omo-agents-<pid>" session. spawnTmuxSession and cleanup both resolve
the name through this helper. Discovery is straightforward from the
host tmux via 'tmux list-sessions | grep omo-agents-'.

Manager test covers two concurrent managers and asserts each kills a
per-pid session name, proving they no longer collide on a global name.
2026-04-18 19:47:36 +09:00
YeonGyu-Kim f8a1a11bb7 fix(team-mode): refactor layout to use testable spawn-process helper
The existing layout.test.ts relied on mock.module("bun", ...) registered
at the top level, but test-setup.ts calls mock.restore() + restoreModuleMocks()
in afterEach, so every test except the first one lost its mocks. CI has
been red on this file since e303feef.

Two changes:

1. layout.ts now imports spawn from the existing spawn-process helper
   instead of "bun" directly, matching the pattern established for
   closeTmuxPane and killTmuxSessionIfExists. This does not change
   runtime behavior - spawn-process just re-exports Bun's spawn.

2. layout.test.ts registers module mocks inside beforeEach and uses the
   ?test=UUID cache-busting dynamic-import pattern so the mocks apply
   on every test run, not just the first.

All 4 layout.test.ts cases now pass.
2026-04-18 19:42:19 +09:00
YeonGyu-Kim ea4f3c81f4 fix(tmux): treat pane-already-closed as success in closeTmuxPane
After send-keys C-c the subprocess running inside the pane (for example
"opencode attach") exits on SIGINT, which causes tmux to destroy the
pane automatically. The subsequent kill-pane then returns exit 1 with
stderr "can't find pane: %NN" even though the end state is exactly
what we wanted.

Before this fix closeTmuxPane reported failure for that branch, which
kept TmuxSessionManager's retryPendingCloses loop marking the (now
deleted) pane as still-pending forever and left stale entries behind
in the tracked sessions map. This is the behavior the user observed
as "screen opens, streaming runs, but cleanup doesn't finish" when
running with tmux.isolation="session".

Now we detect the "can't find pane" stderr and return true, treating
the auto-destroy path the same as an explicit successful kill.
2026-04-18 19:34:54 +09:00
YeonGyu-Kim b9d2acdcf9 fix(background-agent): run manager cleanup on uncaughtException and unhandledRejection
Signal handlers covered SIGINT/SIGTERM/SIGBREAK/beforeExit/exit, but a
synchronous throw or a top-level rejected promise terminated the process
without letting TmuxSessionManager (or any other registered manager) run
its shutdown hook. That reliably left orphan tmux panes after an opencode
crash.

Added registration for uncaughtException and unhandledRejection that fan
out through the existing cleanupAll() path, set process.exitCode = 1,
and arm the same 6 second forced-exit guard we use for signals. Test
helpers hold process-level spies so the new tests do not leak listeners
between runs.
2026-04-18 19:32:04 +09:00
YeonGyu-Kim 21554be870 fix(tmux-subagent): tighten serve/attach cleanup paths so panes and sessions are torn down reliably
Three defects observed with tmux.isolation="session" where the omo-agents
session was left with orphan fish panes after subagents finished:

1. cleanup() never ran 'tmux kill-session -t omo-agents'. If any pane
   lingered (for example because opencode attach stayed blocked on SSE),
   the isolated session survived process shutdown. Now we explicitly kill
   the shared session through killTmuxSessionIfExists when isolation is
   "session".

2. session.error events bypassed tmux cleanup entirely. Only session.deleted
   closed panes, so any provider error that did not escalate into a delete
   left the pane behind. Added onSessionError on TmuxSessionManager, wired
   from plugin/event.ts, which funnels through the same onSessionDeleted
   close path for tracked sessions only.

3. retryPendingCloses() only ran when a new session was created. If the
   main process went idle after a failed close, the pending session stayed
   pending forever. TmuxPollingManager now accepts the retry callback and
   fires it on every tick, alongside the existing stability-based close
   sweep.

Manager tests cover isolation=session kill invocation, inline/window
isolation skipping the kill, the onSessionError happy + untracked paths,
and an isolated-session kill failure that must not break cleanup.
2026-04-18 19:31:45 +09:00
YeonGyu-Kim de8a0167e6 feat(tmux): add killTmuxSessionIfExists utility for explicit session teardown
Adds killTmuxSessionIfExists(sessionName), a best-effort no-op when the
named session is absent. Drains both stdio streams so it does not leak
pipe buffers the way closeTmuxPane historically did.

Also exports ISOLATED_SESSION_NAME ("omo-agents") from session-spawn so
callers can tear down the shared isolated session without hard-coding
the name in multiple places.
2026-04-18 19:31:22 +09:00
YeonGyu-Kim 2a99a524ea fix(tmux): drain kill-pane stdout to prevent pipe backpressure hang
closeTmuxPane spawned kill-pane with stdout: "pipe" but never drained the
stream, which could leave the subprocess hanging indefinitely when tmux
wrote anything to stdout (for example under --force-close race conditions).

- send-keys now uses stdout: "ignore" so there is no pipe to drain
- kill-pane keeps the pipe but drains stdout/stderr alongside proc.exited
- switch imports to the new spawn-process helper so the behavior is
  covered by hermetic tests that mock the spawn boundary
2026-04-18 19:31:04 +09:00