From ada86458bc028b8859d1c463aad28ee2dcf9da1a Mon Sep 17 00:00:00 2001 From: Kyle Mathews Date: Tue, 3 Mar 2026 09:55:10 -0700 Subject: [PATCH 1/2] improve `intent list` output with table layout and skill hierarchy Replace the flat skill listing with a two-section layout: a summary table (package/version/skill-count/requires) for quick scanning, followed by a skill tree that shows parent/child relationships via indentation. Type tags are conditionally displayed only when skills define them, and column widths are computed globally across all packages for consistent alignment. Co-Authored-By: Claude Opus 4.6 --- packages/intent/src/cli.ts | 127 +++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 11 deletions(-) diff --git a/packages/intent/src/cli.ts b/packages/intent/src/cli.ts index fe5def3..24b13cf 100644 --- a/packages/intent/src/cli.ts +++ b/packages/intent/src/cli.ts @@ -24,6 +24,100 @@ function getMetaDir(): string { // Commands // --------------------------------------------------------------------------- +function padColumn(text: string, width: number): string { + return text.length >= width ? text + ' ' : text.padEnd(width) +} + +function printTable( + headers: string[], + rows: string[][], +): void { + const widths = headers.map((h, i) => + Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)) + 2, + ) + + const headerLine = headers.map((h, i) => padColumn(h, widths[i]!)).join('') + const separator = widths.map((w) => '─'.repeat(w)).join('') + + console.log(headerLine) + console.log(separator) + for (const row of rows) { + console.log(row.map((cell, i) => padColumn(cell, widths[i]!)).join('')) + } +} + +interface SkillDisplay { + name: string + description: string + type?: string +} + +function printSkillTree( + skills: SkillDisplay[], + opts: { nameWidth: number; showTypes: boolean }, +): void { + const roots: string[] = [] + const children = new Map() + + for (const skill of skills) { + const slashIdx = skill.name.indexOf('/') + if (slashIdx === -1) { + roots.push(skill.name) + } else { + const parent = skill.name.slice(0, slashIdx) + if (!children.has(parent)) children.set(parent, []) + children.get(parent)!.push(skill) + } + } + + if (roots.length === 0) { + for (const skill of skills) { + if (!roots.includes(skill.name)) roots.push(skill.name) + } + } + + for (const rootName of roots) { + const rootSkill = skills.find((s) => s.name === rootName) + if (!rootSkill) continue + + printSkillLine(rootName, rootSkill, 4, opts) + + for (const sub of children.get(rootName) ?? []) { + const childName = sub.name.slice(sub.name.indexOf('/') + 1) + printSkillLine(childName, sub, 6, opts) + } + } +} + +function printSkillLine( + displayName: string, + skill: SkillDisplay, + indent: number, + opts: { nameWidth: number; showTypes: boolean }, +): void { + const nameStr = ' '.repeat(indent) + displayName + const padding = ' '.repeat(Math.max(2, opts.nameWidth - nameStr.length)) + const typeCol = opts.showTypes + ? (skill.type ? `[${skill.type}]` : '').padEnd(14) + : '' + console.log(`${nameStr}${padding}${typeCol}${skill.description}`) +} + +function computeSkillNameWidth( + allPackageSkills: SkillDisplay[][], +): number { + let max = 0 + for (const skills of allPackageSkills) { + for (const s of skills) { + const slashIdx = s.name.indexOf('/') + const displayName = slashIdx === -1 ? s.name : s.name.slice(slashIdx + 1) + const indent = slashIdx === -1 ? 4 : 6 + max = Math.max(max, indent + displayName.length) + } + } + return max + 2 +} + async function cmdList(args: string[]): Promise { const jsonOutput = args.includes('--json') @@ -49,18 +143,29 @@ async function cmdList(args: string[]): Promise { return } - console.log(`Intent-enabled packages (${result.packages.length} found):\n`) - + const totalSkills = result.packages.reduce((sum, p) => sum + p.skills.length, 0) + console.log( + `\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`, + ) + + // Summary table + const rows = result.packages.map((pkg) => [ + pkg.name, + pkg.version, + String(pkg.skills.length), + pkg.intent.requires?.join(', ') || '–', + ]) + printTable(['PACKAGE', 'VERSION', 'SKILLS', 'REQUIRES'], rows) + + // Skills detail + const allSkills = result.packages.map((p) => p.skills) + const nameWidth = computeSkillNameWidth(allSkills) + const showTypes = result.packages.some((p) => p.skills.some((s) => s.type)) + + console.log(`\nSkills:\n`) for (const pkg of result.packages) { - const reqStr = pkg.intent.requires?.length - ? ` (requires: ${pkg.intent.requires.join(', ')})` - : '' - console.log(`${pkg.name} v${pkg.version}${reqStr}`) - - for (const skill of pkg.skills) { - const desc = skill.description ? ` ${skill.description}` : '' - console.log(` ${skill.name.padEnd(32)}${desc}`) - } + console.log(` ${pkg.name}`) + printSkillTree(pkg.skills, { nameWidth, showTypes }) console.log() } From 97d7fc5b45d4904cb9d972f41faf06846718958e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:56:09 +0000 Subject: [PATCH 2/2] ci: apply automated fixes --- packages/intent/src/cli.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/intent/src/cli.ts b/packages/intent/src/cli.ts index 24b13cf..16d804a 100644 --- a/packages/intent/src/cli.ts +++ b/packages/intent/src/cli.ts @@ -28,12 +28,9 @@ function padColumn(text: string, width: number): string { return text.length >= width ? text + ' ' : text.padEnd(width) } -function printTable( - headers: string[], - rows: string[][], -): void { - const widths = headers.map((h, i) => - Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)) + 2, +function printTable(headers: string[], rows: string[][]): void { + const widths = headers.map( + (h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)) + 2, ) const headerLine = headers.map((h, i) => padColumn(h, widths[i]!)).join('') @@ -103,9 +100,7 @@ function printSkillLine( console.log(`${nameStr}${padding}${typeCol}${skill.description}`) } -function computeSkillNameWidth( - allPackageSkills: SkillDisplay[][], -): number { +function computeSkillNameWidth(allPackageSkills: SkillDisplay[][]): number { let max = 0 for (const skills of allPackageSkills) { for (const s of skills) { @@ -143,7 +138,10 @@ async function cmdList(args: string[]): Promise { return } - const totalSkills = result.packages.reduce((sum, p) => sum + p.skills.length, 0) + const totalSkills = result.packages.reduce( + (sum, p) => sum + p.skills.length, + 0, + ) console.log( `\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`, )