Commit Graph

6612 Commits

Author SHA1 Message Date
YeonGyu-Kim d3318617d0 fix(background-agent): clean child session-agent state on pre-start abort and normalize stored agent
Two adjacent gaps cubic flagged on the previous diff:

1. spawner.startTask stored input.agent (potentially prefixed with sort
   marker and ZWSP) in setSessionAgent, but the prompt body used the
   stripped/normalized form. The session-agent registry therefore did
   not match what promptAsync actually dispatched. Capture the
   normalized agent once at the top of startTask and use it for
   setSessionAgent plus the launch log lines.
2. manager.startTask wrote setSessionAgent(sessionID, input.agent)
   before the cancelled and stale-attempt cleanup branches, but those
   branches only cleared subagentSessions and the delegated bootstrap.
   The session->agent mapping survived as orphan state after an aborted
   launch. Call clearSessionAgent inside both early-return paths so
   nothing remains tied to a session we just aborted.

Adds focused tests for both: spawner persistence parity with promptAsync
and manager cancellation cleanup leaving getSessionAgent undefined.
2026-05-17 00:30:50 +09:00
YeonGyu-Kim cc97a023cc test(agents): drop unsafe AgentFactory cast and add typed empty skills
Tests that mock an AgentFactory were using an `as AgentFactory` cast
and a separate mutation of `mockFactory.mode` to satisfy the type.
Replace with Object.assign so the factory type is constructed correctly
without casts. Also type the empty discoveredSkills fixture so its
element type is inferred from the function signature instead of
collapsing to never[].
2026-05-17 00:09:21 +09:00
YeonGyu-Kim 791fbf3e55 refactor(delegate-task): share buildSyncPromptTools between bootstrap and prompt dispatch
Two call sites built the sync delegate tool gate independently:
sync-prompt-sender's prompt body construction and sync-task's bootstrap
registration. Drift between them would let bootstrap claim one tool set
while the actual prompt sent a different one. Extract buildSyncPromptTools
and route both call sites through it so the registered bootstrap and the
dispatched prompt always agree.
2026-05-17 00:09:11 +09:00
YeonGyu-Kim ea5f6ddfd7 fix(call-omo-agent): register bootstrap and session agent before sync prompt dispatch
call_omo_agent sync path created the child OpenCode session and went
straight into promptAsync without registering child session agent,
session tools, or bootstrap state. If first dispatch failed before any
durable user message persisted, runtime fallback could not reconstruct
the original prompt or the agent identity for that child session.

Bind setSessionAgent and setSessionTools to the child session id with
the same tool restrictions that the prompt body sends, register a
delegated child session bootstrap with the prompt text, fallback chain,
and prompt tools, then clean bootstrap + session tools in finally for
sessions this call created.
2026-05-17 00:08:56 +09:00
YeonGyu-Kim 097d7dc547 fix(background-agent): keep delegated skill, permission, and child agent across retries
Three coupled gaps surfaced after the initial spawn fix:

1. fallback-retry-handler dropped task.skillContent and
   task.sessionPermission when rebuilding LaunchInput, so the retried
   background task lost the delegated system prompt and question-deny
   permission rule.
2. manager.startTask never bound the child sessionID to the resolved
   agent via setSessionAgent, leaving runtime fallback and other hooks
   with no idea which agent owned the new child session.
3. The fallback-to-general path in spawner.ts rebuilt the prompt body
   without going through buildFallbackBody, so bootstrap state, session
   tools, and session agent updates drifted apart.

