CLI for Fedify 2.0: Cross-runtime transition and Optique adoption
The current Fedify CLI implementation has been working well for our Deno-focused ecosystem, but as we prepare for Fedify 2.0, we're hitting some architectural limitations that are becoming increasingly apparent. Right now, our CLI is built with Cliffy, which means it only runs natively on Deno. For Node.js and Bun users who install via npm, they're actually downloading a compiled binary produced by deno compile rather than getting the actual JavaScript source. This feels somewhat awkward for what is fundamentally a JavaScript-based tool.
The compiled binary approach has served us reasonably well, but it creates a disconnect between the tool's JavaScript nature and how users actually consume it. Node.js developers expect to install JavaScript packages that run in their runtime, not pre-compiled executables. Additionally, Cliffy has some quirks that we've been working around—most notably the ANSI escape sequence issue that we had to fix in #257/#341, where it was outputting color codes even when stdout isn't a terminal. It also struggles with more complex CLI structures that we anticipate needing as Fedify's feature set expands.
For Fedify 2.0, we want to provide a more natural experience across all major JavaScript runtimes. This means the CLI should run natively on Deno, Node.js, and Bun without requiring compilation or runtime-specific workarounds. To address these needs, I've been developing Optique, a type-safe combinatorial CLI parser specifically designed with Fedify's requirements in mind. You can read more about the motivation and design principles behind Optique in the Why Optique? documentation. Optique handles cross-runtime compatibility out of the box and provides the composable architecture we need for building more sophisticated CLI interfaces.
The migration to Optique would not only solve our immediate cross-runtime needs but also position us well for the more complex CLI features we're planning for Fedify 2.0. The parser combinators approach should give us the flexibility to handle nested subcommands and reusable option groups in a way that's both maintainable and type-safe. I think this transition aligns well with our broader goals of making Fedify more accessible across the JavaScript ecosystem.
Can I work on this?
@sij411 Sure! Thanks!
FYI: I'll implement skeletons for every arguments, and lookup command only. I think it would be best to handle the full implementation and testing for the remaining arguments in separate sub-issues.
Great work on the CLI migration to Optique! With #396, #397, #398, #399, #400, #408, and #456 all completed, we're indeed close to finishing this major transition. Before we can call #374 complete, I believe we need some final polishing touches to ensure the CLI is production-ready.
Key areas that need attention:
1. Documentation and help messages
The --help messages throughout the CLI need refinement. We should ensure:
- Consistent formatting and terminology across all commands
- Clear descriptions of what each command does
- Proper examples for complex commands
- Alignment with Optique's documentation standards
2. Output stream management
Currently, output is being sent to stdout/stderr without clear conventions. We need to establish and implement consistent patterns:
- stdout: Primary output that users might pipe or redirect (JSON output, lookup results, etc.)
- stderr: Status messages, progress indicators, warnings, and errors
- This is especially important since Fedify CLI is designed to work with other Unix tools in pipelines
3. Terminal detection and formatting
Need to verify proper behavior when:
NO_COLORenvironment variable is setisatty()returns false (non-TTY environments)- Running in CI/CD environments
Specific checks:
- Spinners should be disabled in non-interactive contexts
- Color output should be stripped appropriately
- Progress indicators should switch to simple text output
- Ensure compatibility with common CI systems (GitHub Actions, GitLab CI, etc.)
4. Global state refactoring
The implementation currently relies on global state in several places, which could cause issues with:
- Testing (test isolation problems)
- Concurrent operations
- Code maintainability
We should refactor to:
- Pass state through function parameters or context objects
- Use dependency injection where appropriate
- Minimize or eliminate global variables
5. Cross-runtime consistency
Now that we support Deno, Node.js, and Bun natively:
- Ensure consistent behavior across all runtimes
- Test edge cases specific to each runtime
- Verify performance is acceptable on all platforms
6. Additional improvements to consider:
- Error handling: Ensure consistent error messages and exit codes
- Input validation: Strengthen validation for all command inputs
- Performance: Profile and optimize any slow operations
- Testing coverage: Ensure comprehensive tests for all commands across all runtimes
Would it be helpful if I create separate issues for each of these areas, or should we track them all under this umbrella issue? I'm happy to start working on any of these improvements—just let me know which areas you'd like to prioritize!
If the optique codes are on the 'next' branch, then to keep this big issue and open sub-issues aren't bad idea. Separate issues sound also good. Totally up to you.