Skip to content

Conversation

@gene9831
Copy link
Collaborator

@gene9831 gene9831 commented Dec 30, 2025

Summary by CodeRabbit

  • New Features
    • Comprehensive documentation badge system (new/deprecated/beta/alpha/version/custom).
    • Inline markdown badges via simple syntax.
    • Sidebar badges driven by page frontmatter.
    • Light/dark styling for badge variants.
    • New guide documenting badge usage and configuration.
    • New header-actions slot for the MCP Server Picker component.
    • Improved input behavior: Ctrl+Enter/Shift+Enter insert newlines and switch to multi-line when appropriate.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

Walkthrough

Adds a VitePress badge system (sidebar + markdown) with utilities, styles, and docs; updates docs build tooling and scripts; introduces Sender newline handling and a new MCP Server Picker slot; adds TypeScript config for docs; restructures CI workflows (new PR CI, e2e removal) and supporting scripts for building and copying docs/playground.

Changes

Cohort / File(s) Summary
Badge plugin core & utils
docs/.vitepress/plugins/badge/SidebarPlugin.ts, docs/.vitepress/plugins/badge/MarkdownPlugin.ts, docs/.vitepress/plugins/badge/utils.ts, docs/.vitepress/plugins/badge/constants.ts, docs/.vitepress/plugins/badge/index.ts
New VitePress plugins and helpers: SidebarBadgePlugin reads frontmatter badges and injects into sidebar; MarkdownBadgePlugin replaces inline badge tokens during markdown rendering; utilities/constants generate badge HTML and map types/classes.
VitePress integration & config
docs/.vitepress/config.mts, docs/.vitepress/themeConfig.ts, docs/tsconfig.json
Registers/uses badge plugins and replaces explicit nav/sidebar with themeConfig spread; adds docs TypeScript configuration for .vitepress sources.
Docs content & styling
docs/src/guide/plugin-badge.md, docs/src/components/*, docs/.vitepress/theme/style.css
Adds user guide for badge plugins, updates component docs (sender behavior, MCP server picker slot), and adds badge CSS (variants + dark-mode).
Docs package changes
docs/package.json
Adds devDependencies (gray-matter, @types/node) used by badge plugins.
Root scripts & build tooling
package.json, scripts/build-docs.js, scripts/copy-playground.js
Reworks project scripts: new build-docs orchestration (with --nocomponents), parameterized playground copy script, many new npm scripts, and package name change.
Component behavior
packages/components/src/sender/composables/useKeyboardHandler.ts, packages/components/src/mcp-server-picker/index.vue
Sender: adds insertNewLine and handleNewLine to support Ctrl+Enter / Shift+Enter newline-switch behavior and refactors key handling. MCP server picker: adds header-actions named slot.
GitHub Actions — added/removed workflows
.github/workflows/pr-ci.yml, .github/workflows/pr-ci-build.yml, .github/workflows/pr-ci-e2e-test.yml, .github/workflows/pr-ci-publish-packages.yml, .github/workflows/pr-cleanup.yml, .github/workflows/pr-deploy-preview.yml, .github/workflows/auto-publish.yml, .github/workflows/dispatch-publish.yml, (deleted) .github/workflows/e2e-tests.yml
Replaces monolithic E2E workflow with modular CI workflows for build, e2e, publish, deploy preview and cleanup; removes previous e2e workflow; consolidates docs/playground build into docs build step and exposes PLAYGROUND_BASE env.
Docs Type/ci artifacts
docs/.vitepress/plugins/badge/* + docs/.vitepress/config.mts (cohort overlap noted)
Ensure badge plugins rely on gray-matter file reads and markdown renderer hooks — file I/O and Markdown renderer interactions warrant attention during review.

Sequence Diagram(s)

sequenceDiagram
    participant VitePress
    participant SidebarPlugin
    participant FS as FileSystem
    participant GrayMatter as FrontMatter

    VitePress->>SidebarPlugin: configResolved(vpConfig)
    activate SidebarPlugin
    SidebarPlugin->>SidebarPlugin: locate sidebar entries (array/object)
    loop each sidebar item with `link`
        SidebarPlugin->>FS: resolve file path (root + srcDir + link)
        FS-->>SidebarPlugin: markdown content
        SidebarPlugin->>GrayMatter: parse(markdown)
        GrayMatter-->>SidebarPlugin: data.badge
        SidebarPlugin->>SidebarPlugin: withBadge(item.text, badge)
        SidebarPlugin->>SidebarPlugin: update item.text
    end
    SidebarPlugin-->>VitePress: modified config
    deactivate SidebarPlugin
Loading
sequenceDiagram
    participant MarkdownRenderer
    participant MarkdownPlugin
    participant BadgeUtils

    MarkdownRenderer->>MarkdownPlugin: register plugin (md.use)
    activate MarkdownPlugin
    MarkdownPlugin->>MarkdownPlugin: override text renderer rule
    deactivate MarkdownPlugin

    MarkdownRenderer->>MarkdownPlugin: render text node
    activate MarkdownPlugin
    MarkdownPlugin->>MarkdownPlugin: test MARKDOWN_BADGE_REGEX
    alt match
        MarkdownPlugin->>BadgeUtils: createBadgeHTML(token)
        BadgeUtils-->>MarkdownPlugin: badge HTML
        MarkdownPlugin-->>MarkdownRenderer: return transformed HTML
    else no match
        MarkdownPlugin-->>MarkdownRenderer: delegate to default renderer
    end
    deactivate MarkdownPlugin
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • hexqi

Poem

🐰 I nibbled tokens, stitched a badge so bright,
On sidebars and markdown it now takes flight.
Ctrl or Shift, a newline hop—away we go,
Build scripts hum and previews gently glow.
Hooray for tiny badges—hop, celebrate! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'sync(release/v0.3.x): sync develop features' clearly indicates a synchronization of features from develop to the release branch, which aligns with the changeset containing badge plugins, documentation, CI/CD updates, and component enhancements.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 30, 2025

✅ Preview build completed successfully!

Click the image above to preview.
Preview will be automatically removed when this PR is closed.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 30, 2025

Copy link

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
scripts/copy-playground.js (1)

32-35: Use dynamic paths in log messages.

The log messages reference hardcoded paths (docs/dist/playground) but the script now copies from user-provided source/dest arguments, which could be different.

🔎 Suggested fix
-  console.log('Copying playground dist to docs/dist/playground...')
+  console.log(`Copying from ${source} to ${dest}...`)
   cpSync(source, dest, { recursive: true, force: true })
-  console.log('✓ Successfully copied playground to docs/dist/playground')
+  console.log(`✓ Successfully copied from ${source} to ${dest}`)
🧹 Nitpick comments (4)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)

87-102: Consider improving scroll behavior to keep cursor visible.

The function correctly inserts the newline and updates the cursor position. However, setting scrollTop = scrollHeight always scrolls to the bottom, which may scroll past the cursor if the newline was inserted in the middle of a long text.

🔎 Suggested improvement

Consider letting the browser handle cursor visibility or using a more targeted scroll approach:

     // 设置光标位置到换行符之后,并滚动到光标位置
     setTimeout(() => {
       const newCursorPos = start + 1
       target.selectionStart = target.selectionEnd = newCursorPos
-      // 滚动到光标所在位置,确保光标可见
-      target.scrollTop = target.scrollHeight
     }, 0)

Alternatively, calculate the cursor's actual position and scroll to that specific location, or rely on the browser's default behavior which typically keeps the cursor visible after programmatic selection changes.

scripts/build-docs.js (1)

22-24: Consider logging the full error for debugging.

The error handler only logs error.message, which may lose valuable debugging information like stack traces.

🔎 Suggested improvement
 } catch (error) {
-  console.error('Error building docs:', error.message)
+  console.error('Error building docs:', error)
   process.exit(1)
 }
.github/workflows/pr-deploy-preview.yml (1)

66-79: Consider case-insensitive SHA regex.

The regex /@[a-f0-9]{40}/ on line 73 only matches lowercase hex digits, but Git SHAs could theoretically contain uppercase letters. While GitHub typically uses lowercase, using a case-insensitive pattern would be more robust.

🔎 Suggested improvement
             const packages = output.packages.map((p) => {
-              const shortUrl = p.url.replace(/@[a-f0-9]{40}/, '@' + sha);
+              const shortUrl = p.url.replace(/@[a-fA-F0-9]{40}/, '@' + sha);
               return 'pnpm add ' + shortUrl;
             }).join('\n\n');
docs/.vitepress/plugins/badge/SidebarPlugin.ts (1)

137-162: Consider handling links that already include .md extension.

The file path construction on line 146 appends .md to the link, which could result in .md.md if the link already includes the extension. While VitePress links typically omit the extension, defensive handling would be more robust.

🔎 Suggested improvement
 function readBadgeFromFrontmatter(
   link: string,
   rootDir: string,
   srcDir: string,
   baseDir: string,
   matter: any,
   debug: boolean,
 ): string | undefined {
   try {
+    const linkPath = link.endsWith('.md') ? link : `${link}.md`
-    const filePath = path.join(rootDir, srcDir, baseDir, `${link}.md`)
+    const filePath = path.join(rootDir, srcDir, baseDir, linkPath)

     if (!fs.existsSync(filePath)) {
       return undefined
     }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1feaea6 and bbb912c.

📒 Files selected for processing (27)
  • .github/workflows/auto-publish.yml
  • .github/workflows/dispatch-publish.yml
  • .github/workflows/e2e-tests.yml
  • .github/workflows/pr-ci-build.yml
  • .github/workflows/pr-ci-e2e-test.yml
  • .github/workflows/pr-ci-publish-packages.yml
  • .github/workflows/pr-ci.yml
  • .github/workflows/pr-cleanup.yml
  • .github/workflows/pr-deploy-preview.yml
  • docs/.vitepress/config.mts
  • docs/.vitepress/plugins/badge/MarkdownPlugin.ts
  • docs/.vitepress/plugins/badge/SidebarPlugin.ts
  • docs/.vitepress/plugins/badge/constants.ts
  • docs/.vitepress/plugins/badge/index.ts
  • docs/.vitepress/plugins/badge/utils.ts
  • docs/.vitepress/theme/style.css
  • docs/.vitepress/themeConfig.ts
  • docs/package.json
  • docs/src/components/mcp-server-picker.md
  • docs/src/components/sender.md
  • docs/src/guide/plugin-badge.md
  • docs/tsconfig.json
  • package.json
  • packages/components/src/mcp-server-picker/index.vue
  • packages/components/src/sender/composables/useKeyboardHandler.ts
  • scripts/build-docs.js
  • scripts/copy-playground.js
💤 Files with no reviewable changes (1)
  • .github/workflows/e2e-tests.yml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-18T09:29:47.974Z
Learnt from: SonyLeo
Repo: opentiny/tiny-robot PR: 119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。

Applied to files:

  • docs/.vitepress/theme/style.css
🧬 Code graph analysis (7)
docs/.vitepress/plugins/badge/MarkdownPlugin.ts (3)
docs/.vitepress/plugins/badge/index.ts (1)
  • MarkdownBadgePlugin (6-6)
docs/.vitepress/plugins/badge/constants.ts (1)
  • MARKDOWN_BADGE_REGEX (48-48)
docs/.vitepress/plugins/badge/utils.ts (1)
  • createBadgeHTML (57-61)
docs/.vitepress/plugins/badge/SidebarPlugin.ts (2)
docs/.vitepress/plugins/badge/index.ts (2)
  • SidebarBadgeOptions (10-10)
  • SidebarBadgePlugin (5-5)
docs/.vitepress/plugins/badge/utils.ts (1)
  • withBadge (66-69)
docs/.vitepress/config.mts (3)
docs/.vitepress/plugins/badge/SidebarPlugin.ts (1)
  • SidebarBadgePlugin (35-73)
docs/.vitepress/plugins/badge/MarkdownPlugin.ts (1)
  • MarkdownBadgePlugin (34-53)
docs/.vitepress/themeConfig.ts (1)
  • themeConfig (61-61)
docs/.vitepress/plugins/badge/utils.ts (1)
docs/.vitepress/plugins/badge/constants.ts (5)
  • VERSION_NUMBER_REGEX (43-43)
  • BadgeValue (13-13)
  • BadgeType (8-8)
  • BADGE_TEXT_MAP (18-23)
  • BADGE_CLASS_MAP (28-33)
scripts/build-docs.js (1)
scripts/copy-playground.js (1)
  • args (5-5)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)
packages/components/src/sender/index.type.ts (1)
  • SubmitTrigger (15-15)
scripts/copy-playground.js (1)
scripts/build-docs.js (1)
  • args (4-4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build / build
🔇 Additional comments (42)
packages/components/src/mcp-server-picker/index.vue (1)

306-306: LGTM! Clean extensibility enhancement.

The new header-actions slot provides a well-positioned extensibility point in the header area, allowing consumers to inject custom actions without modifying the component's core behavior.

docs/src/components/mcp-server-picker.md (1)

83-89: LGTM! Documentation accurately reflects the new slot.

The Slots section correctly documents the new header-actions slot with an accurate description and proper formatting consistent with the rest of the documentation.

docs/src/components/sender.md (3)

20-24: Documentation accurately describes the new auto-switch behavior.

The updated tip correctly explains both width-based and keyboard-triggered mode switching. This aligns with the implementation in useKeyboardHandler.ts.


149-175: Comprehensive documentation of keyboard behavior.

The information block and tip sections clearly explain the interaction between submission types and newline shortcuts. The behavior descriptions accurately match the implementation in useKeyboardHandler.ts.


162-163: Keyboard reference table correctly updated.

The updated entries for Ctrl+Enter and Shift+Enter accurately reflect their dual functionality based on submitType configuration.

packages/components/src/sender/composables/useKeyboardHandler.ts (2)

109-129: Well-structured newline handling logic.

The function correctly implements the documented behavior for Ctrl+Enter and Shift+Enter when submitType="enter". The early return pattern, mutually exclusive modifier checks, and optional mode switching are all properly implemented.


134-187: Improved control flow with clearer prioritization.

The updated handleKeyPress function now prioritizes newline handling before other operations, which correctly prevents conflicts with submission logic. The simplified submission check using checkSubmitShortcut improves readability and maintainability.

docs/tsconfig.json (1)

1-15: LGTM! TypeScript configuration is well-structured.

The tsconfig.json is properly configured for a VitePress documentation site with appropriate compiler options, including strict mode and bundler module resolution.

.github/workflows/dispatch-publish.yml (1)

85-91: LGTM! Docs build consolidation is correctly implemented.

The workflow now uses the new build:docs --nocomponents command, which aligns with the components already being built in step 7. The PLAYGROUND_BASE environment variable is properly scoped to the Build VitePress step.

docs/.vitepress/theme/style.css (1)

227-288: LGTM! Comprehensive badge styling with dark mode support.

The version badge styles are well-structured with clear variants (new, deprecated, beta, alpha) and proper dark mode adaptations. The styling integrates cleanly with the badge plugin system.

.github/workflows/auto-publish.yml (1)

106-112: LGTM! Consistent docs build refactoring.

The auto-publish workflow correctly uses the new build:docs --nocomponents command, maintaining consistency with the dispatch-publish workflow and the new build orchestration approach.

docs/src/guide/plugin-badge.md (1)

1-285: LGTM! Comprehensive and well-structured documentation.

The badge plugin guide provides clear explanations, practical examples, and complete configuration instructions. The documentation covers both Markdown content badges and sidebar badges thoroughly, with helpful usage scenarios and notes.

.github/workflows/pr-cleanup.yml (1)

1-34: LGTM! Well-designed cleanup workflow.

The PR cleanup workflow properly handles preview deployment teardown using pull_request_target for write permissions, includes appropriate error tolerance with continue-on-error: true, and provides user feedback via comments. The workflow is secure as it doesn't checkout potentially untrusted code.

docs/package.json (1)

10-10: Both package versions are valid and secure.

Verified: @types/[email protected] and [email protected] exist on npm and have no known security advisories. No CVEs are reported for either version.

docs/.vitepress/themeConfig.ts (1)

1-61: LGTM! Clean VitePress theme configuration.

The centralized theme configuration structure is well-organized and properly separates navigation, sidebar, and shared items. The export pattern aligns with how it's consumed in config.mts.

docs/.vitepress/config.mts (4)

6-7: LGTM! Proper plugin and config imports.

The badge plugin imports and themeConfig import are correctly structured and align with the new modular configuration approach.


40-40: LGTM! Badge plugin correctly registered.

The SidebarBadgePlugin() is properly added to the Vite plugins array and will process sidebar items to add version badges.


62-63: LGTM! Markdown badge plugin correctly configured.

The MarkdownBadgePlugin is properly registered to process version badge markers in Markdown content.


70-70: LGTM! ThemeConfig properly spread.

The spread of themeConfig correctly merges the centralized navigation and sidebar configuration from themeConfig.ts.

package.json (2)

2-2: LGTM! Package rename for clarity.

The rename from "root" to "robot-root" provides better clarity for the monorepo root package.


10-11: LGTM! Consolidated build scripts.

The transition to dedicated Node scripts (build-docs.js and explicit arguments to copy-playground.js) improves maintainability and aligns with the refactored script implementations.

scripts/copy-playground.js (2)

4-16: LGTM! Good refactor to CLI-driven paths.

The transition from hardcoded paths to command-line arguments makes the script more flexible and reusable. The path resolution logic correctly handles both absolute and relative paths.


18-30: LGTM! Comprehensive validation.

The validation checks for source existence and destination parent directory are thorough and provide clear error messages.

.github/workflows/pr-ci-build.yml (1)

15-62: LGTM! Well-structured build workflow.

The build job properly sets up the environment, caches dependencies, builds components and docs, and uploads artifacts with appropriate retention. The artifact naming using the PR head SHA ensures uniqueness.

.github/workflows/pr-ci.yml (1)

1-43: LGTM! Well-orchestrated CI pipeline.

The workflow properly coordinates build, publish, and e2e-test jobs with appropriate conditions and dependencies. The concurrency control prevents redundant runs, and the PR title-based skip logic is sensible for documentation-only changes.

Note: The skip-playground: true parameter passed to the build workflow is currently unused (flagged separately in pr-ci-build.yml).

.github/workflows/pr-ci-e2e-test.yml (1)

1-58: LGTM! Well-structured E2E test workflow.

The workflow properly sets up the test environment, downloads build artifacts, installs Playwright with Chromium dependencies, and uploads test reports. The 60-minute timeout is reasonable for E2E tests, and the artifact retention (13 days) provides a good balance for debugging.

docs/.vitepress/plugins/badge/index.ts (1)

1-10: LGTM! Clean barrel export.

The barrel export properly consolidates the badge plugin ecosystem exports, providing a single entry point for consumers. The separation of named exports, wildcard exports, and type-only exports follows best practices.

.github/workflows/pr-deploy-preview.yml (3)

108-116: LGTM!

The Surge deployment configuration is correct. The domain naming pattern ensures unique preview URLs per PR, and the artifact path aligns with the expected build output structure.


118-145: Well-designed preview feedback flow.

The three-stage comment system (deploying → success/failed) provides excellent user feedback. The use of maintain-one-comment with markers ensures a clean PR conversation without comment spam.


9-47: Excellent error handling and security posture.

The workflow demonstrates good practices:

  • Minimal required permissions
  • Clear conditional execution logic
  • Proper error handling for required artifacts
  • Graceful degradation for optional artifacts
docs/.vitepress/plugins/badge/SidebarPlugin.ts (4)

100-132: LGTM!

The sidebar processing logic correctly handles nested structures, uses Set-based deduplication to prevent duplicate badge application, and gracefully skips items without links.


52-71: Good error handling with informative logging.

The plugin includes comprehensive error handling that prevents crashes while providing useful feedback through console warnings and the optional debug mode.


24-37: Clear interface with sensible defaults.

The plugin options interface is well-documented. The srcDir default of 'src' appears project-specific; ensure it aligns with your VitePress configuration.


52-53: gray-matter is properly declared in dependencies.

The plugin dynamically imports gray-matter at lines 52-53, and this dependency is correctly listed in docs/package.json as version ^4.0.3. No action needed.

docs/.vitepress/plugins/badge/MarkdownPlugin.ts (2)

37-52: Correct stateful regex handling.

The implementation properly resets lastIndex on line 43 before using the global regex in replace(). This prevents bugs that could arise from the regex's stateful behavior.


34-52: Well-structured markdown-it plugin.

The plugin follows markdown-it conventions correctly by preserving the original renderer and providing appropriate fallbacks. The early return pattern on line 48 is efficient.

docs/.vitepress/plugins/badge/constants.ts (2)

35-43: Well-documented version regex.

The regex correctly validates version numbers and includes helpful comments explaining the pattern and examples of valid/invalid inputs.


45-48: LGTM!

The markdown badge regex correctly captures all badge types and uses a global flag for multiple matches. The pattern aligns well with VERSION_NUMBER_REGEX.

docs/.vitepress/plugins/badge/utils.ts (4)

8-20: Solid XSS prevention.

The escapeHtml function correctly escapes all critical HTML special characters. Keeping it private and simple is appropriate for this use case.


29-44: Clean badge resolution logic.

The functions correctly handle both predefined badge types and version numbers. The fallback to the badge value itself (line 43) provides flexibility for custom badges.


54-61: Secure HTML generation.

The function correctly escapes user-controlled text while using predefined CSS classes from the constants map. The order of operations ensures XSS protection.


63-69: LGTM!

The withBadge function provides a clean API for appending badges to text, with appropriate spacing.

@gene9831 gene9831 closed this Dec 30, 2025
@gene9831 gene9831 force-pushed the pick/develop-to-0.3.0-1230 branch from bbb912c to 1feaea6 Compare December 30, 2025 08:39
@github-actions
Copy link
Contributor

github-actions bot commented Dec 30, 2025

🧹 Preview Cleaned Up

The preview deployment has been removed.

@gene9831 gene9831 reopened this Dec 30, 2025
@gene9831 gene9831 marked this pull request as draft December 30, 2025 08:46
Copy link

@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: 0

🧹 Nitpick comments (3)
docs/.vitepress/plugins/badge/SidebarPlugin.ts (3)

1-1: Consider specifying which ESLint rules to disable.

A blanket eslint-disable suppresses all linting for the file. It's better practice to disable only the specific rules that conflict with this code.

🔎 Suggested improvement
-/* eslint-disable */
+/* eslint-disable @typescript-eslint/no-explicit-any */

