feat(doctor): add repair/force flows

This commit is contained in:
Peter Steinberger
2026-01-08 21:47:35 +01:00
parent 712a7dddf6
commit 2d4ec35e1c
7 changed files with 80 additions and 8 deletions

View File

@@ -8,14 +8,20 @@ export type DoctorOptions = {
yes?: boolean;
nonInteractive?: boolean;
deep?: boolean;
repair?: boolean;
force?: boolean;
};
export type DoctorPrompter = {
confirm: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmRepair: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmAggressive: (params: Parameters<typeof confirm>[0]) => Promise<boolean>;
confirmSkipInNonInteractive: (
params: Parameters<typeof confirm>[0],
) => Promise<boolean>;
select: <T>(params: Parameters<typeof select>[0], fallback: T) => Promise<T>;
shouldRepair: boolean;
shouldForce: boolean;
};
export function createDoctorPrompter(params: {
@@ -24,24 +30,42 @@ export function createDoctorPrompter(params: {
}): DoctorPrompter {
const yes = params.options.yes === true;
const requestedNonInteractive = params.options.nonInteractive === true;
const shouldRepair = params.options.repair === true || yes;
const shouldForce = params.options.force === true;
const isTty = Boolean(process.stdin.isTTY);
const nonInteractive = requestedNonInteractive || (!isTty && !yes);
const canPrompt = isTty && !yes && !nonInteractive;
const confirmDefault = async (p: Parameters<typeof confirm>[0]) => {
if (nonInteractive) return false;
if (shouldRepair) return true;
if (!canPrompt) return Boolean(p.initialValue ?? false);
return guardCancel(await confirm(p), params.runtime) === true;
};
return {
confirm: confirmDefault,
confirmSkipInNonInteractive: async (p) => {
confirmRepair: async (p) => {
if (nonInteractive) return false;
return confirmDefault(p);
},
confirmAggressive: async (p) => {
if (nonInteractive) return false;
if (shouldRepair && shouldForce) return true;
if (shouldRepair && !shouldForce) return false;
if (!canPrompt) return Boolean(p.initialValue ?? false);
return guardCancel(await confirm(p), params.runtime) === true;
},
confirmSkipInNonInteractive: async (p) => {
if (nonInteractive) return false;
if (shouldRepair) return true;
return confirmDefault(p);
},
select: async <T>(p: Parameters<typeof select>[0], fallback: T) => {
if (!canPrompt) return fallback;
if (!canPrompt || shouldRepair) return fallback;
return guardCancel(await select(p), params.runtime) as T;
},
shouldRepair,
shouldForce,
};
}