Skip to content

feat: run ompweb's own omp build over its own channel instead of RPC - #460

Closed
andrebrait wants to merge 37 commits into
ompweb-dev:mainfrom
andrebrait:feat/omp-runner
Closed

andrebrait wants to merge 37 commits into
ompweb-dev:mainfrom
andrebrait:feat/omp-runner

Conversation

@andrebrait

@andrebrait andrebrait commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

ompweb stops driving omp through omp --mode rpc-ui and runs its own omp build, runner/ (ompweb-omp): upstream omp's CLI pinned to an exact npm release (@oh-my-pi/pi-coding-agent@18.19.0) whose session factory connects every session to ompweb host over ompweb's own NDJSON channel. The host receives the same AgentSession events and calls the same session methods omp's TUI does, so RPC gaps (the whole ask form and its pre-checked choices, missing hooks, negotiation and chunking quirks, the session-edit extension) go away. Design: docs/specs/2026-11-12-omp-runner-design.md.

  • runner/: entry, launch swap, headless mode (--headless, channel on stdio), Unix-socket transport for TUI-started sessions, command groups ported from RPC's handlers, event bridge with delta message_update, client-message correlation rebuilt in the runner, per-platform binary build and workflow.
  • ompweb: process layer, daemon channels, rpc-manager, auth login route speak the channel; whole-form ask rendered natively (with omp's automatic "Other" choice); edit_message is a native command; the daemon listens on $XDG_RUNTIME_DIR/ompweb/host.sock and adopts TUI-started runner sessions.
  • Removed: RPC v1/v2 negotiation, rpc_chunk, set_ask_dialog, the session-edit extension, skill diagnostics (only in an unmerged omp PR).

Testing

  • Runner: tsc clean, bun test 11/11, compiled ompweb-omp-linux-x64 --version and --smoke-test pass, headless get_state answers.
  • End to end (server + daemon + compiled runner, real model): prompt streams and persists; whole ask form with explanatory text and a pre-checked default answered from the web; set_model then edit_message; a TUI-started session appears live in the web with prompts going both ways.
  • Focused host tests ported to the channel pass with the project's --timeout 30000; the remaining fake omp children (agent-tools, api-contract, message-outbox-review, outbox-handoff, session-resume, session-routes) are ported too. Full suite left to CI.

Known gaps

  • Headless mode swaps omp's rpc-mode.ts and lifts the no-model exit in main.ts with a Bun plugin (runner/src/rpc-mode-swap.ts); the build fails loudly if an omp bump moves that check.
  • set_model no longer saves the default model role (RPC did).
  • Rebased on main (includes the shared provider logins from feat(hosts): share this server's provider logins with linked hosts #449).

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

andrebrait added a commit to andrebrait/integration-ci that referenced this pull request Nov 12, 2026
ompweb's own omp build (runner/, ompweb-dev/ompweb#460) must sit next to the
binary; scripts/build-binary.ts copies it from runner/release. Each target
installs its own natives addon before the runner build.
@andrebrait
andrebrait force-pushed the feat/omp-runner branch 2 times, most recently from 40c5677 to 63e3309 Compare November 12, 2026 17:27
@andrebrait

Copy link
Copy Markdown
Collaborator Author

@codex review

@andrebrait

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Action not completed

Review skipped: 150 files exceed the limit of 100.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-12T18:06:30.457262Z
We couldn’t complete this review. Comment @codex review to try again.
8e10f61 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Failed to sample tokens
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@andrebrait

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Failed to sample tokens
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Start of a custom omp entry that would host ompweb sessions over a local
socket. Paused: omp collab already covers most of the design, and the
direction (collab guest, custom build or hybrid) is pending.
runner/ is ompweb's own omp build on pinned @oh-my-pi/pi-coding-agent 18.19.0.
src/cli.ts stands in for upstream cli.ts as the process entry and swaps the
launch command for one whose session factory (src/session.ts) shares every
session through the host's loopback collab relay (runtime overrides only)
and attaches the NDJSON control socket (src/control.ts: get_state, set_model).
src/relay.ts is the loopback relay; scripts/ holds the guest and host probes.

Verified: --smoke-test ok; stock and runner TUIs joined by the guest probe;
a guest prompt raised an ask that the guest answered; set_model over the
control socket switched the TUI model and reached the guest as entry+state.
Drop the collab relay, overrides and guest probe. The session factory now
connects src/channel.ts: hello with the session file, every AgentSession
event, commands (get_state, set_model, prompt, abort) against the same
AgentSession the TUI drives, and dialogs raced between the TUI and the host
by wrapping the tool UI context (first answer wins, the other side closes).

Verified: --smoke-test ok; a host-sent prompt opened an ask whose whole HTML
form (checked state included) reached the host as formDialog; the host
answer closed the TUI form; a TUI answer sent ui_end to the host.
src/commands/ holds one CommandTable and FrameTable per group (prompting,
model, session, tools, agents) behind a shared CommandContext; the channel
dispatches cmd frames by op and other host frames by t.
Agents were cut off mid-task; this preserves their partial edits
(runner headless/events/correlation, ompweb process/daemon/manager/auth,
TUI attach socket, release/smoke), plus the spec and DESIGN/AGENTS updates.
Not verified as a whole.
Skill diagnostics came from an unmerged omp PR that the pinned runner
lacks; the feature, its setting toggle and docs are removed. Root tsconfig
excludes runner/, which has its own. E2E (server+daemon+compiled runner):
prompt, whole ask form with pre-checked default, set_model+edit_message and
TUI attach all passed.
…layout

Fake omp children in host tests speak hello/cmd/res/event instead of RPC;
RemoteRpcTransport tags link samples from hello/session frames. The web ask
form adds the automatic Other choice per radio/checkbox group, as omp does.
Fake hosts and workers in agent-tools, api-contract, message-outbox-review,
outbox-handoff, session-resume and session-routes speak hello/cmd/res/event;
the rename-during-edit test holds a native edit_message command. The late
second RPC response case is gone: the channel reports it as prompt_error.
Both handlers existed but were missing from the command table, so the
daemon's event filter and the outbox status probe got unknown-command errors.
The root suite ignores runner/** (its deps live in runner/node_modules);
runner gets a typecheck and bun test job on PRs that touch it. zh-TW, added
on main, still carried the removed skill-diagnostics keys.
…p dirs

npm test lists the app directories instead of ignoring runner/** (the
ignore glob missed Windows paths). Smoke needs a real runner: CI builds it
first, and packed-install smokes pass it with --omp until the per-platform
runner packages are published.
…ing HOME

omp's daemon broker, LSP mux and embedding server detach and outlive the
session by design; on Windows they keep the throwaway HOME locked.
…ng it

The server closes the peer dialog without waiting for omp, so the child's
answer record can land after the cancel frame (seen on Windows CI).
A freshly copied runner binary's first start on Windows waits on the
antivirus scan; the 10 s probe reported omp as missing for the whole
daemon session. Smoke waits up to 60 s for the link.
The runner cannot add clientMessageId to omp's entries, so it journals
{clientMessageId, entryId} in a custom entry. The session reader now takes
the id from either source, on the active branch only, for outbox
reconciliation, full context and history pages.
Runner: headless mode boots through runRootCommand's runSessionHost hook
(upstream PR pending; carried as a Bun patch of the exact diff) instead of
swapping omp's rpc-ui mode with a build plugin, and no runner module imports
omp's RPC helpers any more (prompt results, goals, session events and
settle, message paging, host tools/URIs, btw, dictation, live, subagents are
ported onto omp's non-RPC modules).

ompweb: the server passes the runner's ui_request/ui_end/ui frames through
unchanged and the browser renders each omp dialog method from its own
arguments, answering ui_response with the exact omp return value; the
extension_ui_* translation is gone.
Daemon: unowned res frames are dropped and startup configure is
fire-and-forget (a slow extension startup no longer resolves the web's
commands with stray replies); a TUI runner cannot attach to a session that
already has a live channel ({t:"refused"}); the host link moves to protocol
v10 (MIN = VERSION), deleting spawnLegacy, legacy channels and every older
version gate; a restarted server sees each event once and in order
(continuous rejoin); the host socket is created under umask 0177; numeric
string dialog ids are normalised; dead capability and lifecycle plumbing
removed.

Runner: only interactive TUIs dial the host, redialling stops after a
refusal, no dialling on Windows yet, open dialogs are re-sent after a
redial and ui_end follows a failed local dialog; tests now kill the
reviewer's mutants and cover edit_message.

Browser: agent forms with controls named like HTMLFormElement members
still submit. Docs: spec, README, AGENTS.md and DESIGN.md describe the
runner and its channel.
Fake daemons serve v10 open instead of the removed spawn op, hellos and
welcomes use LINK_PROTOCOL_VERSION, and the removed ready capability is
gone from expectations. Tests of below-v10 join blocks are deleted (such a
host is refused at link time); session-resume asserts that v10 hosts own
their runs. clusterJoinBlock drops its dead protocol parameter.
…ne redial test

On a slow socket (Windows' small loopback buffers) the resend outlasted the
test's ack hold: the released acks cover the lines main got before the drop,
so the daemon rightly skipped the rest of the resend and the test waited for
lines that would never come again. Hold acks until a full window is resent.
…e it listens

omp children spawned during the pending listen() (restored sessions at startup) inherited umask 0177, so every file and directory their tools created was 0600.
ompweb preflight starts the session omp as a new host session would (same resolver and spawn, --no-session, scratch cwd) and waits up to 30 s for its hello. The host updater and the web self-update worker run the candidate's preflight in the live environment before stopping anything and abort on failure. An npm ompweb host now resolves the runner from its own package.
…ently and is found by a marker only it embeds
runner/scripts/use-omp-build.ts fetches the omp-packages zip of the
andrebrait/oh-my-pi release runner/omp-build.json pins into runner/vendor/,
or re-pins to a given tag (file: deps and overrides for every @oh-my-pi
package and native leaf, bun install, fails if any resolves from npm).
Every runner install fetches first.

The pin itself (omp-build.json, package.json, bun.lock, dropping
runner/patches/) needs the first fork release with the zip:
  bun runner/scripts/use-omp-build.ts <tag> && git rm -r runner/patches
Each ompweb release ships its omp runner, and `omp update` on that
runner would replace it with upstream's binary. The omp row now shows
the host's omp version with "Updated with ompweb" and no button:
HostUpdateTarget is "ompweb", HostUpdateInfo.omp is { currentVersion }
(from `omp --version`), hosts refuse an omp target, /api/omp-update
keeps only restart, and the omp update check, cached check, worker
branch and self-update kind are gone. The hub reduces an older
daemon's omp row to its version; recorded omp operations stay readable.
@andrebrait

Copy link
Copy Markdown
Collaborator Author

Moved to #473: the head branch now lives on this repository.

@andrebrait andrebrait closed this Nov 13, 2026
andrebrait added a commit that referenced this pull request Nov 13, 2026
Daemon: unowned res frames are dropped and startup configure is
fire-and-forget (a slow extension startup no longer resolves the web's
commands with stray replies); a TUI runner cannot attach to a session that
already has a live channel ({t:"refused"}); the host link moves to protocol
v10 (MIN = VERSION), deleting spawnLegacy, legacy channels and every older
version gate; a restarted server sees each event once and in order
(continuous rejoin); the host socket is created under umask 0177; numeric
string dialog ids are normalised; dead capability and lifecycle plumbing
removed.

Runner: only interactive TUIs dial the host, redialling stops after a
refusal, no dialling on Windows yet, open dialogs are re-sent after a
redial and ui_end follows a failed local dialog; tests now kill the
reviewer's mutants and cover edit_message.

Browser: agent forms with controls named like HTMLFormElement members
still submit. Docs: spec, README, AGENTS.md and DESIGN.md describe the
runner and its channel.
andrebrait added a commit that referenced this pull request Nov 13, 2026
…473)

* wip: scaffold runner package pinned to @oh-my-pi/pi-coding-agent 18.19.0

Start of a custom omp entry that would host ompweb sessions over a local
socket. Paused: omp collab already covers most of the design, and the
direction (collab guest, custom build or hybrid) is pending.

* wip: ompweb omp runner — collab view plane plus control socket

runner/ is ompweb's own omp build on pinned @oh-my-pi/pi-coding-agent 18.19.0.
src/cli.ts stands in for upstream cli.ts as the process entry and swaps the
launch command for one whose session factory (src/session.ts) shares every
session through the host's loopback collab relay (runtime overrides only)
and attaches the NDJSON control socket (src/control.ts: get_state, set_model).
src/relay.ts is the loopback relay; scripts/ holds the guest and host probes.

Verified: --smoke-test ok; stock and runner TUIs joined by the guest probe;
a guest prompt raised an ask that the guest answered; set_model over the
control socket switched the TUI model and reached the guest as entry+state.

* wip: runner speaks its own channel instead of collab

Drop the collab relay, overrides and guest probe. The session factory now
connects src/channel.ts: hello with the session file, every AgentSession
event, commands (get_state, set_model, prompt, abort) against the same
AgentSession the TUI drives, and dialogs raced between the TUI and the host
by wrapping the tool UI context (first answer wins, the other side closes).

Verified: --smoke-test ok; a host-sent prompt opened an ask whose whole HTML
form (checked state included) reached the host as formDialog; the host
answer closed the TUI form; a TUI answer sent ui_end to the host.

* wip: split runner commands into per-group handler tables

src/commands/ holds one CommandTable and FrameTable per group (prompting,
model, session, tools, agents) behind a shared CommandContext; the channel
dispatches cmd frames by op and other host frames by t.

* wip: snapshot of parallel agent work at session interruption

Agents were cut off mid-task; this preserves their partial edits
(runner headless/events/correlation, ompweb process/daemon/manager/auth,
TUI attach socket, release/smoke), plus the spec and DESIGN/AGENTS updates.
Not verified as a whole.

* wip: drop skill diagnostics, exclude runner from root tsc

Skill diagnostics came from an unmerged omp PR that the pinned runner
lacks; the feature, its setting toggle and docs are removed. Root tsconfig
excludes runner/, which has its own. E2E (server+daemon+compiled runner):
prompt, whole ask form with pre-checked default, set_model+edit_message and
TUI attach all passed.

* wip: port host test fixtures to the runner channel; ask form Other + layout

Fake omp children in host tests speak hello/cmd/res/event instead of RPC;
RemoteRpcTransport tags link samples from hello/session frames. The web ask
form adds the automatic Other choice per radio/checkbox group, as omp does.

* test: port remaining fake omp children to the runner channel

Fake hosts and workers in agent-tools, api-contract, message-outbox-review,
outbox-handoff, session-resume and session-routes speak hello/cmd/res/event;
the rename-during-edit test holds a native edit_message command. The late
second RPC response case is gone: the channel reports it as prompt_error.

* test: fix lint in ported login test and multi-server fixture

* fix(runner): register set_event_filter and get_client_message_status

Both handlers existed but were missing from the command table, so the
daemon's event filter and the outbox status probe got unknown-command errors.

* ci: test runner/ in its own job; drop removed keys from zh-TW

The root suite ignores runner/** (its deps live in runner/node_modules);
runner gets a typecheck and bun test job on PRs that touch it. zh-TW, added
on main, still carried the removed skill-diagnostics keys.

* ci: build the omp runner before the smoke tests; scope npm test to app dirs

npm test lists the app directories instead of ignoring runner/** (the
ignore glob missed Windows paths). Smoke needs a real runner: CI builds it
first, and packed-install smokes pass it with --omp until the per-platform
runner packages are published.

* ci(smoke): retry the temp-dir removal while Windows releases the runner's files

* ci(smoke): stop the runner's detached brokers on Windows before removing HOME

omp's daemon broker, LSP mux and embedding server detach and outlive the
session by design; on Windows they keep the throwaway HOME locked.

* test(hosts): wait for the fake omp to record the answer before counting it

The server closes the peer dialog without waiting for omp, so the child's
answer record can land after the cancel frame (seen on Windows CI).

* fix(hosts): give the runner version probe 30 s

A freshly copied runner binary's first start on Windows waits on the
antivirus scan; the 10 s probe reported omp as missing for the whole
daemon session. Smoke waits up to 60 s for the link.

* fix(sessions): read the runner's client-message-entry journal

The runner cannot add clientMessageId to omp's entries, so it journals
{clientMessageId, entryId} in a custom entry. The session reader now takes
the id from either source, on the active branch only, for outbox
reconciliation, full context and history pages.

* feat: drop the last omp RPC dependencies

Runner: headless mode boots through runRootCommand's runSessionHost hook
(upstream PR pending; carried as a Bun patch of the exact diff) instead of
swapping omp's rpc-ui mode with a build plugin, and no runner module imports
omp's RPC helpers any more (prompt results, goals, session events and
settle, message paging, host tools/URIs, btw, dictation, live, subagents are
ported onto omp's non-RPC modules).

ompweb: the server passes the runner's ui_request/ui_end/ui frames through
unchanged and the browser renders each omp dialog method from its own
arguments, answering ui_response with the exact omp return value; the
extension_ui_* translation is gone.

* chore(lint): let the runner drop fields through rest-sibling destructuring

* test: port tests from main's cluster work to channel dialog frames

* fix: address the #460 review round

Daemon: unowned res frames are dropped and startup configure is
fire-and-forget (a slow extension startup no longer resolves the web's
commands with stray replies); a TUI runner cannot attach to a session that
already has a live channel ({t:"refused"}); the host link moves to protocol
v10 (MIN = VERSION), deleting spawnLegacy, legacy channels and every older
version gate; a restarted server sees each event once and in order
(continuous rejoin); the host socket is created under umask 0177; numeric
string dialog ids are normalised; dead capability and lifecycle plumbing
removed.

Runner: only interactive TUIs dial the host, redialling stops after a
refusal, no dialling on Windows yet, open dialogs are re-sent after a
redial and ui_end follows a failed local dialog; tests now kill the
reviewer's mutants and cover edit_message.

Browser: agent forms with controls named like HTMLFormElement members
still submit. Docs: spec, README, AGENTS.md and DESIGN.md describe the
runner and its channel.

* test: move host fixtures to link protocol v10

Fake daemons serve v10 open instead of the removed spawn op, hellos and
welcomes use LINK_PROTOCOL_VERSION, and the removed ready capability is
gone from expectations. Tests of below-v10 join blocks are deleted (such a
host is refused at link time); session-resume asserts that v10 hosts own
their runs. clusterJoinBlock drops its dead protocol parameter.

* test(hosts): hold acks until a full window is resent in the 20,000-line redial test

On a slow socket (Windows' small loopback buffers) the resend outlasted the
test's ack hold: the released acks cover the lines main got before the drop,
so the daemon rightly skipped the rest of the resend and the test waited for
lines that would never come again. Hold acks until a full window is resent.

* ci: install the runner's dependencies before the test suite

* test(hosts): a fake runner the host hangs up on ignores EPIPE

* fix(hosts): port cluster configuration to link protocol v10 and the runner channel

* fix(hosts): the host socket no longer narrows the daemon's umask while it listens

omp children spawned during the pending listen() (restored sessions at startup) inherited umask 0177, so every file and directory their tools created was 0600.

* feat(hosts): preflight the session omp before an upgrade switches

ompweb preflight starts the session omp as a new host session would (same resolver and spawn, --no-session, scratch cwd) and waits up to 30 s for its hello. The host updater and the web self-update worker run the candidate's preflight in the live environment before stopping anything and abort on failure. An npm ompweb host now resolves the runner from its own package.

* fix(hosts): narrow the host socket directory to 0700 and close the server if the socket chmod fails

* fix(hosts): preflight requires the channel protocol, shuts omp down gently and is found by a marker only it embeds

* fix(update): web preflight checks the candidate's own omp and a failed update disarms the launcher

* docs: preflight and protocol-10 cluster upgrade notes

* test(rpc): speak the runner channel in the awaiting-input test from #461

* feat(runner): compile ompweb-omp against the fork's omp packages

runner/scripts/use-omp-build.ts fetches the omp-packages zip of the
andrebrait/oh-my-pi release runner/omp-build.json pins into runner/vendor/,
or re-pins to a given tag (file: deps and overrides for every @oh-my-pi
package and native leaf, bun install, fails if any resolves from npm).
Every runner install fetches first.

The pin itself (omp-build.json, package.json, bun.lock, dropping
runner/patches/) needs the first fork release with the zip:
  bun runner/scripts/use-omp-build.ts <tag> && git rm -r runner/patches

* ci(release): ship the newest omp integration build with every release

* build(runner): pin omp to the fork build v18.20.0-int.202611130808.gfd57e86

* feat(hosts): omp updates with ompweb

Each ompweb release ships its omp runner, and `omp update` on that
runner would replace it with upstream's binary. The omp row now shows
the host's omp version with "Updated with ompweb" and no button:
HostUpdateTarget is "ompweb", HostUpdateInfo.omp is { currentVersion }
(from `omp --version`), hosts refuse an omp target, /api/omp-update
keeps only restart, and the omp update check, cached check, worker
branch and self-update kind are gone. The hub reduces an older
daemon's omp row to its version; recorded omp operations stay readable.

* test(hosts): drop the omp runtime update tests; cover the host update flow and the read-only omp row

* docs: design and plan for building omp in the fork and shipping it with ompweb

* fix(hosts): host binary updates fit a release with its omp runner

A release now carries ompweb (~112 MB) plus ompweb-omp (~284 MB on
linux-x64), which the 256 MiB member and 200 MiB archive limits
refused. The limits are now 512 MiB per member and per archive and
1 GiB expanded, exported as HOST_RELEASE_MAX_*. The download streams to
a file while it is hashed (no Buffer.concat), a .tar.gz is gunzipped to
a scratch tar on disk, and each member is copied out of it in 8 MiB
pieces, so a ~400 MB release peaks at ~145 MB RSS instead of holding
the archive plus its gunzip output. The download (and the npm install)
get 15 min instead of 120 s; the host update lease grows to 30 min to
cover it.

scripts/check-host-release-archive.ts unpacks a built archive through
the same checks and limits; verify-pr's binary job and
build-release-binaries.sh run it on every archive they build.

* ci(release): pin and install the runner before npm test

The tests import the runner (lib/hosts/omp-socket.test.mjs imports
runner/src/channel.ts), whose dependencies only the re-pin installs, so
every tag failed at npm test. Re-pinning first also runs the tests
against the omp build the release ships rather than the committed pin.

* feat(hosts)!: link protocol 11 and refuse every daemon below it

Published prerelease daemons already said v10 while their channels
still carried omp RPC frames; this server sends them runner frames that
they drop silently, so a session never becomes ready and nothing says
which side to update. 11 is the same wire as 10, renumbered, and the
minimum: a v10 daemon gets close 4426 ("needs upgrade"), and a v11
daemon told the server speaks 10 logs "update ompweb on the server".

* refactor(hosts): drop link compat for daemons below the minimum protocol

With every daemon at 11 or later, a v4 peer (whole lines, no ack
window) and a pre-v8 pool member can no longer link: LinkSender loses
its `parts` flag, the hub its v4 window exemption, pool selection its
linkProtocol >= 8 check, and their tests go with them.

* test(hosts): cover what the update mutations slipped past; drop a vacuous test

- a recorded `omp` update operation reads through the route (no 502),
  and a missing or non-string omp version is a 502;
- the daemon refuses an `omp` update target and starts nothing;
- preflight names an omp without the execute bit "not executable";
- a running update makes an available compatible release not
  installable.

"a spawned omp loads the session-edit extension" asserted nothing since
the extension went away (it checked that the bun binary exists).

* fix(omp): one "Reinstall ompweb" message for a missing omp

Seven callers still said "Install oh-my-pi or set OMP_WEB_OMP_BIN",
which cannot help: a stock omp does not speak the runner channel. They
now share omp-cli's OMP_NOT_FOUND (rpc-process's wording), and the two
callers that map it to `omp_not_found` match on that constant. The
errors.omp_not_found string follows in all four locales.

* fix(service): never pin the services to a stock omp found on PATH

The systemd and launchd installers wrote OMP_WEB_OMP_BIN=$(which omp)
into the service environment. That override wins over ompweb's own
ompweb-omp, and a stock omp cannot run ompweb's sessions, so every
session on such a machine failed. Only an explicit OMP_WEB_OMP_BIN is
written now; the install test puts a stock omp on PATH and checks
neither the env file nor the unit names it.

* build(runner): re-pin without breaking vendor/ on a bad release

use-omp-build.ts unpacks into vendor.new/ and swaps it in only once
index.json holds every required package, so a missing leaf or a failed
download leaves vendor/ matching bun.lock. Overrides are replaced, not
merged, so a package the new release dropped keeps no override, and the
download is retried once.

* fix(update): give the candidate preflight room for its own timeouts

ompweb preflight can take 30 s for the hello, about 7 s to stop omp and
30 s for the version probe, over the 60 s both updaters allowed it; a
slow first start failed an update the check would have passed. Both
now allow 120 s.

* docs(code): drop comments that still describe omp RPC mode

* test(host): expect the current link protocol from the CLI daemon status

* feat(omp): every install fetches its omp runner from its own release

No more runner npm packages. A release attaches ompweb-omp-<platform>
and ompweb-omp.sha256; lib/omp/runner-fetch.ts downloads this
version's asset, checks it against that listing, and renames it into
place executable: beside a compiled ompweb, else into a per-version
cache under the agent dir (omp-web/omp/<version>/), which resolveOmpBin
now probes instead of @kahme247/ompweb-omp-<platform>. OMP_WEB_OMP_BIN
still wins, and a source checkout still uses its own runner build.

- `ompweb fetch-omp` fetches it when missing. The host updater and the
  web self-update run the candidate's fetch-omp (15 min) before its
  preflight, so the candidate is checked with the runner it will run.
- The web server and `ompweb host` fetch it at start, in the
  background, when it is missing.
- A failed fetch names the asset URL and OMP_WEB_OMP_BIN.

The release repository is read from package.json's `repository` only
(lib/release-repo.ts): the runner download, the host binary download
(passed to the self-contained worker in its descriptor), the candidate
protocol lookup and the binary update link.

* ci(release): attach the omp runners to the release, not to npm or the archives

publish.yml builds the archives --no-runner, attaches the five runners
and their ompweb-omp.sha256 to the release, and publishes the GitHub
release before the npm package, whose installs fetch their runner from
it. The per-platform runner npm packages and the optionalDependencies
pinning are gone. The binary smoke gets the runner with --omp, since a
draft release serves no assets. Prereleases keep the runner in their
archives: their binaries carry the version of a release that is not
theirs.

* docs: bring README, AGENTS, DESIGN, CHANGELOG and the specs in line with the runner that ships

* docs: every install fetches its omp runner from its release; hosts need one manual update

* chore: the omp fork is ompweb-dev/oh-my-pi

* fix(ask): hide the composer while a form ask is open, as the TUI does

omp's ask tool calls ui.formDialog whenever the UI provides it, so the
runner's ask arrives as formDialog. The composer stayed visible for it,
and a steer sent from there interrupted the ask ("Ask interrupted by
message").

* fix(ask): hold steers while an ask is open

omp's ask tool aborts when a user steer arrives. A steer already in the
outbox now waits until the ask is answered, and send_to_session refuses a
steer into a session waiting on an ask.

* fix(ask): send a held steer as soon as the ask closes

The wrapper now reports when a session's last open ask closes (answered,
cancelled, expired or its child gone), and the outbox delivers a steer it
held for that ask at once, instead of on its retry timer.

* fix(agent-tools): send a steer into an open ask as a follow-up

A steer would interrupt the target's open ask. send_to_session now
delivers it as a follow-up and reports that delivery in its result,
instead of refusing it.

* docs(rpc-manager): note that the rpc naming is a leftover

* build(runner): pin omp to the fork build v18.20.0-int.202611131515.g11d9dc7

* fix(runner): re-pinning rehashes tarballs whose name did not change between omp builds

* fix(runner): send a relocation's notice before the moved session's identity

A non-owning session's first-write relocation sent the new session frame
before the persistence notice, so the daemon dropped the original id's
aliases and a later open by that id started a second child.

* fix(hosts): give the other servers a shared prompt's outcome for notifications

A prompt's prompt_result/prompt_error went only to the submitting server,
so the elected notifier saw session_settled without the failure and
reported a false Completed. Peers now get peer_prompt_outcome (no command
id), which only feeds their notification detector.
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