35-38: Consider stronger typing for the plugin return type.

The return type any loses type safety. While VitePress/Vite plugin types can be complex, using Plugin from Vite would improve IDE support and catch issues earlier.

🔎 Suggested improvement
+import type { Plugin } from 'vite'
+
-export function SidebarBadgePlugin(options?: SidebarBadgeOptions): any {
+export function SidebarBadgePlugin(options?: SidebarBadgeOptions): Plugin {

145-161: Validate that badge value is a string before returning.

The frontmatter data.badge could be any type (number, object, array). The current type assertion could propagate unexpected values.

🔎 Suggested fix
     const content = fs.readFileSync(filePath, 'utf-8')
     const { data } = matter(content)
 
-    return data.badge as string | undefined
+    return typeof data.badge === 'string' ? data.badge : undefined
   } catch (error) {
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bbb912c and 89ece5d.

📒 Files selected for processing (10)
  • docs/.vitepress/config.mts
  • docs/.vitepress/plugins/badge/MarkdownPlugin.ts
  • docs/.vitepress/plugins/badge/SidebarPlugin.ts
  • docs/.vitepress/plugins/badge/constants.ts
  • docs/.vitepress/plugins/badge/index.ts
  • docs/.vitepress/plugins/badge/utils.ts
  • docs/.vitepress/theme/style.css
  • docs/package.json
  • docs/src/guide/plugin-badge.md
  • docs/tsconfig.json
✅ Files skipped from review due to trivial changes (1)
  • docs/src/guide/plugin-badge.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/.vitepress/plugins/badge/MarkdownPlugin.ts
  • docs/.vitepress/theme/style.css
  • docs/.vitepress/plugins/badge/constants.ts
  • docs/tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (1)
docs/.vitepress/plugins/badge/SidebarPlugin.ts (1)
docs/.vitepress/plugins/badge/utils.ts (1)
  • withBadge (66-69)
🔇 Additional comments (10)
docs/package.json (1)

10-14: LGTM!

The new devDependencies are appropriate for the badge plugin system: @types/node for Node.js type definitions and gray-matter for frontmatter parsing in the SidebarBadgePlugin.

docs/.vitepress/config.mts (3)

6-6: LGTM!

Clean import of the badge plugins from the new plugin barrel file.


81-81: LGTM!

The SidebarBadgePlugin is correctly integrated into the Vite plugins array. Using default options is appropriate for the standard documentation setup.


103-104: LGTM!

The MarkdownBadgePlugin is correctly integrated using the markdown-it plugin pattern via md.use().

docs/.vitepress/plugins/badge/index.ts (1)

1-10: LGTM!

Clean barrel file that properly centralizes exports for the badge plugin ecosystem. The separation of type exports is a good practice.

docs/.vitepress/plugins/badge/SidebarPlugin.ts (1)

40-72: LGTM on the plugin lifecycle and error handling.

The implementation correctly:

  • Guards against re-processing with the vpConfig check
  • Uses dynamic import for gray-matter (lazy loading)
  • Handles missing config gracefully with warnings
  • Provides debug logging option
docs/.vitepress/plugins/badge/utils.ts (4)

11-20: Good XSS prevention implementation.

The escapeHtml function properly escapes all critical HTML special characters. Using a lookup map with a single regex replacement is efficient.


57-61: LGTM with security consideration noted.

The badge text is properly escaped via escapeHtml. The class name comes from the hardcoded BADGE_CLASS_MAP constants, so it's safe from injection. Good security practice.


32-34: Type assertion relies on external validation.

The cast badge as BadgeType assumes the caller has validated that non-version badges are valid BadgeType values. This works given the current usage pattern, but consider adding validation if the public API surface expands.


66-69: LGTM!

Clean utility function that combines text with the generated badge HTML.

@gene9831 gene9831 closed this Dec 30, 2025
@gene9831 gene9831 force-pushed the pick/develop-to-0.3.0-1230 branch from c0bfdc5 to 1feaea6 Compare December 30, 2025 08:49
@gene9831 gene9831 reopened this Dec 30, 2025
@gene9831 gene9831 marked this pull request as ready for review December 30, 2025 08:58
@hexqi hexqi merged commit e3299a5 into opentiny:release/v0.3.x Dec 30, 2025
7 checks passed
Copy link

@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: 4

♻️ Duplicate comments (5)
.github/workflows/pr-ci-publish-packages.yml (4)

40-41: Consider using frozen lockfile for build reproducibility.

Using --no-frozen-lockfile in CI can lead to non-reproducible builds and unexpected dependency updates. Consider switching to the default frozen lockfile mode (plain pnpm i) to ensure consistency between CI runs.


6-9: Remove unused input or utilize it.

The pr-number input is declared as required but is never referenced in the workflow. Either remove this input if it's not needed, or use it if there's a missing implementation.


43-47: Fix artifact SHA reference for workflow_call context.

This workflow is triggered via workflow_call, not a pull_request event. The expression github.event.pull_request.head.sha will be unavailable, causing the artifact download to fail or use an incorrect SHA.

🔎 Proposed fix

Add a SHA input to the workflow:

 on:
   workflow_call:
     inputs:
       pr-number:
         description: 'Pull Request number'
         type: number
         required: true
+      sha:
+        description: 'Commit SHA to use for artifacts'
+        type: string
+        required: true

Then update the artifact name:

       - name: Download build artifacts
         uses: actions/download-artifact@v4
         with:
-          name: build-${{ github.event.pull_request.head.sha || github.sha }}
+          name: build-${{ inputs.sha }}
           path: .

And update line 69 similarly:

-          name: pkg-pr-new-output-${{ github.event.pull_request.head.sha || github.sha }}
+          name: pkg-pr-new-output-${{ inputs.sha }}

66-71: Fix artifact SHA reference for workflow_call context.

Same issue as the download step: github.event.pull_request.head.sha is unavailable in workflow_call context. Use the inputs.sha approach suggested in the previous comment.

.github/workflows/pr-ci-build.yml (1)

6-9: Unused workflow input.

The skip-playground input is defined but never used in the workflow. Either remove the unused input or implement conditional logic to skip relevant steps when this flag is true.

🧹 Nitpick comments (8)
docs/src/components/sender.md (1)

168-174: Detailed newline shortcut explanation enhances user guidance.

This new tip section provides helpful clarification on exactly which keys insert newlines under different submitType configurations. The breakdown by submitType makes it easy for users to find the behavior they need.

Optional suggestion: Consider adding a simple visual (e.g., a side-by-side comparison showing "Press X to submit, Press Y to newline" for each submitType) in a future iteration if users report confusion, but the current text explanation is clear and complete.

packages/components/src/sender/composables/useKeyboardHandler.ts (1)

87-102: Consider refining scroll behavior after newline insertion.

The insertNewLine function always scrolls to scrollHeight (bottom), which might be disruptive if the user is viewing earlier content in a large textarea. Consider scrolling just enough to make the cursor visible instead:

target.scrollTop = Math.max(0, target.scrollTop + target.offsetHeight)

or use scrollIntoView on the cursor position.

.github/workflows/pr-deploy-preview.yml (1)

108-116: Consider pinning the Surge CLI version.

Using npx surge relies on npm's default resolution, which might fetch different versions over time. For reproducible deployments, consider pinning to a specific version:

-          npx surge --project ./artifacts/docs/dist --domain $DEPLOY_DOMAIN --token $SURGE_TOKEN
+          npx [email protected] --project ./artifacts/docs/dist --domain $DEPLOY_DOMAIN --token $SURGE_TOKEN
.github/workflows/pr-cleanup.yml (1)

18-18: Consider consistent Surge CLI version with deploy workflow.

For consistency with the deploy workflow, consider using the same Surge version approach. If the deploy workflow pins a version (as suggested in my earlier comment), this cleanup workflow should use the same version.

.github/workflows/pr-ci-build.yml (2)

39-40: Consider using frozen lockfile for build reproducibility.

Using --no-frozen-lockfile in CI can lead to non-reproducible builds and unexpected dependency updates. Consider switching to the default frozen lockfile mode (plain pnpm i) to ensure consistency between CI runs.


52-62: Consider exposing SHA as an output or accepting it as input.

For better integration with downstream workflows (like pr-ci-publish-packages.yml), consider either:

  1. Adding a workflow output that exposes the SHA used for artifact naming, or
  2. Accepting SHA as an input to ensure consistency across workflow calls.

This would make artifact references more explicit and reliable across the CI pipeline.

docs/.vitepress/plugins/badge/SidebarPlugin.ts (2)

111-129: Consider handling nested sidebar items.

The current implementation only processes top-level group.items but does not recursively handle nested item structures. If sidebar items can contain nested items arrays, those badges won't be applied.

Verify whether the sidebar structure supports nesting:

#!/bin/bash
# Check if sidebar items can be nested
rg -n "items.*items" docs/.vitepress/config.mts
ast-grep --pattern $'sidebar: {
  $$$
  items: [
    $$$
    items: $_
    $$$
  ]
  $$$
}'

115-126: Consider validating badge values before applying.

The plugin applies any badge value from frontmatter without validation. If an invalid or unexpected badge value is encountered, it might render incorrectly or cause issues in the UI.

Consider adding validation to ensure the badge value matches expected types (e.g., checking against BADGE_TEXT_MAP keys if available) before calling withBadge.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89ece5d and 5a5c797.

📒 Files selected for processing (27)
  • .github/workflows/auto-publish.yml
  • .github/workflows/dispatch-publish.yml
  • .github/workflows/e2e-tests.yml
  • .github/workflows/pr-ci-build.yml
  • .github/workflows/pr-ci-e2e-test.yml
  • .github/workflows/pr-ci-publish-packages.yml
  • .github/workflows/pr-ci.yml
  • .github/workflows/pr-cleanup.yml
  • .github/workflows/pr-deploy-preview.yml
  • docs/.vitepress/config.mts
  • docs/.vitepress/plugins/badge/MarkdownPlugin.ts
  • docs/.vitepress/plugins/badge/SidebarPlugin.ts
  • docs/.vitepress/plugins/badge/constants.ts
  • docs/.vitepress/plugins/badge/index.ts
  • docs/.vitepress/plugins/badge/utils.ts
  • docs/.vitepress/theme/style.css
  • docs/.vitepress/themeConfig.ts
  • docs/package.json
  • docs/src/components/mcp-server-picker.md
  • docs/src/components/sender.md
  • docs/src/guide/plugin-badge.md
  • docs/tsconfig.json
  • package.json
  • packages/components/src/mcp-server-picker/index.vue
  • packages/components/src/sender/composables/useKeyboardHandler.ts
  • scripts/build-docs.js
  • scripts/copy-playground.js
💤 Files with no reviewable changes (1)
  • .github/workflows/e2e-tests.yml
🚧 Files skipped from review as they are similar to previous changes (6)
  • docs/tsconfig.json
  • docs/.vitepress/theme/style.css
  • docs/.vitepress/plugins/badge/index.ts
  • docs/.vitepress/plugins/badge/utils.ts
  • docs/.vitepress/plugins/badge/MarkdownPlugin.ts
  • docs/src/guide/plugin-badge.md
🧰 Additional context used
🧬 Code graph analysis (3)
scripts/copy-playground.js (1)
scripts/build-docs.js (1)
  • args (4-4)
docs/.vitepress/plugins/badge/SidebarPlugin.ts (2)
docs/.vitepress/plugins/badge/index.ts (2)
  • SidebarBadgeOptions (10-10)
  • SidebarBadgePlugin (5-5)
docs/.vitepress/plugins/badge/utils.ts (1)
  • withBadge (66-69)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)
