fix(cli): retain bundled skill and bias setup wizard toward apply

Fix #399: when agent integration is selected but all agents are deselected,
the bundled skill was silently dropped. The skill is now always included
when agent integration is selected, regardless of client selection.

Fix #398: the setup wizard defaulted to cancellation at every step despite
explicit setup intent. The capability picker now pre-selects agent
integration, the agent picker pre-selects all detected agents, the final
confirmation defaults to Yes, and accessible prompts default to Yes for
pre-selected items. Agent option hints now describe the agent instead of
the file operation.

Update tests/cliSetup.test.ts to cover the new skill-retention (#399) and
default-toward-apply (#398) behavior, including accessible-mode opt-out.

Update docs/installation.md to describe the new pre-selection and
Yes-default confirmation.
This commit is contained in:
morluto committed 2026-07-22 17:01:05 +00:00
1 parent eb27f01aee
commit fec5c3ce7f
3 files changed
+118 -44

No files matched your search

+32 -11
View File
@@ -61,7 +61,7 @@ export const confirmInteractiveSetup = async (
selectedActions.length === 1
? "Apply this change?"
: `Apply these ${String(selectedActions.length)} changes?`,
initialValue: false,
initialValue: true,
active: "Yes, apply",
inactive: "No, cancel",
});
@@ -131,9 +131,10 @@ const selectSetupActions = async (
({ kind }) => kind !== "configure_client",
);
const capabilities = setupCapabilities(clientActions, componentActions);
const preselectedCapabilityIds = defaultCapabilityIds(capabilities);
const selectedCapabilities = accessible
? await selectCapabilitiesAccessibly(capabilities)
: await selectCapabilities(capabilities);
? await selectCapabilitiesAccessibly(capabilities, preselectedCapabilityIds)
: await selectCapabilities(capabilities, preselectedCapabilityIds);
if (selectedCapabilities === undefined) return undefined;
const selectedCapabilityIds = new Set(selectedCapabilities);
const bundledSkillAction = componentActions.find(
@@ -147,23 +148,35 @@ const selectSetupActions = async (
.map(({ id }) => id);
if (!selectedCapabilityIds.has(agentIntegrationCapabilityId))
return selectedActionIds;
const bundledSkillId =
bundledSkillAction === undefined ? undefined : bundledSkillAction.id;
if (clientActions.length === 0)
return [
...(bundledSkillAction === undefined ? [] : [bundledSkillAction.id]),
...(bundledSkillId === undefined ? [] : [bundledSkillId]),
...selectedActionIds,
];
const preselectedClientIds = clientActions.map(({ id }) => id);
const selectedClients = accessible
? await selectClientsAccessibly(clientActions)
: await selectClients(clientActions);
? await selectClientsAccessibly(clientActions, preselectedClientIds)
: await selectClients(clientActions, preselectedClientIds);
if (selectedClients === undefined) return undefined;
if (selectedClients.length === 0) return selectedActionIds;
return [
...selectedClients,
...(bundledSkillAction === undefined ? [] : [bundledSkillAction.id]),
...(bundledSkillId === undefined ? [] : [bundledSkillId]),
...selectedActionIds,
];
};
const defaultCapabilityIds = (
capabilities: readonly SetupCapability[],
): readonly string[] => {
const hasAgentIntegration = capabilities.some(
({ id }) => id === agentIntegrationCapabilityId,
);
if (!hasAgentIntegration) return [];
return [agentIntegrationCapabilityId];
};
const setupCapabilities = (
clientActions: readonly SetupAction[],
componentActions: readonly SetupAction[],
@@ -192,6 +205,7 @@ const setupCapabilities = (
const selectCapabilities = async (
capabilities: readonly SetupCapability[],
initialValues: readonly string[],
): Promise<readonly string[] | undefined> => {
const selection = await multiselect({
...promptStreams,
@@ -201,6 +215,7 @@ const selectCapabilities = async (
label: capability.label,
hint: capability.hint,
})),
initialValues: [...initialValues],
required: false,
maxItems: Math.max(
3,
@@ -213,13 +228,15 @@ const selectCapabilities = async (
const selectCapabilitiesAccessibly = async (
capabilities: readonly SetupCapability[],
preselectedIds: readonly string[],
): Promise<readonly string[] | undefined> => {
const preselected = new Set(preselectedIds);
const selected: string[] = [];
for (const capability of capabilities) {
const included = await confirm({
...promptStreams,
message: `Set up ${capability.label}? ${capability.hint}`,
initialValue: false,
initialValue: preselected.has(capability.id),
vertical: true,
});
if (isCancel(included)) return undefined;
@@ -230,6 +247,7 @@ const selectCapabilitiesAccessibly = async (
const selectClients = async (
actions: readonly SetupAction[],
initialValues: readonly string[],
): Promise<readonly string[] | undefined> => {
const selection = await multiselect({
...promptStreams,
@@ -237,8 +255,9 @@ const selectClients = async (
options: actions.map((action) => ({
value: action.id,
label: `${action.label} (detected)`,
hint: `${action.operation} · ${action.target}`,
hint: `Configure the REA MCP server for ${action.label}`,
})),
initialValues: [...initialValues],
required: false,
maxItems: Math.max(
3,
@@ -251,13 +270,15 @@ const selectClients = async (
const selectClientsAccessibly = async (
actions: readonly SetupAction[],
initialValues: readonly string[],
): Promise<readonly string[] | undefined> => {
const preselected = new Set(initialValues);
const selected: string[] = [];
for (const action of actions) {
const included = await confirm({
...promptStreams,
message: `Configure ${action.label}? ${action.target}`,
initialValue: false,
initialValue: preselected.has(action.id),
vertical: true,
});
if (isCancel(included)) return undefined;