mirror of
https://github.com/morluto/rea
synced 2026-10-25 14:01:13 -04:00
refactor(clients): retain inspected command ownership
Carry the command identity already parsed during registration inspection into maintenance selection. Keep activation, validity and public status output separate. Validation: fresh build/catalog and full static checks; registration status, update maintenance and setup cleanup ownership suites passed (90 tests).
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
||||
import {
|
||||
inspectClientRegistrationCommand,
|
||||
type ClientRegistrationCommandFacts,
|
||||
type ClientRegistrationCommandIdentity,
|
||||
packageRunnerRegistrationCommand,
|
||||
} from "./ClientRegistrationIdentity.js";
|
||||
import {
|
||||
@@ -94,6 +95,8 @@ interface ClientRegistrationReadOptions {
|
||||
export interface ClientRegistrationInspection {
|
||||
readonly status: ClientRegistrationStatus;
|
||||
readonly activation: "enabled" | "disabled" | "unknown";
|
||||
/** Ownership remains unknown until this inspection has parsed the launcher. */
|
||||
readonly commandIdentity: ClientRegistrationCommandIdentity;
|
||||
}
|
||||
|
||||
/** Project diagnostics from the same inspection used to select maintenance. */
|
||||
@@ -118,8 +121,9 @@ export const readClientRegistrationInspections = async (
|
||||
const record = (
|
||||
status: ClientRegistrationStatus,
|
||||
activation: ClientRegistrationInspection["activation"] = "unknown",
|
||||
commandIdentity: ClientRegistrationCommandIdentity = "unknown",
|
||||
): void => {
|
||||
inspections.push({ status, activation });
|
||||
inspections.push({ status, activation, commandIdentity });
|
||||
};
|
||||
for (const client of supportedClients(
|
||||
home,
|
||||
@@ -330,6 +334,7 @@ export const readClientRegistrationInspections = async (
|
||||
: undefined,
|
||||
),
|
||||
activation,
|
||||
commandFacts.identity,
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
if (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { RegularFileCleanupFailure } from "../filesystem/OwnedRegularFile.js";
|
||||
|
||||
import { classifyClientRegistrationCommand } from "./ClientRegistrationIdentity.js";
|
||||
import {
|
||||
readClientRegistrationInspections,
|
||||
type ClientRegistrationStatus,
|
||||
@@ -75,7 +74,11 @@ export const existingMaintenanceScope = async (
|
||||
);
|
||||
const clients: string[] = [];
|
||||
const unresolved: ClientRegistrationStatus[] = [];
|
||||
for (const { status: registration, activation } of registrations) {
|
||||
for (const {
|
||||
status: registration,
|
||||
activation,
|
||||
commandIdentity,
|
||||
} of registrations) {
|
||||
if (registration.state === "unknown" || registration.state === "invalid") {
|
||||
unresolved.push(registration);
|
||||
continue;
|
||||
@@ -83,8 +86,7 @@ export const existingMaintenanceScope = async (
|
||||
if (
|
||||
activation !== "enabled" ||
|
||||
(registration.state !== "aligned" && registration.state !== "stale") ||
|
||||
classifyClientRegistrationCommand(registration.command, entryPoint) !==
|
||||
"owned"
|
||||
commandIdentity !== "owned"
|
||||
)
|
||||
continue;
|
||||
clients.push(registration.client);
|
||||
|
||||
@@ -6,7 +6,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { clearClientLocationEnvironment } from "../../fixtures/clientEnvironment.js";
|
||||
|
||||
import { readClientRegistrationStatuses } from "../../../src/application/ClientRegistrationStatus.js";
|
||||
import {
|
||||
readClientRegistrationInspections,
|
||||
readClientRegistrationStatuses,
|
||||
} from "../../../src/application/ClientRegistrationStatus.js";
|
||||
import { configureClientConfiguration } from "../../../src/application/SetupClientConfiguration.js";
|
||||
import { classifyClientRegistrationCommand } from "../../../src/application/ClientRegistrationIdentity.js";
|
||||
import { existingMaintenanceScope } from "../../../src/application/UpdateMaintenance.js";
|
||||
@@ -180,6 +183,14 @@ describe("client registration launcher identity", () => {
|
||||
state: "unknown",
|
||||
remediation: expect.stringContaining("registration was retained"),
|
||||
});
|
||||
expect(status).not.toHaveProperty("commandIdentity");
|
||||
expect(await readClientRegistrationInspections(home, "")).toEqual([
|
||||
expect.objectContaining({
|
||||
status,
|
||||
activation: "enabled",
|
||||
commandIdentity: "unknown",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not use the REA process cwd to resolve a client's relative launcher path", async () => {
|
||||
@@ -230,7 +241,9 @@ describe("client registration launcher identity", () => {
|
||||
state: "unknown",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("client registration package version identity", () => {
|
||||
it.each([
|
||||
["4.1.0", true],
|
||||
["v4.1.0", false],
|
||||
|
||||
@@ -6,6 +6,7 @@ import { err, ok } from "../../src/domain/result.js";
|
||||
import { runUpdate, type UpdateResult } from "../../src/application/Update.js";
|
||||
import { PRODUCT_IDENTITY } from "../../src/identity.js";
|
||||
import { supportedClients } from "../../src/application/SupportedClients.js";
|
||||
import { readClientRegistrationInspections } from "../../src/application/ClientRegistrationStatus.js";
|
||||
import {
|
||||
existingMaintenanceScope,
|
||||
planIntegrationMaintenance,
|
||||
@@ -238,7 +239,7 @@ describe("maintenance activation and layered configuration", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("existing REA integration maintenance", () => {
|
||||
describe("registration ownership in maintenance", () => {
|
||||
it("selects owned registrations while preserving unconfigured, foreign, and disabled choices", async () => {
|
||||
await writeClient("codex", staleCodex);
|
||||
await writeClient("claude_code", '{"mcpServers":{}}');
|
||||
@@ -256,6 +257,40 @@ describe("existing REA integration maintenance", () => {
|
||||
servers: { rea: { type: "stdio", command: entryPoint, args: ["mcp"] } },
|
||||
}),
|
||||
);
|
||||
expect(
|
||||
await readClientRegistrationInspections(home, entryPoint, {
|
||||
environment: process.env,
|
||||
}),
|
||||
).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
status: expect.objectContaining({ client: "codex", state: "stale" }),
|
||||
activation: "enabled",
|
||||
commandIdentity: "owned",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
status: expect.objectContaining({ client: "cursor", state: "stale" }),
|
||||
activation: "enabled",
|
||||
commandIdentity: "foreign",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
status: expect.objectContaining({
|
||||
client: "opencode",
|
||||
state: "stale",
|
||||
}),
|
||||
activation: "disabled",
|
||||
commandIdentity: "owned",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
status: expect.objectContaining({
|
||||
client: "claude_code",
|
||||
state: "missing",
|
||||
}),
|
||||
activation: "unknown",
|
||||
commandIdentity: "unknown",
|
||||
}),
|
||||
]),
|
||||
);
|
||||
await expect(
|
||||
existingMaintenanceScope(home, entryPoint, process.env),
|
||||
).resolves.toEqual({
|
||||
@@ -264,7 +299,9 @@ describe("existing REA integration maintenance", () => {
|
||||
skillDestinations: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("existing REA integration maintenance", () => {
|
||||
it("does not install a missing skill or overwrite an unrelated skill", async () => {
|
||||
await expect(
|
||||
existingMaintenanceScope(home, entryPoint, process.env),
|
||||
|
||||
Reference in New Issue
Block a user