packages/components/src/sender/index.type.ts (1)
  • SubmitTrigger (15-15)
🔇 Additional comments (21)
docs/src/components/sender.md (3)

20-24: Clear and helpful update to auto-switch behavior documentation.

The revised tip accurately explains the two conditions for single-line mode auto-switching: width overflow and Ctrl+Enter/Shift+Enter (when submitType="enter"). This provides users with upfront clarity on the interaction between input modes and keyboard shortcuts.


149-155: Excellent addition of submitType and newline behavior reference.

The new info block clearly documents the three submitType modes and their corresponding newline behavior, along with the important note about auto-switching to multi-line when using newline shortcuts in single-line mode. This serves as a solid reference point for users.


162-163: Keyboard shortcut table correctly reflects updated behavior.

The table now accurately shows that Ctrl+Enter and Shift+Enter apply to both submitType="ctrlEnter" (and submitType="shiftEnter" respectively) and submitType="enter" (for newline). The conditions are correctly combined.

docs/src/components/mcp-server-picker.md (1)

83-89: LGTM! Clear documentation for the new slot.

The Slots section is well-structured and properly documents the new header-actions slot, following the same format as the Props and Events sections.

packages/components/src/mcp-server-picker/index.vue (1)

306-306: LGTM! Proper slot implementation.

