mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
* feat(setup): manage fx registrations with its private profile modes fx becomes a client-table row, so doctor, update and uninstall see the registration rea mcp add wrote, and setup offers fx when ~/.fx or FX_HOME exists. Setup now publishes a private profile through the same owner as mcp add (folder 0700, file 0600) and repairs those modes when the row is otherwise current. Doctor parses fx's array launcher instead of reporting it invalid. * fix(setup): judge fx's private profile by its targets and keep its cleanup owner Address review: privateProfileModesCurrent reads the modes of the canonical file and folder, so a linked profile becomes current; clientConfigurationAligned applies the same modes rule as plan and apply; a private-folder close failure reaches the caller with its cleanup owner instead of becoming a write failure; and the setup plan names the folder and file modes it sets. * fix(setup): keep fx's recovery backups owner-only beside a linked profile Setup and uninstall copied a private profile's original bytes with copyFile, so a backup beside a linked ~/.fx/mcp.json kept the target's readable mode outside the folder setup secures. Both now use the owner-only backup owner that mcp add already used. * feat(setup): manage Junie registrations and apply its location policy (#10712) * feat(setup): manage Junie registrations and apply its location policy Junie becomes a client-table row, so doctor, update and uninstall see the registration rea mcp add wrote, and setup offers Junie when its home exists. Whether Junie loads its default user MCP file now has one owner, read through the client policy block that setup, doctor and mcp add already consult: setup and mcp add refuse, and doctor reports, a registration Junie would not load. * fix(setup): read Junie's user configuration as strict JSON Address review: Junie loads config.json as strict JSON, so comments, trailing commas or an empty file leave its MCP location choice unknown, as before the move into the row. Filesystem tests also clear JUNIE_*, FX_HOME and MCPORTER_CONFIG so a developer's own client locations cannot be inspected or removed. * test(setup): keep the detected client order out of the lifecycle suite body The expected detection order grew with each folded client until the suite callback exceeded the max-lines-per-function lint limit. * fix(update): report a client whose policy setup refuses instead of failing maintenance Junie's disabled default locations (and Gemini's settings policy) make doctor report the registration stale, but setup refuses that client, so selecting it failed every other client's maintenance. The registration inspection now carries the setup blocker, and maintenance lists that client with its reason instead of selecting it. * refactor(setup): read fx's private-profile host through HOST_PLATFORM The fx private-profile mode checks and permissions describe the host REA runs on, so they take it from the host-platform owner instead of reading process.platform (refused by the ratchet from #10911). * feat(setup): manage Goose registrations across its configuration layers (#10715) * feat(setup): manage Goose registrations across its configuration layers Goose becomes a client-table row, so doctor, update and uninstall see the registration rea mcp add wrote, and setup offers Goose when its user file or system file exists. Goose loads its system file and GOOSE_ADDITIONAL_CONFIG_FILES beneath the user file and overlays each extension one field deep; doctor now reports that effective registration, while setup, update and uninstall change only the user file. Doctor also parses Goose's cmd launcher instead of reporting it invalid. * fix(setup): keep Goose's layered environment and load order through setup and uninstall Address review: read Goose's env alias and apply requested settings over envs; keep an inherited lower envs map instead of masking it with an empty default; keep each layer's last load so a repeated user file keeps its precedence; split GOOSE_ADDITIONAL_CONFIG_FILES with Windows quoting; validate only the effective environment across read-only layers; refuse uninstall while a read-only layer keeps REA enabled; and clear Goose's location variables in tests. * fix(setup): apply requested Goose settings over the inherited environment * fix(setup): leave lower-layer Goose settings in force and read admin layers read-only Setup no longer writes its default timeout, enabled, name or description into Goose's user entry when only a lower layer declares that setting, so the inherited value keeps applying and a repeat setup stays current. Uninstall reads Goose's read-only lower layers where Goose reads them, without the write target's ownership check, so an administrator-owned system file no longer blocks removal. The client table accepts an injected Goose system-config path so tests no longer read or skip on the host's /etc/goose/config.yaml; adds a shadowed-invalid-lower-layer regression. * fix(setup): keep an inherited Goose env alias's spelling when writing the user entry Goose overlays each extension field separately, so writing envs into the user file beside a lower layer's env alias left both in force, which readers reject as ambiguous. Setup now writes the user map under the alias a lower layer declares, and mcp add neither adds a default envs map beside an inherited alias nor renames a user alias the lower layer shares. * test(setup): inject Goose's system layer into mcp add selection resolveMcpRegistrationClients accepts the caller's system configuration paths, so the Goose layers test no longer reads the host's /etc/goose/config.yaml. * fix(setup): report REA's Goose registration that only a read-only layer defines * test(setup): pass an isolated Goose system path through update maintenance and the mcp add table * fix(setup): judge Goose uninstall by the merged entry and stop on an unreadable lower layer * fix(setup): select Goose's env alias by presence so a null alias stays malformed * fix(setup): use the shared record predicate for Goose's layered merge after #10588 * feat(setup): give Kilo a client-table row with an async layered location (#10823) * feat(setup): give Kilo a client-table row with an async layered location The client table gains a layeredLocation hook and resolveSupportedClients, which awaits it. Kilo's row resolves its user-scope layers through the same owner rea mcp add uses (KiloClientLocation), so both pick the same write target; the synchronous row keeps kilo.json in Kilo's config root with every candidate layer. The table refuses a relative KILO_CONFIG, KILO_CONFIG_DIR or XDG_CONFIG_HOME because Kilo's working directory is unknown. Refs #7181 * fix(setup): treat every folder Kilo reads as evidence that it is installed * fix(setup): normalize Kilo's absolute table paths and parse its command array * feat(setup): resolve the client table's layered locations in setup, doctor, update and uninstall (#10832) SetupHost (detection and the selectable table), ClientRegistrationStatus, uninstall, doctor's selected-registration environment and the mcp add catalog now read resolveSupportedClients, so each sees the Kilo layer Kilo writes rather than the synchronous default. Refs #7181 * docs(adr): record the one-client-table decision for setup and mcp add * fix(setup): refuse to read a client row whose location is unresolved Doctor's selected-client settings read a Kilo row whose relative KILO_CONFIG left only path evidence, so it inspected a file relative to REA's folder. The shared configuration reader now refuses such a row, so every reader reports the registration as unreadable. * docs(adr): name the row's layeredLocation hook * feat(setup): read KILO_CONFIG_CONTENT as Kilo's top read-only layer (#10851) * feat(setup): read KILO_CONFIG_CONTENT as Kilo's top read-only layer * fix(setup): refuse a Kilo uninstall that would expose or keep another layer's rea entry (#10852) * fix(setup): recheck KILO_CONFIG_CONTENT at write time and name it in doctor's recovery * refactor(mcp): register Kilo through its table row and remove the registration-only catalog kind (#10862) * refactor(mcp): register Kilo through its table row and remove the registration-only catalog kind * refactor(mcp): resolve user-scope targets in the catalog so location modules never import the client table * test(setup): cover Kilo's KILO_CONFIG, home-folder and inline-only layers * fix(setup): report REA's Kilo entry that only KILO_CONFIG_CONTENT sets during uninstall Doctor reports a registration that KILO_CONFIG_CONTENT alone defines, but uninstall found no file entry and reported Kilo as skipped. Uninstall now reports it once as failed and names the variable to edit. * docs(adr): record Kilo's inline layer in the client-table decision * fix(setup): compare Windows environment names without case when a higher layer overrides REA's entry Kilo's inline-layer check and Gemini's system-override check compared environment maps by exact key, so an equal Path beside PATH on Windows was reported as an override and setup refused the client. Both compare the entry as the client launches it. * fix(update): leave a stale Kilo registration KILO_CONFIG_CONTENT sets out of maintenance Setup refuses a refresh the inline layer would override, and one refused client failed every other client's maintenance. The registration inspection now names the inline layer as the setup blocker of a stale entry, and maintenance reports Kilo with that recovery instead of selecting it. * fix(setup): refuse relative JUNIE_HOME and Cline CLI overrides like the other client roots (#10909) * fix(setup): refuse relative JUNIE_HOME and Cline CLI overrides like the other client roots * fix(setup): refuse Windows client paths without a drive that follow the client's current drive * fix(update): select maintenance clients through setup's own refresh refusal check Maintenance predicted setup's refusal with its own rule: any inline rea entry blocked a stale registration, while an aligned one was never checked. A harmless KILO_CONFIG_CONTENT entry (enabled: true) kept a stale Kilo launcher pinned, and an inline value setup would not write (an extra environment variable) let an aligned Kilo registration block every client's maintenance. Setup's refusal checks (client policy, then the inline override comparison of the entry it would write) now live in one reader that setup's alignment check and maintenance share. Maintenance asks it for every owned enabled candidate and reports a refused client with setup's remediation and its real state. * fix(update): keep failed refresh-check reads owned by the supplied maintenance scope clientRefreshRefusal read the client's layers, target file and policy without the caller's resource scope, so a close that failed during those reads threw a cleanup failure no scope retained; maintenance then reported it as text and the scope's close could not retry the descriptor. The refresh reader now takes the scope and passes it to every read. * fix(setup): take the Kilo layer readers' default host from HOST_PLATFORM and the shared record predicate After rebasing on main (#10911, #10588): the new inlineRegistrationOverride and resolveSupportedClients defaults read the running host through the host-platform owner, and the layered launcher merge uses isRecord. * fix(update): keep an unreadable layer's reason in the refresh refusal check readClientRefresh returned undefined for an unreadable or malformed layer, so clientRefreshRefusal reported no refusal and maintenance selected a client whose setup preflight then failed. The reader returns the typed file failure, and the refusal check reports its detail like setup's preflight does. * fix(setup): count REA's entry in KILO_CONFIG_CONTENT as Kilo lifecycle evidence Doctor, update and uninstall inspected a client only when one of its folders existed, so a registration set only by KILO_CONFIG_CONTENT was skipped. A read-only inline layer that sets REA's entry is now evidence on its own. * fix(update): report a client whose only conflict is a discovered provider path as needing setup * fix(update): match discovered settings by the platform's environment identity * fix(update): preflight maintenance with setup's write-target checks and treat discovered inline paths as unknown
3.3 KiB
3.3 KiB
One client table for setup, maintenance and rea mcp add
Status
Accepted, 2026-11.
Context
rea mcp add kept its own table of clients, locations and file dialects,
separate from the table that setup, doctor, update and uninstall read. A client
registered through mcp add was invisible to the lifecycle commands, and each
table interpreted the same configuration files independently. Some clients
(Gemini, Junie, Goose, Kilo) decide which registration they load from more than
one file, from environment variables, or from layers REA must not change, so
two interpretations drifted in where to write and what the effective entry is.
Decision
SupportedClients.ts
is the single client table. Each row is the owner of one client's user-scope
registration, and every command reads that row:
- Dialect and reader facts are separate fields.
formatnames the file dialect REA parses and writes. Read-scope facts that decide what the client loads without being write targets (geminiSettings,junieSettings,zcodeFallbackPath, the orderedconfigPaths) are separate fields, so a consumer never infers loading rules from the dialect. mcpAddexposes a row torea mcp add. It adds aliases and project paths only; the user-scope registration uses the row's location, format, profile and read-scope facts, somcp adddoes not keep a second definition of a table client.- Locations that depend on observed layers use one asynchronous hook.
A row's
layeredLocationreturns the write target and every layer in load order once present files are observed.resolveSupportedClientsapplies it for setup, doctor, update and uninstall, andmcp addresolves Kilo's user scope through the same location owner; the synchronous row keeps the default target and every candidate layer. - Lower layers can be read-only. A row with
readOnlyLowerLayershas layers beforeconfigPaththat belong to the system or an administrator. REA reads them to compute the effective registration and writes onlyconfigPath. An inline layer that a client reads from its environment (Kilo'sKILO_CONFIG_CONTENT) isinlineConfiguration: the highest-precedence layer, read for the effective registration and never written. - Uninstall refuses rather than misreport. When a read-only layer would keep REA's enabled registration in effect, or removing the user entry would expose one, uninstall makes no change and names the layer's owner as the recovery. When only an inline layer sets REA's enabled entry, uninstall reports that client as failed and names the variable to edit, as doctor does. An unreadable layer leaves the outcome unknown and also stops uninstall.
Consequences
- Doctor, update and uninstall see every registration
mcp addwrites, and a client added to the table is available to all commands at once. - A client-specific loading rule has one parser, owned by the row's field; consumers use its parsed facts instead of rereading raw files.
- Commands that need the layered location must call
resolveSupportedClients; the synchronoussupportedClientsview is not sufficient for those rows. - Uninstall can report a registration it cannot remove; that client then needs its layer owner's action before uninstall completes.