mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-25 08:48:08 +02:00
Polish documentation copy
This commit is contained in:
parent
ce23aca4c4
commit
5568b3d37a
65 changed files with 478 additions and 478 deletions
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add a build-time script that prints the full `ktx` CLI command tree (name, aliases, description per node) as an indented text tree, for docs and discovery — without adding a runtime `ktx` subcommand.
|
||||
**Goal:** Add a build-time script that prints the full `ktx` CLI command tree (name, aliases, description per node) as an indented text tree, for docs and discovery - without adding a runtime `ktx` subcommand.
|
||||
|
||||
**Architecture:** Commander.js exposes every registered command as a `Command` instance with `.commands`, `.name()`, `.aliases()`, `.description()` — we walk that tree. The current `runCommanderKtxCli` in `packages/cli/src/cli-program.ts` builds the program inline; we extract that assembly into a pure `buildKtxProgram(...)` helper that any caller can use to materialize the configured root `Command` without parsing argv. A new pure module `command-tree.ts` walks the `Command` into plain data and renders it as indented text. A new TypeScript entrypoint `print-command-tree.ts` compiles alongside `bin.ts` into `dist/print-command-tree.js`, instantiates the program with stub IO/deps, and writes the rendered tree to stdout. A pnpm script under `@ktx/cli` exposes it as `pnpm --filter @ktx/cli run docs:commands`.
|
||||
**Architecture:** Commander.js exposes every registered command as a `Command` instance with `.commands`, `.name()`, `.aliases()`, `.description()` - we walk that tree. The current `runCommanderKtxCli` in `packages/cli/src/cli-program.ts` builds the program inline; we extract that assembly into a pure `buildKtxProgram(...)` helper that any caller can use to materialize the configured root `Command` without parsing argv. A new pure module `command-tree.ts` walks the `Command` into plain data and renders it as indented text. A new TypeScript entrypoint `print-command-tree.ts` compiles alongside `bin.ts` into `dist/print-command-tree.js`, instantiates the program with stub IO/deps, and writes the rendered tree to stdout. A pnpm script under `@ktx/cli` exposes it as `pnpm --filter @ktx/cli run docs:commands`.
|
||||
|
||||
**Tech Stack:** TypeScript (NodeNext ESM), Node 22, Commander 14 via `@commander-js/extra-typings`, vitest 4.
|
||||
|
||||
|
|
@ -12,14 +12,14 @@
|
|||
|
||||
## File Map
|
||||
|
||||
- **Modify:** `packages/cli/src/cli-program.ts` — extract `buildKtxProgram` from `runCommanderKtxCli`.
|
||||
- **Create:** `packages/cli/src/cli-program.test.ts` — vitest tests for the new helper.
|
||||
- **Create:** `packages/cli/src/command-tree.ts` — pure `walkCommandTree` + `formatCommandTree`.
|
||||
- **Create:** `packages/cli/src/command-tree.test.ts` — vitest tests against ad-hoc Command trees.
|
||||
- **Create:** `packages/cli/src/print-command-tree.ts` — script entrypoint; thin glue.
|
||||
- **Create:** `packages/cli/src/print-command-tree.test.ts` — vitest test that calls the script's exported `main()` with a fake stdout and asserts the rendered tree includes known top-level commands.
|
||||
- **Modify:** `packages/cli/package.json` — add `docs:commands` script and include the new entry in tsc build output (no change needed if `tsconfig` already globs `src/**/*.ts`, but verify).
|
||||
- **Modify:** `packages/cli/README.md` (if it exists; otherwise skip) — document `pnpm run docs:commands`.
|
||||
- **Modify:** `packages/cli/src/cli-program.ts` - extract `buildKtxProgram` from `runCommanderKtxCli`.
|
||||
- **Create:** `packages/cli/src/cli-program.test.ts` - vitest tests for the new helper.
|
||||
- **Create:** `packages/cli/src/command-tree.ts` - pure `walkCommandTree` + `formatCommandTree`.
|
||||
- **Create:** `packages/cli/src/command-tree.test.ts` - vitest tests against ad-hoc Command trees.
|
||||
- **Create:** `packages/cli/src/print-command-tree.ts` - script entrypoint; thin glue.
|
||||
- **Create:** `packages/cli/src/print-command-tree.test.ts` - vitest test that calls the script's exported `main()` with a fake stdout and asserts the rendered tree includes known top-level commands.
|
||||
- **Modify:** `packages/cli/package.json` - add `docs:commands` script and include the new entry in tsc build output (no change needed if `tsconfig` already globs `src/**/*.ts`, but verify).
|
||||
- **Modify:** `packages/cli/README.md` (if it exists; otherwise skip) - document `pnpm run docs:commands`.
|
||||
|
||||
Files that change together (cli-program + its test, command-tree + its test, print-command-tree + its test) live next to each other under `packages/cli/src/`, matching the existing convention (e.g. `bin.ts`, `cli-runtime.ts`, `runtime.ts` + `runtime.test.ts`).
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ Files that change together (cli-program + its test, command-tree + its test, pri
|
|||
|
||||
## Task 1: Extract `buildKtxProgram` from `runCommanderKtxCli`
|
||||
|
||||
Refactor only — no behavior change. The current code in `cli-program.ts` interleaves program construction with `parseAsync` dispatch. Splitting them lets the new script reuse construction without invoking the CLI.
|
||||
Refactor only - no behavior change. The current code in `cli-program.ts` interleaves program construction with `parseAsync` dispatch. Splitting them lets the new script reuse construction without invoking the CLI.
|
||||
|
||||
**Files:**
|
||||
- Modify: `packages/cli/src/cli-program.ts:197-275` (function `runCommanderKtxCli`)
|
||||
|
|
@ -88,7 +88,7 @@ describe('buildKtxProgram', () => {
|
|||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/cli-program.test.ts`
|
||||
|
||||
Expected: FAIL — `buildKtxProgram is not exported from './cli-program.js'` (or similar TS/ESM error).
|
||||
Expected: FAIL - `buildKtxProgram is not exported from './cli-program.js'` (or similar TS/ESM error).
|
||||
|
||||
- [ ] **Step 3: Extract `buildKtxProgram` from `runCommanderKtxCli`**
|
||||
|
||||
|
|
@ -160,19 +160,19 @@ Then rewrite the body of `runCommanderKtxCli` (lines 197-275) to delegate progra
|
|||
};
|
||||
```
|
||||
|
||||
Keep the `context` re-declaration only if subsequent code (the `if (argv.length === 0)` branch that calls `runBareInteractiveCommand(program, io, context)`) still needs it. It does — `runBareInteractiveCommand` consumes `context`. Keep `context` exactly as it was after the deletion; do not change `runBareInteractiveCommand`'s signature or behavior. Drop the now-removed individual `register*` calls and their `profileMark` lines from `runCommanderKtxCli`.
|
||||
Keep the `context` re-declaration only if subsequent code (the `if (argv.length === 0)` branch that calls `runBareInteractiveCommand(program, io, context)`) still needs it. It does - `runBareInteractiveCommand` consumes `context`. Keep `context` exactly as it was after the deletion; do not change `runBareInteractiveCommand`'s signature or behavior. Drop the now-removed individual `register*` calls and their `profileMark` lines from `runCommanderKtxCli`.
|
||||
|
||||
- [ ] **Step 4: Run the new test to verify it passes**
|
||||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/cli-program.test.ts`
|
||||
|
||||
Expected: PASS — both `it` blocks green.
|
||||
Expected: PASS - both `it` blocks green.
|
||||
|
||||
- [ ] **Step 5: Run the full CLI test suite to confirm no regression**
|
||||
|
||||
Run: `pnpm --filter @ktx/cli run test 2>&1 | tee /tmp/ktx-cli-test-output.log`
|
||||
|
||||
Expected: PASS overall. Inspect the log if any previously-passing test now fails — most likely a missing register call (compare to lines 221-249 of the pre-change file).
|
||||
Expected: PASS overall. Inspect the log if any previously-passing test now fails - most likely a missing register call (compare to lines 221-249 of the pre-change file).
|
||||
|
||||
- [ ] **Step 6: Type-check**
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ git commit -m "refactor(cli): extract buildKtxProgram for reuse outside runComma
|
|||
|
||||
## Task 2: Pure tree walker `walkCommandTree`
|
||||
|
||||
Take a Commander `Command` and produce plain data: `{ name, description, aliases, children }`. No formatting yet. Pure function — depends only on the public `Command` API.
|
||||
Take a Commander `Command` and produce plain data: `{ name, description, aliases, children }`. No formatting yet. Pure function - depends only on the public `Command` API.
|
||||
|
||||
**Files:**
|
||||
- Create: `packages/cli/src/command-tree.ts`
|
||||
|
|
@ -254,7 +254,7 @@ describe('walkCommandTree', () => {
|
|||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/command-tree.test.ts`
|
||||
|
||||
Expected: FAIL — `walkCommandTree` cannot be resolved.
|
||||
Expected: FAIL - `walkCommandTree` cannot be resolved.
|
||||
|
||||
- [ ] **Step 3: Implement `walkCommandTree`**
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ Expected: no errors.
|
|||
|
||||
## Task 3: Indented-text renderer `formatCommandTree`
|
||||
|
||||
Render a `CommandTreeNode` as plain text. Each node on its own line: `<indent><name>[ (alias1, alias2)][ — description]`. Indent is two spaces per depth level. Children sorted alphabetically by name to keep output stable across changes that reorder registrar calls.
|
||||
Render a `CommandTreeNode` as plain text. Each node on its own line: `<indent><name>[ (alias1, alias2)][ - description]`. Indent is two spaces per depth level. Children sorted alphabetically by name to keep output stable across changes that reorder registrar calls.
|
||||
|
||||
**Files:**
|
||||
- Modify: `packages/cli/src/command-tree.ts`
|
||||
|
|
@ -312,12 +312,12 @@ import { formatCommandTree } from './command-tree.js';
|
|||
describe('formatCommandTree', () => {
|
||||
it('renders a single node with no children', () => {
|
||||
const node = { name: 'solo', description: 'just me', aliases: [], children: [] };
|
||||
expect(formatCommandTree(node)).toBe('solo — just me\n');
|
||||
expect(formatCommandTree(node)).toBe('solo - just me\n');
|
||||
});
|
||||
|
||||
it('renders aliases in parentheses before the description', () => {
|
||||
const node = { name: 'cmd', description: 'does things', aliases: ['c', 'co'], children: [] };
|
||||
expect(formatCommandTree(node)).toBe('cmd (c, co) — does things\n');
|
||||
expect(formatCommandTree(node)).toBe('cmd (c, co) - does things\n');
|
||||
});
|
||||
|
||||
it('omits the dash when description is empty', () => {
|
||||
|
|
@ -338,10 +338,10 @@ describe('formatCommandTree', () => {
|
|||
],
|
||||
};
|
||||
expect(formatCommandTree(tree)).toBe(
|
||||
'root — top\n' +
|
||||
' alpha (al) — a\n' +
|
||||
' inner — i\n' +
|
||||
' beta — b\n',
|
||||
'root - top\n' +
|
||||
' alpha (al) - a\n' +
|
||||
' inner - i\n' +
|
||||
' beta - b\n',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -351,7 +351,7 @@ describe('formatCommandTree', () => {
|
|||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/command-tree.test.ts`
|
||||
|
||||
Expected: FAIL — `formatCommandTree` is not exported.
|
||||
Expected: FAIL - `formatCommandTree` is not exported.
|
||||
|
||||
- [ ] **Step 3: Implement `formatCommandTree`**
|
||||
|
||||
|
|
@ -367,7 +367,7 @@ export function formatCommandTree(node: CommandTreeNode): string {
|
|||
function appendNode(node: CommandTreeNode, depth: number, lines: string[]): void {
|
||||
const indent = ' '.repeat(depth);
|
||||
const aliasPart = node.aliases.length > 0 ? ` (${node.aliases.join(', ')})` : '';
|
||||
const descPart = node.description.length > 0 ? ` — ${node.description}` : '';
|
||||
const descPart = node.description.length > 0 ? ` - ${node.description}` : '';
|
||||
lines.push(`${indent}${node.name}${aliasPart}${descPart}`);
|
||||
|
||||
const sortedChildren = [...node.children].sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
|
@ -419,7 +419,7 @@ describe('renderKtxCommandTree', () => {
|
|||
const output = renderKtxCommandTree();
|
||||
|
||||
const lines = output.split('\n');
|
||||
expect(lines[0]).toMatch(/^ktx( |$|\s—)/);
|
||||
expect(lines[0]).toMatch(/^ktx( |$|\s-)/);
|
||||
|
||||
// Top-level commands are indented exactly two spaces.
|
||||
const topLevel = lines
|
||||
|
|
@ -443,7 +443,7 @@ describe('renderKtxCommandTree', () => {
|
|||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/print-command-tree.test.ts`
|
||||
|
||||
Expected: FAIL — module not found.
|
||||
Expected: FAIL - module not found.
|
||||
|
||||
- [ ] **Step 3: Implement the script**
|
||||
|
||||
|
|
@ -495,7 +495,7 @@ if (invokedAsScript) {
|
|||
|
||||
Run: `pnpm --filter @ktx/cli exec vitest run src/print-command-tree.test.ts`
|
||||
|
||||
Expected: PASS — both assertions green.
|
||||
Expected: PASS - both assertions green.
|
||||
|
||||
- [ ] **Step 5: Type-check**
|
||||
|
||||
|
|
@ -572,9 +572,9 @@ git commit -m "chore(cli): add docs:commands pnpm script"
|
|||
|
||||
After all tasks, confirm:
|
||||
|
||||
- [ ] `pnpm --filter @ktx/cli run type-check` — clean
|
||||
- [ ] `pnpm --filter @ktx/cli run test` — green, including new tests in `cli-program.test.ts`, `command-tree.test.ts`, `print-command-tree.test.ts`
|
||||
- [ ] `pnpm --filter @ktx/cli run docs:commands` — prints `ktx` followed by indented subcommand tree
|
||||
- [ ] `git status --short` — only the files listed in the File Map are modified or created; no incidental edits
|
||||
- [ ] `pnpm --filter @ktx/cli run type-check` - clean
|
||||
- [ ] `pnpm --filter @ktx/cli run test` - green, including new tests in `cli-program.test.ts`, `command-tree.test.ts`, `print-command-tree.test.ts`
|
||||
- [ ] `pnpm --filter @ktx/cli run docs:commands` - prints `ktx` followed by indented subcommand tree
|
||||
- [ ] `git status --short` - only the files listed in the File Map are modified or created; no incidental edits
|
||||
|
||||
If any check fails, fix in place and re-run before declaring done.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue