refactor(cli): sort all list outputs and agent names alphabetically

- update.ts: sort skill selection list alphabetically
- check.ts: sort results by status then name, sort agent names in locations
- install.ts: sort agent names in buildAgentSummary, sort --list output
- sync.ts: sort discovered skills by name before display

Ensures consistent alphabetical ordering across all CLI commands for
better user experience and predictability.
This commit is contained in:
chenbaowang 2026-04-20 19:46:00 +08:00
parent b6301cb9a9
commit e5da7397fa
4 changed files with 21 additions and 9 deletions

View file

@ -70,7 +70,7 @@ export function registerCheck(program: Command) {
name,
status: "ok",
source: entry.source,
location: installedLocations.join(", "),
location: installedLocations.sort((a, b) => a.localeCompare(b)).join(", "),
});
} else {
results.push({
@ -86,11 +86,18 @@ export function registerCheck(program: Command) {
results.push({
name,
status: "orphaned",
location: locations.join(", "),
location: locations.sort((a, b) => a.localeCompare(b)).join(", "),
});
}
}
// Sort results: ok → missing → orphaned, then alphabetically by name
results.sort((a, b) => {
const order = { ok: 0, missing: 1, orphaned: 2 };
const diff = order[a.status] - order[b.status];
return diff !== 0 ? diff : a.name.localeCompare(b.name);
});
if (opts.json) {
console.log(JSON.stringify(results, null, 2));
return;

View file

@ -180,15 +180,17 @@ function buildAgentSummary(targetAgents: AgentInfo[], mode: "symlink" | "copy",
const universal = targetAgents.filter((a) => isUniversalForScope(a, isGlobal));
const symlinked = targetAgents.filter((a) => !isUniversalForScope(a, isGlobal));
const sortNames = (agents: AgentInfo[]) => agents.map((a) => a.name).sort((a, b) => a.localeCompare(b));
if (mode === "symlink") {
if (universal.length > 0) {
lines.push(` universal: ${universal.map((a) => a.name).join(", ")}`);
lines.push(` universal: ${sortNames(universal).join(", ")}`);
}
if (symlinked.length > 0) {
lines.push(` symlink → ${symlinked.map((a) => a.name).join(", ")}`);
lines.push(` symlink → ${sortNames(symlinked).join(", ")}`);
}
} else {
lines.push(` copy → ${targetAgents.map((a) => a.name).join(", ")}`);
lines.push(` copy → ${sortNames(targetAgents).join(", ")}`);
}
return lines;
@ -397,7 +399,8 @@ async function installFromRegistry(slug: string, opts: Record<string, string | s
spinner.succeed(`Found ${skills.length} skill(s) in ${ns}/${actualSlug}`);
if (opts.list) {
for (const s of skills) {
const sorted = [...skills].sort((a, b) => a.name.localeCompare(b.name));
for (const s of sorted) {
info(`${s.name}`);
dim(` ${s.description}`);
}
@ -630,7 +633,8 @@ async function installFromGit(skillName: string, source: string, sourceType: Sou
spinner.succeed(`Found ${skills.length} skill(s)`);
if (opts.list) {
for (const s of skills) {
const sorted = [...skills].sort((a, b) => a.name.localeCompare(b.name));
for (const s of sorted) {
info(`${s.name}`);
dim(` ${s.description}`);
}

View file

@ -49,7 +49,8 @@ export function registerSync(program: Command) {
console.log("");
info(`Found ${skills.length} skill(s):`);
for (const skill of skills) {
const sortedSkills = [...skills].sort((a, b) => a.name.localeCompare(b.name));
for (const skill of sortedSkills) {
console.log(` - ${skill.name} (${skill.description})`);
}
console.log("");

View file

@ -26,7 +26,7 @@ export function registerUpdate(program: Command) {
}
const lockedSkills = await getAllLockedSkills();
const allSkillNames = Object.keys(lockedSkills);
const allSkillNames = Object.keys(lockedSkills).sort((a, b) => a.localeCompare(b));
if (allSkillNames.length === 0) {
error("No skills in lock file.");