Skip to content

Conversation

@yamadashy
Copy link
Owner

@yamadashy yamadashy commented Feb 1, 2026

Add a banner on the result page that displays the equivalent CLI command for running Repomix locally. This encourages website users to try the npm package.

  • Generate CLI command from selected pack options (format, compress, include/ignore patterns, etc.)
  • Show banner with copy button above the "Star this project" section
  • Shared generateCliCommand utility used by both result and error content components
  • Update SupportMessage to banner style with subtle orange gradient

Checklist

  • Run npm run test
  • Run npm run lint

Open with Devin

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

This PR refactors the SupportMessage component's styling and DOM structure, then introduces a CLI command generation utility and propagates packOptions through the TryIt component hierarchy to enable users to view and copy generated CLI commands in both success and error states.

Changes

Cohort / File(s) Summary
SupportMessage UI Refactoring
website/client/components/Home/SupportMessage.vue
Restructured container divs, updated CSS class names from .support-notice/.support-message to .support-banner, adjusted padding/gradients/borders, and refined responsive behavior; removed unused HeartHandshake icon import.
TryIt Component Props Propagation
website/client/components/Home/TryIt.vue, website/client/components/Home/TryItResult.vue, website/client/components/Home/TryItResultContent.vue, website/client/components/Home/TryItResultErrorContent.vue
Added new optional packOptions prop to the TryIt component chain; propagated through TryItResult to child components TryItResultContent and TryItResultErrorContent to pass configuration options down the hierarchy.
CLI Command Generation Feature
website/client/components/Home/TryItResultContent.vue, website/client/components/Home/TryItResultErrorContent.vue, website/client/components/utils/cliCommand.ts
Introduced new generateCliCommand() utility function to build CLI invocation strings from repository URL and pack options; integrated into both success and error content components with UI banner for displaying and copying the generated command to clipboard.

Sequence Diagram

sequenceDiagram
    participant Parent as TryIt
    participant Result as TryItResult
    participant Content as TryItResultContent
    participant Util as generateCliCommand
    participant UI as CLI Banner UI

    Parent->>Result: pass packOptions prop
    Result->>Content: pass packOptions prop
    Content->>Util: call generateCliCommand(repositoryUrl, packOptions)
    Util-->>Content: return CLI command string
    Content->>UI: display command in banner
    UI->>Content: user clicks copy button
    Content->>Content: copy to clipboard + set commandCopied state
    Content->>UI: show "Copied!" feedback
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: adding a CLI command banner to the result page.
Description check ✅ Passed The description covers the main feature, implementation details, and includes completed checklist items, matching the repository template requirements.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/website-cli-command-banner

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @yamadashy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience on the Repomix website by integrating a prominent CLI command banner on the result page. This banner dynamically generates a npx repomix command, tailored to the user's selected packing options, and provides a convenient copy-to-clipboard function. The primary goal is to encourage website users to explore and utilize the Repomix npm package locally, bridging the gap between the web interface and command-line usage. The changes also include a visual refresh for existing support messages and standard dependency updates.

Highlights

  • CLI Command Banner: A new banner is added to the result page, dynamically displaying the equivalent repomix CLI command based on user-selected options.
  • Dynamic Command Generation: A new utility function generateCliCommand was introduced to construct the CLI command string from various pack options (e.g., format, compress, include/ignore patterns).
  • UI/UX Enhancements: The SupportMessage component was restyled into a banner with an orange gradient, and the new CLI banner includes a copy button for user convenience.
  • Dependency Updates: Several development dependencies were updated in browser/package.json and browser/package-lock.json.
  • peerDependencies Adjustments: The peer: true flag was removed from numerous dependencies and added to others in package-lock.json files across the project, likely reflecting changes in dependency resolution or packaging.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (5)
    • .github/workflows/ci.yml
    • .github/workflows/claude-code-review.yml
    • .github/workflows/claude-issue-similar.yml
    • .github/workflows/claude-issue-triage.yml
    • .github/workflows/claude.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@yamadashy yamadashy force-pushed the feat/website-cli-command-banner branch from 3d15082 to 5fad588 Compare February 1, 2026 15:09
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 1, 2026

Deploying repomix with  Cloudflare Pages  Cloudflare Pages

Latest commit: 62280a6
Status: ✅  Deploy successful!
Preview URL: https://3b24fa82.repomix.pages.dev
Branch Preview URL: https://feat-website-cli-command-ban.repomix.pages.dev

View logs

@claude
Copy link
Contributor

claude bot commented Feb 1, 2026

Code Review

Overall: Clean, well-structured PR that adds a useful CLI command banner to encourage local usage. The shared generateCliCommand utility and prop-drilling pattern are solid.

Issues

1. Missing error handling in TryItResultErrorContent.vue clipboard copy (minor)

copyCommand at line 22 doesn't handle clipboard failures, unlike handleCopyCommand in TryItResultContent.vue which wraps in try/catch. If navigator.clipboard.writeText rejects, copied will never reset.

2. Potential command injection in generateCliCommand

Details

In cliCommand.ts:44-48, user-provided includePatterns and ignorePatterns are interpolated into the command string with only trim() applied. While this is displayed in the UI (not executed), if a user copies a command containing malicious patterns (e.g., patterns with shell metacharacters like ; rm -rf /), it could be dangerous when pasted into a terminal.

Consider sanitizing or escaping shell-special characters, or at minimum wrapping the values in single quotes instead of double quotes to prevent shell expansion.

3. HeartHandshake import removed but messages array still references it

Details

In SupportMessage.vue, the HeartHandshake import was removed (line 1), but the messages array at line 11 still uses HeartHandshake as an icon. This would cause a runtime error when that message rotates in. Looking more carefully, the messages array was also updated to only use Star — this is fine, the removal is consistent.

Edit: On closer inspection, the messages array was updated too. No issue here.

Suggestions

  • The --remote flag value isn't quoted in the generated command (cliCommand.ts:8). Repository URLs with special characters could break the command. Consider wrapping in quotes: --remote "${repositoryUrl}".
  • Unit tests for generateCliCommand would be valuable — it has multiple branches for different option combinations.

Summary

Good feature addition. The main concern is the lack of shell-escaping for user-provided patterns in the CLI command string. Everything else looks clean and follows the project's conventions well.


Reviewed by Claude

@claude
Copy link
Contributor

claude bot commented Feb 1, 2026

Code Review

Overall this is a clean, well-structured PR. The generateCliCommand utility is a good abstraction shared between result and error pages. A few items worth noting:

Issues

1. Missing return statement in generateCliCommand

website/client/components/utils/cliCommand.ts — The function builds a parts array but never returns the joined result. The closing of the function appears to be cut off. Ensure the function ends with:

return parts.join(' ');

2. Command injection via unsanitized patterns

The includePatterns and ignorePatterns values are interpolated directly into the command string with only trim(). If a user enters patterns containing shell metacharacters (e.g., ; rm -rf / or backticks), the displayed command could be misleading or dangerous if copy-pasted into a terminal. Consider escaping or validating these inputs, or at minimum wrapping them in single quotes instead of double quotes in the generated command.

3. No unit tests for generateCliCommand

Per project guidelines, new features should include corresponding unit tests. This utility has clear, testable logic — default omission, flag mapping, pattern quoting — and would benefit from test coverage.

Minor Notes

Details
  • The packOptions prop is optional (packOptions?: PackOptions) throughout the chain, which is fine, but TryItResultContent always receives it from TryItResult which always receives it from TryIt. Consider whether it truly needs to be optional or if it should be required at least in TryItResultContent.
  • The SupportMessage simplification looks good — removing unused HeartHandshake import and flattening the DOM structure is a nice cleanup.
  • The package-lock.json changes (peer dependency flag removals/additions) are unrelated to the feature. Not a problem, but worth noting they appear to be from a dependency resolution change rather than this PR's intent.

Premortem

