-
Notifications
You must be signed in to change notification settings - Fork 1
Add tool UI components and GSAP animations #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @ssdeanx, your pull request is larger than the review limit of 150000 diff characters
|
🤖 Hi @ssdeanx, I've received your request, and I'm working on it now! You can track my progress in the logs for more details. |
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughPull request expands the AI tools UI component ecosystem with multiple new specialized card components (browser, calculator, sandbox, execa, polygon tools), refactors landing hero animation from Framer Motion to GSAP with ScrollTrigger effects, strengthens type safety by removing suppression comments, reorganizes tool exports through a central index, updates TypeScript and package configurations, and improves internal typing across several utility and tool modules. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
Summary of ChangesHello @ssdeanx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request focuses on a significant overhaul and expansion of the user interface for various AI-powered tools. It introduces a more robust and interactive experience by integrating new animation libraries, creating dedicated UI components for diverse tool functionalities, and enhancing existing ones with improved data presentation and user controls. The changes aim to make tool outputs more understandable and actionable for users. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
🤖 I'm sorry @ssdeanx, but I was unable to process your request. Please see the logs for more details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive tool UI components for displaying agent execution results and integrates GSAP animations. The changes include new UI components for calculator, browser automation, E2B sandbox, Polygon financial data, and command execution tools, alongside improvements to existing tool components.
Changes:
- Adds 5 new tool UI component files (polygon-tools, execa-tool, calculator-tool, browser-tool, and AGENTS.md documentation)
- Completely rewrites e2b-sandbox-tool.tsx with enhanced interactive features
- Updates 8 existing tool UI components with formatting and type casting changes
- Replaces Framer Motion with GSAP animations in landing-hero.tsx
- Updates package dependencies (Mastra, AI SDK, React Query)
- Modifies tsconfig.json configuration
- Adds proper TypeScript interfaces for GitHub commits
Reviewed changes
Copilot reviewed 18 out of 20 changed files in this pull request and generated 23 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Configuration updates with duplicate/redundant entries |
| package.json | Dependency version bumps and addition of @xterm/xterm |
| src/utils/streamUtils.ts | Changed unknown to any for type parameter |
| src/mastra/tools/github.ts | Added GitHubCommit interface and improved type safety |
| src/components/ai-elements/tools/*.tsx | 8 files reformatted, 5 new tool components added |
| src/components/ai-elements/tools/types.ts | Added 3 new calculator tool types |
| src/components/ai-elements/tool.tsx | Removed @ts-expect-error comments and minor fixes |
| src/components/ai-elements/confirmation.tsx | Removed @ts-expect-error comments |
| app/components/landing-hero.tsx | Replaced Framer Motion with GSAP animations |
Comments suppressed due to low confidence (1)
app/components/landing-hero.tsx:1
- The ScrollTrigger's
onUpdatecallback runs on every scroll event and directly manipulates the DOM viagsap.set. Consider using GSAP'sinvalidateOnRefreshoption or moving the animation property to the ScrollTrigger configuration itself usinganimationproperty for better performance.
'use client'
| export async function handleTextStream( | ||
| streamResult: | ||
| | StreamTextResult<ToolSet, unknown> | ||
| | StreamTextResult<ToolSet, any> |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed from unknown to any, which bypasses type safety. The unknown type is safer as it requires type checking before use. If the actual type is genuinely dynamic, consider using a generic type parameter or a union of known types instead.
| | StreamTextResult<ToolSet, any> | |
| | StreamTextResult<ToolSet, unknown> |
| <CardHeader className="pb-3"> | ||
| <CardTitle className="flex items-center gap-2 text-sm"> | ||
| <Globe className="size-4 animate-pulse" /> | ||
| Scraping {(input as any).url}... |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple as any type assertions indicate the input type isn't properly defined or used. Since WebScraperToolProps defines input: WebScraperUITool['input'], these properties should be accessible without type casting. This suggests either the type definition is incorrect or the component is receiving incorrectly typed data.
| <CardContent> | ||
| <div className="text-sm text-muted-foreground"> | ||
| Extracting content with selector:{' '} | ||
| {(input as any).selector || 'entire page'} |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple as any type assertions indicate the input type isn't properly defined or used. Since WebScraperToolProps defines input: WebScraperUITool['input'], these properties should be accessible without type casting. This suggests either the type definition is incorrect or the component is receiving incorrectly typed data.
| <CardHeader className="pb-3"> | ||
| <CardTitle className="flex items-center gap-2 text-sm"> | ||
| <TreePine className="size-4 animate-pulse" /> | ||
| Extracting site map from {(input as any).url}... |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repeated use of as any type casting for input properties. The SiteMapExtractorUITool['input'] type should define these properties, eliminating the need for type assertions.
| Crawling up to depth {(input as any).maxDepth ?? 2}, max{' '} | ||
| {(input as any).maxPages ?? 50} pages |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repeated use of as any type casting for input properties. The SiteMapExtractorUITool['input'] type should define these properties, eliminating the need for type assertions.
| if (!output) { | ||
| return <LoadingCard title={`Computing matrix ${operationInput ?? 'operation'}`} icon={<Loader2 className="size-4 animate-spin" />} /> | ||
| } | ||
| if (output && typeof output === 'object' && 'error' in output) { |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'output' always evaluates to true.
| if (output && typeof output === 'object' && 'error' in output) { | |
| if (typeof output === 'object' && 'error' in output) { |
| export function BrowserToolCard({ input, output, errorText }: BrowserToolCardProps) { | ||
| if (errorText) return <ErrorCard title="Browser Tool Failed" message={errorText} /> | ||
| if (!output) return <LoadingCard title={`Browsing ${(input as any).url}...`} icon={<Loader2 className="size-4 animate-spin" />} /> | ||
| if (output && typeof output === 'object' && 'error' in output) { |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'output' always evaluates to true.
| if (output && typeof output === 'object' && 'error' in output) { | |
| if (typeof output === 'object' && 'error' in (output as any)) { |
| </CardTitle> | ||
| <div className="flex items-center gap-2"> | ||
| <Badge variant="secondary" className="text-xs">{formatBytes(contentLength)}</Badge> | ||
| {output && (output as any).message && <Badge variant="outline" className="text-xs">message</Badge>} |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'output' always evaluates to true.
| {output && (output as any).message && <Badge variant="outline" className="text-xs">message</Badge>} | |
| {(output as any).message && <Badge variant="outline" className="text-xs">message</Badge>} |
| export function ClickAndExtractCard({ input, output, errorText }: ClickAndExtractCardProps) { | ||
| if (errorText) return <ErrorCard title="Click & Extract Failed" message={errorText} /> | ||
| if (!output) return <LoadingCard title={`Clicking ${(input as any).clickSelector} on ${(input as any).url}...`} icon={<Loader2 className="size-4 animate-spin" />} /> | ||
| if (output && typeof output === 'object' && 'error' in output) return <ErrorCard title="Click & Extract Failed" message={(output as any).error ?? 'Unknown error'} /> |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'output' always evaluates to true.
| if (output && typeof output === 'object' && 'error' in output) return <ErrorCard title="Click & Extract Failed" message={(output as any).error ?? 'Unknown error'} /> | |
| if (typeof output === 'object' && 'error' in output) return <ErrorCard title="Click & Extract Failed" message={(output as any).error ?? 'Unknown error'} /> |
| const [query, setQuery] = useState('') | ||
| if (errorText) return <ErrorCard title="Search Failed" message={errorText} /> | ||
| if (!output) return <LoadingCard title={`Searching for ${(input as any).query}...`} icon={<Loader2 className="size-4 animate-spin" />} /> | ||
| if (output && typeof output === 'object' && 'error' in output) return <ErrorCard title="Search Failed" message={(output as any).error ?? 'Unknown error'} /> |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'output' always evaluates to true.
| if (output && typeof output === 'object' && 'error' in output) return <ErrorCard title="Search Failed" message={(output as any).error ?? 'Unknown error'} /> | |
| if (typeof output === 'object' && 'error' in (output as any)) return <ErrorCard title="Search Failed" message={(output as any).error ?? 'Unknown error'} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant number of new UI components for rendering tool outputs, which greatly enhances the user experience. The refactoring of the e2b-sandbox-tool into smaller, more manageable components is a particularly welcome improvement for maintainability. Additionally, the migration from Framer Motion to GSAP for the landing page animation is well-executed. The main area for improvement across the new components is the heavy reliance on type-casting (as any), which undermines the benefits of TypeScript. Addressing this would significantly improve the robustness and maintainability of the new code. I've also noted a few other areas for improvement regarding React best practices, configuration file cleanup, and type safety.
| ScrollTrigger.create({ | ||
| trigger: heroRef.current, | ||
| start: 'top bottom', | ||
| end: 'bottom top', | ||
| scrub: 1, | ||
| onUpdate: (self) => { | ||
| const progress = self.progress | ||
| gsap.set(heroRef.current, { | ||
| y: -progress * 50, // Parallax effect | ||
| scale: 1 + progress * 0.05, // Slight zoom | ||
| }) | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ScrollTrigger instance is created within the useGSAP hook but is not being cleaned up. While useGSAP handles cleanup for animations created through its context, ScrollTrigger.create() is a direct call and its instances need to be manually killed to prevent memory leaks when the component unmounts. You can do this by returning a cleanup function from the useGSAP callback.
const st = ScrollTrigger.create({
trigger: heroRef.current,
start: 'top bottom',
end: 'bottom top',
scrub: 1,
onUpdate: (self) => {
const progress = self.progress
gsap.set(heroRef.current, {
y: -progress * 50, // Parallax effect
scale: 1 + progress * 0.05, // Slight zoom
})
},
});
return () => {
st.kill();
};
| errorText?: string | ||
| } | ||
|
|
||
| export function ScreenshotCard({ input, output, errorText }: ScreenshotCardProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throughout the new tool components, there's extensive use of type casting with as any, such as (input as any).url. This practice bypasses TypeScript's type safety features, increasing the risk of runtime errors and making the code harder to maintain. Since the component props are already typed (e.g., input: ScreenshotUITool['input']), you should be able to access properties directly. If the inferred types are not precise enough, consider refining them in types.ts or using type guards instead of casting to any.
| useEffect(() => { | ||
| // Update display text when output changes | ||
| setDisplayText((output as { message?: string })?.message ?? '') | ||
| }, [(output as { message?: string })?.message]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dependency array for this useEffect hook is [(output as { message?: string })?.message]. This is not a stable dependency and will cause the effect to run on every render because a new object is created. To correctly track changes, you should depend on the output object itself or a memoized value derived from it.
| }, [(output as { message?: string })?.message]) | |
| }, [output]) |
| )} | ||
| > | ||
| {errorText && <div>{errorText}</div>} | ||
| {(Boolean(errorText)) && <div>{errorText}</div>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of (Boolean(errorText)) for conditional rendering is unnecessary and less idiomatic than a simple truthiness check. In JSX, you can directly use errorText && ... which is more concise and achieves the same result.
| {(Boolean(errorText)) && <div>{errorText}</div>} | |
| {errorText && <div>{errorText}</div>} |
| // Some tools put results in different fields; try common ones | ||
| const results = (output as any).organic_results || (output as any).results || (output as any).data || [] | ||
|
|
||
| const filtered = query ? results.filter((r: any) => JSON.stringify(r).toLowerCase().includes(query.toLowerCase())) : results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filtering search results by stringifying the entire object (JSON.stringify(r)) is inefficient and can lead to inaccurate matches if the query string appears in an unexpected property. It's more performant and reliable to filter against specific, relevant fields like title, link, and snippet.
const filtered = query ? results.filter((r: any) =>
(r.title?.toLowerCase().includes(query.toLowerCase())) ||
(r.link?.toLowerCase().includes(query.toLowerCase())) ||
(r.snippet?.toLowerCase().includes(query.toLowerCase()))
) : results
| export { BatchWebScraperTool } from './batch-web-scraper-tool' | ||
| export { SiteMapExtractorTool } from './site-map-extractor-tool' | ||
| export { LinkExtractorTool } from './link-extractor-tool' | ||
| export { | ||
| FinancialQuoteCard, | ||
| FinancialChart, | ||
| CompanyProfileCard, | ||
| BrowserToolCard, ClickAndExtractCard, | ||
| FillFormCard, | ||
| GoogleSearchCard, | ||
| MonitorPageCard, PdfGeneratorCard, ScreenshotCard | ||
| } from './browser-tool' | ||
| export { CalculatorCard, MatrixCalculatorCard, UnitConverterCard } from './calculator-tool' | ||
| export { | ||
| CheckFileExistsCard, CreateDirectoryCard, CreateSandboxCard, DeleteFileCard, GetFileInfoCard, GetFileSizeCard, ListFilesCard, RunCodeCard, RunCommandCard, WatchDirectoryCard, WriteFileCard, | ||
| WriteFilesCard | ||
| } from './e2b-sandbox-tool' | ||
| export { ExecaToolCard } from './execa-tool' | ||
| export { | ||
| CompanyProfileCard, FinancialChart, FinancialQuoteCard | ||
| } from './financial-tools' | ||
| export { | ||
| RepositoryCard, | ||
| PullRequestList, | ||
| IssueCard, | ||
| CommitHistoryList, | ||
| CommitHistoryList, IssueCard, PullRequestList, RepositoryCard | ||
| } from './github-tools' | ||
| export { WeatherCard, ForecastView } from './weather-tool' | ||
| export { LinkExtractorTool } from './link-extractor-tool' | ||
| export { PolygonCryptoAggregatesCard, PolygonCryptoQuotesCard, PolygonCryptoSnapshotsCard, PolygonStockAggregatesCard, PolygonStockFundamentalsCard, PolygonStockQuotesCard } from './polygon-tools' | ||
| export { | ||
| ArxivPaperCard, | ||
| SearchResultList, | ||
| NewsCarousel, | ||
| ArxivPaperCard, NewsCarousel, SearchResultList | ||
| } from './research-tools' | ||
| export { SiteMapExtractorTool } from './site-map-extractor-tool' | ||
| export * from './types' | ||
| export { ForecastView, WeatherCard } from './weather-tool' | ||
| export { WebScraperTool } from './web-scraper-tool' | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exports in this index file are not in a consistent order. For better long-term maintainability and easier navigation, it's a good practice to keep these exports sorted alphabetically.
export {
ArxivPaperCard, NewsCarousel, SearchResultList
} from './research-tools'
export { BatchWebScraperTool } from './batch-web-scraper-tool'
export {
BrowserToolCard, ClickAndExtractCard,
FillFormCard,
GoogleSearchCard,
MonitorPageCard, PdfGeneratorCard, ScreenshotCard
} from './browser-tool'
export { CalculatorCard, MatrixCalculatorCard, UnitConverterCard } from './calculator-tool'
export {
CheckFileExistsCard, CreateDirectoryCard, CreateSandboxCard, DeleteFileCard, GetFileInfoCard, GetFileSizeCard, ListFilesCard, RunCodeCard, RunCommandCard, WatchDirectoryCard, WriteFileCard,
WriteFilesCard
} from './e2b-sandbox-tool'
export { ExecaToolCard } from './execa-tool'
export {
CompanyProfileCard, FinancialChart, FinancialQuoteCard
} from './financial-tools'
export {
CommitHistoryList, IssueCard, PullRequestList, RepositoryCard
} from './github-tools'
export { LinkExtractorTool } from './link-extractor-tool'
export { PolygonCryptoAggregatesCard, PolygonCryptoQuotesCard, PolygonCryptoSnapshotsCard, PolygonStockAggregatesCard, PolygonStockFundamentalsCard, PolygonStockQuotesCard } from './polygon-tools'
export { SiteMapExtractorTool } from './site-map-extractor-tool'
export * from './types'
export { ForecastView, WeatherCard } from './weather-tool'
export { WebScraperTool } from './web-scraper-tool'| case 'sources': | ||
| case 'member': | ||
| return type as any | ||
| return type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const commits = (res.data ?? []).map((c: GitHubCommit) => ({ | ||
| sha: c.sha, | ||
| message: c.commit?.message ?? '', | ||
| author: (c.commit?.author?.name as string) ?? null, | ||
| author: c.commit?.author?.name ?? null, | ||
| date: c.commit?.author?.date ?? '', | ||
| url: c.html_url ?? '', | ||
| })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| export async function handleTextStream( | ||
| streamResult: | ||
| | StreamTextResult<ToolSet, unknown> | ||
| | StreamTextResult<ToolSet, any> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing the generic type from unknown to any weakens type safety. While this might resolve a compilation issue, it's generally better to avoid any. Consider reverting to unknown and using type guards where the value is accessed, or find a more specific type if possible.
| | StreamTextResult<ToolSet, any> | |
| | StreamTextResult<ToolSet, unknown> |
| "include": [ | ||
| "next-env.d.ts", | ||
| "vitest.config.ts", | ||
| "mdx-components.tsx", | ||
| "eslint.config.js", | ||
| "prettier.config.js", | ||
| "eslint-config-next.d.ts", | ||
| "postcss.config.mjs", | ||
| "next.config.ts", | ||
| "components.json", | ||
| "instrumentation.ts", | ||
| "/.next/types/**/*.ts", | ||
| "/.next/dev/types/**/*.ts", | ||
| "app/**/*.ts", | ||
| "/app/**/*.ts", | ||
| "app/**/*.tsx", | ||
| "/app/**/*.tsx", | ||
| "src/mastra/workflows/*.ts", | ||
| "/app/**/*.mdx ", | ||
| "src/**/*.ts", | ||
| "/src/**/*.js", | ||
| "/src/**/*.tsx", | ||
| "src/**/*.ts", | ||
| "src/**/*.tsx", | ||
| "src/mastra/types/**/*.d.ts", | ||
| "types/**/*.d.ts", | ||
| "utils/**/*.ts", | ||
| "/lib/**/*.ts", | ||
| "utils/**/*.tsx", | ||
| "styles/**/*.ts", | ||
| "styles/**/*.tsx", | ||
| "ui/**/*.ts", | ||
| "/ui/**/*.ts", | ||
| "/ui/**/*.tsx", | ||
| "ui/**/*.tsx", | ||
| "lib/**/*.ts", | ||
| "/lib/**/*.ts", | ||
| "/lib/**/*.tsx", | ||
| "lib/**/*.tsx", | ||
| "hooks/**/*.ts", | ||
| "/hooks/**/*.ts", | ||
| "/hooks/**/*.tsx", | ||
| "hooks/**/*.tsx", | ||
| "pages/**/*.ts", | ||
| "pages/**/*.tsx", | ||
| "convex/**/*.ts", | ||
| "/convex/**/*.ts", | ||
| "/convex/**/*.tsx", | ||
| "convex/**/*.tsx", | ||
| "convex/**/*.d.ts", | ||
| "convex/mastra/**/*.ts", | ||
| "convex/**/*.js", | ||
| // Tests are excluded from the main typecheck run to avoid typechecking test-only imports | ||
| // that may pull in declaration files with unsupported syntax from node_modules. | ||
| "types/**/*.d.ts", | ||
| "/tests/**/*.ts", | ||
| "/types/**.d.ts", | ||
| "/public/", | ||
| ".next/types/**/*.ts", | ||
| ".next/dev/types/**/*.ts" | ||
| ], | ||
| "exclude": [ | ||
| "node_modules", | ||
| "/node_modules/", | ||
| "/node_modules/**/*.js", | ||
| "/node_modules/**/*.json", | ||
| "node_modules/**/*.ts", | ||
| "node_modules/**/*.tsx", | ||
| "node_modules/**/*.d.ts", | ||
| "/node_modules/**/*.tsx", | ||
| "/node_modules/**/*.ts", | ||
| "/node_modules/**/*.d.ts", | ||
| "/dist", | ||
| "dist", | ||
| ".mastra", | ||
| "/.mastra/**/*", | ||
| ".github", | ||
| ".cursor", | ||
| "public", | ||
| "coverage", | ||
| "scripts", | ||
| ".kilocode", | ||
| "/.kilocode/**/*", | ||
| ".next", | ||
| "/.next", | ||
| "tests", | ||
| "/tests/**/*.ts", | ||
| "/tests/**/*.tsx", | ||
| "docs", | ||
| "/docs/**/*md", | ||
| "memory-bank", | ||
| "/memory-bank/**/*.md", | ||
| "node_modules/@crawlee/http/internals/http-crawler.d.ts", | ||
| "/node_modules/@crawlee/http/internals/http-crawler.d.ts", | ||
| "node_modules/@mdx-js/loader/index.d.cts", | ||
| "/node_modules/@mdx-js/loader/index.d.cts" | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The include and exclude arrays contain many redundant, overlapping, and incorrectly formatted paths (e.g., leading slashes, duplicates). This can make the configuration confusing and harder to maintain. It's recommended to clean this up for clarity and to ensure the compiler is including/excluding exactly what you intend. For example, you have duplicates like src/**/*.ts and paths with leading slashes like /app/**/*.ts which might not behave as expected depending on the baseUrl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 39
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/components/ai-elements/confirmation.tsx (1)
103-109: Critical type safety issue: Code uses state values not defined in AI SDK v6.The code uses
'approval-requested','approval-responded', and'output-denied'as validToolUIPart['state']values (lines 104, 123-125, 145-147 in confirmation.tsx; lines 43, 44, 47 in tool.tsx), but AI SDK v6.0.38 only defines:'input-streaming','input-available','output-available', and'output-error'.In strict TypeScript mode, the
Record<ToolUIPart['state'], string>andRecord<ToolUIPart['state'], ReactNode>types in tool.tsx (lines 40, 50) should fail type checking with the extra state values. Either add type suppression comments where needed, or extend/augment theToolUIParttype definition to include the approval workflow states.src/components/ai-elements/tools/types.ts (1)
176-176: Remove commented-out code.Per coding guidelines, commented-out code should be removed. Use version control history if the code needs to be recovered later.
♻️ Proposed fix
-//export type ConvertDataFormatUITool = InferUITool<typeof convertDataFormatTool>src/components/ai-elements/tool.tsx (1)
100-107: Usedata-[state=closed]:for consistency withdata-[state=open]:.While the
closed:custom variant is configured inapp/globals.css, the class names mixclosed:withdata-[state=open]:for the same component state. For clarity and consistency, usedata-[state=closed]:instead ofclosed:to mirror the explicitdata-[state=open]:syntax, making the Radix UI state binding immediately obvious.
🤖 Fix all issues with AI agents
In `@app/components/landing-hero.tsx`:
- Around line 14-44: The GSAP block in useGSAP (the timeline and
ScrollTrigger.create) is unscoped and never cleaned up; change the selector
'.hero-element' to operate only within this component by selecting elements from
heroRef.current (e.g., const elems =
heroRef.current.querySelectorAll('.hero-element') or
gsap.utils.toArray(heroRef.current.querySelectorAll(...))) and use those elems
in tl.fromTo, store the ScrollTrigger instance and the timeline in local vars
(e.g., const tl = gsap.timeline(); const st = ScrollTrigger.create(...)) and
return a cleanup that kills both (st.kill(); tl.kill(); or
ScrollTrigger.getAll/filter+kill) inside the same useGSAP callback so the
ScrollTrigger and timeline are torn down on unmount/remount.
In `@package.json`:
- Line 112: The package.json entry for the dependency "@xterm/xterm" should be
removed because it is unused; delete the "@xterm/xterm": "^6.0.0" line from
package.json, run the project's package manager to update the lockfile (npm
install or yarn install) and rebuild, and search for any imports or references
to "@xterm/xterm" (e.g., in components or terminal-related utilities) to confirm
no runtime usage before committing the change.
In `@src/components/ai-elements/tool.tsx`:
- Line 162: The JSX uses an unnecessary explicit Boolean coercion with extra
parentheses in the expression (Boolean(errorText)) — simplify the conditional
render in the component by removing Boolean(...) and the redundant parentheses
and use a truthy check on errorText instead (i.e., replace the expression that
renders the error div by checking errorText directly); locate the JSX line
referencing errorText in the component (the conditional rendering that outputs
<div>{errorText}</div>) and update it to use a simple truthy check.
In `@src/components/ai-elements/tools/AGENTS.md`:
- Line 3: Replace the H1 heading "# Tools Directory
(`/src/components/ai-elements/tools`)" in AGENTS.md with an H2 (change the
leading "#" to "##") so the document uses H2 for the main section; edit the
heading text "Tools Directory (`/src/components/ai-elements/tools`)" to keep
content identical but prefixed with "##" instead of "#".
In `@src/components/ai-elements/tools/browser-tool.tsx`:
- Around line 418-422: The displayed search result fields contain redundant
fallbacks: replace the duplicated expressions so the title uses the single value
r.title (or a sensible fallback like r.name if needed) instead of r.title ??
r.title, and simplify the snippet expression to r.snippet ?? r.description (or
r.description ?? r.snippet) instead of r.snippet ?? r.description ?? r.snippet;
keep the link line (r.link ?? r.url ?? r.displayed_link) as-is. Update the JSX
inside the component where those expressions appear (the divs referencing
r.title and r.snippet) to remove the redundant fallbacks.
- Around line 159-162: Replace the plain <img> rendering of the screenshot with
Next.js Image to follow component guidelines: import Image from "next/image" in
browser-tool.tsx and render <Image src={dataUrl} alt={`screenshot-${(input as
any).url}`} unoptimized priority className="rounded border max-h-[400px]
object-contain w-full" and provide either explicit width/height props or use
fill with a container to preserve sizing; keep the base64/dataUrl logic and the
Content length display unchanged. Ensure the Image usage matches Next/Image API
(use unoptimized for data URLs) and remove the existing <img> tag where
dataUrl/base64 is used.
- Around line 111-112: The seven exported card component functions
(ScreenshotCard, PdfGeneratorCard, BrowserToolCard, ClickAndExtractCard,
FillFormCard, GoogleSearchCard, MonitorPageCard) lack explicit return type
annotations; update each function signature to declare a React return type
(e.g., : JSX.Element or : React.ReactElement) so they conform to the public API
typing guidelines, ensuring any existing React imports support the chosen type
and keeping the implementations unchanged.
In `@src/components/ai-elements/tools/calculator-tool.tsx`:
- Around line 30-78: Extract the duplicated ErrorCard, LoadingCard, and
downloadFile implementations from calculator-tool.tsx (and the same copies in
execa-tool.tsx and polygon-tools.tsx) into a single shared module (e.g.,
src/components/ai-elements/tools/shared-helpers.tsx), export the three symbols
(ErrorCard, LoadingCard, downloadFile) from that module, then replace the local
definitions in each tool file with imports of those symbols and remove the
duplicated implementations so all tools use the shared helpers.
- Line 12: The file imports the Input component but never uses it; remove the
unused import line "import { Input } from '@/ui/input'" from
src/components/ai-elements/tools/calculator-tool.tsx, or if the intention was to
render a text field in the CalculatorTool component, replace the unused import
by actually using the Input component inside the CalculatorTool render (refer to
the Input symbol and the CalculatorTool component/function) so there are no
unused imports.
- Line 84: The declared but unused prop toolCallId in the CalculatorCardProps,
UnitConverterCardProps, and MatrixCalculatorCardProps interfaces (and in the
corresponding component props for CalculatorCard, UnitConverterCard,
MatrixCalculatorCard) should be removed or actually used; pick one approach:
either remove toolCallId from each interface and from the components' prop
destructuring and any passed callers, or wire it into the DOM for
tracking/accessibility (e.g., add it as a data attribute or id/aria attribute on
the root element of each component such as data-tool-call-id={toolCallId} or
id={`tool-call-${toolCallId}`}); update any callers to stop passing the prop if
removed, and adjust types so no unused prop remains.
- Around line 300-315: The rendering assumes `result` is a 2D array which can
cause a runtime error when `row.map` is called; in the JSX branch that uses
`hasResult`/`showJson` (around the mapping of `result` rows) normalize and
validate `result` before rendering (e.g. compute a safe `rows` variable: if
`Array.isArray(result)` and `Array.isArray(result[0])` use `result` as-is, else
if `Array.isArray(result)` wrap it as `[result]`, otherwise render a fallback),
and update the mapping to only call `row.map` when `Array.isArray(row)` (render
non-array values as a single cell) so `row.map` cannot throw in
`calculator-tool.tsx` (affecting the hasResult/showJson rendering block).
- Line 26: The import statement in calculator-tool.tsx currently brings in
unused symbols useEffect and useRef; remove those two from the import so only
the used items (useState and type ChangeEvent) are imported, and verify the
CalculatorTool component (or any functions in this file) still compile without
references to useEffect/useRef.
In `@src/components/ai-elements/tools/e2b-sandbox-tool.tsx`:
- Around line 105-115: Change the return type of mapToBundledLanguage from any
to a concrete union of supported Shiki bundled language strings (or the Shiki
BundledLanguage type) so callers get proper type-safety; update the function
signature (mapToBundledLanguage(lang?: string):
'bash'|'typescript'|'javascript'|'python'|'json'|'html' or
mapToBundledLanguage(lang?: string): BundledLanguage) and import BundledLanguage
from 'shiki' if you choose that option, leaving the internal logic unchanged but
ensuring all return branches conform to the chosen type.
- Around line 142-143: These exported React component functions lack explicit
return type annotations; update each exported card component (CreateSandboxCard,
WriteFileCard, WriteFilesCard, ListFilesCard, DeleteFileCard,
CreateDirectoryCard, GetFileInfoCard, CheckFileExistsCard, GetFileSizeCard,
WatchDirectoryCard, RunCommandCard, RunCodeCard) to declare an explicit return
type of React.ReactElement (or React.ReactElement | null if they may return
null) on their function signature, e.g. change `export function
CreateSandboxCard(props: CreateSandboxCardProps)` to include `:
React.ReactElement` (or `: React.ReactElement | null`) and import React if
necessary.
- Around line 288-337: ListFilesCard currently calls useState after early
returns which breaks React hook ordering; move the hook declaration const
[fileQuery, setFileQuery] = useState('') to the top of the ListFilesCard
function (immediately after the function signature) so it always runs on every
render before any conditional returns (errorText or !output), then keep the
subsequent filteredFiles logic and JSX unchanged but referencing
fileQuery/setFileQuery as before.
- Around line 662-688: The RunCommandCard component currently calls React hooks
(useState, useRef, useEffect) after early returns, which violates the Rules of
Hooks; move all hook calls (the useState declarations for stdoutQuery,
stderrQuery, showLineNumbers, autoScrollStdout, autoScrollStderr, the useRef
declarations stdoutBottomRef and stderrBottomRef, and the useEffect blocks that
scroll) to the top of the RunCommandCard function body so they always run before
any conditional returns (keep the early-return checks for errorText, missing
output, and 'error' in output but perform them after the hooks are declared);
ensure derived values like stdout, stderr, stdoutFiltered and stderrFiltered are
computed after the hooks are declared to preserve behavior.
In `@src/components/ai-elements/tools/execa-tool.tsx`:
- Around line 134-135: The current isLikelySuccess heuristic (variable
isLikelySuccess inspecting (output as { message?: string })?.message) is
fragile; update the logic in execa-tool.tsx to prefer an explicit exit code or
flag: first check for an explicit numeric exit code on output (e.g., (output as
any).exitCode or (output as any).code) and use exitCode === 0 for success; if no
exit code is present, either remove the heuristic entirely or only apply it when
an opt-in property is set on output (e.g., (output as any).useSuccessHeuristic
=== true) — adjust the isLikelySuccess assignment to reflect this order of
precedence and ensure you reference the output variable and the isLikelySuccess
identifier when making the change.
- Around line 104-110: The repeated verbose casts of input reduce
readability—create a single typed alias at the top of the component such as
const cmdInput = input as { command: string; args?: string[]; cwd?: string } and
replace all occurrences in functions like copyCommand and the blocks referenced
(around copyCommand, lines ~127-128, and ~158-168) to use cmdInput.command,
cmdInput.args, and cmdInput.cwd; ensure you update all 8+ cast sites to use this
alias so the code is clearer and maintainable.
- Line 12: Remove the unused FileText import from
src/components/ai-elements/tools/execa-tool.tsx by deleting FileText from the
import list where icons are imported (so the import statement no longer
references FileText), and run a quick linter/build to verify no other references
to FileText remain in the file (no changes to any functions or components like
the Execa tool component are needed).
- Line 22: The ExecaToolCardProps type declares toolCallId but ExecaToolCard
doesn't use it; remove toolCallId from ExecaToolCardProps and from the
ExecaToolCard props destructuring (and from any places that pass it) to
eliminate the unused prop, or if it is required for future behavior, explicitly
use it inside ExecaToolCard (e.g., include it in logging, data-attributes, or as
a key) — update the ExecaToolCardProps declaration and the ExecaToolCard
component signature accordingly to keep props consistent.
- Around line 85-88: The effect's dependency uses a complex expression which can
be re-evaluated each render; extract the message value into a stable local
variable (e.g., const message = (output as { message?: string })?.message ?? '')
and then change the useEffect in execa-tool.tsx to depend on that variable and
call setDisplayText(message) inside the effect so the dependency array contains
the simple identifier "message" instead of the complex expression.
In `@src/components/ai-elements/tools/github-tools.tsx`:
- Around line 18-29: The top import block imports unused React types
(JSXElementConstructor, Key, ReactElement, ReactNode, ReactPortal) that aren't
referenced in this file; remove those specific named imports from the import
type statement (the line starting with "import type { JSXElementConstructor,
Key, ReactElement, ReactNode, ReactPortal } from 'react'") so only needed types
remain or delete the entire unused import line if nothing else is required,
ensuring no other code references those symbols (check functions/getters like
GetIssueUITool, ListPullRequestsUITool, ListRepositoriesUITool for used types).
- Around line 83-87: Replace the loose any types by defining proper TypeScript
interfaces for the CommitHistoryList props and commit items: create a
CommitHistoryInput/Output (or a single CommitHistoryProps) interface used as the
generic parameters for ToolProps in the CommitHistoryList signature and a Commit
type for each entry in the commits array; then update the map callback so it
uses commit: Commit (and any other places referencing commit fields) instead of
any. Ensure the new interfaces include the fields referenced in the JSX (e.g.,
author, message, sha, date) and update the function signature
CommitHistoryList({ input, output, errorText }: ToolProps<CommitHistoryInput,
CommitHistoryOutput>) accordingly.
- Around line 414-420: The UI currently uses an unsafe cast (input as
any).issueNumber when rendering the loading state; instead, update the
GetIssueUITool input type to include issueNumber (or otherwise widen its
interface) and access input.issueNumber directly without casting, and then
replace occurrences in the component (e.g., within the conditional that checks
output and the loader text) to use input.issueNumber so TypeScript can validate
the property access.
In `@src/components/ai-elements/tools/link-extractor-tool.tsx`:
- Line 46: The code uses unsafe any casts when accessing input and output in
LinkExtractorUITool rendering (e.g., the expression (input as { url: string
}).url and other any casts at the noted lines); change these to strongly typed
definitions by declaring an explicit prop/interface for the tool input (e.g.,
type LinkExtractorInput = { url: string }) and use LinkExtractorUITool['output']
(or a defined type alias) for the output shape, update the component/function
signatures to accept those types, and replace all (input as any) and (output as
any) casts with the new typed variables so TypeScript enforces safety across the
usages referenced (including the occurrences around the shown lines).
- Around line 134-143: The anchor rendered when link.isValid (the <a> wrapping
<ExternalLink />) lacks an accessible name; update the anchor in
link-extractor-tool component so it provides one—either add an aria-label like
aria-label={`Open ${link.href} in a new tab`} or include visually hidden text
inside the anchor (e.g., a span with sr-only describing the action) while
keeping target="_blank" and rel; ensure the label describes the
destination/action and use the same anchor that renders the ExternalLink icon.
- Around line 8-19: The LinkExtractorToolProps interface declares toolCallId but
it's never used in the LinkExtractorTool component; remove the unused prop by
deleting toolCallId from the LinkExtractorToolProps definition and any related
type references, and update any callers to stop passing toolCallId (or,
alternatively, if tracking is needed, destructure toolCallId in the
LinkExtractorTool function signature and use it where appropriate); specifically
edit LinkExtractorToolProps and the LinkExtractorTool component signature to
keep props in sync.
In `@src/components/ai-elements/tools/polygon-tools.tsx`:
- Around line 91-101: The six Polygon card components declare an unused prop
`toolCallId` — update each component (PolygonStockQuotesCard,
PolygonStockAggregatesCard, PolygonStockFundamentalsCard,
PolygonCryptoQuotesCard, PolygonCryptoAggregatesCard,
PolygonCryptoSnapshotsCard) to either remove `toolCallId` from the props
signature and all related type annotations/call sites, or consistently use it
(for example add it to the rendered root element as a data attribute like
data-tool-call-id or include it in a visible/debug label); pick one approach and
apply it across all six components so the prop is no longer declared but unused.
- Line 115: The current filter uses
JSON.stringify(p).toLowerCase().includes(query) causing heavy serialization;
update the filtered logic in polygon-tools.tsx to avoid JSON.stringify by
normalizing the query once (e.g., q = query.toLowerCase()) and checking only
known fields on the polygon object (e.g., p.t or p.timestamp for time, p.c or
p.close or p.price for value) by converting each candidate field to string,
lowercasing, and testing .includes(q); apply the same change to the other
similar occurrence in this file so filtering is field-specific and avoids
serializing every object.
- Around line 17-27: Remove the unused icon imports Clock, ExternalLink, and
Search from the import list in
src/components/ai-elements/tools/polygon-tools.tsx (the import that currently
includes AlertCircle, ChartBar, Clock, CopyIcon, Download, ExternalLink,
FileText, Loader2, Search) so only used symbols remain (e.g., AlertCircle,
ChartBar, CopyIcon, Download, FileText, Loader2); update the import statement
accordingly and run the linter/TS build to verify no other references to Clock,
ExternalLink, or Search exist.
- Around line 117-123: The empty catch in the async copyRaw function swallows
clipboard errors; update the catch block in copyRaw (which calls
navigator.clipboard.writeText and then setCopied/setTimeout) to at least surface
errors during development — e.g. log the caught error with console.error or
processLogger.error (guarded by a NODE_ENV !== 'production' check) or add a
clear comment explaining why the error is intentionally ignored so failures are
discoverable while non-fatal.
In `@src/components/ai-elements/tools/site-map-extractor-tool.tsx`:
- Line 9: The prop "toolCallId" is declared but unused in the
SiteMapExtractorTool component; remove it from the component props/type (e.g.,
SiteMapExtractorToolProps or the function signature of SiteMapExtractorTool) and
from any places that pass it in, or if intended to be used, wire it into the
component logic where the tool call is initiated (e.g., include it in the call
payload or logging). Update the prop type/interface and all call sites
accordingly so there are no unused prop declarations.
- Line 5: Remove the unused icon imports ExternalLink and Link from the
lucide-react import in site-map-extractor-tool.tsx so only the used icons
(FileText and TreePine) remain; update the import statement that currently
imports ExternalLink, FileText, Link, TreePine to import only FileText and
TreePine and run lint/TS check to ensure no other references to ExternalLink or
Link exist.
- Around line 88-90: The UI shows "Depth: -Infinity" when pages is empty because
Math.max(...pages.map(...)) returns -Infinity; update the computation in the
SiteMapExtractor component (where Badge displays Depth and pages is mapped) to
handle an empty pages array—compute a safe max like using Math.max(0,
...pages.map(p => p.depth)) or conditionally set maxDepth = pages.length ?
Math.max(...pages.map(p => p.depth)) : 0 before rendering the Badge so it never
displays -Infinity.
In `@src/components/ai-elements/tools/web-scraper-tool.tsx`:
- Line 17: The prop toolCallId declared in the component props interface of
src/components/ai-elements/tools/web-scraper-tool.tsx is unused; either remove
toolCallId from the props interface and from any call sites, or use it in the
WebScraperTool component body (for example attach it to the root element as a
key/data attribute or aria attribute, or pass it into the existing
analytics/logging call such as sendAnalyticsEvent or onScrapeStart) so the
identifier is actually consumed; update the props interface and component
implementation consistently and adjust any callers accordingly.
- Around line 67-72: Destructuring sets extractedData from content which may be
undefined, causing extractedData.length and extractedData.map to throw; change
the destructure to provide a safe default (e.g., const { extractedData = [],
rawContent, markdownContent } = content) or add guards before using
extractedData (check Array.isArray(extractedData) or use (extractedData ||
[]).length and (extractedData || []).map) so references to extractedData.length
and extractedData.map in this component (web-scraper-tool.tsx) are safe.
- Line 11: Remove the unused "Link" import from lucide-react in the
web-scraper-tool.tsx module; locate the import statement importing Link
(alongside other icons) at the top of the file and delete Link from that import
list (or remove the import entirely if nothing else is imported), ensuring the
WebScraperTool component references remain unchanged.
In `@src/utils/streamUtils.ts`:
- Around line 100-105: Change the explicit any used in the streamResult type
inside handleTextStream: update StreamTextResult<ToolSet, any> to either
StreamTextResult<ToolSet, unknown> or simply StreamTextResult<ToolSet> (to use
the SDK default), since the function only reads the textStream
AsyncIterable<string> property and never relies on the second generic parameter;
update the function signature accordingly where streamResult is declared to
restore stronger typing for StreamTextResult and keep references to
handleTextStream, StreamTextResult, ToolSet, and textStream intact.
In `@tsconfig.json`:
- Around line 34-94: The tsconfig.json include array contains duplicate and
inconsistent path patterns (e.g., duplicate "src/**/*.ts" and "types/**/*.d.ts",
and conflicting/test paths like "/tests/**/*.ts" vs earlier exclusions, plus
mixed leading-slash entries such as "/app/**/*.ts" and "app/**/*.ts"); clean
this by deduplicating entries, normalizing paths to remove leading slashes (use
"app/**/*.ts" not "/app/**/*.ts"), remove any test globs that contradict your
exclusions (remove "/tests/**/*.ts" if tests are supposed to be excluded), and
consolidate similar entries (keep single "src/**/*.ts" and single
"types/**/*.d.ts") within the "include" array so only canonical, non-conflicting
patterns remain.
♻️ Duplicate comments (1)
src/components/ai-elements/tools/polygon-tools.tsx (1)
65-88: DuplicateLoadingCardandErrorCardhelpersThese helper components are duplicated across multiple tool files in this PR. As noted in calculator-tool.tsx, extract these into a shared module.
| useGSAP(() => { | ||
| const tl = gsap.timeline() | ||
|
|
||
| // Stagger entrance animation for child elements | ||
| tl.fromTo( | ||
| '.hero-element', | ||
| { opacity: 0, y: 20 }, | ||
| { | ||
| opacity: 1, | ||
| y: 0, | ||
| duration: 0.6, | ||
| ease: 'power2.out', | ||
| stagger: 0.1, | ||
| } | ||
| ) | ||
|
|
||
| // Add ScrollTrigger for parallax effect | ||
| ScrollTrigger.create({ | ||
| trigger: heroRef.current, | ||
| start: 'top bottom', | ||
| end: 'bottom top', | ||
| scrub: 1, | ||
| onUpdate: (self) => { | ||
| const progress = self.progress | ||
| gsap.set(heroRef.current, { | ||
| y: -progress * 50, // Parallax effect | ||
| scale: 1 + progress * 0.05, // Slight zoom | ||
| }) | ||
| }, | ||
| }) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Missing cleanup for ScrollTrigger and potential scope issue with class selector.
Two concerns with this GSAP implementation:
-
The
useGSAPhook is called without a scope ref or dependency array. While@gsap/react'suseGSAPhandles cleanup automatically when given a scope, using a class selector like.hero-elementwithout scoping may animate elements outside this component. -
The
ScrollTrigger.create()instance should be killed on cleanup to prevent memory leaks if the component remounts.
♻️ Recommended fix: Scope animations and ensure proper cleanup
export function LandingHero() {
const heroRef = useRef<HTMLDivElement>(null)
+ const containerRef = useRef<HTMLElement>(null)
- useGSAP(() => {
+ useGSAP(() => {
const tl = gsap.timeline()
// Stagger entrance animation for child elements
tl.fromTo(
'.hero-element',
{ opacity: 0, y: 20 },
{
opacity: 1,
y: 0,
duration: 0.6,
ease: 'power2.out',
stagger: 0.1,
}
)
// Add ScrollTrigger for parallax effect
- ScrollTrigger.create({
+ const st = ScrollTrigger.create({
trigger: heroRef.current,
start: 'top bottom',
end: 'bottom top',
scrub: 1,
onUpdate: (self) => {
const progress = self.progress
gsap.set(heroRef.current, {
y: -progress * 50, // Parallax effect
scale: 1 + progress * 0.05, // Slight zoom
})
},
})
- })
+
+ return () => {
+ st.kill()
+ }
+ }, { scope: containerRef })
return (
- <section className="relative h-[800px] w-full overflow-hidden border-b border-border bg-background">
+ <section ref={containerRef} className="relative h-[800px] w-full overflow-hidden border-b border-border bg-background">🤖 Prompt for AI Agents
In `@app/components/landing-hero.tsx` around lines 14 - 44, The GSAP block in
useGSAP (the timeline and ScrollTrigger.create) is unscoped and never cleaned
up; change the selector '.hero-element' to operate only within this component by
selecting elements from heroRef.current (e.g., const elems =
heroRef.current.querySelectorAll('.hero-element') or
gsap.utils.toArray(heroRef.current.querySelectorAll(...))) and use those elems
in tl.fromTo, store the ScrollTrigger instance and the timeline in local vars
(e.g., const tl = gsap.timeline(); const st = ScrollTrigger.create(...)) and
return a cleanup that kills both (st.kill(); tl.kill(); or
ScrollTrigger.getAll/filter+kill) inside the same useGSAP callback so the
ScrollTrigger and timeline are torn down on unmount/remount.
| "@tanstack/react-table": "^8.21.3", | ||
| "@tslab/typescript-for-tslab": "^5.1.3", | ||
| "@vercel/otel": "^2.1.0", | ||
| "@xterm/xterm": "^6.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify xterm usage in codebase
echo "=== Searching for xterm imports and usage ==="
rg -n "xterm" --type=ts --type=tsx -g '!package*.json'Repository: ssdeanx/AgentStack
Length of output: 152
🏁 Script executed:
#!/bin/bash
# Verify xterm usage in codebase - retry with valid file types
echo "=== Searching for xterm imports and usage ==="
rg -n "xterm" --type=ts --type=js -g '!package*.json'
echo ""
echo "=== Searching without file type restrictions ==="
rg -n "xterm" -g '!package*.json'
echo ""
echo "=== Checking package.json context around `@xterm/xterm` ==="
rg -B5 -A5 "@xterm/xterm" package.jsonRepository: ssdeanx/AgentStack
Length of output: 621
Remove unused @xterm/xterm dependency unless actively used.
The @xterm/xterm v6.0.0 dependency was added to package.json but appears to have no imports or usage anywhere in the codebase. Unused dependencies increase bundle size, create unnecessary security surface, and should be removed unless there's a concrete plan to implement them immediately.
🤖 Prompt for AI Agents
In `@package.json` at line 112, The package.json entry for the dependency
"@xterm/xterm" should be removed because it is unused; delete the
"@xterm/xterm": "^6.0.0" line from package.json, run the project's package
manager to update the lockfile (npm install or yarn install) and rebuild, and
search for any imports or references to "@xterm/xterm" (e.g., in components or
terminal-related utilities) to confirm no runtime usage before committing the
change.
| )} | ||
| > | ||
| {errorText && <div>{errorText}</div>} | ||
| {(Boolean(errorText)) && <div>{errorText}</div>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Minor: Redundant parentheses around Boolean coercion.
The double parentheses (Boolean(errorText)) are unnecessary.
♻️ Proposed fix
- {(Boolean(errorText)) && <div>{errorText}</div>}
+ {Boolean(errorText) && <div>{errorText}</div>}Or simply use the truthy check:
- {(Boolean(errorText)) && <div>{errorText}</div>}
+ {errorText && <div>{errorText}</div>}📝 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.
| {(Boolean(errorText)) && <div>{errorText}</div>} | |
| {errorText && <div>{errorText}</div>} |
🤖 Prompt for AI Agents
In `@src/components/ai-elements/tool.tsx` at line 162, The JSX uses an unnecessary
explicit Boolean coercion with extra parentheses in the expression
(Boolean(errorText)) — simplify the conditional render in the component by
removing Boolean(...) and the redundant parentheses and use a truthy check on
errorText instead (i.e., replace the expression that renders the error div by
checking errorText directly); locate the JSX line referencing errorText in the
component (the conditional rendering that outputs <div>{errorText}</div>) and
update it to use a simple truthy check.
| @@ -0,0 +1,116 @@ | |||
| <!-- AGENTS-META {"title":"Agent Tools UI Components","version":"1.0.0","last_updated":"2025-01-09T12:00:00Z","applies_to":"/src/components/ai-elements/tools","tags":["layer:frontend","domain:ui","type:components","status:stable"],"status":"stable"} --> | |||
|
|
|||
| # Tools Directory (`/src/components/ai-elements/tools`) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Avoid using H1 heading in markdown content.
As per coding guidelines, H1 headings should not be used as they are generated from the title. Use ## (H2) for the main section heading instead.
📝 Suggested fix
-# Tools Directory (`/src/components/ai-elements/tools`)
+## Tools Directory (`/src/components/ai-elements/tools`)📝 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.
| # Tools Directory (`/src/components/ai-elements/tools`) | |
| ## Tools Directory (`/src/components/ai-elements/tools`) |
🤖 Prompt for AI Agents
In `@src/components/ai-elements/tools/AGENTS.md` at line 3, Replace the H1 heading
"# Tools Directory (`/src/components/ai-elements/tools`)" in AGENTS.md with an
H2 (change the leading "#" to "##") so the document uses H2 for the main
section; edit the heading text "Tools Directory
(`/src/components/ai-elements/tools`)" to keep content identical but prefixed
with "##" instead of "#".
| export function ScreenshotCard({ input, output, errorText }: ScreenshotCardProps) { | ||
| const [copied, setCopied] = useState(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n src/components/ai-elements/tools/browser-tool.tsx | head -150Repository: ssdeanx/AgentStack
Length of output: 5506
🏁 Script executed:
wc -l src/components/ai-elements/tools/browser-tool.tsxRepository: ssdeanx/AgentStack
Length of output: 115
🏁 Script executed:
rg "export function" src/components/ai-elements/tools/browser-tool.tsx -nRepository: ssdeanx/AgentStack
Length of output: 695
🏁 Script executed:
sed -n '181p;241p;295p;342p;384p;440p' src/components/ai-elements/tools/browser-tool.tsxRepository: ssdeanx/AgentStack
Length of output: 583
🏁 Script executed:
sed -n '181,188p' src/components/ai-elements/tools/browser-tool.tsxRepository: ssdeanx/AgentStack
Length of output: 537
Add explicit return types to all exported card component functions.
This file exports 7 card component functions without return type annotations: ScreenshotCard, PdfGeneratorCard, BrowserToolCard, ClickAndExtractCard, FillFormCard, GoogleSearchCard, and MonitorPageCard. All public functions must declare return types per coding guidelines.
✍️ Example
-export function ScreenshotCard({ input, output, errorText }: ScreenshotCardProps) {
+export function ScreenshotCard({ input, output, errorText }: ScreenshotCardProps): JSX.Element {🤖 Prompt for AI Agents
In `@src/components/ai-elements/tools/browser-tool.tsx` around lines 111 - 112,
The seven exported card component functions (ScreenshotCard, PdfGeneratorCard,
BrowserToolCard, ClickAndExtractCard, FillFormCard, GoogleSearchCard,
MonitorPageCard) lack explicit return type annotations; update each function
signature to declare a React return type (e.g., : JSX.Element or :
React.ReactElement) so they conform to the public API typing guidelines,
ensuring any existing React imports support the chosen type and keeping the
implementations unchanged.
| FileText, | ||
| Globe, | ||
| Image as ImageIcon, | ||
| Link, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Unused import: Link
The Link icon is imported from lucide-react but never used in this component. Remove unused imports to keep the bundle clean.
import {
ExternalLink,
FileText,
Globe,
Image as ImageIcon,
- Link,
} from 'lucide-react'🤖 Prompt for AI Agents
In `@src/components/ai-elements/tools/web-scraper-tool.tsx` at line 11, Remove the
unused "Link" import from lucide-react in the web-scraper-tool.tsx module;
locate the import statement importing Link (alongside other icons) at the top of
the file and delete Link from that import list (or remove the import entirely if
nothing else is imported), ensuring the WebScraperTool component references
remain unchanged.
| input: WebScraperUITool['input'] | ||
| output?: WebScraperUITool['output'] | ||
| errorText?: string | ||
| toolCallId: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Unused prop: toolCallId
The toolCallId prop is declared in the interface but never used in the component body. Either remove it from the interface or use it (e.g., for keying, analytics, or accessibility).
🤖 Prompt for AI Agents
In `@src/components/ai-elements/tools/web-scraper-tool.tsx` at line 17, The prop
toolCallId declared in the component props interface of
src/components/ai-elements/tools/web-scraper-tool.tsx is unused; either remove
toolCallId from the props interface and from any call sites, or use it in the
WebScraperTool component body (for example attach it to the root element as a
key/data attribute or aria attribute, or pass it into the existing
analytics/logging call such as sendAnalyticsEvent or onScrapeStart) so the
identifier is actually consumed; update the props interface and component
implementation consistently and adjust any callers accordingly.
| const content = (output as any).content || {} | ||
| const { | ||
| extractedData, | ||
| rawContent, | ||
| markdownContent, | ||
| } = content |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential runtime error when accessing extractedData
extractedData is destructured from content which defaults to {}. If content.extractedData is undefined, accessing extractedData.length on line 92 and iterating with .map() on line 150 will throw a TypeError.
🐛 Proposed fix
const content = (output as any).content || {}
const {
- extractedData,
+ extractedData = [],
rawContent,
markdownContent,
} = content🤖 Prompt for AI Agents
In `@src/components/ai-elements/tools/web-scraper-tool.tsx` around lines 67 - 72,
Destructuring sets extractedData from content which may be undefined, causing
extractedData.length and extractedData.map to throw; change the destructure to
provide a safe default (e.g., const { extractedData = [], rawContent,
markdownContent } = content) or add guards before using extractedData (check
Array.isArray(extractedData) or use (extractedData || []).length and
(extractedData || []).map) so references to extractedData.length and
extractedData.map in this component (web-scraper-tool.tsx) are safe.
| export async function handleTextStream( | ||
| streamResult: | ||
| | StreamTextResult<ToolSet, unknown> | ||
| | StreamTextResult<ToolSet, any> | ||
| | { textStream: AsyncIterable<string> }, | ||
| streamController: ReadableStreamDefaultController<Uint8Array> | ||
| ): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Vercel AI SDK StreamTextResult generic parameter type definition
💡 Result:
Short answer — StreamTextResult uses two generics: TOOLS (the tool-set shape) and OUTPUT (the model/agent output type). Typical signature:
StreamTextResult
Meanings:
- TOOLS — the tools available to the call (used to type tool calls / tool-related parts).
- OUTPUT — the typed shape of any additional model/agent output data.
References: Vercel AI SDK docs showing StreamText/Agent signatures and the generic params. [1][2]
Sources
- StreamText / streamText docs (AI SDK reference). [1]
- Agent interface (shows StreamTextResult<TOOLS, OUTPUT> generics). [2]
🏁 Script executed:
# First, let's examine the actual file to understand the context
cat -n src/utils/streamUtils.ts | head -120Repository: ssdeanx/AgentStack
Length of output: 4725
🏁 Script executed:
# Check if ai library is installed and what version
cat package.json | grep -A 2 '"ai"'Repository: ssdeanx/AgentStack
Length of output: 272
Avoid explicit any type — use unknown instead.
The second generic parameter of StreamTextResult defaults to unknown in Vercel AI SDK v6, but this function explicitly uses any on line 102. Since the function only accesses the textStream property (which is AsyncIterable<string>) and never uses the second generic parameter, there's no reason to weaken type safety with any.
Replace StreamTextResult<ToolSet, any> with StreamTextResult<ToolSet, unknown> or simply omit the second parameter to rely on the SDK's default.
🤖 Prompt for AI Agents
In `@src/utils/streamUtils.ts` around lines 100 - 105, Change the explicit any
used in the streamResult type inside handleTextStream: update
StreamTextResult<ToolSet, any> to either StreamTextResult<ToolSet, unknown> or
simply StreamTextResult<ToolSet> (to use the SDK default), since the function
only reads the textStream AsyncIterable<string> property and never relies on the
second generic parameter; update the function signature accordingly where
streamResult is declared to restore stronger typing for StreamTextResult and
keep references to handleTextStream, StreamTextResult, ToolSet, and textStream
intact.
| "include": [ | ||
| "next-env.d.ts", | ||
| "vitest.config.ts", | ||
| "mdx-components.tsx", | ||
| "eslint.config.js", | ||
| "prettier.config.js", | ||
| "eslint-config-next.d.ts", | ||
| "postcss.config.mjs", | ||
| "next.config.ts", | ||
| "components.json", | ||
| "instrumentation.ts", | ||
| "/.next/types/**/*.ts", | ||
| "/.next/dev/types/**/*.ts", | ||
| "app/**/*.ts", | ||
| "/app/**/*.ts", | ||
| "app/**/*.tsx", | ||
| "/app/**/*.tsx", | ||
| "src/mastra/workflows/*.ts", | ||
| "/app/**/*.mdx ", | ||
| "src/**/*.ts", | ||
| "/src/**/*.js", | ||
| "/src/**/*.tsx", | ||
| "src/**/*.ts", | ||
| "src/**/*.tsx", | ||
| "src/mastra/types/**/*.d.ts", | ||
| "types/**/*.d.ts", | ||
| "utils/**/*.ts", | ||
| "/lib/**/*.ts", | ||
| "utils/**/*.tsx", | ||
| "styles/**/*.ts", | ||
| "styles/**/*.tsx", | ||
| "ui/**/*.ts", | ||
| "/ui/**/*.ts", | ||
| "/ui/**/*.tsx", | ||
| "ui/**/*.tsx", | ||
| "lib/**/*.ts", | ||
| "/lib/**/*.ts", | ||
| "/lib/**/*.tsx", | ||
| "lib/**/*.tsx", | ||
| "hooks/**/*.ts", | ||
| "/hooks/**/*.ts", | ||
| "/hooks/**/*.tsx", | ||
| "hooks/**/*.tsx", | ||
| "pages/**/*.ts", | ||
| "pages/**/*.tsx", | ||
| "convex/**/*.ts", | ||
| "/convex/**/*.ts", | ||
| "/convex/**/*.tsx", | ||
| "convex/**/*.tsx", | ||
| "convex/**/*.d.ts", | ||
| "convex/mastra/**/*.ts", | ||
| "convex/**/*.js", | ||
| // Tests are excluded from the main typecheck run to avoid typechecking test-only imports | ||
| // that may pull in declaration files with unsupported syntax from node_modules. | ||
| "types/**/*.d.ts", | ||
| "/tests/**/*.ts", | ||
| "/types/**.d.ts", | ||
| "/public/", | ||
| ".next/types/**/*.ts", | ||
| ".next/dev/types/**/*.ts" | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Duplicate and conflicting path patterns in include array.
The include array contains several issues:
- Duplicates:
"src/**/*.ts"appears at lines 53 and 56;"types/**/*.d.ts"at lines 59 and 88 - Conflicting patterns: Tests are included at line 89 (
"/tests/**/*.ts") but excluded at lines 119-121 - Inconsistent path formats: Mixed use of leading slashes (e.g.,
"/app/**/*.ts"vs"app/**/*.ts")
♻️ Recommended: Consolidate and deduplicate patterns
"include": [
"next-env.d.ts",
"vitest.config.ts",
"mdx-components.tsx",
"eslint.config.js",
"prettier.config.js",
"eslint-config-next.d.ts",
"postcss.config.mjs",
"next.config.ts",
"components.json",
"instrumentation.ts",
- "/.next/types/**/*.ts",
- "/.next/dev/types/**/*.ts",
- "app/**/*.ts",
- "/app/**/*.ts",
- "app/**/*.tsx",
- "/app/**/*.tsx",
- "src/mastra/workflows/*.ts",
- "/app/**/*.mdx ",
- "src/**/*.ts",
- "/src/**/*.js",
- "/src/**/*.tsx",
- "src/**/*.ts",
- "src/**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "app/**/*.ts",
+ "app/**/*.tsx",
+ "app/**/*.mdx",
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "src/**/*.js",
"src/mastra/types/**/*.d.ts",
"types/**/*.d.ts",
- "utils/**/*.ts",
- "/lib/**/*.ts",
- "utils/**/*.tsx",
- "styles/**/*.ts",
- "styles/**/*.tsx",
- "ui/**/*.ts",
- "/ui/**/*.ts",
- "/ui/**/*.tsx",
- "ui/**/*.tsx",
- "lib/**/*.ts",
- "/lib/**/*.ts",
- "/lib/**/*.tsx",
- "lib/**/*.tsx",
- "hooks/**/*.ts",
- "/hooks/**/*.ts",
- "/hooks/**/*.tsx",
- "hooks/**/*.tsx",
+ "utils/**/*.{ts,tsx}",
+ "styles/**/*.{ts,tsx}",
+ "ui/**/*.{ts,tsx}",
+ "lib/**/*.{ts,tsx}",
+ "hooks/**/*.{ts,tsx}",
"pages/**/*.ts",
"pages/**/*.tsx",
- "convex/**/*.ts",
- "/convex/**/*.ts",
- "/convex/**/*.tsx",
- "convex/**/*.tsx",
+ "convex/**/*.{ts,tsx,js}",
"convex/**/*.d.ts",
- "convex/mastra/**/*.ts",
- "convex/**/*.js",
- // Tests are excluded from the main typecheck run to avoid typechecking test-only imports
- // that may pull in declaration files with unsupported syntax from node_modules.
- "types/**/*.d.ts",
- "/tests/**/*.ts",
- "/types/**.d.ts",
- "/public/",
- ".next/types/**/*.ts",
- ".next/dev/types/**/*.ts"
+ "convex/mastra/**/*.ts"
],📝 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.
| "include": [ | |
| "next-env.d.ts", | |
| "vitest.config.ts", | |
| "mdx-components.tsx", | |
| "eslint.config.js", | |
| "prettier.config.js", | |
| "eslint-config-next.d.ts", | |
| "postcss.config.mjs", | |
| "next.config.ts", | |
| "components.json", | |
| "instrumentation.ts", | |
| "/.next/types/**/*.ts", | |
| "/.next/dev/types/**/*.ts", | |
| "app/**/*.ts", | |
| "/app/**/*.ts", | |
| "app/**/*.tsx", | |
| "/app/**/*.tsx", | |
| "src/mastra/workflows/*.ts", | |
| "/app/**/*.mdx ", | |
| "src/**/*.ts", | |
| "/src/**/*.js", | |
| "/src/**/*.tsx", | |
| "src/**/*.ts", | |
| "src/**/*.tsx", | |
| "src/mastra/types/**/*.d.ts", | |
| "types/**/*.d.ts", | |
| "utils/**/*.ts", | |
| "/lib/**/*.ts", | |
| "utils/**/*.tsx", | |
| "styles/**/*.ts", | |
| "styles/**/*.tsx", | |
| "ui/**/*.ts", | |
| "/ui/**/*.ts", | |
| "/ui/**/*.tsx", | |
| "ui/**/*.tsx", | |
| "lib/**/*.ts", | |
| "/lib/**/*.ts", | |
| "/lib/**/*.tsx", | |
| "lib/**/*.tsx", | |
| "hooks/**/*.ts", | |
| "/hooks/**/*.ts", | |
| "/hooks/**/*.tsx", | |
| "hooks/**/*.tsx", | |
| "pages/**/*.ts", | |
| "pages/**/*.tsx", | |
| "convex/**/*.ts", | |
| "/convex/**/*.ts", | |
| "/convex/**/*.tsx", | |
| "convex/**/*.tsx", | |
| "convex/**/*.d.ts", | |
| "convex/mastra/**/*.ts", | |
| "convex/**/*.js", | |
| // Tests are excluded from the main typecheck run to avoid typechecking test-only imports | |
| // that may pull in declaration files with unsupported syntax from node_modules. | |
| "types/**/*.d.ts", | |
| "/tests/**/*.ts", | |
| "/types/**.d.ts", | |
| "/public/", | |
| ".next/types/**/*.ts", | |
| ".next/dev/types/**/*.ts" | |
| ], | |
| "include": [ | |
| "next-env.d.ts", | |
| "vitest.config.ts", | |
| "mdx-components.tsx", | |
| "eslint.config.js", | |
| "prettier.config.js", | |
| "eslint-config-next.d.ts", | |
| "postcss.config.mjs", | |
| "next.config.ts", | |
| "components.json", | |
| "instrumentation.ts", | |
| ".next/types/**/*.ts", | |
| ".next/dev/types/**/*.ts", | |
| "app/**/*.ts", | |
| "app/**/*.tsx", | |
| "app/**/*.mdx", | |
| "src/**/*.ts", | |
| "src/**/*.tsx", | |
| "src/**/*.js", | |
| "src/mastra/types/**/*.d.ts", | |
| "types/**/*.d.ts", | |
| "utils/**/*.{ts,tsx}", | |
| "styles/**/*.{ts,tsx}", | |
| "ui/**/*.{ts,tsx}", | |
| "lib/**/*.{ts,tsx}", | |
| "hooks/**/*.{ts,tsx}", | |
| "pages/**/*.ts", | |
| "pages/**/*.tsx", | |
| "convex/**/*.{ts,tsx,js}", | |
| "convex/**/*.d.ts", | |
| "convex/mastra/**/*.ts" | |
| ], |
🤖 Prompt for AI Agents
In `@tsconfig.json` around lines 34 - 94, The tsconfig.json include array contains
duplicate and inconsistent path patterns (e.g., duplicate "src/**/*.ts" and
"types/**/*.d.ts", and conflicting/test paths like "/tests/**/*.ts" vs earlier
exclusions, plus mixed leading-slash entries such as "/app/**/*.ts" and
"app/**/*.ts"); clean this by deduplicating entries, normalizing paths to remove
leading slashes (use "app/**/*.ts" not "/app/**/*.ts"), remove any test globs
that contradict your exclusions (remove "/tests/**/*.ts" if tests are supposed
to be excluded), and consolidate similar entries (keep single "src/**/*.ts" and
single "types/**/*.d.ts") within the "include" array so only canonical,
non-conflicting patterns remain.
No description provided.