Skip to content

test: enhance help sync test to verify subcommand documentation#1664

Open
withsivram wants to merge 2 commits intoeyaltoledano:mainfrom
withsivram:feat/enhance-help-sync-test-issue-1596
Open

test: enhance help sync test to verify subcommand documentation#1664
withsivram wants to merge 2 commits intoeyaltoledano:mainfrom
withsivram:feat/enhance-help-sync-test-issue-1596

Conversation

@withsivram
Copy link

@withsivram withsivram commented Mar 20, 2026

Summary

  • Adds a comprehensive test (apps/cli/tests/unit/help-documentation-sync.spec.ts) that verifies help documentation stays in sync with CLI commands at both the command and subcommand level
  • Verifies tags subcommands (add, use, remove, rename, copy, list) are correctly documented with the unified subcommand structure, not deprecated standalone commands
  • Verifies list command options (--ready, --blocking, --with-subtasks, --json, -w, --all-tags, etc.) are documented in help
  • Includes bidirectional checks: no phantom subcommands in help, no undocumented subcommands in source
  • Extracts subcommands and options directly from the TypeScript source files to catch drift automatically

Test plan

  • All 17 tests pass (6 command-level sync tests + 11 subcommand documentation tests)
  • Tests correctly extract subcommands from tags.command.ts and verify against help in ui.js
  • Tests correctly extract options from list.command.ts and verify against help in ui.js
  • Handles edge cases: default-action subcommands (tags list), short flags (-w vs --watch)
  • Clear error messages guide developers to fix documentation when tests fail

Closes #1596

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Added automated checks that ensure CLI help text stays synchronized with implemented commands and subcommands.
    • Validates tag-related commands and their documented default actions, and verifies key list/filter/output options are documented.
    • Fails if help contains obsolete entries or omits implemented commands, helping keep end-user help accurate.

eyaltoledano#1596)

Add comprehensive test that verifies not just command existence in help
documentation, but also subcommand and option documentation accuracy:

- Tags subcommands: verifies all subcommands from tags.command.ts are
  documented, deprecated standalone commands are not shown, and the
  list default action is properly documented with its options
- List command options: verifies filtering options (--ready, --blocking,
  --with-subtasks), format options (--json, -f, -c), watch mode (-w),
  and cross-tag listing (--all-tags) are all documented
- General coverage: bidirectional checks ensure no phantom subcommands
  exist in help and no implemented subcommands are missing from help

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 20, 2026 16:44
@changeset-bot
Copy link

changeset-bot bot commented Mar 20, 2026

⚠️ No Changeset found

Latest commit: 81ee5f7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

Adds a Vitest unit test that verifies CLI implementations (legacy and modern) are synchronized with help text from scripts/modules/ui.js, including command presence, tags subcommands, and list command options.

Changes