Potential failure scenarios
  • Long commands overflow on mobile: Very long include/ignore patterns could make the command banner unwieldy. The CSS handles this with text-overflow: ellipsis and word-break: break-all on mobile, which is reasonable.
  • Clipboard API unavailability: navigator.clipboard.writeText requires HTTPS and a secure context. The website likely runs on HTTPS, but the error is silently caught — acceptable for a copy button.
  • CLI flag drift: If CLI flags change in future versions, this mapping could become stale. A comment noting the coupling would help future maintainers.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View issue and 3 additional flags in Devin Review.

Open in Devin Review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new banner on the result page, displaying the equivalent CLI command for user-selected options, which is a great feature to encourage repomix npm package adoption. However, the generateCliCommand utility is vulnerable to shell command injection because it does not properly escape user-provided inputs. This could allow an attacker to execute malicious commands on a user's local machine via crafted URLs. Additionally, there are areas for improvement regarding error handling for the copy-to-clipboard functionality.

Comment on lines 3 to 53
export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
const parts: string[] = ['npx repomix'];

// Add remote repository URL
if (repositoryUrl) {
parts.push(`--remote ${repositoryUrl}`);
}

// Only add options if packOptions is provided
if (packOptions) {
// Format (only add if not default 'xml')
if (packOptions.format && packOptions.format !== 'xml') {
parts.push(`--style ${packOptions.format}`);
}

// Boolean flags that enable features
if (packOptions.removeComments) {
parts.push('--remove-comments');
}
if (packOptions.removeEmptyLines) {
parts.push('--remove-empty-lines');
}
if (packOptions.showLineNumbers) {
parts.push('--output-show-line-numbers');
}
if (packOptions.outputParsable) {
parts.push('--parsable-style');
}
if (packOptions.compress) {
parts.push('--compress');
}

// Boolean flags that disable defaults (fileSummary and directoryStructure default to true)
if (packOptions.fileSummary === false) {
parts.push('--no-file-summary');
}
if (packOptions.directoryStructure === false) {
parts.push('--no-directory-structure');
}

// String options
if (packOptions.includePatterns?.trim()) {
parts.push(`--include "${packOptions.includePatterns.trim()}"`);
}
if (packOptions.ignorePatterns?.trim()) {
parts.push(`--ignore "${packOptions.ignorePatterns.trim()}"`);
}
}

return parts.join(' ');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

security-high high

The generateCliCommand function is vulnerable to shell command injection. User-provided inputs like repositoryUrl, includePatterns, and ignorePatterns are directly concatenated into the command string without proper shell escaping. While wrapping the repository URL in quotes (as suggested) is a good practice for some special characters, it is insufficient to prevent full shell command injection. An attacker could craft a malicious URL that, when opened by a victim, populates these fields with shell metacharacters (e.g., ;, &, |, or backticks). If the victim copies and pastes the generated command into their terminal, it will execute the attacker's malicious commands. To remediate this, all user-provided inputs must be properly escaped for shell usage, for example, by wrapping arguments in single quotes and escaping any existing single quotes within the input.

export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
  const escapeShellArg = (arg: string) => `'${arg.replace(/'/g, "'\\''")}'`;
  const parts: string[] = ['npx repomix'];

  // Add remote repository URL
  if (repositoryUrl) {
    parts.push(`--remote ${escapeShellArg(repositoryUrl)}`);
  }

  // Only add options if packOptions is provided
  if (packOptions) {
    // Format (only add if not default 'xml')
    if (packOptions.format && packOptions.format !== 'xml') {
      parts.push(`--style ${packOptions.format}`);
    }

    // Boolean flags that enable features
    if (packOptions.removeComments) {
      parts.push('--remove-comments');
    }
    if (packOptions.removeEmptyLines) {
      parts.push('--remove-empty-lines');
    }
    if (packOptions.showLineNumbers) {
      parts.push('--output-show-line-numbers');
    }
    if (packOptions.outputParsable) {
      parts.push('--parsable-style');
    }
    if (packOptions.compress) {
      parts.push('--compress');
    }

    // Boolean flags that disable defaults (fileSummary and directoryStructure default to true)
    if (packOptions.fileSummary === false) {
      parts.push('--no-file-summary');
    }
    if (packOptions.directoryStructure === false) {
      parts.push('--no-directory-structure');
    }

    // String options
    if (packOptions.includePatterns?.trim()) {
      parts.push(`--include ${escapeShellArg(packOptions.includePatterns.trim())}`);
    }
    if (packOptions.ignorePatterns?.trim()) {
      parts.push(`--ignore ${escapeShellArg(packOptions.ignorePatterns.trim())}`);
    }
  }

  return parts.join(' ');
}