The header-actions slot is correctly placed in the header's right section, providing a clean extension point for consumers to add custom header actions.

docs/.vitepress/plugins/badge/constants.ts (1)

1-48: LGTM! Well-structured badge constants.

The type definitions, mappings, and regex patterns are clearly documented and correctly implemented. The VERSION_NUMBER_REGEX properly supports semantic versioning with optional prefixes and metadata, and the MARKDOWN_BADGE_REGEX correctly matches badge markers in documentation.

packages/components/src/sender/composables/useKeyboardHandler.ts (2)

109-129: LGTM! Clean newline handling logic.

The handleNewLine function correctly manages Ctrl+Enter and Shift+Enter behavior, properly switching modes when needed and inserting newlines appropriately.


134-187: LGTM! Well-structured keyboard event handling.

The refactored handleKeyPress function has a clear flow with proper priority ordering: composing check → newline handling → suggestion navigation → escape handling → submit check. The simplified submit logic is cleaner and easier to maintain.

.github/workflows/pr-deploy-preview.yml (2)

61-106: LGTM! Robust package preview comment handling.

The script properly handles both creating and updating package preview comments using an identifier marker, ensuring idempotent updates and preventing comment spam.


22-28: The artifact naming is correct and will match in all valid execution scenarios. The pr-ci-build.yml workflow uploads artifacts as build-${{ github.event.pull_request.head.sha || github.sha }} when called from pr-ci.yml (triggered by PR events), and pr-deploy-preview.yml downloads the same artifact using build-${{ github.event.workflow_run.head_sha }}. The condition github.event.workflow_run.event == 'pull_request' ensures the deploy workflow only runs for PR-triggered CI runs, guaranteeing the SHA variables match.

