mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
* feat(setup): register OMP during setup Add OMP (oh-my-pi) as a setup, doctor and uninstall client. Setup writes a type: stdio entry to the user-level agent mcp.json that OMP reads, following PI_CONFIG_DIR, an absolute PI_CODING_AGENT_DIR and the OMP_PROFILE/PI_PROFILE named profile. It removes rea from OMP's disabledServers denylist, which would otherwise hide the registration, and doctor reports a listed registration as stale. Closes #1257 Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(setup): honor OMP's enabledServers allowlist in doctor OMP's user enabledServers allowlist forces an entry with enabled: false on, unless disabledServers also lists it. Doctor reported such a working registration as stale. Also format the FAQ client list. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(setup): keep OMP's allowlisted entry in update maintenance rea update skipped an owned OMP entry with enabled: false even when OMP's enabledServers allowlist runs it. Apply the same forced-enable rule as doctor. Share the client-location environment reset across the client tests instead of repeating it in each file. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
127 lines
4.0 KiB
JavaScript
127 lines
4.0 KiB
JavaScript
import { chmod, mkdir, symlink, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { supportedClients } from "../dist/application/SupportedClients.js";
|
|
|
|
/** Create an isolated prefix, fake PATH, client configs, and environment. */
|
|
export async function verifyPackageEnvironment({
|
|
root,
|
|
workspace,
|
|
evidenceRoot,
|
|
referenceRoot,
|
|
}) {
|
|
const prefix = join(workspace, "prefix");
|
|
const home = join(workspace, "home");
|
|
const fakeBin = join(workspace, "bin");
|
|
await mkdir(fakeBin, { recursive: true });
|
|
await Promise.all([
|
|
mkdir(evidenceRoot, { recursive: true }),
|
|
mkdir(join(referenceRoot, "src"), { recursive: true }),
|
|
]);
|
|
await Promise.all([
|
|
writeFile(
|
|
join(referenceRoot, "src", "main.ts"),
|
|
'import "./dependency";\n',
|
|
),
|
|
writeFile(
|
|
join(referenceRoot, "src", "dependency.ts"),
|
|
"export const value = 1;\n",
|
|
),
|
|
writeFile(join(referenceRoot, ".env"), "PACKAGE_SECRET_SENTINEL=1\n"),
|
|
]);
|
|
const brew = join(fakeBin, "brew");
|
|
const swVers = join(fakeBin, "sw_vers");
|
|
const npx = join(fakeBin, "npx");
|
|
const npxLog = join(workspace, "npx.log");
|
|
const hopper = join(workspace, "hopper");
|
|
await writeFile(
|
|
brew,
|
|
'#!/bin/sh\nif [ "$1" = "--prefix" ]; then echo /fake/cask; fi\nexit 0\n',
|
|
);
|
|
await writeFile(swVers, "#!/bin/sh\necho 14.5\n");
|
|
await writeFile(
|
|
npx,
|
|
'#!/bin/sh\nprintf "%s\\n" "$*" > "$REA_NPX_LOG"\necho "│ ✓ Cursor: isolated │"\n',
|
|
);
|
|
await writeFile(hopper, "#!/bin/sh\nexit 0\n");
|
|
await Promise.all([
|
|
chmod(brew, 0o755),
|
|
chmod(swVers, 0o755),
|
|
chmod(hopper, 0o755),
|
|
chmod(npx, 0o755),
|
|
]);
|
|
const claudeDir = supportedClients(home, process.platform, {}).find(
|
|
({ name }) => name === "claude_desktop",
|
|
)?.markerPath;
|
|
if (claudeDir === undefined)
|
|
throw new Error("Claude Desktop fixture has no configuration directory");
|
|
const codexDir = join(home, ".codex");
|
|
const cursorDir = join(home, ".cursor");
|
|
await Promise.all([
|
|
mkdir(claudeDir, { recursive: true }),
|
|
mkdir(codexDir, { recursive: true }),
|
|
mkdir(cursorDir, { recursive: true }),
|
|
]);
|
|
const claudeConfig = join(claudeDir, "claude_desktop_config.json");
|
|
const codexConfig = join(codexDir, "config.toml");
|
|
const codexTarget = join(home, "managed-codex.toml");
|
|
const cursorConfig = join(cursorDir, "mcp.json");
|
|
const cursorTarget = join(home, "managed-cursor.json");
|
|
await writeFile(claudeConfig, '{"existing":true}\n');
|
|
await writeFile(codexTarget, 'model = "gpt-5"\n');
|
|
await writeFile(cursorTarget, '{"existing":true}\n');
|
|
await symlink(codexTarget, codexConfig);
|
|
await symlink(cursorTarget, cursorConfig);
|
|
const environment = {
|
|
...process.env,
|
|
HOME: home,
|
|
USERPROFILE: home,
|
|
APPDATA: join(home, "AppData", "Roaming"),
|
|
CLAUDE_CONFIG_DIR: home,
|
|
CODEX_HOME: codexDir,
|
|
COPILOT_HOME: join(home, ".copilot"),
|
|
GROK_HOME: join(home, ".grok"),
|
|
SAND_DATA_ROOT: join(home, ".grokbot"),
|
|
OMP_PROFILE: undefined,
|
|
PI_CODING_AGENT_DIR: undefined,
|
|
PI_CONFIG_DIR: undefined,
|
|
PI_PROFILE: undefined,
|
|
OPENCODE_CONFIG: undefined,
|
|
XDG_CONFIG_HOME: join(home, ".config"),
|
|
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
|
|
REA_ANALYSIS_PROVIDER: "auto",
|
|
...packageHopperEnvironment(root),
|
|
REA_NPX_LOG: npxLog,
|
|
REA_REFERENCE_SECRET_PATTERNS_JSON: JSON.stringify([".env"]),
|
|
};
|
|
return {
|
|
prefix,
|
|
home,
|
|
npxLog,
|
|
claudeConfig,
|
|
codexConfig,
|
|
codexTarget,
|
|
cursorConfig,
|
|
cursorTarget,
|
|
environment,
|
|
};
|
|
}
|
|
|
|
export const packageHopperEnvironment = (root, platform = process.platform) => {
|
|
const fakeLauncher = join(root, "tests/fixtures/fakeLauncher.mjs");
|
|
if (platform !== "linux")
|
|
return {
|
|
HOPPER_LAUNCHER_PATH: process.execPath,
|
|
HOPPER_LOADER_ARGS_JSON: JSON.stringify([fakeLauncher]),
|
|
};
|
|
return {
|
|
HOPPER_LAUNCHER_PATH: "/bin/sh",
|
|
HOPPER_LOADER_ARGS_JSON: JSON.stringify([
|
|
"-c",
|
|
'node_path=$1; shift; "$node_path" "$@"',
|
|
"rea-package-hopper",
|
|
process.execPath,
|
|
fakeLauncher,
|
|
]),
|
|
};
|
|
};
|