Cohort / File(s) Summary
Help documentation sync test
apps/cli/tests/unit/help-documentation-sync.spec.ts
New comprehensive test that parses legacy scripts/modules/commands.js and modern apps/cli/src/commands/* to extract commands/subcommands/options and compares them against displayHelp() entries in scripts/modules/ui.js. Includes special-case mappings, exclusions, subcommand-level checks for tags, and option cross-checks for list.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • Crunchyman-ralph
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding enhanced help sync test to verify subcommand documentation, matching the PR objectives.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from #1596: verifies tags subcommands, checks list options, extracts options/subcommands from source files, and implements bidirectional validation.
Out of Scope Changes check ✅ Passed All changes are scoped to the new test file validating help documentation sync; no unrelated modifications to production code or other areas.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Vitest unit test to keep the CLI help documentation (scripts/modules/ui.js) synchronized with the actual CLI command implementations (legacy scripts/modules/commands.js and modern apps/cli/src/commands/*), including checks for tags subcommands and key list options.

Changes:

  • Introduces apps/cli/tests/unit/help-documentation-sync.spec.ts with command-level help/CLI sync checks.
  • Adds subcommand-level verification for tags (including default-action handling for list).
  • Adds option-level verification for list help documentation against the TypeScript implementation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +59 to +84
function extractCommandsFromModernTs(): string[] {
const commands = new Set<string>();

try {
const files = readdirSync(MODERN_COMMANDS_DIR);

for (const file of files) {
if (!file.endsWith('.command.ts') || file.includes('.spec.')) continue;

const filePath = resolve(MODERN_COMMANDS_DIR, file);
const content = readFileSync(filePath, 'utf-8');

// Match super(name || 'command-name') or super('command-name') patterns
const superRegex = /super\((?:name \|\| )?['"]([^'"]+)['"]\)/g;
let match;
while ((match = superRegex.exec(content)) !== null) {
commands.add(match[1]);
}
}
} catch (error) {
// Directory might not exist in some configurations
console.warn('Could not read modern commands directory:', error);
}

return Array.from(commands).sort();
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractCommandsFromModernTs() only scans top-level apps/cli/src/commands/*.command.ts files and therefore misses commands that are implemented/registered elsewhere (e.g. autopilot is defined in apps/cli/src/commands/autopilot/index.ts and included in apps/cli/src/command-registry.ts). This creates a coverage gap where the command-level sync tests can pass even when help is missing commands that exist in the CLI. Consider sourcing modern commands from the command registry (or recursively scanning subdirectories / additional filename patterns) so the test reflects the actual registration surface.

Copilot uses AI. Check for mistakes.
Comment on lines +232 to +240
const COMMAND_NAME_MAPPINGS: Record<string, string> = {
// Tags subcommands in help map to legacy CLI commands
tags: 'tags', // tags list
// The following are legacy commands being deprecated
'add-tag': 'add-tag',
'use-tag': 'use-tag',
'delete-tag': 'delete-tag',
'rename-tag': 'rename-tag',
'copy-tag': 'copy-tag'
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COMMAND_NAME_MAPPINGS currently includes tags: 'tags', which makes the command-level sync checks ignore the tags command entirely (it is filtered out via Object.values(COMMAND_NAME_MAPPINGS) / Object.keys(COMMAND_NAME_MAPPINGS)). That means if tags is accidentally removed from help (or removed from the CLI), these tests won’t catch it. Suggest removing the identity mapping for tags (or changing the filter logic to only exempt mappings where help name differs from CLI name).

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/cli/tests/unit/help-documentation-sync.spec.ts (1)

78-81: Drop raw console.* diagnostics from this suite.

The assertion messages already carry the useful failure context, so these branches mostly add noisy stdout/stderr. Please route them through the shared logger or remove them.

As per coding guidelines, "Do not add direct console.log calls outside the logging utility - use the central log function instead".

Also applies to: 265-272, 294-301, 383-389, 415-425, 453-455, 466-470, 544-548, 580-581, 682-688, 755-763

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/tests/unit/help-documentation-sync.spec.ts` around lines 78 - 81,
Replace raw console.* calls in the test file with the project's shared logging
utility (or remove them) — specifically change the catch block that currently
does console.warn('Could not read modern commands directory:', error) to use the
central logger (e.g., logger.warn('Could not read modern commands directory',
error) or simply drop the message), and do the same for all other
console.log/console.warn/console.error occurrences noted (lines/groups 265-272,
294-301, 383-389, 415-425, 453-455, 466-470, 544-548, 580-581, 682-688, 755-763)
so tests no longer emit raw stdout/stderr but route through the shared log API
or remove the noise.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/cli/tests/unit/help-documentation-sync.spec.ts`:
- Around line 366-380: The test currently checks implemented subcommands by
substring-matching helpContent (from getHelpContent) which allows false
positives; update the assertions to parse exact help-entry names from the CLI
help output and compare those names to implementedSubcommands instead of using
helpContent.includes(...). Reuse the existing name-extraction logic used
elsewhere in this spec (the "name:" parsing helper) to produce a list like
parsedHelpNames, then compute missingSubcommands =
implementedSubcommands.filter(subcmd =>
!TAGS_DEFAULT_ACTION_SUBCOMMANDS.includes(subcmd) &&
!parsedHelpNames.includes(`tags ${subcmd}`)); apply the same change to the other
blocks noted (lines ~398-412, 434-463, 714-725) so all tests use exact
help-entry name comparison rather than substring matching.
- Around line 171-193: The test's option extraction in
extractOptionsFromModernTs() silently returns an empty array on read/parse
failure which makes assertions vacuously pass; update the try/catch and
post-parse check so that if options.length === 0 (either because the file
couldn't be read or no flags were parsed) the function throws an Error (or the
test fails) with a clear message including the target command file name (e.g.,
list.command.ts) and the symbol extractOptionsFromModernTs, so tests fail fast
and surface parsing/read problems instead of returning [].

---

Nitpick comments:
In `@apps/cli/tests/unit/help-documentation-sync.spec.ts`:
- Around line 78-81: Replace raw console.* calls in the test file with the
project's shared logging utility (or remove them) — specifically change the
catch block that currently does console.warn('Could not read modern commands
directory:', error) to use the central logger (e.g., logger.warn('Could not read
modern commands directory', error) or simply drop the message), and do the same
for all other console.log/console.warn/console.error occurrences noted
(lines/groups 265-272, 294-301, 383-389, 415-425, 453-455, 466-470, 544-548,
580-581, 682-688, 755-763) so tests no longer emit raw stdout/stderr but route
through the shared log API or remove the noise.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 96fa9218-44b9-474e-8d4a-ece510c5ce8f

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1211b and 5cd6e80.

📒 Files selected for processing (1)
  • apps/cli/tests/unit/help-documentation-sync.spec.ts

…se matching

- Scan subdirectory index.ts files (e.g. autopilot/index.ts) for top-level
  commands that were previously missed by flat readdirSync
- Remove identity mapping (tags: 'tags') from COMMAND_NAME_MAPPINGS so the
  tags command is properly validated in both sync directions
- Add extractHelpEntryNames() for precise name-based matching instead of
  substring matching against raw ui.js content (CodeRabbit line 380)
- Make extractOptionsFromModernTs() fail-fast on read errors and add
  sanity-check assertion for extracted options (CodeRabbit line 193)
- Remove raw console.log/console.warn calls — assertion messages carry
  all needed context (CodeRabbit nitpick)
- Add autopilot to INTENTIONALLY_UNDOCUMENTED (cloud/development command
  not yet in legacy help)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/cli/tests/unit/help-documentation-sync.spec.ts (2)

283-290: Consider using a dedicated deprecated commands list for clarity.

The identity mappings ('add-tag': 'add-tag', etc.) work but are semantically awkward. A dedicated DEPRECATED_COMMANDS array would more clearly express the intent and simplify the filtering logic.

♻️ Optional refactor for clarity
+/**
+ * Legacy commands being deprecated in favor of 'tags' subcommands.
+ * Exempted from help validation during migration.
+ */
+const DEPRECATED_COMMANDS = [
+	'add-tag',
+	'use-tag',
+	'delete-tag',
+	'rename-tag',
+	'copy-tag'
+];
+
-/**
- * Commands documented in help that map to different CLI command names.
- * ...
- */
-const COMMAND_NAME_MAPPINGS: Record<string, string> = {
-	// The following are legacy commands being deprecated
-	'add-tag': 'add-tag',
-	'use-tag': 'use-tag',
-	'delete-tag': 'delete-tag',
-	'rename-tag': 'rename-tag',
-	'copy-tag': 'copy-tag'
-};
+const COMMAND_NAME_MAPPINGS: Record<string, string> = {};

