Repository navigation
feat(docs): migrate documentation from MkDocs to Docusaurus v3 - #792
Conversation
|
Important Review skippedToo many files! This PR contains 110 files, which is 10 over the limit of 100. You can disable this status message by setting the
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. Comment |
✅ Single Commit Policy - COMPLIANTStatus: Policy requirements met • 1 commit • Valid format • Ready for merge 📊 View validation details📝 Commit Details
✅ Validation Results
🤖 Automated validation by NeuroLink Single Commit Enforcement |
Documentation Validation Results🚀 Documentation validation passed!
📦 Build artifact uploaded successfully. Ready for deployment preview. Commit: |
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
There was a problem hiding this comment.
Actionable comments posted: 17
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
docs/cli-guide.md (1)
1235-1256: Consider documentation completeness for release branch.Nine video demonstrations are marked as "(Video coming soon)" in this CLI guide. While the placeholder text is consistent and clear, shipping release documentation with multiple "coming soon" items may impact user experience.
Consider one of these approaches:
- Option 1: Complete the video content before merging to release
- Option 2: Remove the placeholder entries until videos are ready, then add them in a follow-up PR
- Option 3: If incremental documentation releases are intentional, add a note at the top of the video section explaining the rollout plan
The added feature list (lines 1251-1256) looks good and provides clear expectations for the upcoming content.
docs/sdk-custom-tools.md (1)
1663-1664: Both new resource links point to the same destination.The "MCP SDK Integration Proof Tests" and "Real AI-MCP Integration Demo" links both point to
development/testing.md. These appear to be either placeholder links or incorrectly configured, as distinct resources should point to different locations or different anchors within the same page.🔗 Suggested fix: add specific anchors or correct the links
If both resources are in the same file but different sections:
- [MCP SDK Integration Proof Tests](development/testing.md) -- [Real AI-MCP Integration Demo](development/testing.md) +- [Real AI-MCP Integration Demo](development/testing.md#real-ai-mcp-integration-demo)Or if they should point to different files, update accordingly.
docs/business-value.md (1)
1-2: Add required frontmatter to satisfy frontmatter validationThe validation job reports missing required
descriptionfields. This file has no frontmatter, so it will likely fail validation. Please add frontmatter here to unblock the docs pipeline.✅ Proposed frontmatter
+--- +title: Business Value Guide: Analytics & Evaluation Features +description: Real-world ROI and business impact of NeuroLink analytics and evaluation features. +--- + # 💰 Business Value Guide: Analytics & Evaluation Featuresdocs/cookbook/structured-output.md (1)
1-3: Add required frontmatter to satisfy frontmatter validationThis file has no frontmatter, and the validation job reports missing required
descriptionfields. Add frontmatter here to avoid failingvalidate:frontmatter.✅ Proposed frontmatter
+--- +title: Structured Output with JSON Schema +description: Generate validated JSON responses using schemas and NeuroLink structured output. +--- + # Structured Output with JSON Schemaneurolink-demo/README.md (1)
5-5: Broken anchor link:[object Object]instead of proper slug.This appears to be a bug from a build/generation script that serialized a JavaScript object instead of a string. The link will be broken in the rendered markdown.
🔧 Fix the anchor
-- [🚀 Next Steps](#[object Object]) +- [🚀 Next Steps](`#-next-steps`)docs/demos/videos.md (1)
1-3: Add frontmatter to satisfy validation and metadata requirements.Frontmatter validation is failing; this page has no frontmatter. Add at least
titleanddescription(andsidebar_positionif your schema requires it).🛠️ Suggested frontmatter block
+--- +title: Video Demonstrations +description: Professional demo videos showcasing NeuroLink CLI, MCP, and business workflows. +--- + # Video Demonstrationsdocs/visual-demos.md (1)
1-3: Add required frontmatter (pipeline is failing).Frontmatter validation reports missing
descriptionand duplicatesidebar_position. Please add frontmatter with a description and choose a uniquesidebar_positionin this directory.🧾 Example frontmatter
+--- +title: "Visual Demonstrations" +description: "Screenshots, videos, and demo walkthroughs for NeuroLink." +sidebar_position: 60 # ensure this is unique in the directory +--- # 🎬 Visual Demonstrations
🤖 Fix all issues with AI agents
In @.github/workflows/docs-pr-validation.yml:
- Around line 66-68: The "Validate frontmatter" workflow step (id: frontmatter,
name: Validate frontmatter, run: pnpm run validate:frontmatter) is failing the
entire docs PRs; add continue-on-error: true to that step to allow the job to
complete while surfacing warnings during migration, so modify the step
definition to include continue-on-error: true and remove it later once
frontmatter issues are fixed.
In @.github/workflows/docs-version.yml:
- Around line 89-124: The Create Pull Request step is using ${{
secrets.GITHUB_TOKEN }} which prevents downstream pull_request workflows from
triggering; replace the token input in the peter-evans/create-pull-request@v6
step with a repository secret containing a PAT or GitHub App token (e.g., ${{
secrets.DOCS_PR_PAT }}) that has repo:status and workflow scopes, update any
documentation about the secret creation, and ensure the workflow caller still
uses the same step name "Create Pull Request" and branch/base settings so the PR
is created with that PAT and will trigger docs-pr-validation.
In `@docs-site/.gitignore`:
- Around line 1-4: The validation failure is caused by missing frontmatter
(title, description, sidebar_position) in the markdown files under ./docs;
update the source files or enhance the sync-docs.ts script to inject required
Docusaurus frontmatter when converting MkDocs to Docusaurus format: modify
sync-docs.ts to parse the first heading or metadata to generate a title,
synthesize a short description (or pull from existing MkDocs metadata), and
compute/assign sidebar_position (e.g., from original order or a mapping), then
write the frontmatter block (title, description, sidebar_position) to each
output markdown so validate:frontmatter will pass. Ensure you target files in
./docs/ rather than editing .gitignore.
In `@docs-site/package.json`:
- Around line 24-28: The `@docusaurus/`* dependencies are mismatched
(plugin-client-redirects is ^3.9.2 while core, preset-classic, and theme-common
are ^3.7.0); update package.json so all `@docusaurus` packages use the same
version (choose either ^3.7.0 or ^3.9.2) by editing the entries for
`@docusaurus/plugin-client-redirects`, `@docusaurus/core`,
`@docusaurus/preset-classic`, and `@docusaurus/theme-common` to the chosen version,
then reinstall dependencies (npm/yarn) to regenerate the lockfile.
In `@docs-site/scripts/sync-docs.ts`:
- Around line 416-437: The current frontmatter generation causes missing
descriptions and many duplicate sidebar_position values; modify
generateSidebarPosition to return number | undefined (remove the default 50 and
only keep deterministic mappings for filenames like
index/getting-started/installation/etc.), add an
extractDescriptionFromContent(content: string): string | null helper that strips
code blocks and headings and returns the first non-empty plaintext line, and
change the caller that sets processed.sidebar_position to only assign it when
generateSidebarPosition returns a defined number (otherwise delete
processed.sidebar_position); finally, if processed.description is empty,
populate it from extractDescriptionFromContent(content).
- Around line 368-372: The convertGridCards function currently removes the
entire <div class="grid cards" ...> block (losing inner markdown); change the
replacement to unwrap the container and preserve its inner content by matching
the opening tag and its attributes, capturing the inner HTML/markdown (using a
capturing group like ([\s\S]*?)) and replacing the whole match with the captured
group, or alternatively run two replacements that strip only the opening tag and
the closing </div> for elements whose class attribute contains "grid cards";
update convertGridCards to use that capturing/strip approach so card contents
are retained.
In `@docs-site/scripts/validate-frontmatter.ts`:
- Around line 36-41: The current frontmatter validation constants
(TITLE_MIN_LENGTH, DESCRIPTION_MIN_LENGTH, etc.) are too strict for migrated
content; modify scripts/validate-frontmatter.ts to support a strict mode flag
and default to non-strict behavior: add CLI parsing (e.g., parse process.argv
for "--strict") in validate-frontmatter.ts, change validation logic that
currently throws errors when a check fails to instead issue console.warn or
accumulate warnings unless strict is true, and only treat failures as errors
(throw/exit non-zero) when strict is enabled; update package.json to add two
scripts (validate:frontmatter runs without --strict and
validate:frontmatter:strict runs with --strict) so CI can opt into strict
checking while local/initial migration uses warnings.
In `@docs-site/src/components/CopyPageButton/index.tsx`:
- Around line 11-17: The handleCopy function currently calls
navigator.clipboard.writeText without guarding for availability or failures;
update handleCopy to check for navigator.clipboard (and
navigator.clipboard.writeText) before calling, wrap the writeText call in a
try/catch to handle NotAllowedError or other rejections, and ensure setCopied is
only set true on success (and optionally provide a failure path such as logging
the error or showing a fallback UI); reference the handleCopy function and
navigator.clipboard.writeText and adjust setCopied usage accordingly.
In `@docs-site/src/components/Search/EmptySearch.tsx`:
- Around line 14-19: QUICK_LINKS contains root-relative URLs that won't resolve
with routeBasePath "/docs"; update the entries in the QUICK_LINKS constant so
each url is prefixed with "/docs" (e.g., "/docs/getting-started", "/docs/sdk",
"/docs/cli") and replace the non-existent "/features/mcp-tools-showcase" with
the correct MCP docs path (for example "/docs/mcp/overview" or the actual MCP
doc route used in the site) so all links point to valid /docs routes.
In `@docs-site/src/components/Search/SearchResultItem.tsx`:
- Around line 61-83: In SearchResultItem
(docs-site/src/components/Search/SearchResultItem.tsx) sanitize any HTML before
using dangerouslySetInnerHTML: import DOMPurify and call DOMPurify.sanitize(...)
for breadcrumbParts entries, for title, and for content, allowing only safe
tags/attributes (e.g., keep <mark> for highlights) and then pass the sanitized
strings into dangerouslySetInnerHTML; update the breadcrumb map
(breadcrumbParts), the title assignment (resultTitle), and the content block
(resultContent) to use the sanitized values instead of the raw variables.
In `@docs-site/src/hooks/useAlgoliaSearch.ts`:
- Around line 135-192: The search call currently creates an AbortController but
never passes its signal to clientRef.current.search and relies on
abortControllerRef.current later, allowing stale responses to overwrite newer
state; fix by adding a per-request token: add a requestIdRef (e.g.,
requestIdRef.current++ before the search), capture const localRequestId =
requestIdRef.current, pass abortControllerRef.current.signal into
clientRef.current.search's options, and before any state updates (setResults,
setTotalResults, setSelectedIndex, setError, setIsLoading, and caching via
searchCache.set(trimmedQuery, ...)) verify that localRequestId ===
requestIdRef.current; also make the same increment/invalidating update in the
hook cleanup function so unmounting increments requestIdRef to ignore any
in-flight callbacks.
In `@docs-site/src/theme/prism-neurolink-light.ts`:
- Around line 56-78: The styles array in prism-neurolink-light.ts contains
overlapping token definitions: earlier entries set "keyword"/"selector"/"tag" to
red/purple (the objects with types ["atrule","keyword","attr-name","selector"]
and ["function","deleted","tag"]) but a later object (types
["tag","selector","keyword"]) redefines them to green (`#22863a`) which silently
overrides the earlier rules; fix by removing the duplicate types from the final
object or moving that final object earlier in the styles array so the intended
red/purple rules (the objects above) take precedence—update the types arrays
accordingly to avoid duplicate "keyword"/"selector"/"tag" entries.
In `@docs-site/src/theme/Root.tsx`:
- Around line 10-35: Update the PostHog initialization in posthog.init so
session recording is privacy-safe: set session_recording.maskAllInputs to true
(and provide a non-null maskInputFn or sensible maskTextSelector), set
respect_dnt to true, and only enable session_recording after explicit user
consent gating logic (e.g., check a consent flag before passing
session_recording). Also remove the duplicate initial pageview by deleting or
guarding the pageview call inside the loaded callback (the one referenced as
loaded) so usePageTracking() on mount is the single source of the initial
pageview.
In `@docs-site/static/llms.txt`:
- Around line 5-7: Replace the legacy docs host in the generated output by
updating the generator so the "Full documentation:
https://neurolink.juspay.io/llms-full.txt" link (and any other occurrences such
as the ones around lines referenced in the review) points to the new docs
domain; modify the generator/template that emits the "Generated: ..." block and
the "Full documentation:" URL to use the new host and then re-run the generator
so docs-site/static/llms.txt contains the updated links.
In `@docs/advanced/index.md`:
- Around line 243-245: The "Performance Tuning" link currently points to a
non-existent target '../deployment/configuration.md'; update the markdown link
referenced as "Performance Tuning" in docs/advanced/index.md to either point to
the correct existing documentation file (replace
'../deployment/configuration.md' with the correct path) or create the missing
target file at '../deployment/configuration.md' with the intended content so the
link resolves; ensure the link text "Performance Tuning" and the path are
consistent with your documentation structure.
In `@docs/getting-started/providers/google-vertex.md`:
- Line 957: Update the broken link that currently points to
"/reference/troubleshooting" so it goes directly to the correct troubleshooting
subsection "/troubleshooting#google-gemini-too-many-states-for-serving-error";
locate the anchor text "Troubleshooting Guide" or the URL string
"/reference/troubleshooting" in the
docs/getting-started/providers/google-vertex.md content and replace it with
"/troubleshooting#google-gemini-too-many-states-for-serving-error" so users land
on the "Too many states for serving" section.
In `@docs/guides/migration/index.md`:
- Around line 1-3: Add a YAML frontmatter block at the very top of the file
(above the "# Migration Guides" header) to satisfy validation; include required
fields such as title: "Migration Guides", description: a short summary, slug:
"migration", and any site-specific metadata like sidebar_label or
sidebar_position expected by the pipeline (wrap them between --- and place
before the existing content). Ensure the frontmatter keys match the project's
other docs frontmatter conventions so the validator accepts this page.
🟡 Minor comments (24)
docs-site/src/components/CopyPageButton/index.tsx-20-24 (1)
20-24: Set explicit button type to avoid accidental form submits.✅ Suggested fix
<button onClick={handleCopy} className={styles.button} title="Copy page content" + type="button" >docs-site/src/components/CopyPageButton/index.tsx-25-52 (1)
25-52: Add accessible text or hide decorative SVGs.
The SVGs need a title or explicit aria metadata to satisfy the a11y lint rule.✅ Suggested fix
<svg className={styles.icon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} + aria-hidden="true" + focusable="false" > + <title>Copied</title> <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /> </svg> ) : ( <svg className={styles.icon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} + aria-hidden="true" + focusable="false" > + <title>Copy</title> <path strokeLinecap="round" strokeLinejoin="round" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" /> </svg>docs/features/structured-output.md-168-168 (1)
168-168: Restore the#generateanchor fragment in the API Reference link.The
generate()section exists in the API reference with a stable anchor ID ({#generate}at line 132), but removing the fragment from the link breaks deep-linking. Users will land at the top of the API reference page instead of jumping directly to thegenerate()section. Update the link to:[API Reference](../sdk/api-reference.md#generate)docs/sdk-custom-tools.md-1659-1659 (1)
1659-1659: Restore the anchor fragment to the API Reference link.The link to
sdk/api-reference.mdhas the anchor#neurolink-classremoved. The NeuroLink Class section exists in the API reference (line 5), so removing the anchor causes users to land at the page top instead of the intended section, degrading navigation.docs-site/src/components/icons/ArrowIcon.tsx-8-24 (1)
8-24: Fix rotate() values to include angle units.
rotate(-90),rotate(90), androtate(180)require explicit angle units (deg, rad, grad, or turn) to be applied. Without units, these values are ignored by the browser. Note:rotate(0)is valid without units, but adding units is harmless.Suggested fix
- up: "rotate(-90)", - down: "rotate(90)", - left: "rotate(180)", + up: "rotate(-90deg)", + down: "rotate(90deg)", + left: "rotate(180deg)",docs/reference/analytics.md-182-186 (1)
182-186: Update documentation examples to use correct import paths or remove analyticsUtils references.The import path
@juspay/neurolink/utils/analyticsUtilsis not a valid export. TheanalyticsUtilsmodule (containingformatTokenUsage,calculateTokenCost, andcombineTokenUsage) is not exposed through the package's public API. The package exports only:
.(main entry point)./types./cli./package.jsonEither remove the analyticsUtils examples from the documentation, or add a
./utilssubpath export topackage.jsonif these utilities are intended to be public.docs/demos/index.md-174-177 (1)
174-177: Update placeholder path to match actual asset location.The example shows
path/to/cli-demo.pngwhich is a generic placeholder. This should either be updated to the actual path (../assets/images/cli-demo.png) or removed if the image doesn't exist yet.📝 Proposed fix
### Documentation Embedding ```markdown - + _NeuroLink CLI with provider status and text generation_</details> </blockquote></details> <details> <summary>docs/demos/screenshots.md-9-12 (1)</summary><blockquote> `9-12`: **Create a tracking mechanism for 35 pending screenshot assets in documentation.** The repository contains 35 placeholder comments across `docs/demos/` (27 in `screenshots.md`, 8 in `index.md`), with no dedicated issue or checklist to track their completion. While a `todos/` directory exists for code refactoring, documentation asset completion is not tracked. Establish explicit tracking (GitHub issue, checklist, or milestone) to ensure these assets are captured before the documentation is published. </blockquote></details> <details> <summary>docs-site/static/llms.txt-147-152 (1)</summary><blockquote> `147-152`: **License badge URL is truncated.** The MIT badge link ends at `https://opensource.` which renders a broken link. Please regenerate the llms.txt output or restore the full license URL in the source. </blockquote></details> <details> <summary>docs/visual-demos.md-156-160 (1)</summary><blockquote> `156-160`: **Capitalize GitHub in MCP table.** Use the official capitalization for the platform name. <details> <summary>✏️ Suggested edit</summary> ```diff -| **Server Installation** |  | Installing external MCP servers (filesystem, github, etc.) | +| **Server Installation** |  | Installing external MCP servers (filesystem, GitHub, etc.) |docs-site/src/theme/Root.tsx-38-76 (1)
38-76: Initial pageview is captured twice.The
loadedcallback inposthog.init()(line 38-51) captures a pageview on initialization, and theusePageTrackinghook's effect runs on mount (line 59-76) with the same location, capturing a second event. Add a first-run guard to prevent the duplicate:🧭 Suggested guard
-import React, { useEffect } from "react"; +import React, { useEffect, useRef } from "react"; @@ function usePageTracking() { const location = useLocation(); + const isFirstRef = useRef(true); useEffect(() => { if (typeof window === "undefined" || !posthog.__loaded) return; + if (isFirstRef.current) { + isFirstRef.current = false; + return; + } @@ }, [location.pathname, location.search, location.hash]); }docs-site/src/components/GithubLink/index.tsx-18-26 (1)
18-26: Add accessible text for the SVG icon.The SVG is missing an accessible name, which triggers the a11y lint and can be read ambiguously by assistive tech. Add a title (and optional aria-label) to the SVG.
Proposed fix
- <svg className={styles.icon} viewBox="0 0 24 24" fill="currentColor"> + <svg + className={styles.icon} + viewBox="0 0 24 24" + fill="currentColor" + role="img" + aria-label="GitHub" + > + <title>GitHub</title> <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" /> </svg>docs-site/src/components/Search/SearchInput.tsx-42-43 (1)
42-43: Fix invalidaria-labelon<div>element.The
aria-labelattribute is not supported on a plain<div>element. For the loading spinner to be accessible, addrole="status"to make the ARIA attribute valid.🛠️ Proposed fix
- {isLoading ? ( - <div className={styles.loadingSpinner} aria-label="Loading" /> + {isLoading ? ( + <div className={styles.loadingSpinner} role="status" aria-label="Loading" />docs-site/src/css/custom.css-81-89 (1)
81-89: The CSScolorproperty has no effect on<img>elements.Setting
coloron an<img>element won't change the image appearance. If the logo is a raster image (PNG/JPG), this rule is ineffective. If it's an SVG usingcurrentColor, the SVG must be inlined or loaded via a component that passes the color as a fill/stroke property.Consider using Docusaurus's themed image component or providing separate light/dark logo files instead.
docs-site/src/css/fonts.css-44-49 (1)
44-49: Thefont-display: swaprule onhtmlis ineffective.
font-displayis a@font-facedescriptor, not a CSS property that can be applied to elements. This rule has no effect. The Google Fonts URLs already includedisplay=swapparameter, so font swapping is already enabled correctly.🧹 Suggested removal
-/* ---- Font Loading Optimization ---- */ - -/* Prevent layout shift during font loading */ -html { - font-display: swap; -} - /* ---- Font Size Scale ---- */docs-site/src/pages/index.tsx-8-147 (1)
8-147: Add accessibility attributes to SVG icons.All inline SVG icons are flagged by static analysis for missing accessibility attributes. Since these icons are decorative (used alongside text labels), they should be hidden from assistive technologies using
aria-hidden="true".For icons that convey meaning independently (like ArrowRightIcon in buttons), consider adding
role="img"andaria-label.♿ Example fix for decorative icons
const ProviderIcon = () => ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" + aria-hidden="true" >For the ArrowRightIcon used in CTA buttons:
const ArrowRightIcon = () => ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={styles.arrowIcon} + aria-hidden="true" >docs-site/src/css/custom.css-91-110 (1)
91-110: These CSS rules appear unused and target non-existent elements.The selectors
.themedComponent--light_ElNyand.themedComponent_rrg5contain auto-generated hashes that don't match any rendered components in the codebase—no components apply these class names. The comment "Also handle themed components if Docusaurus uses them" suggests this is speculative defensive code.Either remove these rules or, if they're truly needed for Docusaurus-generated content, use stable selectors instead:
[data-theme="dark"] [class*="themedComponent--light"] { display: none !important; }docs-site/src/components/Search/SearchModal.tsx-73-82 (1)
73-82: Guard selection updates when there are no results.Line 75-82:
results.length - 1becomes-1when empty, so ArrowDown can setselectedIndexto-1. Consider short-circuiting when there are no results to keep selection non-negative.🛠️ Suggested fix
case "ArrowDown": + if (results.length === 0) return; e.preventDefault(); setSelectedIndex(Math.min(selectedIndex + 1, results.length - 1)); break; case "ArrowUp": + if (results.length === 0) return; e.preventDefault(); setSelectedIndex(Math.max(selectedIndex - 1, 0)); break;docs-site/src/components/ProviderModelsTable/index.tsx-32-34 (1)
32-34: Use a stable unique key for rows.Line 32-34:
key={model.name}can collide if different providers share model names. Use a composite key to keep React reconciliation stable.🔧 Suggested fix
- <tr key={model.name}> + <tr key={`${model.provider}:${model.name}`}>docs-site/src/components/Search/EmptySearch.tsx-45-70 (1)
45-70: Use semantic buttons for recent-search items.Line 45-70:
div role="button"triggers a11y lint and misses native button semantics. Prefer a real<button>for the selectable item and keep the remove button as a sibling to avoid nested interactive elements.🛠️ Suggested structure (CSS updates needed)
- <li key={query}> - <div - className={styles.recentSearchItem} - onClick={() => onRecentSearchClick(query)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - onRecentSearchClick(query); - } - }} - role="button" - tabIndex={0} - > - <SearchIcon className={styles.recentSearchIcon} /> - <span className={styles.recentSearchText}>{query}</span> - <button - type="button" - className={styles.recentSearchRemove} - onClick={(e) => { - e.stopPropagation(); - onRemoveRecentSearch(query); - }} - aria-label={`Remove "${query}" from recent searches`} - > - <CloseIcon className={styles.recentSearchRemoveIcon} /> - </button> - </div> - </li> + <li key={query} className={styles.recentSearchItem}> + <button + type="button" + className={styles.recentSearchButton} + onClick={() => onRecentSearchClick(query)} + > + <SearchIcon className={styles.recentSearchIcon} /> + <span className={styles.recentSearchText}>{query}</span> + </button> + <button + type="button" + className={styles.recentSearchRemove} + onClick={(e) => { + e.stopPropagation(); + onRemoveRecentSearch(query); + }} + aria-label={`Remove "${query}" from recent searches`} + > + <CloseIcon className={styles.recentSearchRemoveIcon} /> + </button> + </li>docs-site/src/components/Search/SearchResults.tsx-139-150 (1)
139-150: A11y: static wrapper has pointer interaction.The wrapper
<div>usesonMouseEnter(line 149), which violatesnoStaticElementInteractions. Move the hover handler to theSearchResultItemanchor by adding anonMouseEnterprop that callshandleMouseEnter(item.flatIndex).docs-site/src/components/Button/index.tsx-31-36 (1)
31-36: Add explicittype="button"default to prevent accidental form submissions.HTML button elements default to
type="submit", which can trigger unintended form submissions if this component is used inside forms. This risk is especially relevant for a reusable component. Other button implementations in the codebase (SearchInput, EmptySearch, SearchWrapperMobile) already explicitly settype="button", establishing a consistent pattern.Suggested fix
-export function Button({ className, variant, size, ...props }: ButtonProps) { +export function Button({ className, variant, size, type = "button", ...props }: ButtonProps) { return ( <button + type={type} className={buttonVariants({ variant, size, className })} {...props} /> ); }docs-site/src/components/SearchWrapperMobile.tsx-195-197 (1)
195-197: Addrole="status"for accessible loading indicator.A plain
<div>with onlyaria-labellacks semantic role for assistive technology. Userole="status"to properly announce the loading state (it includes implicitaria-live="polite"andaria-atomic="true").For best accessibility, include visible/accessible text content (e.g., "Loading results…") instead of relying solely on
aria-label. The suggested fix below is a valid improvement:✅ Suggested fix
- {isLoading && ( - <div className={styles.loadingSpinner} aria-label="Loading" /> - )} + {isLoading && ( + <div + className={styles.loadingSpinner} + role="status" + aria-label="Loading" + /> + )}docs-site/src/css/utilities.css-654-698 (1)
654-698: Fix.show-tablet-onlyso it doesn’t render on mobile.Right now it only hides on desktop (Line 694), so it still shows on mobile. If the intent is “tablet only,” hide it at the mobile breakpoint too.
✅ Suggested fix
@@ `@media` (max-width: 576px) { @@ /* Hide on mobile */ .hide-mobile { display: none; } + + /* Hide tablet-only on mobile */ + .show-tablet-only { + display: none; + } }
🧹 Nitpick comments (27)
docs-site/src/components/YouTube/index.tsx (1)
9-18: Consider privacy/perf hardening for embeds (nocookie + lazy + encode).
If docs should minimize tracking and improve load time, switch to theyoutube-nocookie.comdomain, encode theid, and lazy-load the iframe.♻️ Suggested update
export function YouTube({ id, title = "YouTube video" }: YouTubeProps) { return ( <div className={styles.wrapper}> <iframe className={styles.iframe} - src={`https://www.youtube.com/embed/${id}`} + src={`https://www.youtube-nocookie.com/embed/${encodeURIComponent(id)}`} title={title} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen + loading="lazy" /> </div> ); }docs/cookbook/streaming-with-retry.md (1)
277-277: Consider adding an anchor to link directly to the streaming method.The target file
docs/sdk/api-reference.mdexists and documents thestream(options)method under the Core Methods section. Adding an anchor like../sdk/api-reference.md#streamwould allow users to jump directly to the relevant streaming API instead of landing at the top of the page.docs-site/src/components/PropertiesTable/PropertiesTable.module.css (2)
114-116: Hardcoded color breaks theming consistency.Line 81 uses
var(--neurolink-accent-subtle)for the.typebackground, but the dark mode override uses a hardcodedrgba(59, 130, 246, 0.15). This inconsistency makes future theme updates error-prone and harder to maintain.♻️ Proposed fix to use CSS variable
[data-theme="dark"] .type { - background: rgba(59, 130, 246, 0.15) !important; + background: var(--neurolink-accent-subtle) !important; }If the dark mode value needs to differ from the variable, consider defining a dark mode variant of
--neurolink-accent-subtleintokens.cssinstead.
98-108: Remove redundant dark mode selectors (lines 98-108).The
[data-theme="dark"]rules for.table thead,.table tbody tr:nth-child(even), and.table tbody tr:hoverreference the same CSS variables as their light mode counterparts. Since--neurolink-surface-1,--neurolink-surface-2, and--neurolink-surface-3are already theme-aware (defined with different values under[data-theme="dark"]in tokens.css), these overrides are unnecessary. Remove them to reduce duplication.Note: Keep the
[data-theme="dark"] .table coderule (line 110–112) since it uses--neurolink-surface-4instead of the light mode's--neurolink-surface-3.docs-site/src/components/CopyPageButton/CopyPageButton.module.css (1)
39-44: Use a data-attribute for copied state instead of relying on SVG path detection.The current CSS selector
.button:has(.icon path[d*="M5 13"])couples the styling to the SVG implementation and is fragile—if the SVG path changes, the CSS breaks. Adata-copiedattribute makes the state explicit and maintainable. The component already trackscopiedstate, so this is a straightforward refactor:♻️ Suggested change
CSS:
-.button:has(.icon path[d*="M5 13"]) { +.button[data-copied="true"] { color: var(--neurolink-success-text); border-color: var(--neurolink-success-border); background: var(--neurolink-success-bg); }JSX:
<button onClick={handleCopy} className={styles.button} title="Copy page content" + data-copied={copied} >docs/guides/index.md (1)
38-108: Stabilize the “Migration Guides” anchor with an explicit heading ID.
#-migration-guidesis fragile across slugging rules. Prefer an explicit ID to keep links stable.Proposed fix
-## 🔄 Migration Guides +## 🔄 Migration Guides {`#migration-guides`} ... -- **Migrating from another framework?** See our [Migration Guides](`#-migration-guides`) +- **Migrating from another framework?** See our [Migration Guides](`#migration-guides`)docs-site/src/components/ui/Kbd.tsx (1)
9-11: Consider trimming className to avoid trailing whitespace.The current template literal produces a trailing space when
classNameis undefined. While functionally harmless, it's cleaner to avoid extra whitespace in the DOM.♻️ Cleaner className handling
export function Kbd({ children, className }: KbdProps) { - return <kbd className={`${styles.kbd} ${className || ""}`}>{children}</kbd>; + return <kbd className={`${styles.kbd}${className ? ` ${className}` : ""}`}>{children}</kbd>; }Alternatively, consider using a utility like
clsxif the project already has it as a dependency.docs-site/src/components/icons/ReturnIcon.tsx (2)
1-1: Unused React import.With React 17+ and the new JSX transform (which Docusaurus uses), this import is unnecessary since
Reactisn't directly referenced in the component.♻️ Remove unused import
-import React from "react"; - interface ReturnIconProps {
9-14: Consider adding default width/height for predictable sizing.The SVG lacks explicit
widthandheightattributes. Without them, the icon's size depends entirely on CSS, which could cause unexpected rendering if the parent doesn't constrain dimensions.♻️ Add default dimensions
<svg className={className} + width={24} + height={24} fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true" >docs-site/src/theme/prism-neurolink-dark.ts (2)
38-66: Duplicate token type definitions forinsertedanddeleted.The token types
insertedanddeletedare defined twice with different styles:
- Lines 49 and 62:
inserted→ blue (#60a5fa),deleted→ purple (#c084fc)- Lines 105-110 and 112-117:
inserted→ green (#4ade80),deleted→ red (#f87171)In Prism themes, later style definitions override earlier ones for the same token type. The diff highlighting section (lines 104-117) will take precedence, making the earlier definitions dead code.
Consider removing
insertedfrom line 49 anddeletedfrom line 62 to avoid confusion and ensure intentional styling.Suggested fix
{ types: [ "entity", "url", "symbol", "number", "boolean", "variable", "constant", "property", "regex", - "inserted", ], style: { color: "#60a5fa", // Blue (NeuroLink accent) }, }, { types: ["atrule", "keyword", "attr-name", "selector"], style: { color: "#f87171", // Red for keywords }, }, { - types: ["function", "deleted", "tag"], + types: ["function", "tag"], style: { color: "#c084fc", // Purple for functions }, },Also applies to: 104-117
73-78: Additional duplicate token definitions fortag,selector,keyword.These token types are already defined at lines 56-60 with red color (
#f87171), but are redefined here with purple (#c678dd). The purple styling will override the red.If the purple color is intentional for these tokens, remove them from the earlier definition at line 56.
docs-site/src/components/Search/Search.module.css (1)
246-264: Consider adding focus styles for keyboard navigation.The result items have hover and selected states, but keyboard users navigating through results would benefit from explicit
:focusor:focus-visiblestyles on.resultItemfor better accessibility.Suggested addition
.resultItem:focus-visible { outline: 2px solid var(--neurolink-accent); outline-offset: -2px; }docs/reference/provider-selection.md (1)
8-9: Consider updating version reference.The "NeuroLink Version: 8.26.1+" is outdated compared to the current version 8.40.1 in
package.json. While the+suffix makes it technically accurate, updating to the current version would better reflect the documentation's relevance..github/workflows/docs-deploy.yml (1)
24-87: Consider adding a job-level timeout.The build job lacks
timeout-minutes, which could lead to hung workflows if the build process stalls (e.g., infinite loop in a script, network issues during dependency installation).⏱️ Proposed fix to add timeout
jobs: build: name: Build Documentation runs-on: ubuntu-latest + timeout-minutes: 15 defaults: run: working-directory: docs-sitedocs/demos/screenshots.md (1)
534-551: Validation script has a glob pattern issue.The bash glob pattern
**/*.{png,jpg,webp}won't work as expected withoutshopt -s globstarbeing enabled first in bash. Also, the regex pattern may not match all valid filenames (e.g., filenames with numbers in feature/context parts).🔧 Proposed fix for the validation script
#!/bin/bash # validate-screenshot-names.sh # Validates screenshot naming convention compliance +shopt -s globstar nullglob for file in docs/assets/images/**/*.{png,jpg,webp}; do filename=$(basename "$file") # Check naming pattern - if [[ ! $filename =~ ^[a-z]+-[a-z]+-[a-z]+(-[a-z0-9]+)?\.(png|jpg|webp)$ ]]; then + if [[ ! $filename =~ ^[a-z]+-[a-z0-9]+-[a-z0-9]+(-[a-z0-9]+)?\.(png|jpg|webp)$ ]]; then echo "❌ Invalid naming: $filename" echo " Expected: category-feature-context[-variant].extension" else echo "✅ Valid naming: $filename" fi donedocs-site/scripts/validate-frontmatter.ts (2)
172-194: Consider makingsidebar_positionoptional for index files.Category index files (like
index.md) often don't need asidebar_positionas they represent the category itself. The current validation treats it as required for all files, which may cause unnecessary errors.🔧 Proposed fix to make sidebar_position optional for index files
// sidebar_position validation (required, number >= 0) - if (frontmatter.sidebar_position === undefined) { + const isIndexFile = relativePath.endsWith('index.md') || relativePath.endsWith('index.mdx'); + if (frontmatter.sidebar_position === undefined && !isIndexFile) { issues.push({ level: "error", file: relativePath, message: "Missing required field: sidebar_position", field: "sidebar_position", });
74-94: Simplify glob pattern matching.The current pattern matching logic handles
**patterns manually but may not cover all edge cases. Consider using theminimatchlibrary (already available viaglobdependency) for more robust pattern matching..github/workflows/docs-pr-validation.yml (1)
18-29: Consider adding timeout to the validate job.The validation job performs multiple operations including a full build. Adding a timeout prevents hung workflows.
⏱️ Proposed fix
validate: name: Validate Documentation runs-on: ubuntu-latest + timeout-minutes: 20 defaults:docs-site/package.json (1)
11-12: Remove duplicate script entry.Both
build:llmsandbuild:llms-txtrun the identical command. Consider removing one to avoid confusion.🧹 Proposed fix
"sync-docs": "tsx scripts/sync-docs.ts", - "build:llms": "tsx scripts/build-llms-txt.ts", "build:llms-txt": "tsx scripts/build-llms-txt.ts",docs-site/scripts/build-llms-txt.ts (1)
277-298: Remove unusedfilesparameter or add dynamic extraction.The
filesparameter is accepted but never used. The function returns a hardcoded provider list regardless of input.♻️ Suggested fix
Either remove the unused parameter:
-function extractProviders(files: DocFile[]): ProviderInfo[] { +function extractProviders(): ProviderInfo[] {Or add a TODO if dynamic extraction is planned:
function extractProviders(files: DocFile[]): ProviderInfo[] { + // TODO: Extract providers dynamically from documentation files const providers: ProviderInfo[] = [docs-site/src/components/ProviderModelsTable/ProviderModelsTable.module.css (1)
112-122: Consider removing redundant dark mode overrides.These dark mode rules apply the same CSS variable values as their light mode counterparts (lines 23-25, 48-50, 52-54). If
--neurolink-surface-*variables already adapt based on theme (the standard pattern for CSS custom properties), these overrides are unnecessary duplication.Only the code background rule (lines 124-126) specifies a different surface level (
surface-4vssurface-3).♻️ Suggested cleanup
/* =========================================== DARK MODE =========================================== */ -[data-theme="dark"] .table thead { - background: var(--neurolink-surface-2); -} - -[data-theme="dark"] .table tbody tr:nth-child(even) { - background: var(--neurolink-surface-1); -} - -[data-theme="dark"] .table tbody tr:hover { - background: var(--neurolink-surface-3); -} - [data-theme="dark"] .table code { background: var(--neurolink-surface-4); }docs-site/src/pages/index.module.css (1)
118-165: Add explicit:focus-visiblestyling for CTA links.The CTA links remove default link styling and rely on hover effects; without an explicit focus-visible state, keyboard users may not get a clear focus indicator if global styles don’t cover these classes. Consider adding a focused outline to match the design.
Proposed CSS
.ctaPrimary:hover { background: var(--neurolink-accent-dark); color: white; text-decoration: none; transform: translateY(-2px); box-shadow: 0 8px 20px hsla(217, 91%, 60%, 0.3); } + +.ctaPrimary:focus-visible { + outline: 2px solid var(--neurolink-accent); + outline-offset: 2px; +} .ctaSecondary { background: var(--neurolink-surface-2); color: var(--neurolink-text-primary); border: 1px solid var(--border); } .ctaSecondary:hover { background: var(--neurolink-surface-3); color: var(--neurolink-text-primary); text-decoration: none; border-color: var(--border-secondary); } + +.ctaSecondary:focus-visible { + outline: 2px solid var(--border-secondary); + outline-offset: 2px; +}docs-site/src/components/Search/SearchInput.tsx (1)
20-22: Consider makingautoFocusdefault tofalsefor better accessibility.The
autoFocusattribute defaults totrue, which can disrupt screen reader users and keyboard navigation by unexpectedly moving focus. Docusaurus search modals typically manage focus programmatically when opened. Consider defaulting tofalseand letting the parent component explicitly opt-in when appropriate.♻️ Suggested change
- autoFocus = true, + autoFocus = false,Also applies to: 36-36
docs-site/src/css/base.css (1)
11-14: The::-moz-selectionpseudo-element is redundant.Modern Firefox (version 62+, released 2018) supports the standard
::selectionpseudo-element. The-moz-prefixed version is no longer needed and can be removed to reduce redundancy.🧹 Suggested removal
::selection { background-color: hsla(217, 91%, 60%, 0.3); color: inherit; } - -::-moz-selection { - background-color: hsla(217, 91%, 60%, 0.3); - color: inherit; -}docs-site/src/css/fonts.css (1)
5-9: Consider performance implications of@importfor fonts.Using CSS
@importfor Google Fonts can delay font loading since the browser must first fetch and parse this CSS file before discovering the font URLs. For optimal performance, fonts are typically loaded via<link rel="preconnect">and<link>tags in the HTML<head>.However, this is acceptable for a documentation site where initial load performance is less critical than an application.
docs-site/src/pages/index.tsx (1)
370-371: Hardcoded model version will become stale.The code example uses
"claude-sonnet-4-20250514"which includes a specific date. Consider using a more generic model identifier or adding a comment to update this periodically.docs-site/src/css/utilities.css (1)
199-371: Respect reduced-motion preferences for animations/transitions.Consider disabling animation/transition utilities when users prefer reduced motion.
♿ Suggested reduced-motion override
@@ .transition-none { transition: none; } + +@media (prefers-reduced-motion: reduce) { + [data-state="open"][data-side] { + animation: none; + } + .animate-fade-in, + .animate-fade-out, + .animate-scale-in, + .animate-scale-out, + .animate-spin, + .animate-pulse { + animation: none; + } + .transition-fast, + .transition-normal, + .transition-slow, + .transition-colors { + transition: none; + } +}
| - name: Validate frontmatter | ||
| id: frontmatter | ||
| run: pnpm run validate:frontmatter |
There was a problem hiding this comment.
Frontmatter validation is blocking PRs.
This step is causing the pipeline failure (271 files with errors). Without continue-on-error: true, no documentation PRs can be merged until all frontmatter issues are resolved. Consider either:
- Adding
continue-on-error: truetemporarily during migration - Fixing all 271 files before merging this PR
- Adjusting the validation script to be less strict initially
🔧 Option 1: Allow validation to pass with warnings during migration
- name: Validate frontmatter
id: frontmatter
+ continue-on-error: true
run: pnpm run validate:frontmatterNote: Remove continue-on-error once all frontmatter issues are resolved.
📝 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.
| - name: Validate frontmatter | |
| id: frontmatter | |
| run: pnpm run validate:frontmatter | |
| - name: Validate frontmatter | |
| id: frontmatter | |
| continue-on-error: true | |
| run: pnpm run validate:frontmatter |
🤖 Prompt for AI Agents
In @.github/workflows/docs-pr-validation.yml around lines 66 - 68, The "Validate
frontmatter" workflow step (id: frontmatter, name: Validate frontmatter, run:
pnpm run validate:frontmatter) is failing the entire docs PRs; add
continue-on-error: true to that step to allow the job to complete while
surfacing warnings during migration, so modify the step definition to include
continue-on-error: true and remove it later once frontmatter issues are fixed.
| - name: Create Pull Request | ||
| if: steps.check.outputs.exists != 'true' | ||
| uses: peter-evans/create-pull-request@v6 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| commit-message: "docs: add documentation version ${{ steps.version.outputs.version }}" | ||
| title: "docs: add documentation version ${{ steps.version.outputs.version }}" | ||
| body: | | ||
| ## Documentation Version Update | ||
|
|
||
| This PR adds versioned documentation for release **${{ github.event.release.tag_name }}**. | ||
|
|
||
| ### Changes | ||
| - Created versioned docs in `versioned_docs/version-${{ steps.version.outputs.version }}/` | ||
| - Created versioned sidebar in `versioned_sidebars/version-${{ steps.version.outputs.version }}-sidebars.json` | ||
| - Updated `versions.json` | ||
|
|
||
| ### Release Information | ||
| - **Tag**: ${{ github.event.release.tag_name }} | ||
| - **Documentation Version**: ${{ steps.version.outputs.version }} | ||
| - **Release URL**: ${{ github.event.release.html_url }} | ||
|
|
||
| --- | ||
|
|
||
| *This PR was automatically created by the Documentation Versioning workflow.* | ||
| branch: docs/version-${{ steps.version.outputs.version }} | ||
| base: release | ||
| add-paths: | | ||
| docs-site/versioned_docs/ | ||
| docs-site/versioned_sidebars/ | ||
| docs-site/versions.json | ||
| labels: | | ||
| documentation | ||
| automated | ||
| reviewers: | | ||
| ${{ github.event.release.author.login }} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
GITHUB_TOKEN pull_request workflow trigger GitHub Actions 2024
💡 Result:
-
Why an
on: pull_requestworkflow may not run when the PR is created/updated by a workflow usingGITHUB_TOKEN: GitHub blocks most events generated with the repository’sGITHUB_TOKENfrom creating new workflow runs (to prevent accidental recursion). The documented exceptions are onlyworkflow_dispatchandrepository_dispatch. So a PR opened via API/CLI in a workflow authenticated withGITHUB_TOKENtypically won’t trigger otherpull_request/push-based workflows. [1] -
Fork PRs (and Dependabot PRs) are additionally restricted: for
pull_requestworkflows coming from forks,GITHUB_TOKENis read-only and secrets aren’t provided (Dependabot PRs are treated like forks). [2][3] -
Token permissions changed for newer orgs/enterprises: defaults can be read-only depending on when the org/enterprise was created, and you may need to explicitly grant
contents: write,pull-requests: write, etc., viapermissions:(this affects what the workflow can do, even when it does run). [4] -
Common workaround (recommended in practice): create the PR (or do the write action that should trigger checks) using a PAT or a GitHub App installation token instead of
GITHUB_TOKEN, so the resulting PR/push event can trigger workflows. [1][5]
Sources: GitHub Docs on triggering workflows and GITHUB_TOKEN recursion prevention [1]; GitHub Docs on fork PR workflow restrictions and read-only GITHUB_TOKEN [2]; GitHub Changelog on Dependabot PRs being treated like forks [3]; GitHub Docs on default GITHUB_TOKEN permissions policies [4]; peter-evans/create-pull-request docs noting that PRs created with default GITHUB_TOKEN won’t trigger on: pull_request/on: push workflows and suggesting other tokens [5].
🏁 Script executed:
find .github/workflows -name "*.yml" -o -name "*.yaml" | head -20Repository: juspay/neurolink
Length of output: 348
🏁 Script executed:
grep -r "on:.*pull_request" .github/workflows/ | head -20Repository: juspay/neurolink
Length of output: 42
🏁 Script executed:
grep -l "pull_request" .github/workflows/*.ymlRepository: juspay/neurolink
Length of output: 210
🏁 Script executed:
cat .github/workflows/docs-pr-validation.ymlRepository: juspay/neurolink
Length of output: 5927
🏁 Script executed:
grep -r "DOCS_BOT_TOKEN\|GH_TOKEN\|PAT" .github/ | grep -v "\.yml" | head -10Repository: juspay/neurolink
Length of output: 114
🏁 Script executed:
grep -i "secrets\." .github/workflows/docs-version.yml | grep -v "GITHUB_TOKEN"Repository: juspay/neurolink
Length of output: 42
Documentation validation won't run for PRs created with GITHUB_TOKEN.
The docs-pr-validation.yml workflow monitors pull_request events on the release branch but won't trigger for PRs created by this workflow using GITHUB_TOKEN. This means versioning PRs will skip documentation validation checks (frontmatter, TypeScript, build, and link validation).
Use a PAT or GitHub App token instead:
🔧 Suggested change
- token: ${{ secrets.GITHUB_TOKEN }}
+ token: ${{ secrets.DOCS_BOT_TOKEN }}🤖 Prompt for AI Agents
In @.github/workflows/docs-version.yml around lines 89 - 124, The Create Pull
Request step is using ${{ secrets.GITHUB_TOKEN }} which prevents downstream
pull_request workflows from triggering; replace the token input in the
peter-evans/create-pull-request@v6 step with a repository secret containing a
PAT or GitHub App token (e.g., ${{ secrets.DOCS_PR_PAT }}) that has repo:status
and workflow scopes, update any documentation about the secret creation, and
ensure the workflow caller still uses the same step name "Create Pull Request"
and branch/base settings so the PR is created with that PAT and will trigger
docs-pr-validation.
| # Docusaurus build artifacts | ||
| .docusaurus/ | ||
| build/ | ||
| docs/ |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Explore the structure of docs-site
ls -la docs-site/ 2>/dev/null | head -20
# Check if .gitignore exists and read it
echo "=== docs-site/.gitignore ==="
cat docs-site/.gitignore 2>/dev/null
# Check for package.json to find validate:frontmatter script
echo -e "\n=== Checking for validate:frontmatter in package.json ==="
find . -name "package.json" -type f | head -5Repository: juspay/neurolink
Length of output: 1402
🏁 Script executed:
#!/bin/bash
# Check if there's a package.json in docs-site and search for validate:frontmatter
if [ -f "docs-site/package.json" ]; then
echo "=== docs-site/package.json scripts ==="
cat docs-site/package.json | grep -A 30 '"scripts"'
fi
# Also check root package.json
if [ -f "package.json" ]; then
echo -e "\n=== Root package.json scripts ==="
cat package.json | grep -A 30 '"scripts"'
fiRepository: juspay/neurolink
Length of output: 3398
🏁 Script executed:
#!/bin/bash
# Search for markdown files in docs-site
echo "=== Markdown files in docs-site ==="
find docs-site -name "*.md" -type f | wc -l
# Look for frontmatter validation configuration
echo -e "\n=== Looking for frontmatter validation config ==="
find . -name "*frontmatter*" -o -name "*validate*" | grep -v node_modules | grep -v ".git"Repository: juspay/neurolink
Length of output: 229
🏁 Script executed:
#!/bin/bash
# Read the validate-frontmatter script to understand what it validates
echo "=== validate-frontmatter.ts ==="
cat docs-site/scripts/validate-frontmatter.ts
# Also search for markdown files more broadly
echo -e "\n=== All markdown files in repo ==="
find . -name "*.md" -type f | grep -v node_modules | grep -v ".git" | head -20Repository: juspay/neurolink
Length of output: 19883
🏁 Script executed:
#!/bin/bash
# Check what docs/ directory contains (it's in .gitignore, so might not be tracked)
echo "=== Checking docs/ directory ==="
ls -la docs-site/docs/ 2>/dev/null || echo "docs-site/docs/ does not exist or is empty"
# Check content directory
echo -e "\n=== Checking content/ directory ==="
find docs-site/content -type f -name "*.md" 2>/dev/null | wc -l
find docs-site/content -type f -name "*.md" 2>/dev/null | head -10
# Check if there are any recent CI failures related to frontmatter
echo -e "\n=== Searching for CI/validation configs ==="
find . -name ".github" -o -name ".gitlab-ci.yml" -o -name "*.yaml" -o -name "*.yml" | grep -E "(github|gitlab|ci|workflow)" | head -10Repository: juspay/neurolink
Length of output: 544
🏁 Script executed:
#!/bin/bash
# Check the CI workflow for frontmatter validation
echo "=== docs-pr-validation.yml ==="
cat .github/workflows/docs-pr-validation.yml
# Also check sync-docs script to understand what it does
echo -e "\n=== sync-docs.ts ==="
head -100 docs-site/scripts/sync-docs.tsRepository: juspay/neurolink
Length of output: 9398
🏁 Script executed:
#!/bin/bash
# Check if there are markdown files in the root docs/ that need syncing
echo "=== Markdown files in root docs/ ==="
find ./docs -name "*.md" -type f 2>/dev/null | wc -l
# List some of them to understand structure
echo -e "\n=== Sample markdown files ==="
find ./docs -name "*.md" -type f 2>/dev/null | head -10Repository: juspay/neurolink
Length of output: 445
🏁 Script executed:
#!/bin/bash
# Check a sample markdown file to see what frontmatter looks like
echo "=== Sample markdown file with frontmatter ==="
head -30 ./docs/advanced/analytics.md
# Check another one
echo -e "\n=== Another sample ==="
head -30 ./docs/advanced/api-reference.md
# Count files that might actually be missing frontmatter
echo -e "\n=== Files without frontmatter (checking for '---' at start) ==="
find ./docs -name "*.md" -type f -exec sh -c 'head -1 "$1" | grep -q "^---" || echo "$1"' _ {} \; 2>/dev/null | wc -lRepository: juspay/neurolink
Length of output: 1349
🏁 Script executed:
#!/bin/bash
# Look at more of sync-docs to understand the transformation
echo "=== More of sync-docs.ts ==="
tail -n +100 docs-site/scripts/sync-docs.ts | head -100
# Check if there are any files that might have issues
echo -e "\n=== Check for files with potential frontmatter issues ==="
find ./docs -name "*.md" -type f -exec grep -l "sidebar_position" {} \; 2>/dev/null | wc -lRepository: juspay/neurolink
Length of output: 3591
This comment should not be on .gitignore—it belongs on the documentation source files.
The .gitignore file contains git exclusion patterns and is unrelated to frontmatter validation. The real issue is that the markdown files in ./docs/ (approximately 269 of 320 files) are missing required frontmatter fields (title, description, sidebar_position). The sync-docs.ts script transforms MkDocs syntax to Docusaurus format but does not add frontmatter metadata.
You'll need to add proper frontmatter headers to the source markdown files before the validate:frontmatter validation will pass. Simply running the validation script will report the missing fields, but the files themselves must be updated with the required metadata.
🧰 Tools
🪛 GitHub Actions: Documentation PR Validation
[error] 1-1: Frontmatter validation failed. 271 markdown files reported errors (e.g., Missing required field: description, duplicate sidebar_position). Command 'pnpm run validate:frontmatter' exited with code 1.
🤖 Prompt for AI Agents
In `@docs-site/.gitignore` around lines 1 - 4, The validation failure is caused by
missing frontmatter (title, description, sidebar_position) in the markdown files
under ./docs; update the source files or enhance the sync-docs.ts script to
inject required Docusaurus frontmatter when converting MkDocs to Docusaurus
format: modify sync-docs.ts to parse the first heading or metadata to generate a
title, synthesize a short description (or pull from existing MkDocs metadata),
and compute/assign sidebar_position (e.g., from original order or a mapping),
then write the frontmatter block (title, description, sidebar_position) to each
output markdown so validate:frontmatter will pass. Ensure you target files in
./docs/ rather than editing .gitignore.
| posthog.init(apiKey, { | ||
| api_host: host, | ||
| // Maximum autocapture settings | ||
| autocapture: true, | ||
| capture_pageview: false, // We handle this manually for SPA navigation | ||
| capture_pageleave: true, | ||
|
|
||
| // Session recording with no masking for maximum visibility | ||
| enable_recording_console_log: true, | ||
| session_recording: { | ||
| maskAllInputs: false, | ||
| maskTextSelector: "", // No text masking | ||
| maskInputFn: null, // No input masking | ||
| }, | ||
|
|
||
| // Heatmaps and performance tracking | ||
| enable_heatmaps: true, | ||
| capture_performance: true, | ||
|
|
||
| // Persistence settings for maximum tracking | ||
| persistence: "localStorage+cookie", | ||
| cross_subdomain_cookie: true, | ||
|
|
||
| // Ignore Do Not Track header | ||
| respect_dnt: false, | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd docs-site && find . -name "Root.tsx" -type f 2>/dev/null | head -5Repository: juspay/neurolink
Length of output: 80
🏁 Script executed:
cat -n "src/theme/Root.tsx" | head -100Repository: juspay/neurolink
Length of output: 110
🏁 Script executed:
# Search for consent-related code
rg "consent|cookie.*consent|banner" docs-site --type tsx --type ts -i -A 2 -B 2Repository: juspay/neurolink
Length of output: 87
🏁 Script executed:
# Search for usePageTracking and page tracking initialization
rg "usePageTracking|capture_pageview|postHog|page.*track" docs-site --type tsx --type ts -A 3 -B 1Repository: juspay/neurolink
Length of output: 87
🏁 Script executed:
find . -name "Root.tsx" -type f 2>/dev/nullRepository: juspay/neurolink
Length of output: 90
🏁 Script executed:
# Once found, read the file without file type filter
rg "posthog.init|maskAllInputs|respect_dnt|maskTextSelector" . -A 2 -B 2Repository: juspay/neurolink
Length of output: 975
🏁 Script executed:
# Search for consent/page tracking patterns in the docs-site
rg "usePageTracking|capture_pageview|consent" . -A 3 -B 1Repository: juspay/neurolink
Length of output: 25369
🏁 Script executed:
cat -n ./docs-site/src/theme/Root.tsxRepository: juspay/neurolink
Length of output: 3757
Session recording captures unmasked data and ignores DNT.
maskAllInputs: false will record all form inputs (passwords, emails, credit card data) without masking. Combined with respect_dnt: false, this creates a significant GDPR/CCPA compliance and PII risk for a public docs site. Enable input masking, respect the DNT header, and gate session recording behind explicit user consent.
Additionally, the initial pageview is captured twice: once in the loaded callback (line 40) and again when usePageTracking() fires on component mount (line 63). Remove the duplicate in the loaded callback or add a guard to skip it.
🔒 Safer default baseline
- enable_recording_console_log: true,
- session_recording: {
- maskAllInputs: false,
- maskTextSelector: "", // No text masking
- maskInputFn: null, // No input masking
- },
+ enable_recording_console_log: false,
+ session_recording: {
+ maskAllInputs: true,
+ },
@@
- respect_dnt: false,
+ respect_dnt: true,📝 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.
| posthog.init(apiKey, { | |
| api_host: host, | |
| // Maximum autocapture settings | |
| autocapture: true, | |
| capture_pageview: false, // We handle this manually for SPA navigation | |
| capture_pageleave: true, | |
| // Session recording with no masking for maximum visibility | |
| enable_recording_console_log: true, | |
| session_recording: { | |
| maskAllInputs: false, | |
| maskTextSelector: "", // No text masking | |
| maskInputFn: null, // No input masking | |
| }, | |
| // Heatmaps and performance tracking | |
| enable_heatmaps: true, | |
| capture_performance: true, | |
| // Persistence settings for maximum tracking | |
| persistence: "localStorage+cookie", | |
| cross_subdomain_cookie: true, | |
| // Ignore Do Not Track header | |
| respect_dnt: false, | |
| posthog.init(apiKey, { | |
| api_host: host, | |
| // Maximum autocapture settings | |
| autocapture: true, | |
| capture_pageview: false, // We handle this manually for SPA navigation | |
| capture_pageleave: true, | |
| // Session recording with no masking for maximum visibility | |
| enable_recording_console_log: false, | |
| session_recording: { | |
| maskAllInputs: true, | |
| }, | |
| // Heatmaps and performance tracking | |
| enable_heatmaps: true, | |
| capture_performance: true, | |
| // Persistence settings for maximum tracking | |
| persistence: "localStorage+cookie", | |
| cross_subdomain_cookie: true, | |
| // Ignore Do Not Track header | |
| respect_dnt: true, | |
🤖 Prompt for AI Agents
In `@docs-site/src/theme/Root.tsx` around lines 10 - 35, Update the PostHog
initialization in posthog.init so session recording is privacy-safe: set
session_recording.maskAllInputs to true (and provide a non-null maskInputFn or
sensible maskTextSelector), set respect_dnt to true, and only enable
session_recording after explicit user consent gating logic (e.g., check a
consent flag before passing session_recording). Also remove the duplicate
initial pageview by deleting or guarding the pageview call inside the loaded
callback (the one referenced as loaded) so usePageTracking() on mount is the
single source of the initial pageview.
e0e15ab to
13a109f
Compare
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
13a109f to
b4c44cd
Compare
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
|
@coderabbitai ."Full review, make sure to thoroughly review all the changes, the feedback on the feedback, project patterns and everything. Understand the resolution of the items that you shared in the previous feedback and see what needs to be done better." |
|
I'll thoroughly examine:
Let me perform this comprehensive review now. ✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 6
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🤖 Fix all issues with AI agents
In `@docs-site/package.json`:
- Around line 50-51: The package.json has mismatched React type packages:
"@types/react" is ^19.2.10 and "@types/react-dom" is ^19.2.3 while runtime React
is ^18.3.1; update both "@types/react" and "@types/react-dom" entries to
versions compatible with React 18 (for example ^18.3.26 or newer) so types align
with the runtime, then reinstall (npm/yarn) to refresh lockfile and ensure
type-checking passes.
In `@docs-site/scripts/build-llms-txt.ts`:
- Around line 18-23: Centralize the docs base URL by adding a DOCS_BASE_URL
constant (e.g., const DOCS_BASE_URL = process.env.DOCS_BASE_URL ||
"https://docs.neurolink.ink") near the existing constants (DOCS_DIR, OUTPUT_DIR,
SUMMARY_OUTPUT, FULL_OUTPUT), then replace all hard-coded
"https://neurolink.juspay.io" occurrences in the script (the link-generation
code blocks that produce llms.txt / llms-full.txt — search for where
SUMMARY_OUTPUT/FULL_OUTPUT are written and where links are concatenated) to use
DOCS_BASE_URL so outputs remain configurable; ensure the env var fallback is the
new canonical URL and update every occurrence mentioned in the review (the other
link-generation sites) to reference DOCS_BASE_URL.
- Around line 110-121: The regex that strips <Tabs> blocks only matches plain
"<Tabs>" so props-bearing Tabs (e.g., <Tabs groupId=...>) aren't caught; update
the replace call that operates on the variable stripped (the stripped =
stripped.replace(/<Tabs>[\s\S]*?<\/Tabs>/g, ...) invocation) to match Tabs with
attributes (use a pattern like <Tabs\b[^>]*>[\s\S]*?<\/Tabs>), then continue
extracting code fences from the match as before so code blocks inside
prop-bearing Tabs are preserved.
- Around line 340-372: Normalize the globbed relative path before running
priority matching: create a normalizedFile (e.g., const normalizedFile =
file.split(path.sep).join('/')) inside getDocFiles() and pass normalizedFile
into getPriorityInfo() (and any other priority-matching calls such as getOrder()
if those rely on the same pattern), while keeping file/filePath for filesystem
operations; this ensures getPriorityInfo() and PRIORITY_RULES regexes match
consistently across Windows and POSIX.
In `@docs-site/src/components/Search/EmptySearch.tsx`:
- Around line 45-70: Replace the non-semantic interactive div that has
role="button" and nests a <button> with two sibling semantic buttons: make the
outer clickable area a real <button> (use the existing onRecentSearchClick
handler, remove the onKeyDown/tabIndex logic) styled with
styles.recentSearchItem and containing <SearchIcon> and the query text, and keep
the remove action as a separate sibling <button> using onRemoveRecentSearch
(stopPropagation still applies) with its aria-label; ensure both buttons use the
existing class names (styles.recentSearchItem, styles.recentSearchIcon,
styles.recentSearchText, styles.recentSearchRemove,
styles.recentSearchRemoveIcon) and preserve behavior of onRecentSearchClick and
onRemoveRecentSearch without nesting interactive elements.
- Around line 81-85: The map is calling the React hook useBaseUrl inside
QUICK_LINKS.map which violates the Rules of Hooks; fix by resolving all URLs at
the top of the EmptySearch component before rendering (e.g., create a
resolvedLinks array by mapping QUICK_LINKS and calling useBaseUrl once per item
at the component level to produce a resolvedPath property), then iterate over
resolvedLinks in the JSX and use link.resolvedPath in the Link to prop instead
of calling useBaseUrl inside the render loop.
🟡 Minor comments (15)
docs-site/src/components/CopyPageButton/index.tsx-4-6 (1)
4-6: Unusedtextprop — always copies full page HTML.The
textprop is defined in the interface but never used.handleCopyalways copiesdocument.documentElement.outerHTMLregardless of anytextvalue passed. Either use the prop or remove it.🔧 Proposed fix to use the text prop
const handleCopy = async () => { setStatus("copying"); - const pageContent = document.documentElement.outerHTML; + const pageContent = text || document.documentElement.outerHTML;Also applies to: 8-8, 42-42
docs-site/src/components/CopyPageButton/index.tsx-81-93 (1)
81-93: Add accessible titles to SVG icons.Per the static analysis hint, SVGs should include a
<title>element for screen readers. This ensures users relying on assistive technology understand the icon's purpose.♿ Proposed fix for accessibility
<svg className={styles.icon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} + aria-hidden="true" > + <title>Copied</title> <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /> </svg><svg className={styles.icon} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} + aria-hidden="true" > + <title>Copy</title> <path strokeLinecap="round" strokeLinejoin="round" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" /> </svg>Note: Using
aria-hidden="true"is appropriate here since the adjacent<span>already provides the text label. Alternatively, removearia-hiddenand keep just the<title>.Also applies to: 95-108
docs-site/src/components/PropertiesTable/index.tsx-31-33 (1)
31-33: Make the required "*" screen-reader accessible.The asterisk indicator for required fields is not announced by screen readers without additional context. Add an
aria-labelto make it accessible, and optionally include atitleattribute for sighted users:- {prop.required && <span className={styles.required}>*</span>} + {prop.required && ( + <span className={styles.required} aria-label="Required" title="Required"> + * + </span> + )}docs-site/src/components/PropertiesTable/index.tsx-37-37 (1)
37-37: Fix empty-string defaults to display as code instead of falling back to "—".The current truthy check
prop.default ?treats empty strings as falsy, causing valid empty-string defaults to be replaced with "—". Change toprop.default !== undefinedto correctly distinguish between "no default specified" (undefined) and "empty string is the default" (empty string).Proposed fix
- <td>{prop.default ? <code>{prop.default}</code> : "—"}</td> + <td>{prop.default !== undefined ? <code>{prop.default}</code> : "—"}</td>docs-site/src/components/PropertiesTable/index.tsx-21-24 (1)
21-24: Addscope="col"to header cells for accessibility.Screen readers need explicit column scope declarations to properly announce headers when reading table data cells. This aligns with WCAG Technique H63.
🔧 Proposed fix
- <th>Property</th> - <th>Type</th> - <th>Default</th> - <th>Description</th> + <th scope="col">Property</th> + <th scope="col">Type</th> + <th scope="col">Default</th> + <th scope="col">Description</th>docs-site/src/components/ProviderModelsTable/index.tsx-41-71 (1)
41-71: Add accessible labels for feature icons.
The checkmark/dash glyphs rely on visual meaning andtitleonly. Addaria-label(androle="img") so screen readers announce the state.✅ Suggested fix
- <span className={styles.supported} title="Supported"> + <span + className={styles.supported} + title="Supported" + role="img" + aria-label="Supported" + > ✓ </span> ) : ( - <span className={styles.notSupported} title="Not supported"> + <span + className={styles.notSupported} + title="Not supported" + role="img" + aria-label="Not supported" + > — </span> )}docs-site/src/components/ProviderModelsTable/index.tsx-31-33 (1)
31-33: Use a composite key to avoid duplicate rows.Line 32 uses
model.nameas the key; if the same model name appears under different providers, React can reuse the wrong row. Since bothmodel.providerandmodel.nameare available, use a composite key:Suggested fix
- <tr key={model.name}> + <tr key={`${model.provider}:${model.name}`}>docs-site/src/css/utilities.css-654-684 (1)
654-684: Fix.show-tablet-onlyso it doesn’t appear on mobile.
Right now it shows on mobile widths (<577px). Add a mobile hide rule.✅ Proposed fix
`@media` (max-width: 576px) { .markdown h1 { font-size: 1.5rem; } @@ /* Hide on mobile */ .hide-mobile { display: none; } + + /* Ensure tablet-only content is hidden on mobile */ + .show-tablet-only { + display: none; + } }Also applies to: 686-697
docs-site/src/components/GithubLink/index.tsx-24-26 (1)
24-26: Add accessible title to SVG for screen readers.The static analysis tool correctly identifies that the SVG lacks alternative text. For accessibility, add a
<title>element inside the SVG or usearia-label.🔧 Proposed fix
- <svg className={styles.icon} viewBox="0 0 24 24" fill="currentColor"> + <svg className={styles.icon} viewBox="0 0 24 24" fill="currentColor" aria-label="GitHub"> + <title>GitHub</title> <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" /> </svg>docs-site/src/components/Search/SearchModal.tsx-73-82 (1)
73-82: Guard ArrowDown when there are zero results.With an empty results array,
Math.min(..., -1)setsselectedIndexto-1, which can leave navigation in an invalid state. Clamp to0(or early‑return) when no results.🛠️ Suggested fix
const handleKeyDown = (e: KeyboardEvent) => { switch (e.key) { case "ArrowDown": e.preventDefault(); - setSelectedIndex(Math.min(selectedIndex + 1, results.length - 1)); + const maxIndex = Math.max(results.length - 1, 0); + setSelectedIndex(Math.min(selectedIndex + 1, maxIndex)); break;docs-site/src/components/SearchWrapperMobile.tsx-195-196 (1)
195-196: Fix ARIA on the loading spinner element.A
divwithout an explicit role shouldn’t carryaria-label. Give it a proper status role (or mark it decorative) to satisfy a11y rules.🛠️ Suggested fix
- {isLoading && ( - <div className={styles.loadingSpinner} aria-label="Loading" /> - )} + {isLoading && ( + <div + className={styles.loadingSpinner} + role="status" + aria-live="polite" + aria-label="Loading" + /> + )}docs-site/src/components/Search/SearchInput.tsx-42-44 (1)
42-44: Addroleattribute to loading spinner for valid ARIA usage.The
aria-labelattribute on Line 43 is not supported on plain<div>elements without a role. Addrole="status"to make the accessibility attributes valid.♿ Proposed fix
{isLoading ? ( - <div className={styles.loadingSpinner} aria-label="Loading" /> + <div className={styles.loadingSpinner} role="status" aria-label="Loading" /> ) : value ? (docs-site/src/components/Search/SearchResults.tsx-138-157 (1)
138-157: Add accessibility attributes to interactive container.The
divwithonMouseEnterlacks proper accessibility attributes. Addrole="option"(since the parent hasrole="listbox") andaria-selectedfor screen reader support:♿ Proposed fix
<div key={item.result.objectID} + role="option" + aria-selected={isSelected} style={{ position: "absolute", top: 0, left: 0, width: "100%", height: `${virtualRow.size}px`, transform: `translateY(${virtualRow.start}px)`, }} onMouseEnter={() => handleMouseEnter(item.flatIndex)} >docs-site/src/pages/index.tsx-8-147 (1)
8-147: Addaria-hidden="true"to decorative SVG icons.All SVG icons are decorative (used alongside text labels in features/buttons). Instead of adding title elements, mark them as
aria-hidden="true"to hide from assistive technology while keeping them visually present:♿ Proposed fix (apply to all icon components)
const ProviderIcon = () => ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" + aria-hidden="true" >Apply the same pattern to all icon components:
ToolsIcon,StreamIcon,ShieldIcon,CodeIcon,TerminalIcon,ImageIcon,MemoryIcon,ArrowRightIcon, andCheckIcon.docs-site/src/components/Button/index.tsx-25-37 (1)
25-37: Remove or handleasChildto avoid leaking invalid DOM attributes.
Line 28 declaresasChild, but it isn’t consumed; it’s forwarded via...propsto the<button>as a non-standard attribute. Either implement the behavior or drop the prop.🛠️ Suggested fix (remove unused prop)
-interface ButtonProps - extends React.ButtonHTMLAttributes<HTMLButtonElement>, - VariantProps<typeof buttonVariants> { - asChild?: boolean; -} +interface ButtonProps + extends React.ButtonHTMLAttributes<HTMLButtonElement>, + VariantProps<typeof buttonVariants> {}
🧹 Nitpick comments (28)
docs-site/src/components/YouTube/index.tsx (1)
8-19: Consider using YouTube's privacy-enhanced mode.Given the PR mentions PostHog privacy compliance, consider using
youtube-nocookie.cominstead ofyoutube.comfor the embed URL. This prevents YouTube from storing visitor information unless the video is played.Additionally, adding
loading="lazy"improves page performance for below-the-fold videos.♻️ Suggested improvements
export function YouTube({ id, title = "YouTube video" }: YouTubeProps) { return ( <div className={styles.wrapper}> <iframe className={styles.iframe} - src={`https://www.youtube.com/embed/${id}`} + src={`https://www.youtube-nocookie.com/embed/${id}`} title={title} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen + loading="lazy" /> </div> ); }docs-site/src/components/CopyPageButton/CopyPageButton.module.css (1)
40-44: Fragile selector: coupling CSS to SVG path data.The
:has(.icon path[d*="M5 13"])selector depends on the exactdattribute substring of the checkmark SVG. If the icon changes or is sourced from a library, this breaks silently. Consider using a class-based approach instead.♻️ Suggested refactor using a state class
In the CSS, replace the
:has()selector with a class:-/* Copied state styling */ -.button:has(.icon path[d*="M5 13"]) { +/* Copied state styling */ +.buttonCopied { color: var(--neurolink-success-text); border-color: var(--neurolink-success-border); background: var(--neurolink-success-bg); }Then in
index.tsx, apply the class conditionally:className={`${styles.button} ${status === "copied" ? styles.buttonCopied : ""} copy-button copy-button--${status}`}docs-site/src/components/ui/Kbd.tsx (1)
1-10: Preferclsxfor class merging.
Useclsxto avoid manual string concatenation and trailing spaces.♻️ Proposed refactor
-import type React from "react"; -import styles from "./Kbd.module.css"; +import type React from "react"; +import clsx from "clsx"; +import styles from "./Kbd.module.css"; @@ export function Kbd({ children, className }: KbdProps) { - return <kbd className={`${styles.kbd} ${className || ""}`}>{children}</kbd>; + return <kbd className={clsx(styles.kbd, className)}>{children}</kbd>; }docs-site/src/components/ProviderModelsTable/index.tsx (1)
37-39: Make number formatting deterministic for SSG hydration.
Line 38 usestoLocaleString()without an explicit locale, which can lead to SSR/CSR mismatch if user locale differs from build locale.✅ Suggested fix
- {model.contextWindow.toLocaleString()} + {model.contextWindow.toLocaleString("en-US")}docs-site/src/theme/prism-neurolink-light.ts (1)
38-54: Note:insertedtoken defined twice (intentional cascade).The
insertedtoken appears in the blue color group (line 49) and again in the diff highlighting section (line 111). Since prism-react-renderer applies later rules over earlier ones, the green diff styling will correctly override the blue styling forinsertedtokens. This appears intentional for diff code blocks, but consider adding a brief comment at line 49 noting that the diff-specific styling below takes precedence, to clarify the design intent for future maintainers.Also applies to: 110-116
docs-site/src/theme/prism-neurolink-dark.ts (1)
38-54: Note:insertedtoken defined twice (intentional cascade).Same pattern as the light theme—
insertedappears in the blue color group (line 49) and the diff highlighting section (line 111). The later diff-specific styling correctly overrides for diff code blocks. Consider adding a clarifying comment at line 49 for maintainability.Also applies to: 110-116
docs-site/scripts/create-version.ts (1)
31-45: Guard against invalid or prerelease versions to avoid unintended doc versions.
Currently invalid semver is coerced to0.0, and prerelease tags (e.g.,1.2.0-beta.1) still pass thepatch===0gate.🛠️ Suggested tightening
function parseVersion(version: string): { major: number; minor: number; patch: number; } { - // Handle versions like "1.2.3", "1.2.3-beta.1", etc. - const cleanVersion = version.replace(/^v/, "").split("-")[0]; - const [major, minor, patch] = cleanVersion.split(".").map(Number); + // Handle versions like "1.2.3" and detect prerelease + const cleanVersion = version.replace(/^v/, ""); + const [core] = cleanVersion.split("-"); + const [major, minor, patch] = core.split(".").map(Number); + if ([major, minor, patch].some((n) => Number.isNaN(n))) { + throw new Error(`Invalid version string: ${version}`); + } return { - major: major || 0, - minor: minor || 0, - patch: patch || 0, + major, + minor, + patch, }; } @@ - const { major, minor, patch } = parseVersion(version); + const { major, minor, patch } = parseVersion(version); + if (version.includes("-")) { + console.log(`\nSkipping prerelease version: ${version}`); + return; + }Also applies to: 82-90
docs-site/src/components/Search/SearchResultItem.tsx (1)
75-91: Array index as key is acceptable here but could be improved.The breadcrumb parts are derived from stable hierarchy levels (
lvl0,lvl1,lvl2) that don't reorder dynamically. While usingindexas a key is generally discouraged, it's acceptable in this case since the hierarchy structure is fixed per result.If you want to eliminate the linter warning, consider using the hierarchy level as the key:
♻️ Optional improvement
- {breadcrumbParts.map((part, index) => ( - <React.Fragment key={index}> + {breadcrumbParts.map((part, index) => { + const key = `lvl${index}`; + return ( + <React.Fragment key={key}> {index > 0 && (docs-site/scripts/visual-verification.py (1)
68-69: Remove unnecessary f-string prefix.Line 69 has an f-string without any placeholders. This is harmless but should be a plain string for clarity.
🔧 Suggested fix
if has_404: - print(f" ⚠ WARNING: Page may contain 404 content") + print(" ⚠ WARNING: Page may contain 404 content")docs-site/src/components/icons/ArrowIcon.tsx (1)
6-12: Consider movingrotationsobject outside the component.The
rotationsobject is static and gets recreated on every render. Moving it outside the function scope avoids unnecessary object allocations.♻️ Suggested refactor
+const ROTATIONS = { + up: "rotate(-90deg)", + down: "rotate(90deg)", + left: "rotate(180deg)", + right: "rotate(0deg)", +} as const; + export function ArrowIcon({ className, direction = "right" }: ArrowIconProps) { - const rotations = { - up: "rotate(-90deg)", - down: "rotate(90deg)", - left: "rotate(180deg)", - right: "rotate(0deg)", - }; - return ( <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true" - style={{ transform: rotations[direction] }} + style={{ transform: ROTATIONS[direction] }} >docs-site/src/components/Button/Button.module.css (2)
58-62: Consider using a design token for the primary button text color.The
color: whiteis hardcoded while other properties use CSS custom properties. For consistency and potential future theming flexibility, consider defining a token like--neurolink-text-on-accentor similar.♻️ Suggested improvement
.primary { background: var(--neurolink-accent); - color: white; + color: var(--neurolink-text-on-accent, `#ffffff`); border-color: var(--neurolink-accent); }
141-143: Hardcoded rgba value in dark mode could use a token.The outline hover background uses
rgba(59, 130, 246, 0.15)directly, whereas light mode usesvar(--neurolink-accent-subtle). Consider defining a dark mode token for consistency.docs-site/package.json (1)
11-12: Duplicate script entries for the same task.
build:llmsandbuild:llms-txtboth executetsx scripts/build-llms-txt.ts. Consider removing one to avoid confusion.♻️ Remove duplicate script
"sync-docs": "tsx scripts/sync-docs.ts", - "build:llms": "tsx scripts/build-llms-txt.ts", "build:llms-txt": "tsx scripts/build-llms-txt.ts",docs-site/src/css/tokens.css (1)
29-34: Icon token naming starts at level 2.The icon color tokens start at
--neurolink-icons-2rather than--neurolink-icons-1. If this is intentional (e.g., level 1 is reserved or implicit), consider adding a brief comment. Otherwise, starting at 1 would be more intuitive.docs-site/src/components/icons/CloseIcon.tsx (1)
7-13: Consider adding default dimensions to prevent layout shifts.The SVG lacks explicit
widthandheightattributes. While the parent component or CSS typically controls sizing, adding default dimensions (e.g.,width={24} height={24}) provides a fallback and prevents potential layout shifts if the icon renders before styles load.♻️ Add default dimensions
<svg className={className} fill="none" viewBox="0 0 24 24" + width={24} + height={24} stroke="currentColor" aria-hidden="true" >docs-site/src/components/CardGrid/CardGrid.module.css (2)
5-22: Consider adding a default column configuration.The grid relies on
data-colsattribute for column definition. Ifdata-colsis not set (or set to an unexpected value), the grid won't have explicit column rules. Adding a default ensures graceful fallback.♻️ Add default column configuration
.grid { display: grid; gap: var(--spacing-4); margin: var(--spacing-6) 0; + grid-template-columns: repeat(3, 1fr); /* Default fallback */ }
117-119: Dark mode icon background uses hardcoded rgba value.Similar to Button.module.css, the dark mode icon background uses
rgba(59, 130, 246, 0.15)directly. For consistency, consider using a token or the same value defined elsewhere (this matches the outline hover in Button dark mode)..github/workflows/docs-deploy.yml (1)
25-31: Consider addingtimeout-minutesto prevent runaway builds.The build job has no timeout configured. If the build hangs (e.g., due to a dependency issue or infinite loop), it could consume runner minutes indefinitely.
💡 Suggested improvement
build: name: Build Documentation runs-on: ubuntu-latest + timeout-minutes: 15 defaults: run: working-directory: docs-sitedocs-site/sidebars.ts (1)
37-48: Minor inconsistency:collapsedproperty is omitted.For consistency with other categories (e.g., MCP, Memory, Workflows), consider explicitly setting
collapsed: trueon the SDK category. This isn't a bug since Docusaurus defaults to collapsed, but explicit configuration improves maintainability.💅 Suggested improvement
{ type: "category", label: "SDK", + collapsed: true, items: [docs-site/docusaurus.config.ts (1)
22-23: Consider stricter broken link handling for production builds.Setting
onBrokenLinksandonBrokenAnchorsto"warn"allows builds to succeed with broken links, which could lead to 404s in production. Consider using"throw"for production or at least in CI to catch issues before deployment.💡 Suggested approach
- onBrokenLinks: "warn", - onBrokenAnchors: "warn", + onBrokenLinks: process.env.NODE_ENV === "production" ? "throw" : "warn", + onBrokenAnchors: process.env.NODE_ENV === "production" ? "throw" : "warn",docs-site/src/components/SearchWrapperMobile.tsx (1)
66-73: Clear the focus timer on close.If the panel closes quickly, the pending timeout can still fire and focus the input after close. Consider cleaning it up.
♻️ Suggested refactor
useEffect(() => { if (isOpen) { - setTimeout(() => { + const timer = setTimeout(() => { inputRef.current?.focus(); }, 100); + return () => clearTimeout(timer); } }, [isOpen]);docs-site/src/css/components.css (3)
228-238: Consider removing!importantdeclarations.The
!importantdeclarations on lines 231-232 and 236-237 for sidebar caret icons can lead to specificity issues and make future maintenance harder. If these are needed to override Docusaurus defaults, consider using more specific selectors instead.
16-18: Consider using CSS variables for hardcoded colors.Several rgba values are hardcoded (e.g.,
rgba(10, 10, 10, 0.85)on line 17,rgba(255, 255, 255, 0.8)implied in other contexts). For consistency with the design token system, consider defining these as CSS variables intokens.css.Also applies to: 69-74
97-141: Inline SVG icons are duplicated between themes.The GitHub and Discord SVG icons are defined twice (once for light, once for dark) with only the fill color differing. Consider using CSS
filterorcurrentColorto reduce duplication and simplify theme switching.♻️ Example approach using currentColor
.header-github-link::before { content: ""; width: 24px; height: 24px; display: flex; - background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23333' d='M12 .297c-6.63... + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='currentColor' d='M12 .297c-6.63... no-repeat; + /* Use CSS filter for color inversion in dark mode instead of duplicate SVG */ } - -[data-theme="dark"] .header-github-link::before { - background: url("data:image/svg+xml,...") no-repeat; -}REQUIRED_ENVIRONMENT_VARIABLES.md (1)
13-14: Minor: Capitalize "GitHub" consistently.Per standard branding, "GitHub" should be capitalized with a capital "H" in these locations:
- Line 13:
.github/workflows/docs-version.yml→ The path is correct, but surrounding text should use "GitHub"- Line 183:
.github/workflows/release.yml→ Same note- Line 296:
.github/workflows/→ Same noteThis is a minor documentation polish item.
Also applies to: 183-183, 296-296
docs-site/src/components/Steps/index.tsx (1)
24-24: Consider semantic flexibility for step titles.The hardcoded
<h4>for step titles may cause heading hierarchy issues if Steps are used in different page contexts. Consider making the heading level configurable or using a semantically neutral element like<div>with appropriate styling.♻️ Optional: Make heading level configurable
interface StepItemProps { title: string; children: React.ReactNode; + as?: 'h3' | 'h4' | 'h5' | 'div'; } -export function StepItem({ title, children }: StepItemProps) { +export function StepItem({ title, children, as: Component = 'h4' }: StepItemProps) { return ( <div className={styles.step}> <div className={styles.stepIndicator}> <span className={styles.stepNumber} /> </div> <div className={styles.stepContent}> - <h4 className={styles.stepTitle}>{title}</h4> + <Component className={styles.stepTitle}>{title}</Component> <div className={styles.stepDescription}>{children}</div> </div> </div> ); }docs-site/src/components/SidebarBadge.tsx (1)
46-60: Badge parsing utility works correctly but has implicit priority ordering.The
parseBadgeFromLabelfunction returns the first matching badge type. SinceObject.entriespreserves insertion order in modern JavaScript engines, the current order (new→beta→deprecated→experimental) defines implicit priority. If a label somehow contained multiple badge markers, only the first would be detected. This is likely acceptable behavior, but consider documenting it if badge priority matters.docs-site/src/components/Search/SearchResults.tsx (1)
44-57: MemoizeflatItemsto prevent unnecessary re-renders.
flatItemsis recreated on every render, causingrowVirtualizerto recalculate sizes and the scroll-to-index effect to re-run unnecessarily. Memoize it withuseMemo:♻️ Proposed fix
+import { useVirtualizer } from "@tanstack/react-virtual"; +import React, { useCallback, useEffect, useMemo, useRef } from "react"; - // Flatten results for virtualization while keeping track of indices - const flatItems: Array< - | { type: "header"; group: string } - | { type: "result"; result: SearchResult; flatIndex: number } - > = []; - let flatIndex = 0; - - for (const { group, items } of groupedResults) { - flatItems.push({ type: "header", group }); - for (const result of items) { - flatItems.push({ type: "result", result, flatIndex }); - flatIndex++; - } - } + // Flatten results for virtualization while keeping track of indices + const flatItems = useMemo(() => { + const items: Array< + | { type: "header"; group: string } + | { type: "result"; result: SearchResult; flatIndex: number } + > = []; + let flatIndex = 0; + + for (const { group, items: groupItems } of groupedResults) { + items.push({ type: "header", group }); + for (const result of groupItems) { + items.push({ type: "result", result, flatIndex }); + flatIndex++; + } + } + return items; + }, [groupedResults]);
| // Configuration | ||
| const DOCS_DIR = path.resolve(__dirname, "../docs"); | ||
| const OUTPUT_DIR = path.resolve(__dirname, "../static"); | ||
| const SUMMARY_OUTPUT = path.join(OUTPUT_DIR, "llms.txt"); | ||
| const FULL_OUTPUT = path.join(OUTPUT_DIR, "llms-full.txt"); | ||
|
|
There was a problem hiding this comment.
Make the docs base URL configurable to avoid stale links.
This script hard-codes https://neurolink.juspay.io, but the PR objective says docs now live at https://docs.neurolink.ink. The generated llms*.txt would publish outdated links. Centralize a base URL (env-driven) so the output stays consistent with deployment.
🔧 Proposed fix
const DOCS_DIR = path.resolve(__dirname, "../docs");
const OUTPUT_DIR = path.resolve(__dirname, "../static");
const SUMMARY_OUTPUT = path.join(OUTPUT_DIR, "llms.txt");
const FULL_OUTPUT = path.join(OUTPUT_DIR, "llms-full.txt");
+const DOCS_BASE_URL = process.env.DOCS_BASE_URL ?? "https://docs.neurolink.ink";
+const LLMS_URL = `${DOCS_BASE_URL}/llms.txt`;
+const LLMS_FULL_URL = `${DOCS_BASE_URL}/llms-full.txt`;
@@
- lines.push(`Full documentation: https://neurolink.juspay.io/llms-full.txt`);
+ lines.push(`Full documentation: ${LLMS_FULL_URL}`);
@@
- lines.push("- Full text: https://neurolink.juspay.io/llms-full.txt");
- lines.push("- Web docs: https://neurolink.juspay.io");
+ lines.push(`- Full text: ${LLMS_FULL_URL}`);
+ lines.push(`- Web docs: ${DOCS_BASE_URL}`);
lines.push("- GitHub: https://github.com/juspay/neurolink");
@@
- lines.push(`Summary version: https://neurolink.juspay.io/llms.txt`);
+ lines.push(`Summary version: ${LLMS_URL}`);
@@
- lines.push("For the latest documentation, visit: https://neurolink.juspay.io");
+ lines.push(`For the latest documentation, visit: ${DOCS_BASE_URL}`);Also applies to: 421-423, 505-508, 529-531, 581-582
🤖 Prompt for AI Agents
In `@docs-site/scripts/build-llms-txt.ts` around lines 18 - 23, Centralize the
docs base URL by adding a DOCS_BASE_URL constant (e.g., const DOCS_BASE_URL =
process.env.DOCS_BASE_URL || "https://docs.neurolink.ink") near the existing
constants (DOCS_DIR, OUTPUT_DIR, SUMMARY_OUTPUT, FULL_OUTPUT), then replace all
hard-coded "https://neurolink.juspay.io" occurrences in the script (the
link-generation code blocks that produce llms.txt / llms-full.txt — search for
where SUMMARY_OUTPUT/FULL_OUTPUT are written and where links are concatenated)
to use DOCS_BASE_URL so outputs remain configurable; ensure the env var fallback
is the new canonical URL and update every occurrence mentioned in the review
(the other link-generation sites) to reference DOCS_BASE_URL.
| // Remove JSX components but try to extract meaningful content | ||
| stripped = stripped.replace(/<Tabs>[\s\S]*?<\/Tabs>/g, (match) => { | ||
| // Extract code blocks from tabs | ||
| const codeBlocks = match.match(/```[\s\S]*?```/g) || []; | ||
| return codeBlocks.join("\n\n"); | ||
| }); | ||
| stripped = stripped.replace(/<TabItem[^>]*>/g, ""); | ||
| stripped = stripped.replace(/<\/TabItem>/g, ""); | ||
|
|
||
| // Remove other React components | ||
| stripped = stripped.replace(/<[A-Z][a-zA-Z]*[^>]*\/>/g, ""); | ||
| stripped = stripped.replace(/<[A-Z][a-zA-Z]*[^>]*>[\s\S]*?<\/[A-Z][a-zA-Z]*>/g, ""); |
There was a problem hiding this comment.
Preserve <Tabs ...> content when extracting code blocks.
Docusaurus <Tabs> almost always carries props (e.g., groupId, defaultValue). The current regex only matches <Tabs> with no attributes, so those blocks fall through to the generic component strip and lose their content (including code fences). This drops meaningful docs from llms*.txt.
🔧 Proposed fix
- stripped = stripped.replace(/<Tabs>[\s\S]*?<\/Tabs>/g, (match) => {
+ stripped = stripped.replace(/<Tabs\b[^>]*>[\s\S]*?<\/Tabs>/g, (match) => {
// Extract code blocks from tabs
const codeBlocks = match.match(/```[\s\S]*?```/g) || [];
return codeBlocks.join("\n\n");
});📝 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.
| // Remove JSX components but try to extract meaningful content | |
| stripped = stripped.replace(/<Tabs>[\s\S]*?<\/Tabs>/g, (match) => { | |
| // Extract code blocks from tabs | |
| const codeBlocks = match.match(/```[\s\S]*?```/g) || []; | |
| return codeBlocks.join("\n\n"); | |
| }); | |
| stripped = stripped.replace(/<TabItem[^>]*>/g, ""); | |
| stripped = stripped.replace(/<\/TabItem>/g, ""); | |
| // Remove other React components | |
| stripped = stripped.replace(/<[A-Z][a-zA-Z]*[^>]*\/>/g, ""); | |
| stripped = stripped.replace(/<[A-Z][a-zA-Z]*[^>]*>[\s\S]*?<\/[A-Z][a-zA-Z]*>/g, ""); | |
| // Remove JSX components but try to extract meaningful content | |
| stripped = stripped.replace(/<Tabs\b[^>]*>[\s\S]*?<\/Tabs>/g, (match) => { | |
| // Extract code blocks from tabs | |
| const codeBlocks = match.match(/ |
🤖 Prompt for AI Agents
In `@docs-site/scripts/build-llms-txt.ts` around lines 110 - 121, The regex that
strips <Tabs> blocks only matches plain "<Tabs>" so props-bearing Tabs (e.g.,
<Tabs groupId=...>) aren't caught; update the replace call that operates on the
variable stripped (the stripped = stripped.replace(/<Tabs>[\s\S]*?<\/Tabs>/g,
...) invocation) to match Tabs with attributes (use a pattern like
<Tabs\b[^>]*>[\s\S]*?<\/Tabs>), then continue extracting code fences from the
match as before so code blocks inside prop-bearing Tabs are preserved.
| async function getDocFiles(): Promise<DocFile[]> { | ||
| const pattern = "**/*.md"; | ||
| const files = await glob(pattern, { cwd: DOCS_DIR, nodir: true }); | ||
|
|
||
| const docFiles: DocFile[] = []; | ||
|
|
||
| for (const file of files) { | ||
| // Skip excluded directories | ||
| const parts = file.split(path.sep); | ||
| if (parts.some((part) => EXCLUDED_DIRS.includes(part))) { | ||
| continue; | ||
| } | ||
|
|
||
| const filePath = path.join(DOCS_DIR, file); | ||
| const rawContent = fs.readFileSync(filePath, "utf-8"); | ||
| const { data, content } = matter(rawContent); | ||
|
|
||
| const section = getSection(file); | ||
| const title = extractTitle(data, content, file); | ||
| const strippedContent = stripFormatting(content); | ||
| const { priority, includeInSummary } = getPriorityInfo(file); | ||
| const order = getOrder(section, data, path.basename(file), priority); | ||
|
|
||
| docFiles.push({ | ||
| relativePath: file, | ||
| section, | ||
| title, | ||
| content: strippedContent, | ||
| rawContent: content, | ||
| priority, | ||
| includeInSummary, | ||
| order, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if .mdx files exist under docs-site/docs
echo "=== Checking for .mdx files ==="
find docs-site/docs -name "*.mdx" -type f 2>/dev/null | head -20
echo ""
echo "Total .mdx files:"
find docs-site/docs -name "*.mdx" -type f 2>/dev/null | wc -lRepository: juspay/neurolink
Length of output: 112
🏁 Script executed:
#!/bin/bash
# Find PRIORITY_RULES definition to understand its structure
echo "=== Searching for PRIORITY_RULES ==="
rg 'PRIORITY_RULES' docs-site/scripts/build-llms-txt.ts -B 2 -A 10Repository: juspay/neurolink
Length of output: 1399
🏁 Script executed:
#!/bin/bash
# Examine the getSection() and getPriorityInfo() functions
echo "=== Examining getSection() function ==="
ast-grep --pattern 'function getSection($_) {
$$$
}'Repository: juspay/neurolink
Length of output: 99
🏁 Script executed:
#!/bin/bash
# Look at the full context around PRIORITY_RULES and getPriorityInfo
rg 'getPriorityInfo|getSection|PRIORITY_RULES' docs-site/scripts/build-llms-txt.ts -B 2 -A 5Repository: juspay/neurolink
Length of output: 1546
🏁 Script executed:
#!/bin/bash
# Search for .mdx references and Docusaurus mentions
echo "=== Searching for .mdx references ==="
rg '\.mdx|mdx' docs-site/scripts/ --type ts -i
echo ""
echo "=== Checking package.json or config for Docusaurus/mdx ==="
rg 'docusaurus|mdx|markdown' docs-site/ --type json -i | head -20Repository: juspay/neurolink
Length of output: 2073
🏁 Script executed:
#!/bin/bash
# Check the full context of how glob results are used
cat -n docs-site/scripts/build-llms-txt.ts | sed -n '340,380p'Repository: juspay/neurolink
Length of output: 1450
🏁 Script executed:
#!/bin/bash
# Verify the exact behavior: check if the code runs successfully on current state
# and see what files are being processed
rg 'const files = await glob' docs-site/scripts/build-llms-txt.ts -B 2 -A 15Repository: juspay/neurolink
Length of output: 628
Normalize paths before getPriorityInfo() matching to ensure cross-platform compatibility.
The file variable from glob() uses OS-specific path separators (\ on Windows, / on Unix), but PRIORITY_RULES patterns exclusively use / (e.g., /^getting-started\//, /^sdk\/index\.md$/). On Windows, this breaks regex matching: "getting-started\readme.md" won't match /^getting-started\//. Normalizing paths to use / ensures consistent rule matching across platforms.
🛠️ Proposed fix
const section = getSection(file);
const title = extractTitle(data, content, file);
const strippedContent = stripFormatting(content);
- const { priority, includeInSummary } = getPriorityInfo(file);
+ const normalizedPath = file.split(path.sep).join("/");
+ const { priority, includeInSummary } = getPriorityInfo(normalizedPath);
@@
- relativePath: file,
+ relativePath: normalizedPath,📝 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.
| async function getDocFiles(): Promise<DocFile[]> { | |
| const pattern = "**/*.md"; | |
| const files = await glob(pattern, { cwd: DOCS_DIR, nodir: true }); | |
| const docFiles: DocFile[] = []; | |
| for (const file of files) { | |
| // Skip excluded directories | |
| const parts = file.split(path.sep); | |
| if (parts.some((part) => EXCLUDED_DIRS.includes(part))) { | |
| continue; | |
| } | |
| const filePath = path.join(DOCS_DIR, file); | |
| const rawContent = fs.readFileSync(filePath, "utf-8"); | |
| const { data, content } = matter(rawContent); | |
| const section = getSection(file); | |
| const title = extractTitle(data, content, file); | |
| const strippedContent = stripFormatting(content); | |
| const { priority, includeInSummary } = getPriorityInfo(file); | |
| const order = getOrder(section, data, path.basename(file), priority); | |
| docFiles.push({ | |
| relativePath: file, | |
| section, | |
| title, | |
| content: strippedContent, | |
| rawContent: content, | |
| priority, | |
| includeInSummary, | |
| order, | |
| }); | |
| async function getDocFiles(): Promise<DocFile[]> { | |
| const pattern = "**/*.md"; | |
| const files = await glob(pattern, { cwd: DOCS_DIR, nodir: true }); | |
| const docFiles: DocFile[] = []; | |
| for (const file of files) { | |
| // Skip excluded directories | |
| const parts = file.split(path.sep); | |
| if (parts.some((part) => EXCLUDED_DIRS.includes(part))) { | |
| continue; | |
| } | |
| const filePath = path.join(DOCS_DIR, file); | |
| const rawContent = fs.readFileSync(filePath, "utf-8"); | |
| const { data, content } = matter(rawContent); | |
| const section = getSection(file); | |
| const title = extractTitle(data, content, file); | |
| const strippedContent = stripFormatting(content); | |
| const normalizedPath = file.split(path.sep).join("/"); | |
| const { priority, includeInSummary } = getPriorityInfo(normalizedPath); | |
| const order = getOrder(section, data, path.basename(file), priority); | |
| docFiles.push({ | |
| relativePath: normalizedPath, | |
| section, | |
| title, | |
| content: strippedContent, | |
| rawContent: content, | |
| priority, | |
| includeInSummary, | |
| order, | |
| }); |
🤖 Prompt for AI Agents
In `@docs-site/scripts/build-llms-txt.ts` around lines 340 - 372, Normalize the
globbed relative path before running priority matching: create a normalizedFile
(e.g., const normalizedFile = file.split(path.sep).join('/')) inside
getDocFiles() and pass normalizedFile into getPriorityInfo() (and any other
priority-matching calls such as getOrder() if those rely on the same pattern),
while keeping file/filePath for filesystem operations; this ensures
getPriorityInfo() and PRIORITY_RULES regexes match consistently across Windows
and POSIX.
b4c44cd to
ff7395e
Compare
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
ff7395e to
f24e6d7
Compare
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
|
@coderabbitai Full review, make sure to thoroughly review all the changes, the feedback on the feedback, project patterns and everything. Understand the resolution of the items that you shared in the previous feedback and see what needs to be done better. The comments where we have resolved things you need to reply to those comments with the current status after the resolution. |
🧩 Analysis chain
Let me first gather detailed information about the PR structure and existing review comments: After gathering this information, I'll trigger a comprehensive review that will:
🏁 Script executed: Length of output: 3001 Let me fetch the detailed review comments to understand what was previously flagged: 🏁 Script executed: Length of output: 95074 🏁 Script executed: Length of output: 3251 🏁 Script executed: Length of output: 4615 Let me examine the current state of key files that had issues flagged in the previous review: 🏁 Script executed: Length of output: 4738 🏁 Script executed: Length of output: 4059 🏁 Script executed: Length of output: 4041 🏁 Script executed: Length of output: 2798 #!/bin/bash
echo "=== Checking EmptySearch.tsx for quick links and useBaseUrl ==="
sed -n '10,25p' docs-site/src/components/Search/EmptySearch.tsx
sed -n '75,95p' docs-site/src/components/Search/EmptySearch.tsx
echo -e "\n=== Checking useAlgoliaSearch.ts for race condition fix ==="
sed -n '130,175p' docs-site/src/hooks/useAlgoliaSearch.ts
sed -n '225,235p' docs-site/src/hooks/useAlgoliaSearch.ts#!/bin/bash
echo "=== Checking prism-neurolink-light.ts for duplicate token types ==="
sed -n '50,85p' docs-site/src/theme/prism-neurolink-light.ts
echo -e "\n=== Checking broken link in docs/advanced/index.md ==="
sed -n '240,250p' docs/advanced/index.md
echo -e "\n=== Checking broken link in google-vertex.md ==="
sed -n '952,962p' docs/getting-started/providers/google-vertex.md#!/bin/bash
echo "=== Checking path normalization in build-llms-txt.ts ==="
sed -n '355,395p' docs-site/scripts/build-llms-txt.ts
echo -e "\n=== Checking if docs/guides/migration/index.md has frontmatter ==="
head -15 docs/guides/migration/index.md#!/bin/bash
echo "=== Checking accessibility issues in EmptySearch.tsx ==="
sed -n '40,72p' docs-site/src/components/Search/EmptySearch.tsx
echo -e "\n=== Summary of package.json dependency issues ==="
echo "React runtime versions:"
cat docs-site/package.json | jq '.dependencies.react, .dependencies["react-dom"]'
echo -e "\nReact type versions:"
cat docs-site/package.json | jq '.devDependencies["@types/react"], .devDependencies["@types/react-dom"]'✅ Actions performedFull review triggered. |
Complete migration of documentation site from MkDocs to Docusaurus v3.7.0 with enhanced features, security improvements, and comprehensive fixes. - Migrated from MkDocs to Docusaurus v3.7.0 - New documentation site structure in docs-site/ - Enhanced search with Algolia integration - PostHog analytics with GDPR/CCPA compliance - GitHub Actions workflows for deployment and versioning - Support for both /docs and /llms-full.txt endpoints - Fixed XSS vulnerability in search results (DOMPurify sanitization) - PostHog privacy compliance (GDPR/CCPA) - Clipboard API error handling for browser compatibility - Fixed grid cards content loss during migration - Fixed search race condition with request ID tracking - Fixed GitHub token workflow (DOCS_BOT_TOKEN support) - Fixed Docusaurus plugin version compatibility (3.7.0) - Fixed Prism syntax highlighting duplicate tokens - Fixed 3 broken documentation links - Fixed quick links in search empty state - Updated domain references (neurolink.juspay.io → docs.neurolink.ink) - Added: 300+ files in docs-site/ (Docusaurus installation) - Modified: 13 files across security, configuration, and documentation - Deleted: mkdocs.yml and MkDocs configuration - Created REQUIRED_ENVIRONMENT_VARIABLES.md (DOCS_BOT_TOKEN setup) - Created PR792_EXECUTION_PLAN.md (implementation strategy) - Created PR792_COMPLETION_SUMMARY.md (comprehensive fix report) - All 888/888 tests passing - TypeScript compilation: 0 errors - Security scan: No critical vulnerabilities - Build validation: All checks passed
f24e6d7 to
496ce27
Compare
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
|
🎉 This PR is included in version 8.41.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Complete migration of documentation platform from MkDocs to Docusaurus 3.7.0 with enhanced styling, automation, and developer experience improvements.
Major Changes:
Infrastructure:
Breaking Changes:
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.