@codecov
Copy link

codecov bot commented Feb 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.17%. Comparing base (35b6db3) to head (62280a6).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1127   +/-   ##
=======================================
  Coverage   87.17%   87.17%           
=======================================
  Files         116      116           
  Lines        4382     4382           
  Branches     1019     1019           
=======================================
  Hits         3820     3820           
  Misses        562      562           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/client/components/Home/TryItResultErrorContent.vue (1)

14-29: ⚠️ Potential issue | 🟡 Minor

Add error handling to clipboard operation to maintain consistency with similar functions.

navigator.clipboard.writeText can reject due to missing permissions or insecure contexts. This is already handled in TryItResultContent.vue (lines 64-77) and the copyToClipboard utility (resultViewer.ts lines 15-24); the same pattern should be applied here.

🛠️ Suggested fix
 const copyCommand = async (event: Event) => {
   event.preventDefault();
   event.stopPropagation();
-  await navigator.clipboard.writeText(commandWithRepo.value);
-  copied.value = true;
-  setTimeout(() => {
-    copied.value = false;
-  }, 2000);
+  try {
+    await navigator.clipboard.writeText(commandWithRepo.value);
+    copied.value = true;
+    setTimeout(() => {
+      copied.value = false;
+    }, 2000);
+  } catch (err) {
+    console.error('Failed to copy command:', err);
+  }
 };
🤖 Fix all issues with AI agents
In `@website/client/components/utils/cliCommand.ts`:
- Around line 3-52: The generateCliCommand function currently injects
user-controlled strings directly into the shell command; escape repositoryUrl,
includePatterns and ignorePatterns by applying POSIX single-quote escaping
before embedding (e.g., trim the value, replace each single quote ' with '\''
then wrap the whole value in single quotes) and use the escaped values in the
parts.push calls for --remote, --include and --ignore; keep existing logic for
defaults and boolean flags unchanged but ensure you use the escaped variable
names instead of the raw packOptions fields.
🧹 Nitpick comments (1)
website/client/components/Home/SupportMessage.vue (1)

5-25: Consider removing or extracting the commented-out sponsor message.

The commented-out sponsor block (lines 6-13) is dead code. If it's intended for future use, consider tracking it in a separate issue or adding a TODO comment explaining when it should be re-enabled. Additionally, with only one message in the array, the random selection logic on line 24 always returns index 0—this could be simplified if multiple messages aren't planned.

Comment on lines 3 to 52
export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
const parts: string[] = ['npx repomix'];

// Add remote repository URL
if (repositoryUrl) {
parts.push(`--remote ${repositoryUrl}`);
}

// Only add options if packOptions is provided
if (packOptions) {
// Format (only add if not default 'xml')
if (packOptions.format && packOptions.format !== 'xml') {
parts.push(`--style ${packOptions.format}`);
}

// Boolean flags that enable features
if (packOptions.removeComments) {
parts.push('--remove-comments');
}
if (packOptions.removeEmptyLines) {
parts.push('--remove-empty-lines');
}
if (packOptions.showLineNumbers) {
parts.push('--output-show-line-numbers');
}
if (packOptions.outputParsable) {
parts.push('--parsable-style');
}
if (packOptions.compress) {
parts.push('--compress');
}

// Boolean flags that disable defaults (fileSummary and directoryStructure default to true)
if (packOptions.fileSummary === false) {
parts.push('--no-file-summary');
}
if (packOptions.directoryStructure === false) {
parts.push('--no-directory-structure');
}

// String options
if (packOptions.includePatterns?.trim()) {
parts.push(`--include "${packOptions.includePatterns.trim()}"`);
}
if (packOptions.ignorePatterns?.trim()) {
parts.push(`--ignore "${packOptions.ignorePatterns.trim()}"`);
}
}