docs/package.json (1)

10-10: LGTM! Appropriate devDependencies for badge plugin support.

The additions of @types/node for TypeScript type definitions and gray-matter for frontmatter parsing align well with the new badge plugin functionality introduced in this PR.

Also applies to: 14-14

docs/.vitepress/config.mts (1)

6-7: LGTM! Clean integration of badge plugins and centralized theme config.

The badge plugins are properly registered in both the Vite plugin chain (SidebarBadgePlugin) and the markdown-it processor (MarkdownBadgePlugin). Extracting the theme configuration to a separate module improves maintainability.

Also applies to: 40-40, 62-63, 70-70

.github/workflows/pr-cleanup.yml (1)

23-34: LGTM! Proper cleanup status communication.

The cleanup comment uses maintain-one-comment with a body identifier, ensuring idempotent updates and clear communication of the cleanup status to PR participants.

scripts/build-docs.js (1)

1-25: LGTM!

The build orchestration logic is clear and correct. The conditional component build based on the --nocomponents flag, sequential execution of builds, and error handling are well implemented.

.github/workflows/auto-publish.yml (1)

106-111: LGTM!

The consolidated docs build approach with the --nocomponents flag is efficient since components are already built in step 7. The addition of PLAYGROUND_BASE environment variable aligns with the unified docs build strategy.

