Files
rea/src/application/SetupClients.ts
T
morluto 9abdad335c fix(setup): preserve configuration identity and inspection uncertainty
Refs #4378, #4384, #4432, #4496, #4501.

Keep inaccessible MSIX targets unknown, preserve literal AppData roots, and distinguish absent skill destinations from retained files. Isolate registration tests from host provider discovery.

Windows package behavior was exercised through filesystem fixtures; the installed Windows Claude application was not verified.
2026-10-17 00:44:02 +08:00

75 lines
3.5 KiB
TypeScript

import type {
ClientConfigurationResult,
SetupHost,
SetupProviderEnvironment,
SetupProgressEvent,
} from "./SetupTypes.js";
import type { SetupClient } from "./SupportedClients.js";
export const failedConfigurationMessage = (
result: Extract<ClientConfigurationResult, { readonly status: "failed" }>,
): string => {
if (result.reason === "target_changed")
return "The client began reading a different configuration file after the plan was shown, so no change was made. Rerun setup to review the new target.";
if (result.reason === "target_unavailable")
return `The client configuration read target could not be established because ${result.failure.path} could not be inspected: ${result.failure.detail}. Repair access to that path, then rerun setup.`;
if (result.reason === "path")
return "Agent configuration path could not be safely verified. Check its permissions and, if it is a symbolic link, verify that the link resolves to a regular file owned by the current user, then rerun setup.";
if (result.reason === "backup")
return "Agent configuration could not be backed up, so no change was made. Check file permissions, then rerun setup.";
if (result.reason === "write")
return "Agent configuration could not be updated. Check file permissions, then rerun setup.";
if (result.reason === "rollback")
return result.backupPath === undefined
? `Agent configuration rollback failed at ${result.failure.path}: ${result.failure.detail}; the failed first-run file may remain. Remove or repair it before rerunning setup.`
: `Agent configuration rollback failed at ${result.failure.path}: ${result.failure.detail}. Inspect the preserved backup at ${result.backupPath} and restore the intended configuration, then rerun setup.`;
return "Agent configuration could not be verified after writing. Repair the configuration file or restore its `.rea.backup`, then rerun setup.";
};
/** Configure every detected agent and report the first failed transaction. */
export const configureDetectedClients = async (options: {
readonly host: SetupHost;
readonly detectedClients: readonly SetupClient[];
readonly providerEnvironment: SetupProviderEnvironment;
readonly command: readonly string[];
readonly clients: Record<string, ClientConfigurationResult>;
readonly appliedActions: string[];
readonly onProgress?: (event: SetupProgressEvent) => void;
}): Promise<string | undefined> => {
let failure: string | undefined;
for (const client of options.detectedClients) {
const actionId = `configure_client:${client.name}`;
const label = client.displayName ?? client.name;
options.onProgress?.({ actionId, label, state: "started" });
const result = await options.host.configureClient(
client,
options.providerEnvironment,
options.command,
);
options.clients[client.name] = result;
if (result.status === "failed") {
failure ??= failedConfigurationMessage(result);
options.onProgress?.({
actionId,
label,
state: "failed",
detail: failedConfigurationMessage(result),
});
} else if (result.status === "configured") {
options.appliedActions.push(`configured_${client.name}`);
options.onProgress?.({ actionId, label, state: "completed" });
} else {
options.onProgress?.({
actionId,
label,
state: "warning",
detail:
result.status === "unchanged"
? "Already current"
: "Manual configuration required",
});
}
}
return failure;
};