return parts.join(' ');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Escape user-controlled values in the generated shell command.
repositoryUrl, includePatterns, and ignorePatterns can contain spaces/quotes/metacharacters; emitting them unescaped makes the copied command unsafe or broken.

✅ Suggested fix (minimal shell escaping)
 export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
   const parts: string[] = ['npx repomix'];
+  const shellEscape = (value: string) => `"${value.replace(/(["\\$`])/g, '\\$1')}"`;

   // Add remote repository URL
   if (repositoryUrl) {
-    parts.push(`--remote ${repositoryUrl}`);
+    parts.push(`--remote ${shellEscape(repositoryUrl.trim())}`);
   }

   // Only add options if packOptions is provided
   if (packOptions) {
@@
     if (packOptions.includePatterns?.trim()) {
-      parts.push(`--include "${packOptions.includePatterns.trim()}"`);
+      parts.push(`--include ${shellEscape(packOptions.includePatterns.trim())}`);
     }
     if (packOptions.ignorePatterns?.trim()) {
-      parts.push(`--ignore "${packOptions.ignorePatterns.trim()}"`);
+      parts.push(`--ignore ${shellEscape(packOptions.ignorePatterns.trim())}`);
     }
   }

   return parts.join(' ');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
const parts: string[] = ['npx repomix'];
// Add remote repository URL
if (repositoryUrl) {
parts.push(`--remote ${repositoryUrl}`);
}
// Only add options if packOptions is provided
if (packOptions) {
// Format (only add if not default 'xml')
if (packOptions.format && packOptions.format !== 'xml') {
parts.push(`--style ${packOptions.format}`);
}
// Boolean flags that enable features
if (packOptions.removeComments) {
parts.push('--remove-comments');
}
if (packOptions.removeEmptyLines) {
parts.push('--remove-empty-lines');
}
if (packOptions.showLineNumbers) {
parts.push('--output-show-line-numbers');
}
if (packOptions.outputParsable) {
parts.push('--parsable-style');
}
if (packOptions.compress) {
parts.push('--compress');
}
// Boolean flags that disable defaults (fileSummary and directoryStructure default to true)
if (packOptions.fileSummary === false) {
parts.push('--no-file-summary');
}
if (packOptions.directoryStructure === false) {
parts.push('--no-directory-structure');
}
// String options
if (packOptions.includePatterns?.trim()) {
parts.push(`--include "${packOptions.includePatterns.trim()}"`);
}
if (packOptions.ignorePatterns?.trim()) {
parts.push(`--ignore "${packOptions.ignorePatterns.trim()}"`);
}
}
return parts.join(' ');
export function generateCliCommand(repositoryUrl: string | undefined, packOptions?: PackOptions): string {
const parts: string[] = ['npx repomix'];
const shellEscape = (value: string) => `"${value.replace(/(["\\$`])/g, '\\$1')}"`;
// Add remote repository URL
if (repositoryUrl) {
parts.push(`--remote ${shellEscape(repositoryUrl.trim())}`);
}
// Only add options if packOptions is provided
if (packOptions) {
// Format (only add if not default 'xml')
if (packOptions.format && packOptions.format !== 'xml') {
parts.push(`--style ${packOptions.format}`);
}
// Boolean flags that enable features
if (packOptions.removeComments) {
parts.push('--remove-comments');
}
if (packOptions.removeEmptyLines) {
parts.push('--remove-empty-lines');
}
if (packOptions.showLineNumbers) {
parts.push('--output-show-line-numbers');
}
if (packOptions.outputParsable) {
parts.push('--parsable-style');
}
if (packOptions.compress) {
parts.push('--compress');
}
// Boolean flags that disable defaults (fileSummary and directoryStructure default to true)
if (packOptions.fileSummary === false) {
parts.push('--no-file-summary');
}
if (packOptions.directoryStructure === false) {
parts.push('--no-directory-structure');
}
// String options
if (packOptions.includePatterns?.trim()) {
parts.push(`--include ${shellEscape(packOptions.includePatterns.trim())}`);
}
if (packOptions.ignorePatterns?.trim()) {
parts.push(`--ignore ${shellEscape(packOptions.ignorePatterns.trim())}`);
}
}
return parts.join(' ');
}
🤖 Prompt for AI Agents
In `@website/client/components/utils/cliCommand.ts` around lines 3 - 52, The
generateCliCommand function currently injects user-controlled strings directly
into the shell command; escape repositoryUrl, includePatterns and ignorePatterns
by applying POSIX single-quote escaping before embedding (e.g., trim the value,
replace each single quote ' with '\'' then wrap the whole value in single
quotes) and use the escaped values in the parts.push calls for --remote,
--include and --ignore; keep existing logic for defaults and boolean flags
unchanged but ensure you use the escaped variable names instead of the raw
packOptions fields.

