Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ interface PromptOption<Value extends string> {
export interface SelectParams<Value extends string> {
readonly message: string;
readonly options: readonly PromptOption<Value>[];
/** Which option the cursor starts on. Omit to let the prompt library fall back to its own default (the first option) — pass this explicitly whenever the safest or most common answer isn't the first one listed, so the on-screen reading order and the default-on-Enter answer can differ deliberately rather than being forced to match. */
readonly initialValue?: Value;
}

/** Parameters for a multi-select prompt. */
Expand Down Expand Up @@ -103,6 +105,7 @@ export const realPromptsPort: PromptsPort = {
.select({
message: params.message,
options: toClackOptions(params.options),
...(params.initialValue === undefined ? {} : { initialValue: params.initialValue }),
})
.then((value): Value | symbol => {
if (typeof value === "symbol" || isKnownOptionValue(value, params.options)) {
Expand Down
19 changes: 19 additions & 0 deletions src/identityManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,25 @@ describe("identityManager", () => {
expect(readIdentity(paths, "joseph.mearman@exadev.io")).toBeDefined();
expect(readActiveIdentity(paths)).toBe("joseph.mearman@exadev.io");
});

it("defaults the profile-creation prompt's cursor to skip, so a bare Enter creates no profile", async () => {
const selectCalls: SelectParams<string>[] = [];
const base = scriptedIdentityPrompts(["create", "skip"]);
const spying: PromptsPort = {
...base,
select: (params) => {
selectCalls.push(params);
return base.select(params);
},
};

await runIdentityWizard(spying, paths, "work");

const profilePrompt = selectCalls.find((call) => call.message.includes("configuration profile"));
expect(profilePrompt?.initialValue).toBe("skip");
// The option order stays create-then-skip regardless — initialValue moves the default answer without reordering what's read on screen.
expect(profilePrompt?.options.map((option) => option.value)).toEqual(["create", "skip"]);
});
});

describe("isIdentityDirectoryName", () => {
Expand Down
2 changes: 2 additions & 0 deletions src/identityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export async function runIdentityWizard(prompts: PromptsPort, paths: LayoutPaths
{ value: "create", label: "Create and configure a profile" },
{ value: "skip", label: "Skip for now" },
],
// Most identities need no profile of their own at all — they're meant to fall through to whatever the global default (or a directory rule) already resolves to, and a profile only earns its keep once an identity genuinely needs to diverge from that. Defaulting the cursor to "skip" makes the common, no-profile-needed case the one a bare Enter confirms, without reordering the options and making "skip" read as the first, most prominent choice on screen.
initialValue: "skip",
});
if (!prompts.isCancel(profileChoice) && profileChoice === "create") {
const result = await runProfileWizard(prompts, { paths, defaultNewName: name });
Expand Down
Loading