Skip to content

fix(providers): register omo in the runtime lists the type system cannot see - #43

Merged
devswha merged 3 commits into
mainfrom
fix/omo-runtime-registration
Aug 13, 2026
Merged

fix(providers): register omo in the runtime lists the type system cannot see#43
devswha merged 3 commits into
mainfrom
fix/omo-runtime-registration

Conversation

@devswha

@devswha devswha commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Follow-up to #39. Adding omo to the type unions was not enough: three runtime lookups were left behind, so the provider typechecked, passed 917 tests, went green in CI, and behaved wrongly at every layer.

What was broken

1. omo read gjc's transcripts.

const agentRoot = this.provider === 'omp'
  ? path.join(os.homedir(), '.omp', 'agent')
  : path.join(os.homedir(), '.gjc', 'agent');   // omo lands here

A ternary routes a new union member into its else branch with no type error. Result: 632 gjc sessions indexed as omo, and none of omo's own 5 transcripts ever read.

omo rows: 632 | pointing outside ~/.omo: 632
  e.g. /home/devswha/.gjc/agent/sessions/-workspace-oh-my-docs/…jsonl

2. omo never appeared in the sidebar. Two Array.includes allowlists in useExternalCliSessions dropped it after the backend had correctly reported "kind":"omo".

3. omo replies never refreshed. Its transcript root was missing from PROVIDER_WATCH_PATHS, so the startup scan indexed sessions that no watcher ever updated — sends worked, responses never appeared.

Fix

Root and title lookups become exhaustive Record<PiTranscriptProvider, …>, so the next provider is a compile error rather than a silent fallthrough. The remaining allowlists get omo wherever omp already appears: external spawn (supportedClis), completion identity, event-driven notifications, and the notification label map (omo showed as "Assistant").

Also replaces the placeholder logo with the official oh-my-openagent/.github/assets/omo-icon-light.svg.

Regression lock

pi-transcript-roots.test.ts asserts each pi provider resolves to its own ~/.<provider>/agent and that no two share a root. Verified by mutation: pointing omo back at .gjc fails the test.

Verification

After the fix, against real data:

omo rows: 5 | pointing outside ~/.omo: 0
omo transcripts on disk: 5

The 632 mis-attributed rows were purged and the scan markers cleared. Full gate green: typecheck, lint, identity, server, client.

Note for reviewers

All three defects share one shape — correct types, wrong runtime list. The compiler enumerated the 12 exhaustive Records that needed omo and caught none of these, because Array.includes and ? : are invisible to it. Worth remembering when the next provider lands.

devswha and others added 3 commits August 13, 2026 19:39
…not see

Adding omo to the unions in #39 left three runtime lookups untouched, so the
provider typechecked and shipped while behaving wrongly at every layer.

- omo read gjc's transcripts. The agent home came from
  `provider === 'omp' ? '.omp' : '.gjc'`, and a ternary routes a new union
  member into its else branch without a type error. 632 gjc sessions were
  indexed as omo, and none of omo's own five transcripts were ever read.
- omo never appeared in the sidebar. Two `Array.includes` allowlists in
  useExternalCliSessions filtered it out after the backend reported it.
- omo replies never refreshed. Its transcript root was missing from
  PROVIDER_WATCH_PATHS, so the initial scan found sessions that no watcher
  ever updated.

The root and title lookups are now exhaustive Records, which makes the next
provider a compile error instead of a silent fallthrough. The remaining
allowlists (external spawn, completion identity, event-driven notifications,
notification label) get omo wherever omp already appears.

Also swaps the placeholder logo for the official
`oh-my-openagent/.github/assets/omo-icon-light.svg`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The message-author chain ends in `: t('messageTypes.claude')`, so omo fell
through to the Claude label the same way its transcript root fell through to
gjc. Follows the gjc/omp pattern of an i18n key with a defaultValue, so no
locale file changes are needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… display

Four defects found by running omo through ChatMux end to end.

- omo could not continue a session. `--resume` means different things in the
  two CLIs: Oh My Pi resumes the given id, omo takes no value and opens an
  interactive picker, which under `--print` with no stdin exits 13 without
  running the turn. Measured across valid id, wrong cwd, and `--resume=<id>`;
  all exit non-zero. omo's equivalent is `--session-id`, verified to resume an
  existing id and create a missing one.
- Ordinary CLI logging surfaced as chat errors. Both CLIs write config notices
  and hook status to stderr on runs that exit 0, and every line was forwarded
  as an error message. stderr is now buffered and reported only when the
  process actually fails.
- Assistant avatars were gjc-only. `transcriptView` existed solely to hide the
  author row for every live provider except gjc; the prop is removed, so all
  providers show their icon and name. omo also fell through the author chain
  to the Claude label.
- The omo logo rendered small. The official asset sits at ~63% of its canvas,
  so the viewBox is cropped to the mark's measured bounds.

omo's send runtime stays unregistered in spawnFns: sending to a session that
is already live in a tmux pane would start a second headless process on the
same transcript. Filed separately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@devswha
devswha merged commit b25aac3 into main Aug 13, 2026
2 checks passed
@devswha
devswha deleted the fix/omo-runtime-registration branch August 13, 2026 12:40
devswha added a commit that referenced this pull request Aug 13, 2026
…sions (#46)

extractExternalResumeSessionId matched only the pi-derived --resume|-r form
for omo, but omo's canonical continuation flag is --session-id (its --resume
takes no value and opens a picker) -- the same fact #43 established for the
headless runtime in server/pi-cli.ts. A tmux pane started with
`omo --session-id <id>` therefore never linked back to its transcript
session. omo now tries --session-id first and keeps the --resume fallback;
omp is unchanged and never accepts --session-id.
devswha added a commit that referenced this pull request Aug 13, 2026
… omo runtime (#47)

chat.send routed every message to spawnFns[provider] without checking
whether the target transcript is currently owned by a live tmux pane, so a
second headless CLI resumed the same session id: two processes interleaved
one JSONL and the live agent never saw the message (#44, observed on omo).

- New live-spawn-guard service: before starting a run, chat.send resolves
  the fresh external-CLI roster and refuses with SESSION_LIVE_IN_TMUX when a
  pane of the same provider owns the exact provider session id. Fail-open on
  unavailable discovery evidence: a false block would break the core chat
  path, a false allow merely restores pre-guard behavior.
- Guarded providers are the six headless-resume CLIs (claude, codex, cursor,
  opencode, omp, omo). gjc is exempt: its live sessions are reached through
  the SDK connect lane, which attaches instead of forking.
- With the guard in place, spawnOmo/abortOmoSession are registered, closing
  the omo send gap left by #43. The pi runtime abort-handle capture and the
  chat.abort failure branch now include omo alongside gjc/omp.

Verified end to end on this host: a real omo pane started with
--session-id <id> in tmux blocks the spawn with the owning session name,
an unrelated id and the same id under omp pass, and killing the pane
releases the guard.

Closes #44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant