@runa-cmd/help 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +279 -0
  3. package/dist/ansi/codes.d.ts +33 -0
  4. package/dist/ansi/codes.d.ts.map +1 -0
  5. package/dist/ansi/codes.js +54 -0
  6. package/dist/ansi/codes.js.map +1 -0
  7. package/dist/ansi/detect.d.ts +36 -0
  8. package/dist/ansi/detect.d.ts.map +1 -0
  9. package/dist/ansi/detect.js +82 -0
  10. package/dist/ansi/detect.js.map +1 -0
  11. package/dist/ansi/downsample.d.ts +22 -0
  12. package/dist/ansi/downsample.d.ts.map +1 -0
  13. package/dist/ansi/downsample.js +126 -0
  14. package/dist/ansi/downsample.js.map +1 -0
  15. package/dist/index.d.ts +26 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +23 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/plugin.d.ts +18 -0
  20. package/dist/plugin.d.ts.map +1 -0
  21. package/dist/plugin.js +63 -0
  22. package/dist/plugin.js.map +1 -0
  23. package/dist/primitives/box.d.ts +23 -0
  24. package/dist/primitives/box.d.ts.map +1 -0
  25. package/dist/primitives/box.js +76 -0
  26. package/dist/primitives/box.js.map +1 -0
  27. package/dist/primitives/columns.d.ts +15 -0
  28. package/dist/primitives/columns.d.ts.map +1 -0
  29. package/dist/primitives/columns.js +37 -0
  30. package/dist/primitives/columns.js.map +1 -0
  31. package/dist/primitives/join.d.ts +32 -0
  32. package/dist/primitives/join.d.ts.map +1 -0
  33. package/dist/primitives/join.js +89 -0
  34. package/dist/primitives/join.js.map +1 -0
  35. package/dist/primitives/list.d.ts +22 -0
  36. package/dist/primitives/list.d.ts.map +1 -0
  37. package/dist/primitives/list.js +25 -0
  38. package/dist/primitives/list.js.map +1 -0
  39. package/dist/primitives/styled.d.ts +28 -0
  40. package/dist/primitives/styled.d.ts.map +1 -0
  41. package/dist/primitives/styled.js +59 -0
  42. package/dist/primitives/styled.js.map +1 -0
  43. package/dist/primitives/table.d.ts +19 -0
  44. package/dist/primitives/table.d.ts.map +1 -0
  45. package/dist/primitives/table.js +50 -0
  46. package/dist/primitives/table.js.map +1 -0
  47. package/dist/primitives/wrap.d.ts +10 -0
  48. package/dist/primitives/wrap.d.ts.map +1 -0
  49. package/dist/primitives/wrap.js +69 -0
  50. package/dist/primitives/wrap.js.map +1 -0
  51. package/dist/render.d.ts +8 -0
  52. package/dist/render.d.ts.map +1 -0
  53. package/dist/render.js +219 -0
  54. package/dist/render.js.map +1 -0
  55. package/dist/theme.d.ts +12 -0
  56. package/dist/theme.d.ts.map +1 -0
  57. package/dist/theme.js +45 -0
  58. package/dist/theme.js.map +1 -0
  59. package/dist/types.d.ts +60 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +2 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +63 -0
