Add scriptsInfo metadata and CI validation for script documentation - #135
Conversation
- Updated package.json and docs/package.json scriptsInfo to allow arrays for desc/args. - Updated cli-fuzzy.js to properly render multi-line descriptions.
…onsistency - Adds `validate-scripts` to package.json and docs/package.json - Ensures every script has a corresponding scriptsInfo entry - Fails CI if there is any mismatch
WalkthroughAdds centralized scriptsInfo metadata to root and docs package.json, a validator script, refactored help CLIs with shared libraries, a CI workflow that validates script-related changes, and a reusable commenter workflow that posts validation failures to PRs; documentation pages updated accordingly. Changes
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub
participant CI as CI Workflow
participant Runner as Job Runner
participant Validator as validate-scripts
participant PKG as package.json(s)
participant Commenter as commenter workflow
participant PR as Pull Request
GH->>CI: trigger on push/main or pull_request
CI->>Runner: checkout (fetch-depth:0), setup Node, npm ci
Runner->>Runner: compute common ancestor & changed files
alt scripts changed
Runner->>Validator: run validate-scripts (capture validation.log)
Validator->>PKG: read & parse root and docs package.json
Validator->>Validator: flatten scriptsInfo and compare with scripts
alt validation fails
Validator->>Runner: exit non-zero (validation.log)
Runner->>Commenter: workflow_call(issue_number, message=validation.log)
Commenter->>PR: create comment with validation output
else validation passes
Validator->>Runner: exit 0
end
else no script changes
Runner->>CI: skip validation
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
Comment |
81431bb to
643c839
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (8)
scripts/lib/colors.js (2)
26-45: Consider freezing the codes object for consistency.While the ANSI mappings are correct, freezing the
codesobject would align with the immutability pattern used for theColorsenum and prevent accidental runtime modifications.Apply this diff if desired:
-const codes = { +const codes = Object.freeze({ reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m", blue: "\x1b[34m", magenta: "\x1b[35m", cyan: "\x1b[36m", white: "\x1b[37m", bgRed: "\x1b[41m", bgGreen: "\x1b[42m", bgYellow: "\x1b[43m", bgBlue: "\x1b[44m", bgMagenta: "\x1b[45m", bgCyan: "\x1b[46m", bgWhite: "\x1b[47m", -}; +});
47-51: Consider adding input validation for the text parameter.While the color support and enum validation are handled correctly, non-string inputs (null, undefined, objects) will be coerced to strings, which may produce unexpected output like "undefined" or "[object Object]".
For more robust behavior, consider:
export function colorText(text, colorEnum) { + if (text == null) return ''; if (!supportsColor || !codes[colorEnum]) return text; return `${codes[colorEnum]}${text}${codes.reset}`; }package.json (1)
79-84: Inconsistent args format in lint:fix.The
argsarray forlint:fixcontains"Equivalent to: eslint . --fix", which differs from the standard format used elsewhere (e.g.,"-- fix Automatically fix fixable issues"). For consistency, either remove this entry or reformat it to match the pattern used by other scripts.Apply this diff to align with the established pattern:
"lint:fix": { "desc": "Run ESLint and automatically fix issues", "args": [ - "Equivalent to: eslint . --fix" + "Note: Runs 'eslint . --fix'" ] },Or simply remove the
argsfield if no additional context is needed:"lint:fix": { - "desc": "Run ESLint and automatically fix issues", - "args": [ - "Equivalent to: eslint . --fix" - ] + "desc": "Run ESLint and automatically fix issues" },scripts/validate-scripts.js (1)
5-7: Add error handling for file operations.The function lacks error handling for file read or JSON parse failures. If the file doesn't exist or contains invalid JSON, the error message won't be helpful.
Apply this diff to add better error handling:
function loadPackageJson(filePath) { - return JSON.parse(fs.readFileSync(filePath, "utf-8")); + try { + return JSON.parse(fs.readFileSync(filePath, "utf-8")); + } catch (error) { + console.error(`❌ Failed to load ${filePath}: ${error.message}`); + process.exit(1); + } }.github/workflows/commenter.yml (1)
61-77: Remove redundant conditional logic.Both branches of the
if (inputs.is_pr)statement perform identicalcreateCommentcalls on theissuesAPI. The distinction between PR and issue is unnecessary here since GitHub's API treats PR comments as issue comments.Apply this diff to simplify:
- if (inputs.is_pr) { - // Pull Request comment - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body - }); - } else { - // Issue comment - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body - }); - } + // GitHub API treats PR comments as issue comments + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body + });You can keep the
is_prinput for documentation purposes or remove it entirely if not needed..github/workflows/ci.yml (1)
13-16: Update GitHub Actions to latest versions.Static analysis tools report that
actions/checkout@v3andactions/setup-node@v3are outdated. Update tov4for both actions to ensure compatibility with current GitHub Actions runners.Apply this diff:
- - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 22scripts/lib/cli-fuzzy.js (1)
51-54: Review early return logic for non-interactive mode.When
skipIfInitialSearchis true, the function closes the readline interface and returns immediately. However, thelineandcloseevent handlers are registered after this check (lines 56-69). Consider moving the early return before setting up the handlers, or restructure the flow to avoid registering unused handlers.rl.setPrompt(colorText("> ", Colors.CYAN)); - rl.prompt(); // If initialSearch was provided, and we just want one-shot results, skip the interactive prompt if (skipIfInitialSearch) { return rl.close(); } + rl.prompt(); + rl.on("line", line => {scripts/help.js (1)
9-9: Add optional error handling for robustness.The data reading logic is correct and uses the proper ESM pattern with
new URL(). However, the code lacks error handling ifreadPackageJsonScriptsfails (e.g., missing or malformedpackage.json).Consider adding a try-catch block for better error messages:
+try { const { flat: items, basicItems } = readPackageJsonScripts(new URL("../package.json", import.meta.url)); +} catch (error) { + console.error("Failed to read package.json scripts:", error.message); + process.exit(1); +}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.github/workflows/ci.yml(1 hunks).github/workflows/commenter.yml(1 hunks)docs/package.json(2 hunks)docs/scripts/help.js(1 hunks)package.json(2 hunks)scripts/help.js(1 hunks)scripts/lib/cli-fuzzy.js(1 hunks)scripts/lib/colors.js(1 hunks)scripts/lib/read-packageJson-scripts.js(1 hunks)scripts/validate-scripts.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
docs/scripts/help.js (2)
scripts/lib/read-packageJson-scripts.js (1)
readPackageJsonScripts(3-23)scripts/lib/cli-fuzzy.js (1)
runFuzzyCli(5-19)
scripts/lib/read-packageJson-scripts.js (1)
scripts/lib/cli-fuzzy.js (2)
groups(85-85)group(88-88)
scripts/validate-scripts.js (2)
scripts/lib/read-packageJson-scripts.js (1)
JSON(4-4)scripts/lib/cli-fuzzy.js (1)
group(88-88)
scripts/help.js (3)
docs/scripts/help.js (3)
title(4-7)items(9-9)initialSearch(12-12)scripts/lib/read-packageJson-scripts.js (1)
readPackageJsonScripts(3-23)scripts/lib/cli-fuzzy.js (1)
runFuzzyCli(5-19)
🪛 actionlint (1.7.9)
.github/workflows/ci.yml
13-13: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
15-15: the runner of "actions/setup-node@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
🔇 Additional comments (11)
scripts/lib/colors.js (3)
1-3: LGTM!The TTY-based color detection is the standard approach for Node.js terminal utilities.
5-24: LGTM!The frozen enum pattern provides immutability and a clear contract for allowed color values. The comprehensive palette covers common terminal styling needs.
53-56: LGTM!Clean convenience wrapper that delegates appropriately to
colorText.docs/package.json (1)
1-137: LGTM! scriptsInfo structure is complete and consistent.The
scriptsInfometadata is well-structured and covers all scripts defined in thescriptssection. The delegation to the root validate-scripts vianpm run --prefix ..is a clean approach to reuse validation logic.docs/scripts/help.js (1)
1-19: LGTM! Clean refactoring to use shared utilities.The refactored help script elegantly delegates to the new shared libraries. The use of
import.meta.urlfor path resolution is appropriate for ES modules.scripts/lib/cli-fuzzy.js (1)
1-115: LGTM! Well-structured interactive CLI with fuzzy search.The implementation provides a clean API with good separation of concerns. The fuzzy search integration, colored output, and grouped display are well-executed. The defensive handling of
info.descas both array and string (lines 106-112) is good practice.scripts/validate-scripts.js (1)
55-59: Verify path resolution for different working directories.The script uses
path.resolve("./package.json")which resolves relative to the current working directory. Ensure the validation script is always invoked from the repository root, or adjust to useimport.meta.urlorprocess.cwd()with explicit directory checks.Run this script to confirm the validation script is always invoked from the repository root:
#!/bin/bash # Check where validate-scripts is invoked from in package.json rg -n "validate-scripts" package.json docs/package.jsonscripts/help.js (4)
4-7: LGTM!The title constant is clear and informative, providing both a header for the CLI and a link to additional documentation.
11-12: LGTM!The CLI argument capture is implemented correctly using the standard Node.js pattern. The comment explains the purpose clearly, and
process.argv.slice(2)will correctly capture arguments passed vianpm run help -- search-term.
14-19: Excellent refactor improving modularity!The orchestration is clean and well-structured. By delegating to
runFuzzyCli, the code achieves better separation of concerns and reusability, which aligns perfectly with the PR objectives to unify help scripts across the repository.
1-2: Imports are correctly structured and reference valid modules.Both
cli-fuzzy.jsandread-packageJson-scripts.jsexist inscripts/lib/with the expected exports:runFuzzyCliandreadPackageJsonScriptsrespectively. The imports at lines 1-2 are properly configured for ESM modules.
f8f35da to
dee4913
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
.github/workflows/ci.yml (2)
34-35: Add fallback for initial push scenario.The
git diffcommand uses${{ github.event.before }}which will be all-zeros (0000000000000000000000000000000000000000) on the first push to a branch or after a force push, causing the diff to fail or compare against an invalid commit.Apply this diff to add a fallback:
- files=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }}) + if [[ "${{ github.event.before }}" == "0000000000000000000000000000000000000000" ]]; then + files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git ls-files) + else + files=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }}) + fi echo "Changed files: $files"
63-74: Move reusable workflow call to a separate job.Reusable workflows must be invoked as separate jobs using
uses:at the job level, not as steps within a job. The current syntax at line 65 is invalid and will cause the workflow to fail.Apply this diff to fix the workflow structure:
- name: Run script validation id: validate if: steps.check_changes.outputs.scripts_changed == 'true' + continue-on-error: true shell: bash run: | set -o pipefail npm run validate-scripts 2>&1 | tee validation.log echo "validation_exit_code=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT + echo "validation_log<<EOF" >> $GITHUB_OUTPUT + cat validation.log >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - # Comment on PR if validation fails - - name: Comment on PR if validation fails - if: steps.validate.outputs.validation_exit_code != '0' && github.event_name == 'pull_request' - uses: ./.github/workflows/commenter.yml - with: - issue_number: ${{ github.event.pull_request.number }} - message: | - ⚠️ **Script validation failed!** - The following issues were found with your PR (latest 100 lines): - ``` - $(tail -n 100 validation.log) - ``` - is_pr: true + + comment-on-failure: + needs: validate-scripts + if: needs.validate-scripts.outputs.validation_exit_code != '0' && github.event_name == 'pull_request' + uses: ./.github/workflows/commenter.yml + with: + issue_number: ${{ github.event.pull_request.number }} + message: | + ⚠️ **Script validation failed!** + The following issues were found with your PR: + ``` + ${{ needs.validate-scripts.outputs.validation_log }} + ``` + is_pr: trueAdditionally, add outputs to the validate-scripts job:
jobs: validate-scripts: runs-on: ubuntu-latest + outputs: + validation_exit_code: ${{ steps.validate.outputs.validation_exit_code }} + validation_log: ${{ steps.validate.outputs.validation_log }} steps:
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.github/workflows/ci.yml(1 hunks).github/workflows/commenter.yml(1 hunks)package.json(2 hunks)scripts/help.js(1 hunks)scripts/lib/cli-fuzzy.js(1 hunks)scripts/lib/colors.js(1 hunks)scripts/validate-scripts.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- scripts/lib/cli-fuzzy.js
- scripts/lib/colors.js
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/validate-scripts.js (1)
scripts/lib/read-packageJson-scripts.js (1)
JSON(4-4)
🪛 Biome (2.1.2)
package.json
[error] 81-81: Expected a property but instead found '}'.
Expected a property here.
(parse)
🔇 Additional comments (2)
scripts/validate-scripts.js (1)
1-64: LGTM!The validation script is well-structured and correctly implements two-way validation between
scriptsandscriptsInfoin both root and docs package.json files. The error handling is appropriate, and the logic correctly handles the_metaexclusion when flattening scriptsInfo.package.json (1)
81-81: Static analysis false positive.The Biome error at line 81 appears to be a false positive. The syntax
},correctly closes thelint:fixobject within theLintingcategory. This is valid JSON.
Fix input access in github-script.
The inputs object is not directly accessible in the JavaScript context of github-script. Inputs must be passed through the with: section using ${{ inputs.* }} syntax or as environment variables.
|
@CodeRabbit help |
|
Tip For best results, initiate chat on the files or code changes. @Ryan-Millard, here's what I can help you with: 🤖 CodeRabbit CapabilitiesReview CommandsI can perform various actions on your PR. Simply mention me with these commands:
Interactive ReviewYou can ask me questions about:
Advanced Features
ConfigurationFor repository-wide settings:
Visit CodeRabbit Documentation for detailed configuration options and guides. Example Interactions
Feel free to ask me anything about this PR or request specific analyses! 🚀 |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
|
@CodeRabbit full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
.github/workflows/commenter.yml (2)
36-40: Unusedis_prinput.The
is_prinput is defined but never used in the workflow. The script always usesissues.createCommentregardless of this flag. Either implement the differentiation logic or remove the unused input to avoid confusion.
55-59: Consider escaping the message to prevent syntax errors.If
inputs.messagecontains backticks or${...}patterns, the template literal on line 59 could cause JavaScript syntax errors or unintended interpolation. Consider using a safer approach:script: | const owner = context.repo.owner; const repo = context.repo.repo; const number = ${{ inputs.issue_number }}; - const body = `${{ inputs.message }}`; + const body = String.raw`${{ inputs.message }}`;Alternatively, pass the message via environment variables:
env: COMMENT_BODY: ${{ inputs.message }} script: | const body = process.env.COMMENT_BODY;
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/commenter.yml(1 hunks)docs/scripts/help.js(1 hunks)package.json(2 hunks)scripts/help.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
docs/scripts/help.js (3)
scripts/help.js (3)
title(4-7)items(10-10)initialSearch(13-13)scripts/lib/read-packageJson-scripts.js (1)
readPackageJsonScripts(3-23)scripts/lib/cli-fuzzy.js (1)
runFuzzyCli(5-19)
🔇 Additional comments (4)
docs/scripts/help.js (1)
1-24: Clean orchestrator pattern with proper error handling.The refactored structure correctly delegates to shared utilities while keeping all dependent logic inside the try block, avoiding variable scope issues. The relative import paths correctly reference the shared lib in the parent project.
package.json (2)
7-116: Well-structured scriptsInfo metadata with complete 1:1 mapping.The categorized structure with
_meta.basicfor commonly-used scripts and detailedargsschemas for commands with options provides excellent discoverability. All 25 scripts have correspondingscriptsInfoentries, fulfilling the PR objective of strict 1:1 mapping.
141-142: Newvalidate-scriptsentry completes the CI enforcement objective.The addition of
validate-scriptsensures the 1:1 mapping can be enforced in CI, aligning with the PR's goal of preventing undocumented or stale scripts.scripts/help.js (1)
9-24: Scope issue resolved by keeping dependent code inside try block.The past review flagged that
itemsandbasicItemswere declared in the try block but referenced outside. The current implementation resolves this by keepingrunFuzzyCliinside the try block, which is a valid alternative to the suggested fix of declaring variables outside. Both approaches prevent the ReferenceError.
…help - Changes: scripts/lib/cli-fuzzy.js scripts/lib/read-packageJson-scripts.js
146fffd to
43bd0b1
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
scripts/lib/cli-fuzzy.js (1)
114-130: Complete the defensive validation forinfo.args.The past review comment has been partially addressed—
descriptionandcommandare now checked. However, line 121 still doesn't validate thatinfo.argsis actually an array before iterating. Ifargsis a non-array object with alengthproperty (like a string), the for-of loop on line 122 could produce unexpected results.Apply this diff to complete the fix:
- if (info.args && info.args.length) { + if (Array.isArray(info.args) && info.args.length) { for (const arg of info.args) { console.log(`\t\t ${colorText(arg, Colors.YELLOW)}`); } }
🧹 Nitpick comments (1)
scripts/lib/cli-fuzzy.js (1)
31-37: Consider extracting magic constants.The hardcoded values (line width of 80 and instruction text) could be extracted as constants at the module level for easier maintenance.
+const LINE_WIDTH = 80; +const INSTRUCTIONS = "Type 'a' to list all, 'q' to quit."; + function printHeader(title) { - const line = colorText("─".repeat(80), Colors.BLUE); + const line = colorText("─".repeat(LINE_WIDTH), Colors.BLUE); console.log(line); console.log(colorText(title, Colors.BOLD)); - console.log("Type 'a' to list all, 'q' to quit."); + console.log(INSTRUCTIONS); console.log(line); }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scripts/lib/cli-fuzzy.js(1 hunks)
🔇 Additional comments (5)
scripts/lib/cli-fuzzy.js (5)
5-29: LGTM!The input validation is thorough and the orchestration logic correctly handles the different CLI modes (basic display, initial search, interactive).
39-45: LGTM!The function correctly validates that each basic item exists in the items object before attempting to print it.
47-81: Verify readline cleanup behavior in one-shot mode.When
skipIfInitialSearchis true, line 62 callsrl.close()and immediately returns. The close event handler (lines 77-80) will fire asynchronously, but the function has already returned. While this may work for the one-shot use case, ensure that this pattern doesn't cause issues if the calling code expects synchronous cleanup.If you encounter issues, consider making the cleanup explicit:
function startInteractive(items, skipIfInitialSearch = false) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, completer(line) { const names = Object.keys(items); const hits = fuzzy.filter(line, names).map(x => x.original); return [hits, line]; }, }); rl.setPrompt(colorText("> ", Colors.CYAN)); // If initialSearch was provided, and we just want one-shot results, skip the interactive prompt if (skipIfInitialSearch) { - return rl.close(); + rl.close(); + return; }
83-93: LGTM!The search logic correctly handles empty results and prints matching items.
95-112: LGTM!The grouping logic correctly handles missing group properties with a sensible default and prints items in an organized manner.
e6ea791 to
5fcfd1a
Compare
e4dd3f1 to
2e2a4ce
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
scripts/lib/cli-fuzzy.js (1)
2-2: Verify that thefuzzydependency has been added to package.json.This was previously flagged as a critical issue. The
fuzzylibrary is imported but must be declared in the package.json manifest to avoid runtime failures.Run the following script to verify the dependency was added:
#!/bin/bash # Description: Check if fuzzy dependency exists in package.json cat package.json | jq -r '.dependencies.fuzzy // .devDependencies.fuzzy // "NOT_FOUND"'
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scripts/lib/cli-fuzzy.js(1 hunks)
🔇 Additional comments (5)
scripts/lib/cli-fuzzy.js (5)
31-45: LGTM!The header printing and basic items display logic is well-structured. The defensive check at line 42 ensures
printItemis only called for items that exist in theitemsobject.
47-81: LGTM!The interactive mode implementation is well-designed. The one-shot mode (lines 60-63) correctly handles the case when initial search terms were provided, and the command handlers ('q', 'a', and search) provide good UX.
83-93: LGTM!The search implementation correctly uses fuzzy filtering and provides clear feedback when no matches are found.
95-112: LGTM!The grouping logic effectively organizes items by their group property with a sensible "Other" default, and the output formatting with colored group headers enhances readability.
114-130: Defensive checks properly implemented!The function now correctly handles missing or undefined properties:
- Line 116 handles both string and array descriptions
- Line 117 checks if description exists before printing
- Line 121 validates args is an array before iteration
- Line 127 checks if command exists before printing
This addresses the concerns raised in the previous review.
|
@CodeRabbit generate unit tests |
|
@coderabbitai generate docstrings |
✅ Actions performedInitiated docstring generation; will generate only if new commits exist. |
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @Ryan-Millard. * #135 (comment) The following files were modified: * `scripts/lib/cli-fuzzy.js` * `scripts/lib/colors.js` * `scripts/lib/read-packageJson-scripts.js` * `scripts/validate-scripts.js`
Docstrings generation was requested by @Ryan-Millard. * #135 (comment) The following files were modified: * `scripts/lib/cli-fuzzy.js` * `scripts/lib/colors.js` * `scripts/lib/read-packageJson-scripts.js` * `scripts/validate-scripts.js` Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
An unexpected error occurred during Unit Test Generation. |
✅ Actions performedUnit Test Generation started... |
🧹 Chore / Maintenance Pull Request
📌 What’s Changing
Refactor help scripts in both main app and docs app to:
scriptsInfofield inpackage.jsonthat contains metadata about custom scriptsci.ymlto enforce this so scripts don't get forgotten🔗 Context
Fixes #124
Only changing
scripts&docs/scriptspackage.json&docs/package.jsongithub/workflows/ci.ymlAdded some lib scripts to root for reuse inside docs scripts
🔍 Impact
🧪 Verification
Numerous local runs for both apps - if one works, the other should, too.
✔️ Checklist
mainyet.Summary by CodeRabbit
New Features
Chores
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.