Display equivalent CLI command in result page to encourage npm usage.
The banner shows the npx command with all selected options, allowing
users to easily copy and run the same pack locally.

- Add generateCliCommand utility for consistent command generation
- Share command generation logic between result and error pages
- Style as prominent banner with gradient background
…ions

Refactor SupportMessage to use centered banner layout with yellow gradient.
Update CLI banner to use simple background with command in white box.
@yamadashy yamadashy force-pushed the feat/website-cli-command-banner branch from b291e7d to e274bb2 Compare February 1, 2026 15:18
@claude
Copy link
Contributor

claude bot commented Feb 1, 2026

Code Review

Overall this is a well-structured PR that adds a useful CLI command banner. The generateCliCommand utility is cleanly separated and the prop drilling through the component hierarchy is straightforward. A few issues to address:

Security: Command Injection via User Input

Severity: Medium — Both Gemini and CodeRabbit flagged this, and it's a valid concern. The generateCliCommand function interpolates repositoryUrl, includePatterns, and ignorePatterns directly into a shell command string without any escaping.

While the generated command is only displayed and copied to clipboard (not executed by the website), a user who copies and pastes it into a terminal could be affected by a crafted URL. For example, a malicious repositoryUrl like https://example.com; rm -rf ~ would produce a dangerous command.

Recommendation: At minimum, wrap user-provided values in single quotes and escape embedded single quotes. Something like:

function shellEscape(value: string): string {
  return `'${value.replace(/'/g, "'\\''")}'`;
}

Then use shellEscape(repositoryUrl) for --remote, --include, and --ignore values.

Minor: Missing error handling in TryItResultErrorContent.vue

The copyCommand function in this file doesn't have try/catch around navigator.clipboard.writeText, while the same pattern in TryItResultContent.vue does. This should be consistent. (CodeRabbit also flagged this.)

Minor: Duplicate copy logic

handleCopyCommand in TryItResultContent.vue and copyCommand in TryItResultErrorContent.vue are nearly identical clipboard-copy-with-feedback patterns. Consider extracting a small composable (e.g., useCopyToClipboard) to reduce duplication, though this is low priority.

Looks Good

  • Clean utility extraction in cliCommand.ts
  • Responsive CSS handling for the banner
  • Correct default-skipping logic (not adding --style xml when format is default)
  • SupportMessage refactoring is a nice simplification
Bot Review Evaluation

Gemini — Shell injection concern: Required. Valid security issue, should be addressed before merge.

CodeRabbit — Missing try/catch on clipboard write in error content: Recommended. Consistency improvement, low risk but worth fixing.

CodeRabbit — Nitpick about dead code in SupportMessage: Not needed. The commented-out sponsor message is a common pattern for rotating messages and out of scope for this PR.

Devin — 1 potential issue (details behind external link): Unable to evaluate without access to the Devin Review UI.

🤖 Generated with Claude Code

@claude
Copy link
Contributor

claude bot commented Feb 1, 2026

Code Review

Overall this is a clean, well-structured PR. The generateCliCommand utility is a good abstraction shared between result and error pages. A few items worth addressing:

Security: Command Injection via Copy-Paste

