✨ Add JSON output, review commands, and user auth for CLI#203
✨ Add JSON output, review commands, and user auth for CLI#203
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@claude can you review this PR? |
|
Claude finished @Robdel12's task in 1m 57s —— View job PR Review: ✨ Add JSON output and query commandsI've reviewed the code changes for this PR. Overall, this is a well-structured addition that successfully makes the CLI scriptable. The implementation is clean, follows existing patterns, and has good test coverage. Below are my findings: ✅ Strengths1. Architecture & Design
2. Security
3. Code Quality
4. Documentation
🔍 Issues & RecommendationsCritical1. Security: API token exposure risk in config command (config-cmd.js:58-64) The config command could expose API tokens if field selection is used: // config-cmd.js:58-64
if (config.apiKey) {
displayConfig.api = {
url: config.apiUrl || config.baseUrl,
tokenConfigured: true,
tokenPrefix: `${config.apiKey.substring(0, 8)}...`, // ⚠️ This is good
};
}However, when a user does: vizzly config --json apiThe field selection in output.js:135-153 would return the masked Recommendation: Ensure that field selection ONLY operates on 2. Missing validation for review commands (review.js) The review commands (approve, reject, comment) don't have validation functions exported, unlike other commands: // src/cli.js:774-806 - No validateApproveOptions, validateRejectOptions, validateCommentOptions
program
.command('approve')
.argument('<comparison-id>', 'Comparison ID to approve')
.action(async (comparisonId, options) => {
// No validation here
await approveCommand(comparisonId, options, globalOptions);
});Recommendation: Add validation functions for consistency: export function validateApproveOptions(comparisonId, options = {}) {
let errors = [];
if (!comparisonId || comparisonId.trim() === '') {
errors.push('Comparison ID is required');
}
return errors;
}High Priority3. Inconsistent error handling in JSON mode (multiple files) Some commands exit with code 1 on error in JSON mode without calling // api.js:174
output.data({ /* error data */ });
output.cleanup();
exit(1);
// ✅ Good - cleanup before exit
// But in some error paths:
output.error('...');
exit(1);
// ❌ Missing cleanupRecommendation: Audit all error paths to ensure 4. Field selection doesn't validate field existence (output.js:135-153) The function selectFields(obj, fields) {
// ...
for (let field of fields) {
let value = getNestedValue(obj, field);
if (value !== undefined) { // ⚠️ Silently skips missing fields
setNestedValue(result, field, value);
}
}
return result;
}This could confuse users who misspell field names. They'll get an empty object instead of an error. Recommendation: Consider adding a Medium Priority5. API command allows arbitrary GET requests (api.js:61-70) While POST is properly restricted, GET has no validation: // api.js:49-55
let normalizedEndpoint = endpoint.startsWith('/')
? endpoint
: `/${endpoint}`;
if (!normalizedEndpoint.startsWith('/api/')) {
normalizedEndpoint = `/api${normalizedEndpoint}`;
}This could allow users to hit internal endpoints if the API doesn't have proper authentication checks. Recommendation: Consider adding a whitelist of allowed GET endpoint patterns, similar to the POST whitelist. Or at least document that this is a "power user" feature. 6. Baselines command has potential race condition (baselines.js:88-100) if (existsSync(baselinesDir)) {
baselineFiles = readdirSync(baselinesDir)
.filter(f => f.endsWith('.png'))
.map(f => {
let filePath = join(baselinesDir, f);
let stat = statSync(filePath); // ⚠️ Could fail if file deleted between readdir and stat
// ...
});
}Recommendation: Wrap 7. Missing JSDoc for some exported functions While most functions have JSDoc comments, some are missing:
Recommendation: Add JSDoc for consistency and better IDE support. Low Priority / Nice to Have8. Pagination could be more intuitive The pagination info shows "Use --offset 20" but doesn't show the limit: // builds.js:157-161
if (pagination.total > builds.length) {
output.hint(
`Showing ${builds.length} of ${pagination.total} builds. ` +
`Use --offset ${filters.offset + filters.limit} to see more.`
);
}Recommendation: Include the full command: 9. JSON output structure inconsistency Most commands wrap data in // builds.js:71 - Direct output
output.data(formatBuildForJson(build, options.comparisons));
// vs comparisons.js:68 - Also direct
output.data(formatComparisonForJson(comparison));According to docs/json-output.md:35-39, all output should have the wrapper. The 10. Test coverage gaps While there are tests for new commands, I'd like to see:
📋 Minor Issues
🎯 SummaryApproval recommendation: ✅ Approve with minor fixes This PR successfully achieves its goal of making the CLI scriptable. The implementation is solid, follows good patterns, and is well-documented. The security measures for the API command are appropriate. Must fix before merge:
Should fix: Nice to have: The test failures shown in the Vizzly comment appear to be visual regression tests for the CLI help output, which makes sense given the new commands added. Those should be reviewed and approved in the Vizzly dashboard. Great work on this PR! The JSON output feature will be very valuable for automation and AI agent integration. 🚀 |
Add consistent JSON output support to CLI commands, similar to GitHub's gh CLI: - Add field selection support: `--json id,status,branch` filters output fields - Support dot notation for nested fields: `--json comparisons.total` - Add JSON output to `run` command with build info, git metadata, comparisons - Add JSON output to `tdd run` command with comparison details and summary - Add JSON output to `upload` command with stats and build URL - Handle --wait mode with comparison statistics in JSON - Structured error output in JSON mode Usage: vizzly run "npm test" --json vizzly run "npm test" --json buildId,url,exitCode vizzly tdd run "npm test" --json | jq '.data.summary'
Sprint 2: Add JSON support to secondary commands: - tdd start/stop/status: Server status, port, pid, uptime - tdd list: Uses output.data() for consistency - preview: Enhanced JSON with compression stats, expiry - init: Config path, plugins, skip reason - project:select: Project/org details on success Fix preview tests to provide required build option for dry-run.
New commands for querying data from the CLI: - `vizzly builds` - List builds with filtering (--branch, --status, --limit) - `vizzly builds --build <id>` - Get a specific build - `vizzly comparisons --build <id>` - Get comparisons for a build - `vizzly comparisons --name <pattern>` - Search comparisons by name - `vizzly comparisons --id <id>` - Get a specific comparison - `vizzly config` - Display current configuration - `vizzly config <key>` - Get a specific config value (dot notation) All commands support --json for machine-readable output.
Sprint 4 - Advanced query commands:
- `vizzly baselines` - List local TDD baselines with metadata
- `vizzly baselines --name <pattern>` - Filter by name
- `vizzly baselines --info <name>` - Get detailed info for specific baseline
- `vizzly api <endpoint>` - Raw API access for power users
- `vizzly api /sdk/builds -X GET` - Make authenticated requests
- `vizzly api /sdk/builds -d '{}' -X POST` - POST with body
All commands support --json for machine-readable output.
- project:list now returns structured array with current project marked - project:token includes full project/org info and directory - project:remove skips confirmation in JSON mode for scripting
Comprehensive reference for --json flag and field selection: - Output format and structure - All commands with example output - Scripting examples with jq
- Add vizzly approve, reject, comment commands for review workflows - Restrict vizzly api to GET by default - Whitelist POST only for approve/reject/comment endpoints - Update docs to reflect API restrictions
- Add validation functions for review commands (approve/reject/comment) - Fix baselines race condition with try/catch around statSync - Remove unused getApiUrl import and dead code from builds.js - Remove unrelated plans/menubar-app.md from PR
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Add user JWT fallback in config-loader (enables `vizzly login` for interactive CLI) - Add help examples to builds, comparisons, approve, reject, comment, baselines, api commands - Add `npm run cli` script with .envrc sourcing for local dev - Add .envrc to .gitignore - Fix missing 'review' category in help grouping
This comment has been minimized.
This comment has been minimized.
- Add `vizzly orgs` to list organizations user has access to - Add `vizzly projects` to list projects (with --org filter) - Both commands support --json for scripting/LLM use - Include in Account help category
This comment has been minimized.
This comment has been minimized.
|
@claude please rereview |
|
Claude finished @Robdel12's task in 2m 33s —— View job PR Re-Review: ✨ Add JSON output and query commandsI've completed a thorough re-review of this PR. Great news: the two critical issues from my previous review have been addressed. The code is well-structured and follows good patterns. Below are my detailed findings. ✅ Critical Issues Resolved1. Token Security (Previously Critical #1) The config command properly isolates token data. Field selection operates exclusively on 2. Validation Functions Added (Previously Critical #2) All review commands now have proper validation functions (review.js:311-358):
These are properly exported and follow the same pattern as other commands. ✅ 🔍 New FindingsHigh Priority1. Inconsistent error path cleanup (api.js:163-175) When errors occur in JSON mode, some paths call // api.js:163-175 - GOOD, has cleanup
if (globalOptions.json) {
output.data({ /* error */ });
output.cleanup(); // ✅
exit(1);
return;
}However, checking review.js shows a similar pattern. The concern is whether ALL error paths consistently clean up. A quick audit would be valuable. Recommendation: Run a grep to ensure all 2. Field selection doesn't warn on missing fields (output.js:136-153) The // output.js:146-150
for (let field of fields) {
let value = getNestedValue(obj, field);
if (value !== undefined) { // Silently skips missing fields
setNestedValue(result, field, value);
}
}Impact: Users who typo field names get an empty object instead of helpful feedback: vizzly builds --json "builld.id" # Typo - returns {}Recommendation: Consider adding a verbose warning when requested fields aren't found, or add a 3. Race condition in baselines command (baselines.js:88-100) There's a potential TOCTOU (time-of-check-time-of-use) issue: // baselines.js:88-91
if (existsSync(baselinesDir)) {
baselineFiles = readdirSync(baselinesDir)
.filter(f => f.endsWith('.png'))
.map(f => {
let filePath = join(baselinesDir, f);
let stat = statSync(filePath); // ⚠️ File could be deleted hereRecommendation: Wrap Medium Priority4. Missing JSDoc for formatter functions While most code is well-documented, these functions lack JSDoc:
Recommendation: Add JSDoc for consistency and better IDE autocomplete. 5. API command allows arbitrary GET requests (api.js:49-70) The API command only restricts POST endpoints but allows any GET endpoint: // api.js:49-54
let normalizedEndpoint = endpoint.startsWith('/')
? endpoint
: `/${endpoint}`;
if (!normalizedEndpoint.startsWith('/api/')) {
normalizedEndpoint = `/api${normalizedEndpoint}`;
}While the API should have proper authentication, this is a "power user" feature that could potentially access internal endpoints if the API doesn't validate tokens correctly. Current status: This is acceptable as long as the backend enforces proper authentication. The POST whitelist (lines 187-191) is good security practice. 6. Code duplication opportunity The status icon mapping appears in multiple files:
Recommendation: Extract to a shared utility in Low Priority7. Magic numbers scattered throughout Hardcoded limits (20, 50, 100, 250) appear in multiple files without constants. For example:
Recommendation: Define constants like 8. Pagination hint could be more helpful (builds.js:157-161) Current: output.hint(`Showing ${builds.length} of ${pagination.total} builds. ` +
`Use --offset ${filters.offset + filters.limit} to see more.`);Recommendation: Include the full command for copy-paste convenience: `Use --offset ${filters.offset + filters.limit} --limit ${filters.limit} to see more.`9. Test coverage gaps While the PR includes tests for new commands, these areas could use more coverage:
Not blocking, but would strengthen the test suite. 📊 Code Quality AssessmentStrengths:
Minor improvements needed:
🎯 Recommendation✅ Approve with minor improvements This PR successfully achieves its goal of making the CLI fully scriptable and LLM-friendly. The implementation is solid, secure, and well-tested. The two critical issues from the previous review have been properly addressed. Before merging (optional improvements):
Visual regression tests: 📝 SummaryThis is a comprehensive, well-executed addition to the CLI. The JSON output system is thoughtfully designed with field selection, the new commands follow consistent patterns, and the security measures are appropriate. The code quality is high, and the documentation is excellent. The issues identified above are minor refinements rather than blockers. Great work on this PR! 🚀 |
Address PR review feedback: - Add output.cleanup() to all error paths before process.exit() - Add debug-level warning when field selection doesn't find requested fields - Ensures spinners and other terminal state are properly cleaned up on errors Files fixed: - api.js, review.js (approve/reject/comment), builds.js, comparisons.js - config-cmd.js, orgs.js, projects.js, baselines.js
Vizzly - Visual Test ResultsCLI Reporter - 7 changes need review
Changes needing review (7)fullscreen-viewer · Firefox · 1920×1080 · 5.8% diff bulk-accept-dialog · Firefox · 1920×1080 · 10.3% diff filter-failed-only · Firefox · 1920×1080 · 0.1% diff viewer-slide-mode · Firefox · 1920×1080 · 0.5% diff viewer-zoomed-100 · Firefox · 1920×1080 · 0.3% diff filter-failed-only · Firefox · 375×703 · 0.2% diff ...and 1 more in Vizzly. CLI TUI - 1 change needs review
|







Summary
Comprehensive update to make the CLI fully scriptable and LLM-friendly:
JSON Output (
--json)--jsonfor machine-readable output--json field1,field2{status, data}or{status, error}New Discovery Commands
vizzly orgs- List organizations user has access tovizzly projects- List projects (with--orgfilter)vizzly builds- List and query buildsvizzly comparisons- Query and search comparisonsvizzly baselines- List local TDD baselinesNew Review Commands
vizzly approve <comparison-id>- Approve a comparisonvizzly reject <comparison-id> -r "reason"- Reject with reasonvizzly comment <build-id> "message"- Add build commentUser Authentication
vizzly loginDeveloper Experience
npm run cliscript for local developmentTest plan
All commands manually tested against local API:
vizzly whoami --json- Shows auth status, user info, orgsvizzly orgs --json- Lists 2 orgs with role and project countvizzly projects --json- Lists projects with build countsvizzly builds --json --limit 3- Lists builds with paginationvizzly builds -b <id> --json- Gets single build detailsvizzly builds -b <id> --comparisons --json- Build with comparisonsvizzly comparisons -b <id> --json- Lists comparisons for buildvizzly comparisons --id <id> --json- Gets single comparisonvizzly comparisons --name "index" --json- Searches by namevizzly approve <id> --json- Approved, verified user ID in audit trailvizzly reject <id> -r "Testing CLI rejection" --json- Rejected with reasonvizzly comment <build-id> "Testing build comments from CLI" --json- Comment created with user attributionvizzly baselines --json- Lists 21 local baselinesvizzly api /api/sdk/builds -q limit=1 --json- Raw API access worksvizzly builds --help- Shows examples and workflow guidancevizzly approve --help- Shows examples with workflow steps