docs/.vitepress/themeConfig.ts (1)

1-61: LGTM!

The theme configuration is well-structured with proper reuse of sharedSidebarItems across multiple routes, and clear separation of navigation and sidebar concerns.

.github/workflows/dispatch-publish.yml (1)

85-90: LGTM!

The consolidated docs build approach mirrors the changes in auto-publish.yml and correctly skips component rebuilding since they're already built in step 7.

scripts/copy-playground.js (1)

1-39: LGTM!

The refactoring to use CLI arguments makes the script more flexible and reusable. The validation logic for arguments, source existence, and destination parent directory is thorough, and error handling is appropriate.

docs/.vitepress/plugins/badge/SidebarPlugin.ts (2)

35-73: LGTM with minor observations.

The plugin initialization and config resolution logic is well-structured with proper error handling and debug logging. The early return pattern (line 44) prevents re-processing, and the dynamic import of gray-matter is a good practice for optional dependencies.


145-150: Path construction works correctly for the current sidebar configuration, which uses only simple relative paths.

The code at line 146 constructs paths assuming link values are simple relative paths (e.g., 'quick-start', 'container') without leading slashes. This assumption is valid because the sidebar configuration in themeConfig.ts consistently uses this format. The function includes defensive error handling—it checks file existence before reading and returns undefined gracefully on errors, protecting against malformed links.

