Repository navigation
feat: run ompweb's own omp build over its own channel instead of RPC - #460
andrebrait wants to merge 37 commits into
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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. |
82ba6a7 to
6ae83e6
Compare
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.
40c5677 to
63e3309
Compare
|
@codex review |
|
@coderabbitai review |
Action not completed
|
Codex Review Summary: ❌ FailedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Something went wrong. Try again later by commenting “@codex review”. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
@codex review |
|
Codex Review: Something went wrong. Try again later by commenting “@codex review”. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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.
…rver if the socket chmod fails
…ently and is found by a marker only it embeds
…d update disarms the launcher
f8bfb0d to
b0d93ad
Compare
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.
|
Moved to #473: the head branch now lives on this repository. |
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.
…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.
Summary
ompweb stops driving omp through
omp --mode rpc-uiand 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 toompweb hostover ompweb's own NDJSON channel. The host receives the sameAgentSessionevents and calls the same session methods omp's TUI does, so RPC gaps (the wholeaskform 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 deltamessage_update, client-message correlation rebuilt in the runner, per-platform binary build and workflow.askrendered natively (with omp's automatic "Other" choice);edit_messageis a native command; the daemon listens on$XDG_RUNTIME_DIR/ompweb/host.sockand adopts TUI-started runner sessions.rpc_chunk,set_ask_dialog, the session-edit extension, skill diagnostics (only in an unmerged omp PR).Testing
tscclean,bun test11/11, compiledompweb-omp-linux-x64--versionand--smoke-testpass, headlessget_stateanswers.askform with explanatory text and a pre-checked default answered from the web;set_modelthenedit_message; a TUI-started session appears live in the web with prompts going both ways.--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
rpc-mode.tsand lifts the no-model exit inmain.tswith a Bun plugin (runner/src/rpc-mode-swap.ts); the build fails loudly if an omp bump moves that check.set_modelno longer saves the default model role (RPC did).main(includes the shared provider logins from feat(hosts): share this server's provider logins with linked hosts #449).