@@ -0,0 +1,19 @@
1
+ import type { Block } from '../types.js';
2
+ /** Options for table() */
3
+ export interface TableOptions {
4
+ /**
5
+ * Cell padding [vertical, horizontal] (default: [0, 2]).
6
+ * Horizontal padding is applied as right-padding between columns.
7
+ */
8
+ padding?: [number, number];
9
+ /** Optional header row (rendered with bold if styles available) */
10
+ headers?: string[];
11
+ }
12
+ /**
13
+ * Render rows as a table with auto-sized columns.
14
+ *
15
+ * @param rows - 2D array of cell content
16
+ * @param opts - Table options
17
+ */
18
+ export declare function table(rows: Block[][], opts?: TableOptions): Block;
19
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/primitives/table.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,0BAA0B;AAC1B,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,GAAE,YAAiB,GAAG,KAAK,CAwCrE"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @runa-cmd/help — table() primitive
3
+ *
4
+ * Renders a 2D array of strings/Blocks as aligned columns.
5
+ * No grid lines by default — uses padding-based layout.
6
+ */
7
+ import { visibleWidth } from '../ansi/codes.js';
8
+ /**
9
+ * Render rows as a table with auto-sized columns.
10
+ *
11
+ * @param rows - 2D array of cell content
12
+ * @param opts - Table options
13
+ */
14
+ export function table(rows, opts = {}) {
15
+ const [_vPad, hPad] = opts.padding ?? [0, 2];
16
+ if (rows.length === 0 && !opts.headers)
17
+ return '';
18
+ // Combine headers + rows for column width calculation
19
+ const allRows = opts.headers ? [opts.headers, ...rows] : rows;
20
+ // Find max number of columns
21
+ const numCols = allRows.reduce((max, row) => Math.max(max, row.length), 0);
22
+ // Calculate max visible width per column
23
+ const colWidths = Array.from({ length: numCols }, () => 0);
24
+ for (const row of allRows) {
25
+ for (let col = 0; col < row.length; col++) {
26
+ colWidths[col] = Math.max(colWidths[col], visibleWidth(row[col]));
27
+ }
28
+ }
29
+ // Render each row
30
+ const separator = ' '.repeat(hPad);
31
+ const resultLines = [];
32
+ for (const row of allRows) {
33
+ const cells = [];
34
+ for (let col = 0; col < numCols; col++) {
35
+ const cell = row[col] ?? '';
36
+ if (col < numCols - 1) {
37
+ // Pad to column width (using visible width to account for ANSI)
38
+ const padNeeded = colWidths[col] - visibleWidth(cell);
39
+ cells.push(cell + ' '.repeat(Math.max(0, padNeeded)));
40
+ }
41
+ else {
42
+ // Last column — no trailing padding
43
+ cells.push(cell);
44
+ }
45
+ }
46
+ resultLines.push(cells.join(separator));
47
+ }
48
+ return resultLines.join('\n');
49
+ }
50
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/primitives/table.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAchD;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,IAAe,EAAE,OAAqB,EAAE;IAC7D,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAElD,sDAAsD;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE9D,6BAA6B;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3E,yCAAyC;IACzC,MAAM,SAAS,GAAa,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACrE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC3B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YAC3C,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnE,CAAC;IACF,CAAC;IAED,kBAAkB;IAClB,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,GAAG,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC;gBACvB,gEAAgE;gBAChE,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;gBACtD,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACP,oCAAoC;gBACpC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACF,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Word-wrap text to fit within a given width.
3
+ *
4
+ * - Splits on spaces, re-joins lines under width limit
5
+ * - Respects existing newlines (each \n starts a new line)
6
+ * - Force-breaks words longer than width
7
+ * - Returns an array of lines (no trailing newline)
8
+ */
9
+ export declare function wrapText(text: string, width: number): string[];
10
+ //# sourceMappingURL=wrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap.d.ts","sourceRoot":"","sources":["../../src/primitives/wrap.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAyD9D"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @runa-cmd/help — wrapText() internal utility
3
+ *
4
+ * Word-wraps text to a given width. Used internally by box and columns.
5
+ * NOT exported at package root.
6
+ */
7
+ import { visibleWidth } from '../ansi/codes.js';
8
+ /**
9
+ * Word-wrap text to fit within a given width.
10
+ *
11
+ * - Splits on spaces, re-joins lines under width limit
12
+ * - Respects existing newlines (each \n starts a new line)
13
+ * - Force-breaks words longer than width
14
+ * - Returns an array of lines (no trailing newline)
15
+ */
16
+ export function wrapText(text, width) {
17
+ if (width <= 0)
18
+ return [text];
19
+ const result = [];
20
+ const paragraphs = text.split('\n');
21
+ for (const paragraph of paragraphs) {
22
+ if (paragraph === '') {
23
+ result.push('');
24
+ continue;
25
+ }
26
+ const words = paragraph.split(/\s+/);
27
+ let currentLine = '';
28
+ for (const word of words) {
29
+ const wordWidth = visibleWidth(word);
30
+ // Force-break words longer than width
31
+ if (wordWidth > width) {
32
+ // Flush current line if not empty
33
+ if (currentLine) {
34
+ result.push(currentLine);
35
+ currentLine = '';
36
+ }
37
+ // Break the long word into chunks
38
+ let remaining = word;
39
+ while (remaining.length > width) {
40
+ result.push(remaining.slice(0, width));
41
+ remaining = remaining.slice(width);
42
+ }
43
+ if (remaining) {
44
+ currentLine = remaining;
45
+ }
46
+ continue;
47
+ }
48
+ if (!currentLine) {
49
+ // First word on line
50
+ currentLine = word;
51
+ }
52
+ else if (visibleWidth(currentLine) + 1 + wordWidth <= width) {
53
+ // Fits with a space
54
+ currentLine += ` ${word}`;
55
+ }
56
+ else {
57
+ // Doesn't fit — flush and start new line
58
+ result.push(currentLine);
59
+ currentLine = word;
60
+ }
61
+ }
62
+ // Flush last line of paragraph
63
+ if (currentLine) {
64
+ result.push(currentLine);
65
+ }
66
+ }
67
+ return result;
68
+ }
69
+ //# sourceMappingURL=wrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../src/primitives/wrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAa;IACnD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,IAAI,SAAS,KAAK,EAAE,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChB,SAAS;QACV,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,WAAW,GAAG,EAAE,CAAC;QAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAErC,sCAAsC;YACtC,IAAI,SAAS,GAAG,KAAK,EAAE,CAAC;gBACvB,kCAAkC;gBAClC,IAAI,WAAW,EAAE,CAAC;oBACjB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBACzB,WAAW,GAAG,EAAE,CAAC;gBAClB,CAAC;gBACD,kCAAkC;gBAClC,IAAI,SAAS,GAAG,IAAI,CAAC;gBACrB,OAAO,SAAS,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;oBACjC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;oBACvC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACpC,CAAC;gBACD,IAAI,SAAS,EAAE,CAAC;oBACf,WAAW,GAAG,SAAS,CAAC;gBACzB,CAAC;gBACD,SAAS;YACV,CAAC;YAED,IAAI,CAAC,WAAW,EAAE,CAAC;gBAClB,qBAAqB;gBACrB,WAAW,GAAG,IAAI,CAAC;YACpB,CAAC;iBAAM,IAAI,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,IAAI,KAAK,EAAE,CAAC;gBAC/D,oBAAoB;gBACpB,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACP,yCAAyC;gBACzC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACzB,WAAW,GAAG,IAAI,CAAC;YACpB,CAAC;QACF,CAAC;QAED,+BAA+B;QAC/B,IAAI,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { RenderFnCtx } from './types.js';
2
+ /**
3
+ * Default help renderer — produces formatted help output.
4
+ *
5
+ * Accepts a RenderFnCtx (same shape as the custom render function receives).
6
+ */
7
+ export declare function defaultRenderer(ctx: RenderFnCtx): string;
8
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAwB,WAAW,EAAiB,MAAM,YAAY,CAAC;AAEnF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAkBxD"}
package/dist/render.js ADDED
@@ -0,0 +1,219 @@
1
+ import { bold as ansiBold, fg } from './ansi/codes.js';
2
+ import { join } from './primitives/join.js';
3
+ import { styled } from './primitives/styled.js';
4
+ import { table } from './primitives/table.js';
5
+ /**
6
+ * Default help renderer — produces formatted help output.
7
+ *
8
+ * Accepts a RenderFnCtx (same shape as the custom render function receives).
9
+ */
10
+ export function defaultRenderer(ctx) {
11
+ const { schema, theme } = ctx;
12
+ const renderCtx = { colorDepth: ctx.colorDepth, termWidth: ctx.termWidth };
13
+ const sections = [];
14
+ // Determine if this is a CLISchema (root) or CommandSchema (subcommand)
15
+ const isCLI = 'meta' in schema && 'commands' in schema && 'globalOptions' in schema;
16
+ if (isCLI) {
17
+ const cli = schema;
18
+ sections.push(...renderCLI(cli, theme, renderCtx));
19
+ }
20
+ else {
21
+ const cmd = schema;
22
+ sections.push(...renderCommand(cmd, theme, renderCtx));
23
+ }
24
+ return join.vertical(sections, { gap: 1 });
25
+ }
26
+ // ─── CLI Root Rendering ─────────────────────────────────────
27
+ function renderCLI(cli, theme, ctx) {
28
+ const sections = [];
29
+ // Header
30
+ const name = cli.meta.name;
31
+ const version = cli.meta.version ? ` v${cli.meta.version}` : '';
32
+ sections.push(styled(`${name}${version}`, { bold: true }, ctx));
33
+ if (cli.meta.description) {
34
+ sections.push(styled(cli.meta.description, { dim: true }, ctx));
35
+ }
36
+ // Usage
37
+ const hasCommands = cli.commands.length > 0;
38
+ const usageParts = [name];
39
+ if (hasCommands)
40
+ usageParts.push('<command>');
41
+ usageParts.push('[options]');
42
+ sections.push(join.vertical([
43
+ sectionTitle('USAGE', theme, ctx),
44
+ styled(` ${usageParts.join(' ')}`, {}, ctx),
45
+ ]));
46
+ // Commands
47
+ if (hasCommands) {
48
+ const cmdRows = cli.commands.map((cmd) => [
49
+ styled(cmd.name, { color: 'yellow' }, ctx),
50
+ cmd.description || '',
51
+ ]);
52
+ sections.push(join.vertical([sectionTitle('COMMANDS', theme, ctx), indent(table(cmdRows))]));
53
+ }
54
+ // Global Options
55
+ if (cli.globalOptions.length > 0) {
56
+ sections.push(join.vertical([
57
+ sectionTitle('GLOBAL OPTIONS', theme, ctx),
58
+ indent(renderOptionsTable(cli.globalOptions, theme, ctx)),
59
+ ]));
60
+ }
61
+ return sections;
62
+ }
63
+ // ─── Command Rendering ──────────────────────────────────────
64
+ function renderCommand(cmd, theme, ctx) {
65
+ const sections = [];
66
+ // Header
67
+ const cmdPath = cmd.fullPath.join(' ');
68
+ sections.push(styled(cmdPath, { bold: true }, ctx));
69
+ if (cmd.description) {
70
+ sections.push(styled(cmd.description, { dim: true }, ctx));
71
+ }
72
+ // Usage
73
+ const usageParts = [cmdPath];
74
+ if (cmd.subcommands && cmd.subcommands.length > 0)
75
+ usageParts.push('<command>');
76
+ if (cmd.args.length > 0) {
77
+ for (const arg of cmd.args) {
78
+ usageParts.push(arg.required ? `<${arg.name}>` : `[${arg.name}]`);
79
+ }
80
+ }
81
+ usageParts.push('[options]');
82
+ sections.push(join.vertical([
83
+ sectionTitle('USAGE', theme, ctx),
84
+ styled(` ${usageParts.join(' ')}`, {}, ctx),
85
+ ]));
86
+ // Arguments
87
+ if (cmd.args.length > 0) {
88
+ const argRows = cmd.args.map((arg) => renderArgRow(arg, theme, ctx));
89
+ sections.push(join.vertical([sectionTitle('ARGUMENTS', theme, ctx), indent(table(argRows))]));
90
+ }
91
+ // Options (grouped)
92
+ if (cmd.options.length > 0) {
93
+ sections.push(renderOptionsSection(cmd.options, theme, ctx));
94
+ }
95
+ // Subcommands
96
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
97
+ const cmdRows = cmd.subcommands.map((sub) => [
98
+ styled(sub.name, { color: 'yellow' }, ctx),
99
+ sub.description || '',
100
+ ]);
101
+ sections.push(join.vertical([sectionTitle('COMMANDS', theme, ctx), indent(table(cmdRows))]));
102
+ }
103
+ return sections;
104
+ }
105
+ // ─── Options Rendering ──────────────────────────────────────
106
+ function renderOptionsSection(options, theme, ctx) {
107
+ // Separate options by group
108
+ const grouped = new Map();
109
+ const ungrouped = [];
110
+ for (const opt of options) {
111
+ if (opt.group) {
112
+ const list = grouped.get(opt.group) ?? [];
113
+ list.push(opt);
114
+ grouped.set(opt.group, list);
115
+ }
116
+ else {
117
+ ungrouped.push(opt);
118
+ }
119
+ }
120
+ const parts = [];
121
+ // Ungrouped options first
122
+ if (ungrouped.length > 0) {
123
+ parts.push(join.vertical([
124
+ sectionTitle('OPTIONS', theme, ctx),
125
+ indent(renderOptionsTable(ungrouped, theme, ctx)),
126
+ ]));
127
+ }
128
+ // Each group gets its own section
129
+ for (const [group, opts] of grouped) {
130
+ parts.push(join.vertical([
131
+ sectionTitle(`${group.toUpperCase()} OPTIONS`, theme, ctx),
132
+ indent(renderOptionsTable(opts, theme, ctx)),
133
+ ]));
134
+ }
135
+ // If everything was grouped and there's no ungrouped section
136
+ if (parts.length === 0)
137
+ return '';
138
+ return join.vertical(parts, { gap: 1 });
139
+ }
140
+ function renderOptionsTable(options, theme, ctx) {
141
+ const rows = options.map((opt) => renderOptionRow(opt, theme, ctx));
142
+ return table(rows);
143
+ }
144
+ function renderOptionRow(opt, theme, ctx) {
145
+ // Flag column: --name, -alias
146
+ const flags = [];
147
+ if (opt.alias) {
148
+ for (const a of opt.alias) {
149
+ // Aliases may come with dash prefix ('-e', '--env') or bare ('e', 'env')
150
+ if (a.startsWith('--') || a.startsWith('-')) {
151
+ flags.push(a);
152
+ }
153
+ else {
154
+ flags.push(a.length === 1 ? `-${a}` : `--${a}`);
155
+ }
156
+ }
157
+ }
158
+ flags.push(`--${opt.name}`);
159
+ const flagStr = styled(flags.join(', '), { color: 'yellow' }, ctx);
160
+ // Type column
161
+ const typeParts = [];
162
+ if (opt.type === 'enum' && opt.enumValues) {
163
+ typeParts.push(opt.enumValues.join(' | '));
164
+ }
165
+ else if (opt.type !== 'boolean') {
166
+ typeParts.push(opt.type);
167
+ }
168
+ const typeStr = typeParts.length > 0 ? styled(typeParts.join(''), { dim: true }, ctx) : '';
169
+ // Description column
170
+ const descParts = [];
171
+ if (opt.description)
172
+ descParts.push(opt.description);
173
+ if (opt.required)
174
+ descParts.push(fg('(required)', theme.secondary));
175
+ if (opt.defaultValue !== undefined)
176
+ descParts.push(fg(`[default: ${String(opt.defaultValue)}]`, theme.muted));
177
+ if (opt.deprecated)
178
+ descParts.push(fg(`(deprecated: ${opt.deprecated})`, theme.warning));
179
+ if (opt.env)
180
+ descParts.push(fg(`[env: ${opt.env}]`, theme.muted));
181
+ return [flagStr, typeStr, descParts.join(' ')];
182
+ }
183
+ // ─── Argument Rendering ─────────────────────────────────────
184
+ function renderArgRow(arg, theme, ctx) {
185
+ // Name column
186
+ const nameDisplay = arg.isVariadic ? `${arg.name}...` : arg.name;
187
+ const nameStr = styled(arg.required ? `<${nameDisplay}>` : `[${nameDisplay}]`, { color: 'yellow' }, ctx);
188
+ // Type column
189
+ const typeParts = [];
190
+ if (arg.type === 'enum' && arg.enumValues) {
191
+ typeParts.push(arg.enumValues.join(' | '));
192
+ }
193
+ else {
194
+ typeParts.push(arg.type);
195
+ }
196
+ const typeStr = styled(typeParts.join(''), { dim: true }, ctx);
197
+ // Description column
198
+ const descParts = [];
199
+ if (arg.description)
200
+ descParts.push(arg.description);
201
+ if (arg.required)
202
+ descParts.push(fg('(required)', theme.secondary));
203
+ if (arg.defaultValue !== undefined)
204
+ descParts.push(fg(`[default: ${String(arg.defaultValue)}]`, theme.muted));
205
+ return [nameStr, typeStr, descParts.join(' ')];
206
+ }
207
+ // ─── Helpers ────────────────────────────────────────────────
208
+ function sectionTitle(title, theme, _ctx) {
209
+ // theme colors are already ANSI-resolved, so use fg() directly (not styled.color which re-downsamples)
210
+ return ansiBold(fg(title, theme.primary));
211
+ }
212
+ function indent(block, spaces = 2) {
213
+ const prefix = ' '.repeat(spaces);
214
+ return block
215
+ .split('\n')
216
+ .map((line) => `${prefix}${line}`)
217
+ .join('\n');
218
+ }
219
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { RenderContext, ResolvedTheme, Theme } from './types.js';
2
+ /** Default theme colors — Lipgloss-inspired */
3
+ export declare const defaultTheme: Theme;
4
+ /**
5
+ * Merge a partial theme with defaults and downsample all colors
6
+ * to ANSI-ready escape strings for the current color depth.
7
+ *
8
+ * @param partial - User's partial theme override (or undefined for defaults)
9
+ * @param ctx - RenderContext with colorDepth for downsampling
10
+ */
11
+ export declare function resolveTheme(partial: Partial<Theme> | undefined, ctx: RenderContext): ResolvedTheme;
12
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAItE,+CAA+C;AAC/C,eAAO,MAAM,YAAY,EAAE,KAO1B,CAAC;AAcF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,EACnC,GAAG,EAAE,aAAa,GAChB,aAAa,CAWf"}
package/dist/theme.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @runa-cmd/help — Theme system
3
+ *
4
+ * Provides a default theme, deep-merges partial overrides,
5
+ * and downsamples all colors to the terminal's color depth.
6
+ */
7
+ import { downsampleColor } from './ansi/downsample.js';
8
+ // ─── Default Theme ──────────────────────────────────────────
9
+ /** Default theme colors — Lipgloss-inspired */
10
+ export const defaultTheme = {
11
+ primary: '#7D56F4',
12
+ secondary: '#FF6B6B',
13
+ muted: 'dim',
14
+ error: '#FF0000',
15
+ warning: '#FFAA00',
16
+ success: '#00FF00',
17
+ };
18
+ // ─── Theme Resolution ───────────────────────────────────────
19
+ /** Color keys in the Theme interface */
20
+ const THEME_KEYS = [
21
+ 'primary',
22
+ 'secondary',
23
+ 'muted',
24
+ 'error',
25
+ 'warning',
26
+ 'success',
27
+ ];
28
+ /**
29
+ * Merge a partial theme with defaults and downsample all colors
30
+ * to ANSI-ready escape strings for the current color depth.
31
+ *
32
+ * @param partial - User's partial theme override (or undefined for defaults)
33
+ * @param ctx - RenderContext with colorDepth for downsampling
34
+ */
35
+ export function resolveTheme(partial, ctx) {
36
+ // Merge with defaults
37
+ const merged = { ...defaultTheme, ...partial };
38
+ // Downsample every color to an ANSI escape string
39
+ const resolved = {};
40
+ for (const key of THEME_KEYS) {
41
+ resolved[key] = downsampleColor(merged[key], ctx.colorDepth);
42
+ }
43
+ return resolved;
44
+ }
45
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,+DAA+D;AAE/D,+CAA+C;AAC/C,MAAM,CAAC,MAAM,YAAY,GAAU;IAClC,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,SAAS;IACpB,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CAClB,CAAC;AAEF,+DAA+D;AAE/D,wCAAwC;AACxC,MAAM,UAAU,GAA+B;IAC9C,SAAS;IACT,WAAW;IACX,OAAO;IACP,OAAO;IACP,SAAS;IACT,SAAS;CACT,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC3B,OAAmC,EACnC,GAAkB;IAElB,sBAAsB;IACtB,MAAM,MAAM,GAAU,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtD,kDAAkD;IAClD,MAAM,QAAQ,GAAG,EAAmB,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC9B,QAAQ,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,QAAQ,CAAC;AACjB,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @runa-cmd/help — Type definitions
3
+ *
4
+ * All TypeScript types for the help system.
5
+ * Schema types (CLISchema, CommandSchema, etc.) are imported from @runa-cmd/core.
6
+ * This is a type-only module — no runtime code.
7
+ */
8
+ import type { CLISchema, CommandSchema } from '@runa-cmd/core';
9
+ /** Everything returns a Block — just a string with optional ANSI codes */
10
+ export type Block = string;
11
+ /** Detected color depth of the terminal */
12
+ export type ColorDepth = 'truecolor' | '256' | '16' | 'none';
13
+ /** Render context passed to all primitives (auto-detected or overridden in tests) */
14
+ export interface RenderContext {
15
+ colorDepth: ColorDepth;
16
+ termWidth: number;
17
+ }
18
+ /** Theme colors — all values are hex (#RRGGBB) or named ANSI attribute (e.g. 'dim') */
19
+ export interface Theme {
20
+ /** Titles, borders */
21
+ primary: string;
22
+ /** Required markers, highlights */
23
+ secondary: string;
24
+ /** Descriptions, defaults */
25
+ muted: string;
26
+ /** Error messages */
27
+ error: string;
28
+ /** Warnings */
29
+ warning: string;
30
+ /** Success states */
31
+ success: string;
32
+ }
33
+ /** Theme with all colors resolved to ANSI-ready escape strings */
34
+ export interface ResolvedTheme {
35
+ primary: string;
36
+ secondary: string;
37
+ muted: string;
38
+ error: string;
39
+ warning: string;
40
+ success: string;
41
+ }
42
+ /** What the custom render function receives (Layer 3) */
43
+ export interface RenderFnCtx {
44
+ /** The target schema (root CLI or specific subcommand) */
45
+ schema: CLISchema | CommandSchema;
46
+ /** Resolved theme with ANSI-ready colors */
47
+ theme: ResolvedTheme;
48
+ /** Detected color depth */
49
+ colorDepth: ColorDepth;
50
+ /** Terminal width in columns */
51
+ termWidth: number;
52
+ }
53
+ /** Options for helpPlugin() */
54
+ export interface HelpPluginOptions {
55
+ /** Partial theme override (merged with defaultTheme) */
56
+ theme?: Partial<Theme>;
57
+ /** Custom render function (Layer 3 — full control) */
58
+ render?: (ctx: RenderFnCtx) => string;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI/D,0EAA0E;AAC1E,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAI3B,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7D,qFAAqF;AACrF,MAAM,WAAW,aAAa;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB;AAID,uFAAuF;AACvF,MAAM,WAAW,KAAK;IACrB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAID,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC3B,0DAA0D;IAC1D,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAClC,4CAA4C;IAC5C,KAAK,EAAE,aAAa,CAAC;IACrB,2BAA2B;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAID,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IACjC,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,sDAAsD;IACtD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,MAAM,CAAC;CACtC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@runa-cmd/help",
3
+ "version": "0.1.0",
4
+ "description": "Themeable help output for Runa CLIs with composable layout primitives.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "keywords": [
8
+ "cli",
9
+ "help",
10
+ "ansi",
11
+ "terminal",
12
+ "layout",
13
+ "theme",
14
+ "runa"
15
+ ],
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "peerDependencies": {
25
+ "zod": "^4.0.0",
26
+ "@runa-cmd/core": "0.1.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18.3.0"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/jrodrigopuca/runa-cmd.git",
37
+ "directory": "packages/help"
38
+ },
39
+ "homepage": "https://github.com/jrodrigopuca/runa-cmd/tree/main/packages/help#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/jrodrigopuca/runa-cmd/issues"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md"
46
+ ],
47
+ "devDependencies": {
48
+ "@types/node": "^25.6.0",
49
+ "typescript": "^6.0.2",
50
+ "zod": "^4.3.6",
51
+ "@runa-cmd/core": "0.1.0"
52
+ },
53
+ "scripts": {
54
+ "build": "tsc",
55
+ "dev": "tsc --watch --preserveWatchOutput",
56
+ "typecheck": "tsc --noEmit",
57
+ "test": "vitest run",
58
+ "test:watch": "vitest",
59
+ "lint": "biome check .",
60
+ "lint:fix": "biome check --write .",
61
+ "clean": "rm -rf dist"
62
+ }
63
+ }