package.json (1)

10-11: LGTM! Script refactoring improves maintainability.

The refactored build scripts are cleaner and more maintainable. Moving the build orchestration to scripts/build-docs.js and making the playground copy arguments explicit improves clarity and reduces command-line complexity.

Comment on lines +35 to +36
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use --frozen-lockfile in CI for reproducibility.

Installing dependencies without --frozen-lockfile in CI environments can lead to non-deterministic builds if the lockfile is out of sync with package.json. This can cause tests to pass locally but fail in CI, or vice versa.

🔎 Proposed fix
      - name: Install dependencies
-        run: pnpm i --no-frozen-lockfile
+        run: pnpm i --frozen-lockfile
📝 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
- name: Install dependencies
run: pnpm i --no-frozen-lockfile
- name: Install dependencies
run: pnpm i --frozen-lockfile
🤖 Prompt for AI Agents
In .github/workflows/pr-ci-e2e-test.yml around lines 35 to 36, the CI step runs
"pnpm i --no-frozen-lockfile" which allows installs to modify or ignore the
lockfile and causes non-deterministic builds; change the command to use "pnpm i
--frozen-lockfile" so the job fails if the lockfile is out of sync and ensures
reproducible installs in CI.

Comment on lines +52 to +58
- name: Upload Playwright Test Report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ github.sha }}
path: packages/test/playwright-report/
retention-days: 13
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Inconsistent artifact naming with download step.

