93 lines
4.5 KiB
Markdown
93 lines
4.5 KiB
Markdown
# Wiring: mplex and uiflow (hooks for the integrator)
|
|
|
|
Everything below is applied outside `src/mplex` and `src/plexer/plexer_flow.*`, which the mplex
|
|
port does not own. Nothing here changes behavior of the ported classes.
|
|
|
|
## Build
|
|
|
|
Add `src/mplex/mplex.mk` to the module list (the top Makefile already has `-include src/*/*.mk`,
|
|
so the file is picked up as is). It appends every mplex source and `src/plexer/plexer_flow.cpp`
|
|
to `SRCS`. `ALL_SRCS = $(shell find src -name '*.cpp')` already compiles them into `build/detz`
|
|
and `build/detz_test`; there is no duplicate `main` in `src/` (the standalone binary
|
|
`tests/mplex_cli_main.cpp` is compiled only by the `$(BUILD)/mplex_cli` rule inside `mplex.mk`).
|
|
|
|
Includes: the headers use flat names prefixed `mplex_` / `plexer_flow.h`; the Makefile's
|
|
`-I` for every `src/*` directory is enough. Link needs only libc (no sqlite, no curl).
|
|
|
|
Extra targets defined in `mplex.mk`: `make build/mplex_cli`, `make build/mplex_flow_test`,
|
|
`make mplex-flow-test`, `make mplex-e2e`.
|
|
|
|
## `--mplex [COMMAND...]`
|
|
|
|
tai.py declares `--mplex` with `nargs=argparse.REMAINDER, default=None`: everything after the flag
|
|
belongs to mplex, bare `--mplex` means a new session. `src/cli/cli.cpp:130` already parses this into
|
|
`o.mplex` (`std::optional<std::vector<std::string>>`, set to an empty vector for bare `--mplex`).
|
|
|
|
Dispatch (tai.py 40125-40128): after `--version`, `--cap*`, `--serve-mcp`, `--update-models`,
|
|
`--demo*` and the theme check, before `--plexer-wrap` and `--tui`:
|
|
|
|
```cpp
|
|
#include "mplex_client.h"
|
|
...
|
|
if (opts.mplex.has_value()) {
|
|
std::string home = Env("TAI_HOME").empty() ? HomeDir() + "/.tai" : Env("TAI_HOME");
|
|
return detz::mplex::MplexCli::main(home, *opts.mplex);
|
|
}
|
|
```
|
|
|
|
`MplexCli::main` returns the process exit code and writes its own diagnostics to stderr, exactly
|
|
like the Python (`sessions should be nested with care, unset TAI_PLEXER_ACTIVE to force`,
|
|
`open terminal failed: not a terminal`, `no server running on <sock>`, ...).
|
|
|
|
Argument quirk to keep in step with tai.py: argparse's `nargs=REMAINDER` swallows a literal `--`
|
|
inside the mplex words (tai.py: `--mplex send-keys -X -- cursor-up` loses the `--`), while
|
|
`tests/mplex_cli_main.cpp` passes argv through untouched. The `src/cli` parser must drop/keep `--`
|
|
exactly as `argparse.REMAINDER` does (verify against `python3 tai.py --mplex ls -- x`).
|
|
|
|
The `version` format variable is `detz::kVersion` when the build puts the generated `version.hpp`
|
|
on the include path (the Makefile's `-I$(GEN_INC)` does), `1.44.2` otherwise.
|
|
|
|
## `--plexer-wrap`
|
|
|
|
tai.py 40129-40133: same `home` computation, `profile = args.profile or "default"`:
|
|
|
|
```cpp
|
|
if (opts.plexer_wrap) {
|
|
std::string home = ...; // same as above
|
|
detz::mplex::NativePlexerBackend backend(home, opts.profile.empty() ? "default" : opts.profile);
|
|
return backend.run();
|
|
}
|
|
```
|
|
|
|
`NativePlexerBackend::run()` starts or joins the server and attaches this terminal to a fresh
|
|
session (`MplexCli::main(home, {"new-session"})`).
|
|
|
|
## Shell hook text and detection
|
|
|
|
`detz::mplex::PLEXER_BASHRC_BLOCK`, `FISH_PLEXER_BLOCK`, `PLEXER_BASHRC_MARK_BEGIN/END` and
|
|
`plexer_should_wrap(env)` (header `mplex_client.h`) are byte-identical to the Python constants. The
|
|
installer (`--install`) must write these strings, not copy its own.
|
|
|
|
## Agent tools (`plexer_send`, `plexer_read`, `plexer_type`, `plexer_status`, `plexer_show`)
|
|
|
|
Use `detz::plexer::PlexerControllerFactory::detect()` from `plexer_flow.h` (native when
|
|
`TAI_PLEXER_SOCKET` is set, tmux when `TMUX_PANE` is set, null otherwise, which hides the tools).
|
|
`plexer_show` is `validate_flow_spec(spec)` followed by `PlexerFlow(app).run(*controller)`; its
|
|
result JSON is the return value. The existing skeleton `detz::plexer::Controller/Native/Tmux` in
|
|
`src/plexer/plexer.h` is superseded by `PlexerController` and friends and can be deleted by the
|
|
foundation owner once the tool handlers call the new classes (both can coexist: names differ).
|
|
|
|
## Server process
|
|
|
|
`MplexServer::ensure_running(home)` double-forks a detached daemon that runs the select loop in the
|
|
same binary, so `detz` needs no extra executable. Its stdout/stderr go to
|
|
`<TAI_HOME>/plexer/server.log`. The daemon inherits the environment; `TERM`, `SHELL` and `TAI_HOME`
|
|
behave as in tai.py.
|
|
|
|
## Verified
|
|
|
|
See the report of the porting run: `tests/mplex_flow_test.cpp` (spec/flow corpus against tai.py),
|
|
`tests/mplex_e2e.py` (seven scenarios run through a pty against both `tai.py --mplex` and
|
|
`build/mplex_cli --mplex`, observations compared), `tests/mplex_tmux_oracle.py` (tmux 3.6 oracle for
|
|
the tmux controller).
|