Then update the filters:

 const missingFromHelp = cliCommands.filter(
 	(cmd) =>
 		!helpCommands.includes(cmd) &&
 		!INTENTIONALLY_UNDOCUMENTED.includes(cmd) &&
-		!Object.values(COMMAND_NAME_MAPPINGS).includes(cmd)
+		!DEPRECATED_COMMANDS.includes(cmd)
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/tests/unit/help-documentation-sync.spec.ts` around lines 283 - 290,
Replace the identity entries in COMMAND_NAME_MAPPINGS with a dedicated
DEPRECATED_COMMANDS array (e.g., const DEPRECATED_COMMANDS =
['add-tag','use-tag','delete-tag','rename-tag','copy-tag']) and update any
filtering logic that currently checks COMMAND_NAME_MAPPINGS keys to instead
check membership in DEPRECATED_COMMANDS; keep COMMAND_NAME_MAPPINGS for real
mappings only and modify tests in help-documentation-sync.spec.ts to reference
DEPRECATED_COMMANDS where the intent is to exclude or treat those commands as
deprecated.

515-630: Consider extracting the repeated listMatches extraction into a helper.

The pattern helpContent.match(/name:\s*['"]list['"][^}]+}/g) with the subsequent null check is repeated 5 times across the list command tests. This could be extracted into a helper function to reduce duplication.

♻️ Optional DRY improvement
/**
 * Extract all list command sections from help content.
 * Throws if no list command entries are found.
 */
function getListCommandSections(helpContent: string): string {
	const listMatches = helpContent.match(/name:\s*['"]list['"][^}]+}/g);
	if (!listMatches || listMatches.length === 0) {
		throw new Error('Could not find list command section in help');
	}
	return listMatches.join('\n');
}

Then each test can simply call:

const allListSections = getListCommandSections(helpContent);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/tests/unit/help-documentation-sync.spec.ts` around lines 515 - 630,
Extract the repeated logic that runs
helpContent.match(/name:\s*['"]list['"][^}]+}/g) and the null/length check into
a small helper (e.g. getListCommandSections(helpContent)) that throws the
existing 'Could not find list command section in help' error when nothing is
found and returns the joined string of matches; then replace the repeated blocks
using listMatches and allListSections in the tests (those that call
getHelpContent(), the tests checking filter/format/watch/--all-tags and the one
using extractOptionsFromModernTs) with a single call const allListSections =
getListCommandSections(helpContent).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/cli/tests/unit/help-documentation-sync.spec.ts`:
- Around line 283-290: Replace the identity entries in COMMAND_NAME_MAPPINGS
with a dedicated DEPRECATED_COMMANDS array (e.g., const DEPRECATED_COMMANDS =
['add-tag','use-tag','delete-tag','rename-tag','copy-tag']) and update any
filtering logic that currently checks COMMAND_NAME_MAPPINGS keys to instead
check membership in DEPRECATED_COMMANDS; keep COMMAND_NAME_MAPPINGS for real
mappings only and modify tests in help-documentation-sync.spec.ts to reference
DEPRECATED_COMMANDS where the intent is to exclude or treat those commands as
deprecated.
- Around line 515-630: Extract the repeated logic that runs
helpContent.match(/name:\s*['"]list['"][^}]+}/g) and the null/length check into
a small helper (e.g. getListCommandSections(helpContent)) that throws the
existing 'Could not find list command section in help' error when nothing is
found and returns the joined string of matches; then replace the repeated blocks
using listMatches and allListSections in the tests (those that call
getHelpContent(), the tests checking filter/format/watch/--all-tags and the one
using extractOptionsFromModernTs) with a single call const allListSections =
getListCommandSections(helpContent).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ecaddfb6-335e-4a9f-bff3-a5f0943fa50b

📥 Commits

Reviewing files that changed from the base of the PR and between 5cd6e80 and 81ee5f7.

📒 Files selected for processing (1)
  • apps/cli/tests/unit/help-documentation-sync.spec.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhance help sync test to verify subcommand documentation

2 participants