Gemini and CodeRabbit flagged this, and it's worth discussing. The generateCliCommand function embeds repositoryUrl, includePatterns, and ignorePatterns directly into the command string without escaping. For example, a crafted URL like https://example.com; rm -rf / would produce a dangerous command if pasted into a terminal.

However, the severity is lower than typical injection because:

  1. The command is displayed to the user and copied to clipboard — not executed automatically
  2. Users can inspect the command before running it

That said, sanitizing these inputs is still recommended as defense-in-depth. A simple approach: validate that repositoryUrl looks like a URL, and quote pattern arguments.

Missing Error Handling in TryItResultErrorContent.vue

The copyCommand function in TryItResultErrorContent.vue (line 24) calls navigator.clipboard.writeText() without try/catch, while the same pattern in TryItResultContent.vue (line 64) does have error handling. This inconsistency was also flagged by CodeRabbit. Worth adding for consistency.

Minor Observations

Details
  • packOptions is optional throughout the chain — This is fine for backwards compatibility, but generateCliCommand could benefit from a brief JSDoc comment explaining what happens when packOptions is undefined (just produces a bare npx repomix --remote <url> command).
  • format field naming: The CLI flag is --style but the option is named format in PackOptions. The mapping is correct in the code, but a code comment noting this would help future maintainers.
  • The SupportMessage style refactor looks good — simpler DOM, cleaner CSS.

Premortem / Edge Cases

Details
  • Very long include/ignore patterns: If a user enters many comma-separated patterns, the CLI banner command could overflow its container. The CSS handles this with text-overflow: ellipsis and the mobile breakpoint uses word-break: break-all, so this is covered.
  • Empty repository URL: generateCliCommand handles this gracefully — if repositoryUrl is undefined/empty, the --remote flag is omitted.
  • packOptions format value: The code only skips adding --style for 'xml' (the default). If PackOptions.format ever gets a new value, this logic would need updating. Low risk since the type is a union literal.

Good work — this is a nice UX addition to encourage CLI adoption.

…nd generator

Address PR review comments:
- Add shell escaping for user-controlled values (repositoryUrl, includePatterns, ignorePatterns)
  to prevent command injection when users copy-paste the generated command
- Skip --remote flag for uploaded file names by validating with isValidRemoteValue
- Add unit tests for generateCliCommand covering all option combinations
@claude
Copy link
Contributor

claude bot commented Feb 1, 2026

Code Review

The latest commit addresses the shell escaping and ZIP upload handling concerns from earlier reviews. The code is clean and well-structured. A few remaining observations:

Minor Issues

1. format value not escaped in generated command

Details

cliCommand.ts:19packOptions.format is interpolated directly without shellEscape(). While the format value currently comes from a controlled dropdown (xml, markdown, plain), this is inconsistent with the escaping applied to other user-provided values. Low risk since it's not user-controlled free text, but worth noting for consistency.

2. Error page copyCommand lacks try/catch

Details

In TryItResultErrorContent.vue, the copyCommand function calls navigator.clipboard.writeText() without error handling. Compare with TryItResultContent.vue:handleCopyCommand which properly wraps in try/catch. If clipboard access is denied, the copied ref will never be set and the UI feedback won't work correctly.

Premortem / Edge Cases

  • Long commands with many patterns: The CLI banner uses text-overflow: ellipsis which handles this visually, but extremely long commands might still look awkward on mobile with word-break: break-all. Minor UX concern.
  • isValidRemoteValue accepts any valid URL: A user could provide https://evil.com/exploit as a repository URL and it would pass validation and appear in the command. This is the existing behavior of the validation function, not introduced by this PR, but worth noting.

Positive Notes

  • Shell escaping implementation using the '...' with '\'' pattern is correct and standard.
  • Test coverage for generateCliCommand is thorough — covers all option combinations, shell metacharacters, empty patterns, and ZIP upload filtering.
  • Sharing generateCliCommand between result and error pages via a utility is a good pattern.

LGTM with the minor clipboard error handling nit.


Reviewed by Claude

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.

2 participants