Line 56 uses github.sha for the artifact name, but line 41 uses github.event.pull_request.head.sha || github.sha. This inconsistency could lead to mismatched artifact names when the workflow runs in different contexts.

🔎 Proposed fix
      - name: Upload Playwright Test Report
        uses: actions/upload-artifact@v4
        if: always()
        with:
-          name: playwright-report-${{ github.sha }}
+          name: playwright-report-${{ github.event.pull_request.head.sha || github.sha }}
          path: packages/test/playwright-report/
          retention-days: 13
🤖 Prompt for AI Agents
.github/workflows/pr-ci-e2e-test.yml around lines 52 to 58: the uploaded
Playwright artifact name uses github.sha which is inconsistent with the download
step that expects github.event.pull_request.head.sha || github.sha; update the
artifact name expression to use the same conditional
(github.event.pull_request.head.sha || github.sha) so the upload and download
steps reference an identical artifact name.

Comment on lines +32 to +38
publish-packages:
needs: [build]
if: github.event_name == 'pull_request'
uses: ./.github/workflows/pr-ci-publish-packages.yml
with:
pr-number: ${{ github.event.pull_request.number }}
secrets: inherit
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Pass SHA to publish-packages workflow.

The pr-ci-publish-packages.yml workflow needs a sha input to correctly reference build artifacts (see comments on that file). Add the SHA input here:

🔎 Proposed fix
   publish-packages:
     needs: [build]
     if: github.event_name == 'pull_request'
     uses: ./.github/workflows/pr-ci-publish-packages.yml
     with:
       pr-number: ${{ github.event.pull_request.number }}
+      sha: ${{ github.event.pull_request.head.sha || github.sha }}
     secrets: inherit
🤖 Prompt for AI Agents
In .github/workflows/pr-ci.yml around lines 32 to 38, the publish-packages job
isn't passing the commit SHA to the called workflow; add a sha input to the with
block (matching the pr-ci-publish-packages.yml expected input) and set it to the
PR head SHA (use ${{ github.event.pull_request.head.sha }}), ensuring the child
workflow can correctly reference the build artifacts.

Comment on lines +14 to +21
- name: Remove Surge deployment
run: |
DEPLOY_DOMAIN=preview-${{ github.event.pull_request.number }}-tiny-robot.surge.sh
echo "Removing deployment: $DEPLOY_DOMAIN"
npx surge teardown $DEPLOY_DOMAIN --token $SURGE_TOKEN
env:
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
continue-on-error: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare domain patterns in both workflows
echo "=== Deploy workflow domain pattern ==="
rg "DEPLOY_DOMAIN=" .github/workflows/pr-deploy-preview.yml -A 1
echo ""
echo "=== Cleanup workflow domain pattern ==="
rg "DEPLOY_DOMAIN=" .github/workflows/pr-cleanup.yml -A 1

Repository: opentiny/tiny-robot

Length of output: 424


🏁 Script executed:

#!/bin/bash
# Find the step that outputs pr.number in the deploy workflow
rg -B 5 "steps.pr.outputs.number" .github/workflows/pr-deploy-preview.yml | head -20

Repository: opentiny/tiny-robot

Length of output: 903


🏁 Script executed:

#!/bin/bash
# Find the step that has id: pr and outputs the number
rg -B 2 -A 5 "id: pr" .github/workflows/pr-deploy-preview.yml

Repository: opentiny/tiny-robot

Length of output: 306


Fix domain pattern mismatch between deploy and cleanup workflows.

The cleanup workflow uses github.event.pull_request.number to construct the domain, while the deploy workflow reads the PR number from artifacts/pr_number.txt via steps.pr.outputs.number. This mismatch means cleanup may attempt to remove a different deployment URL than what was deployed.

Update the cleanup workflow to use the same PR number source as deploy:

DEPLOY_DOMAIN=preview-${{ steps.pr.outputs.number }}-tiny-robot.surge.sh

Alternatively, update the deploy workflow to use github.event.pull_request.number directly so both workflows reference the same context variable.

🤖 Prompt for AI Agents
.github/workflows/pr-cleanup.yml lines 14-21: The cleanup job builds the
DEPLOY_DOMAIN using github.event.pull_request.number which differs from the
deploy workflow that uses steps.pr.outputs.number, causing cleanup to target the
wrong URL; update the cleanup workflow to read the PR number from the same
source as deploy by replacing github.event.pull_request.number with
steps.pr.outputs.number (DEPLOY_DOMAIN=preview-${{ steps.pr.outputs.number
}}-tiny-robot.surge.sh), or instead change the deploy workflow to emit/derive
the PR number from github.event.pull_request.number so both workflows use the
same variable.

@gene9831 gene9831 deleted the pick/develop-to-0.3.0-1230 branch December 30, 2025 09:04
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.

3 participants