Persist skillContent and sessionPermission on BackgroundTask, bind
setSessionAgent/updateSessionAgent at session creation and on fallback,
and route the FALLBACK_AGENT retry through buildFallbackBody so the
prompt body, bootstrap tools, and session registries all agree.
2026-05-17 00:08:44 +09:00
YeonGyu-Kim ba648685d4 fix(runtime-fallback): carry delegated system and tools through bootstrap retry
When the first prompt fails before any durable user message persists,
runtime fallback retry was rebuilding the request from parts alone and
losing the delegated agent system prompt and tool gates. Now it threads
bootstrap.system and bootstrap.tools into the retry body alongside the
captured retry parts, so the retried prompt keeps the same scope as the
initial delegate launch.
2026-05-17 00:08:30 +09:00
YeonGyu-Kim 761f682add refactor(delegated-bootstrap): accept optional system and tools
Add optional system and tools fields to DelegatedChildSessionBootstrap
so callers can stash the original delegated context alongside retry
parts. Backward compatible - existing callers stay unchanged.
2026-05-17 00:08:19 +09:00
YeonGyu-Kim 4f9813848a feat: add ci test runner, session routing, bash parser, and test fixtures
- script/run-ci-tests.ts: CI test sharding and isolation logic
- script/run-ci-tests.test.ts: tests for CI test target selection
- src/features/background-agent/session-route.ts: session prompt routing for background agents
- src/hooks/interactive-bash-session/parser.ts: interactive bash output parser
- src/hooks/ralph-loop/completion-promise-detector-test-input.ts: test fixture for completion promise detection
2026-05-16 23:51:43 +09:00
github-actions[bot] 166e5de06c @pizzav-xyz has signed the CLA in code-yeongyu/oh-my-openagent#4084 2026-05-16 11:43:47 +00:00
YeonGyu-Kim 80fa177b11 Merge pull request #4075 from code-yeongyu/feature/migrate-sisyphus-to-omo
Migrate legacy workspace state to .omo
2026-05-16 19:55:34 +09:00
ZeyuFu 572c3c248e fix(notepad-guard): refuse Write tool for .sisyphus/notepads files (#3685)
Adds a new `notepad-write-guard` hook that intercepts Write tool calls
whose target path matches `**/.sisyphus/notepads/**` and throws an
actionable error instead of allowing the write to proceed.

Without this guard, an agent that hits an Edit hash-mismatch failure
could silently fall back to Write, destroying the entire history of an
append-only notepad file (decisions.md, issues.md, etc.).  The file
carries an explicit "NEVER overwrite" warning that the agent ignores
under context pressure.

The guard is path-based so it works regardless of plan name or nesting
depth.  Non-notepad `.sisyphus/**` paths (e.g. plan files) are
unaffected.  The hook is wired into `create-tool-guard-hooks` under the
hook name `notepad-write-guard` and follows the same safeCreateHook +
HookName schema pattern as every other tool-guard hook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 06:52:43 -04:00
ZeyuFu 5e4d45a3ca fix(todo-continuation-enforcer): stop looping after all todos complete (#4013)
Two P0 fixes for the assistant loop that repeats its final summary 3-5 times
after all todos are marked completed before stagnation detection finally halts it.

P0.1 — session-level stop flag: when handleSessionIdle detects incompleteCount===0
it now sets state.allTodosCompletedAt. Subsequent idle events for the same session
bail out immediately at the top of the function before any HTTP fetch or injection
logic runs, preventing the re-entry loop regardless of todo-fetch caching latency.
The flag is cleared by resetContinuationProgress so sessions that receive new todos
after completion resume enforcement normally.

P0.2 — snapshot comparison scope: getTodoSnapshot now only serialises the
{id → status} mapping (sorted by key). Content and priority changes are excluded
from the comparison. Previously those fields were included, causing hasTodoSnapshotChanged
to return true whenever the LLM re-wrote todo text with identical status — which
reported progressSource="todo" and reset stagnationCount to 0, preventing
MAX_STAGNATION_COUNT=3 from ever being reached.

P1 fixes (CONTINUATION_PROMPT adversarial wording, 10 s completion grace period)
are deferred to a follow-up PR as noted in the issue.
2026-05-16 06:31:18 -04:00
YeonGyu-Kim 6573bd9431 chore(workspace): move test discipline rule to omo 2026-05-16 19:27:52 +09:00
YeonGyu-Kim 5a2c3bbba8 fix(workspace): match omo guard paths cross-platform 2026-05-16 19:14:54 +09:00
YeonGyu-Kim b5992b13ec test(shared): stabilize port utility interface check 2026-05-16 18:28:33 +09:00
YeonGyu-Kim cdac0d69bb fix(workspace): report only the active notepad change 2026-05-16 18:12:50 +09:00
YeonGyu-Kim 240a4a17ad fix(workspace): harden omo migration review issues 2026-05-16 18:02:54 +09:00
YeonGyu-Kim fbc5768f9a Merge pull request #3971 from MoerAI/fix/task-examples-add-run-in-background
fix(agents): add run_in_background to category task() examples in prompts (fixes #3960)
2026-05-16 18:02:01 +09:00
YeonGyu-Kim 82ec099c3a fix(atlas): match omo as a path segment 2026-05-16 17:52:28 +09:00
YeonGyu-Kim 63519ec563 docs(workspace): document omo workspace paths 2026-05-16 17:42:06 +09:00
YeonGyu-Kim f10f796318 fix(workspace): keep omo and legacy rules compatible 2026-05-16 17:41:49 +09:00
YeonGyu-Kim 36e373cdbb feat(workspace): point planning guardrails at omo 2026-05-16 17:41:35 +09:00
YeonGyu-Kim a86221b1a9 feat(workspace): store runtime state under omo 2026-05-16 17:40:11 +09:00
YeonGyu-Kim 5dca1a5742 feat(workspace): migrate legacy sisyphus state to omo 2026-05-16 17:39:54 +09:00
YeonGyu-Kim 7c2e2fe1fa fix(background-agent): redact task registry views 2026-05-16 17:12:48 +09:00
YeonGyu-Kim 982fa81367 fix(delegate-task): start child prompts reliably
Preserve delegated child prompt/bootstrap metadata for early runtime fallback before OpenCode has persisted the first user turn. Bind prompt gate calls to the SDK session receiver and keep completed background task lookup visible across plugin manager instances.
2026-05-16 16:27:56 +09:00
YeonGyu-Kim 76e573a920 Merge pull request #4073 from code-yeongyu/fix/team-create-permission-inline-spec
fix(team-mode): accept legacy inline team specs
2026-05-16 15:49:26 +09:00
YeonGyu-Kim d974cd3d3b test(hooks): repair stale retry harnesses 2026-05-16 15:43:15 +09:00
YeonGyu-Kim cf7bf9d02d fix(team-mode): accept legacy inline specs 2026-05-16 15:43:08 +09:00
YeonGyu-Kim a20540579e Merge pull request #4068 from code-yeongyu/feat/pre-publish-fix-v420
v4.2.0: pre-publish review fixes (BLOCKER-1..3, HIGH-5..10, MID-11/12)
2026-05-16 14:50:54 +09:00
ZeyuFu b516d5d41e fix(team-mode): preserve team membership across model fallback (#3898)
When a team-mode subagent hit a fallback model (rate limit / quota
exhaustion on the primary), the fallback continuation started a
fresh subagent session that was not registered in the team's
member registry under the original role. Subsequent
team_send_message / team_status calls from the fallback agent
threw "not in team" because the membership lookup missed.

Capture teamRunId + member identity at fallback initiation and
carry them onto the fallback session so the fallback agent
remains a first-class team participant. If preservation is not
possible, surface a bounded structured error instead of letting
the runtime fail mid-flight with a confusing membership message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 01:47:29 -04:00
ZeyuFu e25f3ca736 fix(tmux-subagent): drain terminal probe replies during delegated pane startup (#2887)
When oh-my-opencode created a delegated tmux pane, terminal
capability/color probe replies emitted by tmux or the freshly
attaching opencode session could end up in the caller pane's
input buffer instead of being consumed by the delegated pane,
appearing as literal text in the main OpenCode chat (e.g.
"414/21212a2/...").

Root cause: buildSplitArgs in team-layout-tmux/layout.ts called
split-window without the -d (detached/don't-switch-focus) flag.
Without -d, tmux briefly grants focus to the new pane during
creation; the outer terminal then sends DA1/DA2 and OSC color
probe replies into what it believes is the active pane, but the
focus handoff races and those bytes land in the caller pane's
stdin buffer instead.

Fix: add -d to every split-window call in buildSplitArgs, matching
the same flag already used in pane-spawn.ts for inline subagent
panes. This keeps the caller pane focused throughout the delegated
pane lifecycle so probe replies are consumed by the correct target.

Existing tests pass; one new test asserts -d is present on every
split-window call to guard this invariant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 01:41:25 -04:00
ZeyuFu 4c36005467 fix(team-mode): reject team_create from hard-reject agents (#3987)
When a hard-reject agent (e.g. prometheus) called team_create with an
explicit `lead` in the spec, the eligibility check that runs in the
no-lead branch of shouldReuseCallerLeadSession was bypassed. The
caller session was never registered in the team, the spawned lead
ran as a detached child, and replies routed to the spawned lead
never reached the caller — the caller became an orphan that could
send but never receive.

Move the caller eligibility guard to the top of team_create.execute
so it runs unconditionally before any team-run state mutates. Throw
an actionable error naming the agent and explaining hard-reject
agents cannot lead teams regardless of an explicit `lead` in the
spec.
2026-05-16 01:40:13 -04:00
ZeyuFu 2bf5038215 fix(team-mode): surface member error to main agent (#3923)
When a team member task errored, the failure stayed in the member's
internal state and the main/coordinator agent's wait/status loop
kept polling indefinitely — the run stalled with no visible error.
Emit a structured `member_error` peer_message into the team mailbox
on member error transition, naming the member and including the
underlying error text so the main agent's next team_status (or
pending-message read) returns a terminal failure instead of an
empty in-progress poll.

Regression test asserts the failure is visible in the main agent's
view after a member task errors mid-execution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 01:40:08 -04:00
ZeyuFu ced95c4bfa fix(team-mode): surface port-0 fallback and silent layout skip (#3963)
When ctx.serverUrl had a port string of "0", TmuxSessionManager
silently replaced it with the localhost:4096 fallback and
createTeamLayout subsequently skipped pane creation without any
user-visible signal. The two-step silent failure made team_mode
tmux_visualization look broken in default TUI mode.

Surface the failure path:

- TmuxSessionManager now retains ctx.serverUrl on the instance and
  exposes it via getCtxServerUrl(), and emits a structured warning
  log on the port-0 fallback branch naming both the discarded URL
  and the fallback it landed on.
- createTeamLayout's "opencode server not reachable" log is
  upgraded to a structured warning including ctxServerUrl and a
  hint to launch with --port N + OPENCODE_PORT=N.

No behavior change to the fallback resolution itself - only the
silence. Existing port-0 fallback tests still pass; two new tests
assert the warning fires on port 0 and is absent for real ports.
2026-05-16 01:23:25 -04:00
YeonGyu-Kim 3f3a63c54d docs(changelog): v4.2.0 entry with known issues and supersession history
Documents the v4.2.0 release window in Keep-a-Changelog format, including prompt gate fixes, internal audits, known issues, and the watchdog supersession history.

Closes LOW-14, LOW-16
2026-05-16 02:13:58 +09:00
YeonGyu-Kim eba17441cf test(mock-module-audit): require lifecycle cleanup for mock.module
New AST-based audit walks all *.test.ts files under src/ and asserts every mock.module(...) call is paired with cleanup. Existing offenders are documented in MOCK_MODULE_LIFECYCLE_ALLOWLIST with TODO references.

Closes HIGH-10
2026-05-16 02:13:11 +09:00
YeonGyu-Kim aaa215c5de docs(release-process): add post-fix repro verification policy
Race-condition and concurrency fixes must include reporter-verified repro confirmation before the originating issue is closed. Adds the checklist and rationale grounded in recent incident examples.

Closes MEDIUM-12
2026-05-16 02:12:28 +09:00
YeonGyu-Kim 3435c9bef2 docs(adr): write prompt-async-gate ADR
Documents the reservation-based duplicate-injection guard introduced in v4.2.0 with accepted status, exported API signatures, release semantics, migration notes, and commit references.

Closes MEDIUM-11
2026-05-16 02:12:01 +09:00
YeonGyu-Kim 102d067022 fix(model-suggestion-retry): release reservation on async error path
The promptWithModelSuggestionRetry async variant did not release the
post-dispatch reservation when the wrapped promptAsync threw. Callers
that immediately retry (such as sendSyncPrompt error toast paths) hit
the gate as reserved and surfaced 'promptAsync skipped by gate: reserved'
instead of the underlying error.

Mirrors the existing sync variant fix from ff1b15d53.

Closes regression introduced by BLOCKER-2 hardening
2026-05-16 01:56:04 +09:00
YeonGyu-Kim 5a8bd05db0 test(prompt-async-gate): replace timer waits with deterministic sync (BLOCKER-3)
Lines 79/142/428 of prompt-async-gate.test.ts used timer-based synchronization, violating .sisyphus/rules/test-discipline.md which forbids time-based test waits. Replace them with explicit dispatch awaits and mocked-time expiry so the assertions do not depend on CI machine speeds.

Closes BLOCKER-3 (Wave 2 cleanup)

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:50:11 +09:00
YeonGyu-Kim 9dd52a0435 docs(changelog): v4.2.0 entry covering BLOCKER + HIGH + KNOWN ISSUES
Closes L14

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:43:57 +09:00
YeonGyu-Kim 7dbb34cd4f refactor(background-agent): wire ParentWakeNotifier into BackgroundManager
Replace the inlined parent-wake coalescing logic in manager.ts with delegation to the ParentWakeNotifier extracted in c1ccf8d09. The four timer Maps and the related methods now live in their own module with a narrow public API, while BackgroundManager retains the wiring point and the enqueue-callback bridge.

Closes HIGH-9 (step 2: integration)

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:43:16 +09:00
YeonGyu-Kim 41ff7bca24 fix(background-agent): release prompt gate before agent fallback retry
Release the model-suggestion prompt reservation before the spawner retries with the fallback agent so the immediate retry is not skipped by the gate.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:42:54 +09:00
YeonGyu-Kim 209063e861 docs(known-issues): document delegate-task early-failure-fallback deferral
PR #3825 introduced a delegated child-session bootstrap to capture first-prompt retry payloads before history is persisted, addressing the empty-history fallback gap. After merge the PR's own regression test failed on clean root bun test (6828 pass / 1 fail), so PR #4044 reverted it. Ship v4.2.0 with the bug documented and a workaround so users have an explicit story for the unfixed delegated child-session early-failure path. Reland will target v4.2.1.

Closes BLOCKER-4 (Path B - reland deferred to v4.2.1)
2026-05-16 01:40:57 +09:00
YeonGyu-Kim 0f8902c49b docs(changelog): v4.2.0 entry
Document all 7+ BLOCKER+HIGH fixes, breaking-change-free additions
(public exports), known issue for delegated child-session fallback
(PR #3825 deferred to v4.2.1), and internal-only changes.

Closes L14
2026-05-16 01:38:59 +09:00
YeonGyu-Kim 4848017219 test(mock-module-audit): require lifecycle cleanup for mock.module
Walk all test files, parse with TypeScript Compiler API, assert every
mock.module(path, factory) invocation has a paired afterEach/afterAll
cleanup. Existing offenders are allowlisted with TODOs for v4.2.1 work.

Closes H10
2026-05-16 01:37:28 +09:00
YeonGyu-Kim 845d862b9b test(prompt-async-gate): replace setTimeout sleeps with deterministic sync
Test-discipline.md forbids setTimeout(resolve, N) and sleep(N) in test bodies. Replace the 3 microtask and expiry sleeps with explicit microtask yields and deterministic clock advancement, preserving the prompt gate invariants without real-time waits.

Closes BLOCKER-3

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:36:57 +09:00
YeonGyu-Kim f8d6f2a2ec docs(known-issues): document delegate-task PR #3825 revert deferral
PR #3825 added a shared bootstrap context to capture delegated
child-session retry payloads before the first prompt dispatch, so
empty-history failures could still retry through the fallback chain.
The PR's own regression test failed on clean root bun test after merge
(6828 pass / 1 fail). PR #4044 reverted the merge to keep dev green.

Ship v4.2.0 with the bug documented and a workaround so users have an
explicit story for the unfixed delegated child-session early-failure
path. Reland targets v4.2.1 once the regression test is stabilized.

Closes BLOCKER-4 (Path B - documentation, reland deferred to v4.2.1)
2026-05-16 01:36:21 +09:00
YeonGyu-Kim c096a596eb test(mock-module-audit): require lifecycle cleanup for mock.module
Closes H10

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-16 01:35:10 +09:00