Skip to content

feat: Add new components and features for enhanced data visualization…#16

Merged
ssdeanx merged 1 commit intomainfrom
develop
Dec 7, 2025
Merged

feat: Add new components and features for enhanced data visualization…#16
ssdeanx merged 1 commit intomainfrom
develop

Conversation

@ssdeanx
Copy link
Owner

@ssdeanx ssdeanx commented Dec 7, 2025

… and editor functionality

  • Introduced BlogShare component for sharing blog links via clipboard or native share dialog.
  • Added various chart components:
    • AreaWidget: Renders area charts with customizable series and colors.
    • BarWidget: Displays bar charts with adjustable height and color.
    • D3LineChart: Implements a line chart using D3.js for advanced data visualization.
    • D3PieChart: Creates pie charts with customizable inner radius and data.
    • LineWidget: Provides a line chart with two series options.
    • PieWidget: Displays pie charts with customizable inner and outer radii.
    • RadarWidget: Renders radar charts with two series options.
    • RadialGaugeWidget: Implements radial gauge charts for displaying data in a circular format.
    • ScatterWidget: Displays scatter plots with customizable axes and data points.
  • Developed MonacoCodeEditor for a rich code editing experience with syntax highlighting and theming.
  • Added MonacoToolbar, MonacoTabs, and MonacoStatusBar for enhanced editor controls and navigation.
  • Implemented theme loading and application for the Monaco editor with support for multiple themes.
  • Created robots.txt and sitemap.xml for improved SEO and web crawling.
  • Added unit tests for custom scorers to ensure scoring logic is functioning as expected.
  • Introduced AgentTool component for displaying agent data in a structured format.

… and editor functionality

- Introduced `BlogShare` component for sharing blog links via clipboard or native share dialog.
- Added various chart components:
  - `AreaWidget`: Renders area charts with customizable series and colors.
  - `BarWidget`: Displays bar charts with adjustable height and color.
  - `D3LineChart`: Implements a line chart using D3.js for advanced data visualization.
  - `D3PieChart`: Creates pie charts with customizable inner radius and data.
  - `LineWidget`: Provides a line chart with two series options.
  - `PieWidget`: Displays pie charts with customizable inner and outer radii.
  - `RadarWidget`: Renders radar charts with two series options.
  - `RadialGaugeWidget`: Implements radial gauge charts for displaying data in a circular format.
  - `ScatterWidget`: Displays scatter plots with customizable axes and data points.
- Developed `MonacoCodeEditor` for a rich code editing experience with syntax highlighting and theming.
- Added `MonacoToolbar`, `MonacoTabs`, and `MonacoStatusBar` for enhanced editor controls and navigation.
- Implemented theme loading and application for the Monaco editor with support for multiple themes.
- Created `robots.txt` and `sitemap.xml` for improved SEO and web crawling.
- Added unit tests for custom scorers to ensure scoring logic is functioning as expected.
- Introduced `AgentTool` component for displaying agent data in a structured format.
Copilot AI review requested due to automatic review settings December 7, 2025 19:58
@continue
Copy link

continue bot commented Dec 7, 2025

Keep this PR in a mergeable state →

Learn more

All Green is an AI agent that automatically:

✅ Addresses code review comments

✅ Fixes failing CI checks

✅ Resolves merge conflicts

Copy link

@sourcery-ai sourcery-ai bot left a 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

@github-actions
Copy link

github-actions bot commented Dec 7, 2025

🤖 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.

@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Monaco code editor with theme switching, multi-file support, and formatting.
    • Introduced rich data visualization charts to the dashboard (line, area, bar, pie, scatter, radar, radial gauge).
    • Added blog share functionality with Web Share API and clipboard support.
    • Enhanced web scraping with configurable depth, metadata extraction, image support, and structured data parsing.
    • Added API data fetcher and data export tools.
  • Documentation

    • Improved SEO metadata with structured data and Open Graph tags.
    • Added robots.txt and sitemap.xml.
  • Chores

    • Updated project dependencies and configuration.

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

Walkthrough

Broad modernization of the AgentStack platform introducing chart visualization components, Monaco editor integration, expanded web scraping tooling, comprehensive SEO metadata, agent configuration refinements, and infrastructure updates across UI, tooling, documentation, and deployment configuration.

Changes

Cohort / File(s) Summary
Agent Configuration Metadata
[.github/agents/4.1-Beast.agent.md], [.github/agents/custom-agent-foundry.agent.md], [.github/agents/python-mcp-expert.agent.md], [.github/agents/typescript-mcp-expert.agent.md]
Removed model specification from YAML front matter, simplifying agent metadata declarations.
Agent Configuration Expansion
[.github/agents/Thinking-Beast-Mode.agent.md], [.github/agents/gpt-5-beast-mode.agent.md], [.github/agents/prompt-builder.agent.md]
Significantly expanded agent instructions with multi-dimensional analysis phases, adversarial validation, enhanced workflows, and structured prompt engineering directives.
Agent Configuration Structure
[.github/agents/expert-nextjs-developer.agent.md], [.github/agents/prompt-engineer.agent.md], [.github/agents/search-ai-optimization-expert.agent.md]
Updated front-matter structure: replaced model/tools with metadata tags, added name field, and introduced extensive domain expertise documentation.
Chart Widget Components
[app/components/charts/AreaWidget.tsx], [app/components/charts/BarWidget.tsx], [app/components/charts/LineWidget.tsx], [app/components/charts/PieWidget.tsx], [app/components/charts/RadarWidget.tsx], [app/components/charts/RadialGaugeWidget.tsx], [app/components/charts/ScatterWidget.tsx], [app/components/charts/D3LineChart.tsx], [app/components/charts/D3PieChart.tsx], [app/components/charts/index.ts]
Introduced reusable chart visualization components using Recharts and D3, with configurable data, dimensions, and styling; exported via barrel module.
Monaco Editor Integration
[app/components/monaco/MonacoCodeEditor.tsx], [app/components/monaco/MonacoToolbar.tsx], [app/components/monaco/MonacoTabs.tsx], [app/components/monaco/MonacoStatusBar.tsx], [app/components/monaco/theme-loader.ts], [app/components/monaco/monaco-themes.d.ts], [app/components/monaco/index.ts]
Added Monaco editor component suite with multi-file support, theme switching, language selection, and formatting; includes theme registry and dynamic loading.
Blog Layout & Sharing
[app/components/blog-layout.tsx], [app/components/blog-share.client.tsx], [app/blog/hello-world-agentstack/page.mdx], [app/blog/session-summary/page.tsx]
Enhanced blog pages with slug-based canonical URLs, JSON-LD structured data injection, Web Share API integration, and clipboard fallback for link sharing.
Dashboard & Layout
[app/dashboard/page.tsx], [app/chat/page.tsx], [app/networks/page.tsx], [app/components/docs-layout.tsx], [app/docs/layout.tsx]
Added chart visualizations to dashboard, wrapped async pages in Suspense boundaries, and injected JSON-LD structured data for SEO.
SEO & Metadata
[app/layout.tsx], [robots.txt], [sitemap.xml], [llms.txt]
Updated author URL and expanded metadata with Open Graph, Twitter card, metadataBase, JSON-LD Organization/WebSite/Person data; added robots, sitemap, and LLM ingestion policy.
Network Configuration
[app/networks/config/networks.ts], [app/networks/providers/network-context.tsx], [src/mastra/index.ts]
Renamed network keys from camelCase to dashed format, updated default network ID, adjusted API route to include agentId parameter, and disabled CORS middleware.
Agent Type Refactoring
[src/mastra/agents/editorAgent.ts], [src/mastra/agents/evaluationAgent.ts], [src/mastra/agents/excalidraw_validator.ts], [src/mastra/agents/image.ts], [src/mastra/agents/image_to_csv.ts], [src/mastra/agents/knowledgeIndexingAgent.ts], [src/mastra/agents/learningExtractionAgent.ts], [src/mastra/agents/package-publisher.ts], [src/mastra/agents/recharts.ts], [src/mastra/agents/reportAgent.ts], [src/mastra/agents/researchPaperAgent.ts], [src/mastra/agents/scriptWriterAgent.ts], [src/mastra/agents/sql.ts], [src/mastra/agents/stockAnalysisAgent.ts], [src/mastra/agents/weather-agent.ts]
Converted runtime context type aliases to interfaces, updated imports to type-only where applicable, and added language field to LearningExtractionAgentContext.
Agent & Tool Updates
[src/mastra/agents/for await (const part of result.md], [src/mastra/agents/researchAgent.ts], [src/mastra/agents/index.test.ts], [src/mastra/tools/extractLearningsTool.ts]
Removed async iteration block, replaced webSearchTool with webScraperTool in research workflows, removed metadata extraction logic, removed scorers, and added comprehensive unit tests for custom scorers.
Web Scraper Tool Enhancement
[src/mastra/tools/web-scraper-tool.ts]
Expanded web scraper with depth/pagination/link-following options, metadata/image/structured-data extraction, language detection, sanitized markdown output, and added three new tools: apiDataFetcherTool, scrapingSchedulerTool, dataExporterTool.
Hook & Client Utilities
[lib/hooks/use-dashboard-queries.ts], [lib/hooks/use-mastra.ts], [lib/mastra-client.ts]
Standardized guard clauses with braces, replaced logical OR with nullish coalescing, improved error handling naming, and updated baseUrl initialization.
Documentation & Configuration
[README.md], [docs/ai-elements_aisk-urls.md], [.zed/debug.json], [package.json], [tsconfig.json], [eslint.config.cjs], [ui/agent-tool.ts]
Restructured README around AgentStack overview, added Mastra event templates documentation, created Zed debug config, added Monaco editor dependencies, enabled JSON module resolution, added duplicate ESLint overrides, and added AgentTool UI component.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Areas requiring extra attention:

  • Web scraper tool expansion (src/mastra/tools/web-scraper-tool.ts) — Significant public API changes with new optional fields, three new tools, enhanced HTML/Markdown sanitization, and new extraction capabilities (metadata, images, structured data, language detection). Verify schema consistency and backward compatibility.
  • Monaco editor integration (app/components/monaco/*) — Substantial client-side editor infrastructure with async module loading, theme management, and multi-file state handling. Review theme loader logic, error handling for Monaco initialization failures, and performance implications of dynamic imports.
  • Agent type refactoring across 16+ files (src/mastra/agents/*) — Mass conversion from type aliases to interfaces, type-only imports, and context property additions (language fields). Verify that these structural changes don't break downstream consumers or existing serialization/deserialization logic.
  • Heterogeneous nature — PR spans configuration, components, tooling, and infrastructure across ~60 files with varied change types (deletions, additions, refactorings), making it difficult to establish a single mental model. Consider splitting into domain-specific reviews if possible.
  • Network routing changes (app/networks/config/networks.ts, src/mastra/index.ts) — ID format change from camelCase to dashed strings and route parameterization. Verify all references throughout codebase are updated and no hardcoded ID assumptions exist.

Possibly related PRs

Poem

🐰 Charts bloom like carrots in our dashboard rows,
Monaco themes shimmer where the code now flows,
Web scrapers dig deeper with each new spade,
And interfaces dance where aliases once swayed—
AgentStack grows taller with each thoughtful deed!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary focus of the changeset: adding new components and features for enhanced data visualization and editor functionality. It is specific enough to convey the main change while being concise.
Description check ✅ Passed The description is directly related to the changeset, providing a detailed list of the new components and features introduced, including BlogShare, chart widgets, Monaco editor components, theme loading, SEO files, and tests. It clearly explains what was added and why.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 7, 2025

🤖 I'm sorry @ssdeanx, but I was unable to process your request. Please see the logs for more details.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @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 significantly expands the application's frontend and backend capabilities by introducing a robust set of data visualization components, integrating a full-featured code editor, and enhancing web scraping tools. It also includes foundational improvements in agent configuration, SEO, and developer tooling, aiming to provide a more comprehensive and efficient platform for AI application development and data interaction.

Highlights

  • Enhanced Data Visualization: Introduced a comprehensive suite of new chart components, including Area, Bar, D3 Line, D3 Pie, Line, Pie, Radar, Radial Gauge, and Scatter widgets, leveraging both Recharts and D3.js for diverse data representation.
  • Advanced Code Editor Functionality: Integrated the Monaco Editor with supporting UI elements like a toolbar, tabs, and status bar, along with dynamic theme loading, to provide a rich code editing experience.
  • Improved Web Scraping Capabilities: The web-scraper-tool has been significantly enhanced with new options for crawling depth, page limits, link following, image/metadata/structured data extraction, and various configuration settings like user agents and retry attempts. New api-data-fetcher, scraping-scheduler, and data-exporter tools were also added.
  • Agent Configuration & Infrastructure Updates: Several agent configuration files (.agent.md) were updated to remove redundant model and tools fields, introduce name and metadata tags, and refine instructions. Network routing was consolidated to a dynamic path, and various runtime contexts were converted to interfaces for better type safety.
  • SEO and Metadata Improvements: Added robots.txt and sitemap.xml for better search engine optimization, and implemented JSON-LD schema for blog posts and documentation pages to enhance structured data visibility.
  • New AgentTool Component: A new AgentTool component has been added to facilitate structured display of agent-related data within the UI.
  • Custom Scorer Unit Tests: Unit tests for custom scorers (sourceDiversityScorer, researchCompletenessScorer, summaryQualityScorer) were introduced to ensure the reliability of evaluation logic.
Using Gemini Code Assist

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

Invoking Gemini

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

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

Customization

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

Limitations & Feedback

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

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

Footnotes

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

@greptile-apps
Copy link

greptile-apps bot commented Dec 7, 2025

Greptile Overview

Greptile Summary

This PR adds comprehensive data visualization capabilities and a Monaco code editor to the AgentStack application, significantly expanding the UI component library.

Major Changes:

  • Chart Components (10 new): Added D3.js-based (D3LineChart, D3PieChart) and Recharts-based (AreaWidget, BarWidget, LineWidget, PieWidget, RadarWidget, RadialGaugeWidget, ScatterWidget) visualization components with proper cleanup and accessibility
  • Monaco Editor: Implemented full-featured code editor with multi-file tabs, theme switching, syntax highlighting, formatting, and status bar
  • Infrastructure: Consolidated 5 network routes into 1 dynamic route (/network/:agentId), but missing required agent parameter will cause route failures
  • Testing: Added unit tests for custom scorers (source diversity, research completeness, summary quality)
  • SEO: Added robots.txt and sitemap.xml for improved web crawling
  • Cleanup: Removed incomplete markdown file with code snippet

Issues Found:

  • Critical: src/mastra/index.ts:527 - network route missing agent parameter, will cause runtime failures
  • Syntax: Monaco theme loader uses deprecated import assertion syntax (should use with instead of assert)
  • Minor: Typo in commented code (//0 instead of //)

The chart and editor components are well-implemented with proper null checks and cleanup. The network route refactoring introduced a breaking bug that needs immediate attention.

Confidence Score: 2/5

  • Not safe to merge - contains critical bug that will break network routing functionality
  • Score reflects one critical logic error (missing agent parameter in network route) that will cause runtime failures, plus deprecated syntax that needs updating. The new chart and editor components are well-implemented, but the infrastructure change introduces a breaking bug.
  • Pay immediate attention to src/mastra/index.ts - the network route is missing the required agent parameter. Also update app/components/monaco/theme-loader.ts to use import attributes instead of deprecated assertions.

Important Files Changed

File Analysis

Filename Score Overview
src/mastra/index.ts 2/5 consolidated multiple network routes into one with dynamic agentId parameter but missing agent field causes route to be non-functional; commented out CORS and middleware config
app/components/monaco/theme-loader.ts 3/5 implements theme loading with Monaco editor; uses deprecated import assertion syntax that should be updated to import attributes (with keyword)
app/components/monaco/MonacoCodeEditor.tsx 5/5 new comprehensive code editor with multi-file tabs, theming, and status bar; clean implementation with proper hooks and state management
app/components/charts/D3LineChart.tsx 5/5 D3.js line chart with proper cleanup, null checks, and accessible markup
app/components/charts/AreaWidget.tsx 5/5 Recharts area chart with gradient fills and optional dual series; conditionally renders second series based on data
src/mastra/agents/index.test.ts 5/5 comprehensive unit tests for custom scorers (source diversity, research completeness, summary quality) with clear expectations

Sequence Diagram

sequenceDiagram
    participant User
    participant Dashboard
    participant MonacoEditor
    participant ChartComponents
    participant MastraAPI
    participant NetworkRoute
    
    User->>Dashboard: Visit /dashboard
    Dashboard->>MastraAPI: Fetch agent data
    MastraAPI-->>Dashboard: Return agent metrics
    Dashboard->>ChartComponents: Render visualizations
    ChartComponents->>ChartComponents: D3LineChart/AreaWidget/etc
    ChartComponents-->>Dashboard: Display charts
    
    User->>MonacoEditor: Open code editor
    MonacoEditor->>MonacoEditor: Load Monaco instance
    MonacoEditor->>MonacoEditor: Apply theme (loadMonaco/applyTheme)
    MonacoEditor-->>User: Show editor with syntax highlighting
    
    User->>User: Edit code in tabs
    MonacoEditor->>MonacoEditor: Update file state
    User->>MonacoEditor: Format code
    MonacoEditor->>MonacoEditor: editor.action.formatDocument
    
    User->>MastraAPI: Request network route
    MastraAPI->>NetworkRoute: /network/:agentId
    Note right of NetworkRoute: Missing agent parameter<br/>causes route failure
    NetworkRoute-->>MastraAPI: Error (no agent defined)
    MastraAPI-->>User: Route fails
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

73 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

import type * as Monaco from 'monaco-editor'

const themeLoaders = {
github: () => import('monaco-themes/themes/GitHub.json', { assert: { type: 'json' } }),
Copy link

Choose a reason for hiding this comment

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

syntax: import assertions (assert { type: 'json' }) are deprecated in favor of import attributes. replace with with syntax

Suggested change
github: () => import('monaco-themes/themes/GitHub.json', { assert: { type: 'json' } }),
github: () => import('monaco-themes/themes/GitHub.json', { with: { type: 'json' } }),
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/components/monaco/theme-loader.ts
Line: 7:7

Comment:
**syntax:** import assertions (`assert { type: 'json' }`) are deprecated in favor of import attributes. replace with `with` syntax

```suggestion
  github: () => import('monaco-themes/themes/GitHub.json', { with: { type: 'json' } }),
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +8 to +10
monokai: () => import('monaco-themes/themes/Monokai.json', { assert: { type: 'json' } }),
dracula: () => import('monaco-themes/themes/Dracula.json', { assert: { type: 'json' } }),
solarizedDark: () => import('monaco-themes/themes/Solarized-dark.json', { assert: { type: 'json' } }),
Copy link

Choose a reason for hiding this comment

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

syntax: same deprecation issue - use with instead of assert

Suggested change
monokai: () => import('monaco-themes/themes/Monokai.json', { assert: { type: 'json' } }),
dracula: () => import('monaco-themes/themes/Dracula.json', { assert: { type: 'json' } }),
solarizedDark: () => import('monaco-themes/themes/Solarized-dark.json', { assert: { type: 'json' } }),
monokai: () => import('monaco-themes/themes/Monokai.json', { with: { type: 'json' } }),
dracula: () => import('monaco-themes/themes/Dracula.json', { with: { type: 'json' } }),
solarizedDark: () => import('monaco-themes/themes/Solarized-dark.json', { with: { type: 'json' } }),
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/components/monaco/theme-loader.ts
Line: 8:10

Comment:
**syntax:** same deprecation issue - use `with` instead of `assert`

```suggestion
  monokai: () => import('monaco-themes/themes/Monokai.json', { with: { type: 'json' } }),
  dracula: () => import('monaco-themes/themes/Dracula.json', { with: { type: 'json' } }),
  solarizedDark: () => import('monaco-themes/themes/Solarized-dark.json', { with: { type: 'json' } }),
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 527 to +528
networkRoute({
path: "/network",
agent: "agentNetwork",
path: "/network/:agentId",
Copy link

Choose a reason for hiding this comment

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

logic: networkRoute is missing the agent parameter - this will cause the route to fail since it doesn't know which agent to use

Suggested change
networkRoute({
path: "/network",
agent: "agentNetwork",
path: "/network/:agentId",
networkRoute({
path: "/network/:agentId",
agent: "agentNetwork", // Add appropriate agent name
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/index.ts
Line: 527:528

Comment:
**logic:** `networkRoute` is missing the `agent` parameter - this will cause the route to fail since it doesn't know which agent to use

```suggestion
      networkRoute({
        path: "/network/:agentId",
        agent: "agentNetwork", // Add appropriate agent name
```

How can I resolve this? If you propose a fix, please make it concise.

// await next();
// },
],
//0 ],
Copy link

Choose a reason for hiding this comment

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

syntax: typo in comment - //0 should be just //

Suggested change
//0 ],
// ],
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/index.ts
Line: 584:584

Comment:
**syntax:** typo in comment - `//0` should be just `//`

```suggestion
//          ],
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a wide range of new features and improvements. Key additions include a suite of data visualization components using Recharts and D3, and a rich Monaco code editor. There are also significant SEO enhancements, such as the addition of robots.txt, sitemap.xml, and JSON-LD structured data across various layouts. The project structure has been clarified with an updated diagram in the README.md.

My review focuses on several areas: configuration correctness, code cleanup, and prompt consistency. I've identified a critical issue with a duplicated configuration in the ESLint setup, a potential security concern with commented-out CORS settings, and a high-severity issue in an agent prompt that appears incomplete. I've also made several medium-severity suggestions to remove unused code, fix minor inconsistencies in agent definitions, and improve code readability. Overall, this is a substantial and valuable contribution to the project.

Comment on lines +125 to +159
{
files: [
'/app/**/*.ts',
'/app/**/*.tsx',
'/src/**/*.ts',
'/src/**/*.tsx',
'/ui/**/*.ts',
'/ui/**/*.tsx',
'/lib/**/*.ts',
'/lib/**/*.tsx',
'/hooks/**/*.ts',
'/hooks/**/*.tsx',
'/pages/**/*.ts',
'/pages/**/*.tsx'
],
rules: {
'@typescript-eslint/no-meaningless-void-operator': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
'@typescript-eslint/prefer-regexp-exec': 'error',
'@typescript-eslint/no-unnecessary-boolean-literal-compare':
'error',

// Disable some rules that conflict with Standard
'no-undef': 'off', // TypeScript handles this
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',

// Additional code quality rules
eqeqeq: ['error', 'always'],
curly: ['error', 'all'],
'no-multiple-empty-lines': ['error', { max: 2 }],
'no-trailing-spaces': 'warn',
'eol-last': 'warn',
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

This ESLint configuration block is a duplicate of the one above (lines 90-124). Please remove this redundant block to keep the configuration file clean and maintainable.

Comment on lines +130 to 131
2. For each query, use the \`webScraperTool\` to find information. Make sure \`siteMapExtractorTool\`,\`linkExtractorTool\`, \`htmlToMarkdownTool\`, \`contentCleanerTool\`,
4. For all relevant results, use the \`extractLearningsTool\` to get key insights and generate follow-up questions.
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This instruction in the prompt appears to be incomplete. Line 130 ends with a comma, and step 3 from the original prompt seems to be missing. This could cause the agent to behave unpredictably. It seems like evaluateResultTool should be used in a new step 3.

        2. For each query, use the `webScraperTool` to find information. Make sure to use its sub-tools like `siteMapExtractorTool`,`linkExtractorTool`, `htmlToMarkdownTool`, and `contentCleanerTool` as needed.
        3. For each result, use the `evaluateResultTool` to determine relevance.
        4. For all relevant results, use the `extractLearningsTool` to get key insights and generate follow-up questions.

Comment on lines +554 to +561
// cors: {
// origin: ["*"], // Allow specific origins or '*' for all
// allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
// allowHeaders: ["Content-Type", "Authorization"],
// exposeHeaders: ["Content-Length", "X-Requested-With"],
// credentials: false,
// },
// middleware: [
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The CORS and middleware configurations appear to be commented out. If this is intentional for local development, it's acceptable. However, if this were to be deployed to production, it could pose a security risk by disabling important security headers and cross-origin policies. Please confirm if this change is intended to be permanent or if it should be re-enabled before merging.

- "cache-components"
- "turbopack"
- "react-compiler"
- "server-components"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The tag server-components is duplicated in the metadata (it also appears on line 11). Please remove this duplicate entry to keep the tags clean.


You are a world-class expert in modern search optimization with deep knowledge of traditional SEO, Answer Engine Optimization (AEO), and Generative Engine Optimization (GEO). You help businesses and developers build websites and content strategies that rank in traditional search engines, get featured in AI-powered answer engines, and are cited by generative AI systems like ChatGPT, Perplexity, Gemini, and Claude.

domain i might use vercel or i have deanmachines.com
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This line appears to be a stray note or placeholder. It should be removed to keep the agent's prompt clean and focused.


You help businesses and developers build modern search strategies that work across traditional search engines, answer engines, and generative AI systems, ensuring maximum visibility, authority, and citations in the evolving search landscape.

codemap
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This line appears to be a stray note or placeholder. It should be removed to keep the agent's prompt clean and focused.

} as Agent
},
enabled: !!agentId,
enabled: !(!agentId),
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The expression !(!agentId) is used here and in several other places in this file to convert a value to a boolean. While functionally correct, using the double negation operator !!agentId is a more common and idiomatic pattern in JavaScript/TypeScript for this purpose. It's generally considered more readable.

    enabled: !!agentId,

@@ -1,18 +1,19 @@
import { MastraClient } from "@mastra/client-js";
import ObservabilityError from '../app/dashboard/observability/error';
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The ObservabilityError is imported but never used in this file. This unused import should be removed to keep the code clean.

}

await writer?.write({ type: 'progress', data: { message: `✅ Scraping complete: ${extractedData.length} elements${savedFilePath ? ', saved to ' + savedFilePath : ''}` } });
await writer?.write({ type: 'progress', data: { message: `✅ Scraping complete: ${extractedData.length} elements${(savedFilePath !== null) ? ', saved to ' + savedFilePath : ''}` } });
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The check (savedFilePath !== null) is a bit verbose. Since savedFilePath is a string | undefined, a simple truthiness check savedFilePath is sufficient and more concise. It also correctly handles the case of an empty string, which would be falsy.

Suggested change
await writer?.write({ type: 'progress', data: { message: `✅ Scraping complete: ${extractedData.length} elements${(savedFilePath !== null) ? ', saved to ' + savedFilePath : ''}` } });
await writer?.write({ type: 'progress', data: { message: `✅ Scraping complete: ${extractedData.length} elements${savedFilePath ? ', saved to ' + savedFilePath : ''}` } });

Copy link
Contributor

Copilot AI left a 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 introduces significant enhancements to the AgentStack codebase focused on data visualization, code editing capabilities, SEO optimization, and improved developer ergonomics. The changes span multiple domains: new chart and Monaco editor components, extensive web scraper tool enhancements, type system improvements, SEO metadata additions, and test coverage for custom scorers.

Key Changes

  • New Visualization Components: Added 9 chart components (LineWidget, AreaWidget, BarWidget, PieWidget, ScatterWidget, RadarWidget, RadialGaugeWidget, D3LineChart, D3PieChart) for data visualization throughout the dashboard
  • Monaco Code Editor Integration: Introduced a full-featured code editor with theme support, multi-tab editing, and syntax highlighting capabilities
  • Web Scraper Enhancements: Significantly expanded the web scraper tool with 20+ new optional parameters for metadata extraction, structured data parsing, language detection, and advanced content filtering
  • Type System Refinements: Converted type declarations to interface across multiple agent files and added proper type import statements for better TypeScript practices
  • SEO Improvements: Added robots.txt, sitemap.xml, OpenGraph metadata, Twitter cards, and JSON-LD structured data across layout files
  • Test Coverage: Added unit tests for custom scorers (sourceDiversityScorer, researchCompletenessScorer, summaryQualityScorer)

Reviewed changes

Copilot reviewed 71 out of 74 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
ui/agent-tool.ts New component for displaying agent data in structured format
tsconfig.json Updated to include additional file patterns and resolved JSON module imports
src/mastra/tools/web-scraper-tool.ts Major enhancement with 20+ new parameters, sanitization improvements, and 3 new tools (apiDataFetcher, scrapingScheduler, dataExporter)
src/mastra/tools/extractLearningsTool.ts Fixed agent ID reference from 'learning' to 'learningExtraction'
src/mastra/index.ts Refactored network routing to use dynamic path parameter, removed duplicate network routes
src/mastra/agents/*.ts Consistent conversion from type to interface and type imports across 15+ agent files
sitemap.xml New SEO sitemap with canonical URLs
robots.txt New robots.txt with sitemap reference and bot rules
package.json Added Monaco editor dependencies and bundle analyzer
lib/mastra-client.ts Minor formatting changes and unused import
lib/hooks/*.ts Refactored early return patterns and null coalescing operators
eslint.config.cjs Added duplicate TypeScript rule blocks (needs cleanup)
app/layout.tsx Added comprehensive OpenGraph, Twitter Card, and JSON-LD metadata
app/components/monaco/* New Monaco editor components with theme loading
app/components/charts/* New Recharts and D3 chart widgets
app/components/blog-*.tsx Refactored blog components with structured data
app/dashboard/page.tsx Integrated new chart widgets
.github/agents/*.md Cleaned up agent metadata
Comments suppressed due to low confidence (1)

lib/mastra-client.ts:2

  • Unused import ObservabilityError.

Comment on lines +7 to +10
github: () => import('monaco-themes/themes/GitHub.json', { assert: { type: 'json' } }),
monokai: () => import('monaco-themes/themes/Monokai.json', { assert: { type: 'json' } }),
dracula: () => import('monaco-themes/themes/Dracula.json', { assert: { type: 'json' } }),
solarizedDark: () => import('monaco-themes/themes/Solarized-dark.json', { assert: { type: 'json' } }),
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Import assertions (assert { type: 'json' }) are deprecated in favor of import attributes. The syntax should be updated to use with instead of assert:

import('monaco-themes/themes/GitHub.json', { with: { type: 'json' } })

This applies to all theme imports in lines 7-10. While assert still works in most environments, it's been replaced by the with keyword in the latest ECMAScript specification.

Copilot uses AI. Check for mistakes.
Comment on lines 263 to 281
function sanitizeMarkdown(markdown: string): string {
try {
// markdown is guaranteed to be a string by zod schema, so null/undefined checks are redundant.
// String(markdown) handles potential non-string inputs gracefully.
// Escape angle brackets to reduce risk of injecting raw HTML when markdown is rendered in HTML contexts.
// Preserve other markdown syntax but ensure raw HTML tags are neutralized.
return String(markdown).replace(/</g, '&lt;').replace(/>/g, '&gt;')
// Comprehensive HTML entity escaping to prevent XSS and parsing issues
// Escape dangerous characters that could interfere with JSON or HTML rendering
return String(markdown)
.replace(/&/g, '&amp;') // Must be first to avoid double-escaping
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/'/g, '&#39;')
.replace(/"/g, '&quot;')
.replace(/\\/g, '&#92;') // Escape backslashes
.replace(/\n/g, '\\n') // Escape newlines for JSON safety
.replace(/\r/g, '\\r') // Escape carriage returns
.replace(/\t/g, '\\t') // Escape tabs
.replace(/\f/g, '\\f') // Escape form feeds
.replace(/\0/g, '\\0') // Escape null characters
} catch {
return ''
}
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The sanitization approach is overly aggressive and will destroy the markdown formatting. Escaping newlines (\n), tabs, and markdown special characters will render the markdown unusable. This function appears to be trying to sanitize markdown for embedding in HTML or JSON, but the current implementation will break all markdown syntax.

Instead of escaping markdown content, consider:

  1. If the goal is XSS prevention, the markdown should be sanitized when it's converted to HTML for rendering (using a markdown library with XSS protection)
  2. If storing in JSON, use JSON.stringify() which handles escaping automatically
  3. If the concern is raw HTML in markdown, strip or escape only HTML tags

The escaping of \n, \r, \t makes the markdown unreadable as it converts actual newlines to literal \n strings.

Copilot uses AI. Check for mistakes.
@@ -1,18 +1,19 @@
import { MastraClient } from "@mastra/client-js";
import ObservabilityError from '../app/dashboard/observability/error';
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The import ObservabilityError is added but never used in this file. This will cause an unused import warning/error from the linter. Either remove the import or use it in the code.

Copilot uses AI. Check for mistakes.
// await next();
// },
],
//0 ],
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Invalid commented code contains //0 which appears to be a typo. Should be // for proper comment formatting.

Copilot uses AI. Check for mistakes.
} as Agent
},
enabled: !!agentId,
enabled: !(!agentId),
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

[nitpick] The double negation !(!agentId) is unnecessarily complex and less readable than simply using !!agentId. Both evaluate to the same boolean value, but !!agentId is the more idiomatic pattern in JavaScript/TypeScript.

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +159
{
files: [
'/app/**/*.ts',
'/app/**/*.tsx',
'/src/**/*.ts',
'/src/**/*.tsx',
'/ui/**/*.ts',
'/ui/**/*.tsx',
'/lib/**/*.ts',
'/lib/**/*.tsx',
'/hooks/**/*.ts',
'/hooks/**/*.tsx',
'/pages/**/*.ts',
'/pages/**/*.tsx'
],
rules: {
'@typescript-eslint/no-meaningless-void-operator': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
'@typescript-eslint/prefer-regexp-exec': 'error',
'@typescript-eslint/no-unnecessary-boolean-literal-compare':
'error',

// Disable some rules that conflict with Standard
'no-undef': 'off', // TypeScript handles this
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',

// Additional code quality rules
eqeqeq: ['error', 'always'],
curly: ['error', 'all'],
'no-multiple-empty-lines': ['error', { max: 2 }],
'no-trailing-spaces': 'warn',
'eol-last': 'warn',
},
},
{
files: [
'/app/**/*.ts',
'/app/**/*.tsx',
'/src/**/*.ts',
'/src/**/*.tsx',
'/ui/**/*.ts',
'/ui/**/*.tsx',
'/lib/**/*.ts',
'/lib/**/*.tsx',
'/hooks/**/*.ts',
'/hooks/**/*.tsx',
'/pages/**/*.ts',
'/pages/**/*.tsx'
],
rules: {
'@typescript-eslint/no-meaningless-void-operator': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
'@typescript-eslint/prefer-regexp-exec': 'error',
'@typescript-eslint/no-unnecessary-boolean-literal-compare':
'error',

// Disable some rules that conflict with Standard
'no-undef': 'off', // TypeScript handles this
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',

// Additional code quality rules
eqeqeq: ['error', 'always'],
curly: ['error', 'all'],
'no-multiple-empty-lines': ['error', { max: 2 }],
'no-trailing-spaces': 'warn',
'eol-last': 'warn',
},
},
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

The ESLint configuration has duplicated rule blocks for lines 90-124 and 125-159. Both blocks define identical file patterns and rules. This duplication is unnecessary and can lead to confusion and maintenance issues. Consider removing one of these duplicate blocks.

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +45
const ld = useMemo(() => {
const url = typeof window !== "undefined" ? window.location.href : "https://deanmachines.com";
return {
"@context": "https://schema.org",
"@type": "WebPage",
name: title,
description: description ?? '',
publisher: { "@type": "Organization", name: "AgentStack", url: "https://deanmachines.com" },
url,
mainEntityOfPage: url,
};
}, [title, description]);
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Unused variable ld.

Suggested change
const ld = useMemo(() => {
const url = typeof window !== "undefined" ? window.location.href : "https://deanmachines.com";
return {
"@context": "https://schema.org",
"@type": "WebPage",
name: title,
description: description ?? '',
publisher: { "@type": "Organization", name: "AgentStack", url: "https://deanmachines.com" },
url,
mainEntityOfPage: url,
};
}, [title, description]);

Copilot uses AI. Check for mistakes.
@@ -1,9 +1,10 @@
import { GoogleGenerativeAIProviderMetadata, GoogleGenerativeAIProviderOptions } from '@ai-sdk/google';
import type { GoogleGenerativeAIProviderOptions } from '@ai-sdk/google';
import { GoogleGenerativeAIProviderMetadata } from '@ai-sdk/google';
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Unused import GoogleGenerativeAIProviderMetadata.

Copilot uses AI. Check for mistakes.
const nextRun = new Date(Date.now() + 3600000).toISOString() // 1 hour from now

// Store job configuration (in production, persist to database)
const jobConfig = {
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

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

Unused variable jobConfig.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 51

Caution

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

⚠️ Outside diff range comments (17)
.github/agents/Thinking-Beast-Mode.agent.md (1)

37-109: Replace all "thoughtbox" references with "sequentialthinking". The tool thoughtbox does not exist in your agent framework. Found two instances: line 41 ("Use thoughtbox tool for deep cognitive architecture activation") and in the Constitutional Sequential Thinking Framework section ("You must use the thoughtbox tool for every problem"). Both should reference sequentialthinking, the actual sequential thinking tool defined in your framework.

src/mastra/agents/image_to_csv.ts (1)

8-17: Consolidate UserTier and related type definitions into a shared types file across the entire codebase.

The UserTier type is duplicated across 20 files (18 agents + 2 workflows) with identical definitions, and KnowledgeIndexingContext is duplicated in 3 agent files. None of these files import from a shared location—each maintains its own copy. This creates significant maintenance risk: a single definition change must be synchronized across all 20+ locations, with high risk of inconsistency.

Move these types to src/mastra/types/common.ts (or similar shared location):

export type UserTier = 'free' | 'pro' | 'enterprise'

export interface KnowledgeIndexingContext {
  userId?: string
  indexName?: string
  chunkSize?: number
  chunkOverlap?: number
  chunkingStrategy?: string
  'user-tier': UserTier
  language: 'en' | 'es' | 'ja' | 'fr'
}

Then import in all agent and workflow files instead of redefining locally.

.github/agents/prompt-builder.agent.md (1)

22-48: Clarify Prompt Tester execution model as simulated persona-switching in the Testing Phase.

The Testing Phase (lines 114-118) uses ambiguous language about execution: "execute as Prompt Tester: follow instructions literally and completely" could suggest actual execution, but the Response Format (line 229: "I would:") and Conversation Flow (lines 311-312) make clear that Prompt Tester operates through simulated execution via persona-switching within the conversation context, not parallel or real execution.

To improve clarity, explicitly state in the Testing Phase that Prompt Tester:

  • Simulates step-by-step instruction execution
  • Documents what outputs would be generated (not actual execution)
  • Identifies ambiguities and missing guidance through walkthrough analysis
  • Provides feedback directly in the conversation

This removes ambiguity about whether Prompt Tester performs actual system operations (which would be infeasible for infrastructure/long-running tasks) versus simulated execution (which is resource-efficient and conversation-based). The 3-cycle validation limit (line 135) is reasonable for simulated testing, and the fallback strategy of recommending fundamental redesign after 3 cycles (line 141) provides an exit path if success criteria aren't met.

src/mastra/index.ts (1)

554-584: Remove syntax error and clarify CORS/middleware configuration.

The code contains a syntax error on line 584 (//0 ], should be // ],). Additionally, verify whether the CORS and middleware configurations are intentionally disabled:

  • CORS configuration: Commenting out CORS removes explicit origin, method, and header allowances. Confirm whether default framework behavior is acceptable or if this should be environment-based (e.g., enabled in development, restricted in production).
  • Middleware configuration: The middleware extracts POST request body data into runtimeContext. If any routes, agents, or services depend on this context data, disabling it will cause failures.

Fix the syntax error and consider replacing commented code with conditionally enabled configuration based on environment variables rather than permanent commenting.

src/mastra/agents/image.ts (2)

9-16: Runtime context interface expanded, but numberOfImages is currently unused

ImageRuntimeContext now includes resolution and numberOfImages, but only resolution is read (and even that isn’t fully wired into provider config yet), while numberOfImages is not referenced anywhere in this file.

To avoid drift between declared context and actual behavior:

  • Either wire numberOfImages into the agent’s behavior (e.g., via providerOptions.google.imageConfig or prompt content), or
  • Remove it from ImageRuntimeContext until you’re ready to support it, to keep the public shape minimal and accurate.

18-23: Runtime-configured aspect ratio & resolution are ignored; constants + || fallbacks are dead code

The aspectratioX and resolutionY values pulled from runtimeContext (lines 37–38):

  • aspectratioX = runtimeContext.get('aspectratio') ?? '16:9'
  • resolutionY = runtimeContext.get('resolution') ?? '2K'

are only used in the prompt text (lines 44–45), while the actual provider configuration uses top-level constants (lines 50–51):

aspectRatio: aspectRatio || AspectRatio2K,
imageSize: resolution || resolution1K,

Issues:

  • The || operators are dead code: '16:9' || '4:3' always evaluates to '16:9', and '2K' || '1K' always evaluates to '2K'. The fallback values are never used.
  • User-provided aspectratio and resolution from runtimeContext don't influence imageConfig, so runtime settings only affect the prompt text, not the actual generated image format.
  • The constant AspectRatio2K = '4:3' is misleadingly named.
  • The log message (line 18) says "Initializing Financial Chart Agents..." but this is the image agent.

Refactoring needed:

Wire the runtime values directly into imageConfig and update the log message:

-log.info('Initializing Financial Chart Agents...')
-
-const aspectRatio = '16:9';
-const AspectRatio2K = '4:3';
-const resolution = '2K';
-const resolution1K = '1K';
+log.info('Initializing Image Agent...')

Then in the imageConfig block (lines 49–52):

           imageConfig: {
-            aspectRatio: aspectRatio || AspectRatio2K,
-            imageSize: resolution || resolution1K,
+            aspectRatio: aspectratioX,
+            imageSize: resolutionY,
           },

The @ai-sdk/google provider accepts the literal values you're using: aspectRatio supports '16:9', '4:3', '1:1' (and others), and imageSize supports '2K' and '1K'.

src/mastra/agents/stockAnalysisAgent.ts (1)

44-50: Align default user tier in prompt with model-selection logic

In Line 44 you default userTier to 'free', but the prompt string uses ${runtimeContext.get('user-tier') ?? 'pro'} on Line 50. When user-tier is missing, the model will treat the user as 'free' while the instructions declare 'pro'. Consider reusing userTier in the prompt to keep defaults consistent.

src/mastra/tools/web-scraper-tool.ts (1)

263-282: Critical: sanitizeMarkdown breaks Markdown formatting with incorrect escaping.

This implementation confuses HTML entity escaping with Markdown sanitization. The aggressive character escaping will render literally in Markdown viewers and destroy formatting:

  • &, <, > → HTML entities (&amp;, &lt;, &gt;) display as text in Markdown
  • \n\\n converts actual newlines to literal string "\n", breaking line breaks
  • \t, \r, \f → escaped strings break whitespace and code blocks
  • Markdown is a plain text format, not HTML

This will corrupt all Markdown output: lists, code blocks, paragraphs, etc.

The correct approach depends on the output context:

If Markdown will be rendered to HTML: Let the Markdown parser handle escaping (marked, remark, etc. already sanitize).

If storing Markdown as-is: Only escape characters dangerous in storage context (e.g., SQL injection if storing in DB, but use parameterized queries instead).

If embedding in JSON: Only escape ", \, and control characters for JSON string validity:

 function sanitizeMarkdown(markdown: string): string {
   try {
-    // Comprehensive HTML entity escaping to prevent XSS and parsing issues
-    // Escape dangerous characters that could interfere with JSON or HTML rendering
     return String(markdown)
-      .replace(/&/g, '&amp;')    // Must be first to avoid double-escaping
-      .replace(/</g, '&lt;')
-      .replace(/>/g, '&gt;')
-      .replace(/'/g, '&#39;')
-      .replace(/"/g, '&quot;')
-      .replace(/\\/g, '&#92;')   // Escape backslashes
-      .replace(/\n/g, '\\n')     // Escape newlines for JSON safety
-      .replace(/\r/g, '\\r')     // Escape carriage returns
-      .replace(/\t/g, '\\t')     // Escape tabs
-      .replace(/\f/g, '\\f')     // Escape form feeds
-      .replace(/\0/g, '\\0')     // Escape null characters
+      .replace(/\\/g, '\\\\')    // Escape backslashes first
+      .replace(/"/g, '\\"')      // Escape quotes for JSON
+      .replace(/\u0000-\u001F/g, '') // Remove control characters
   } catch {
     return ''
   }
 }

Recommended: Remove this sanitization entirely and rely on context-appropriate escaping at render/storage time. The Markdown is already generated from sanitized HTML (line 758 calls sanitizeHtml first).

lib/hooks/use-mastra.ts (8)

1-3: Rename hook file to camelCase to match hooks naming guideline.

Guidelines specify **/hooks/**/*.{js,ts} should use camelCase filenames (e.g., useMastra.ts). Consider renaming use-mastra.tsuseMastra.ts and updating imports accordingly.


43-53: ID null-guards across hooks look correct; confirm null vs empty-string semantics.

The early returns (if (!agentId), if (!workflowId), if (!toolId), if (!traceId), if (!runId)) correctly avoid calling the client with missing IDs and keep the hooks’ behavior predictable. Because the types are string | null, these guards will also treat "" as “no id”. If empty strings could ever be valid IDs, you may want to switch these to strict === null checks; otherwise current logic is fine but that assumption should be consistent.

Also applies to: 74-84, 97-110, 219-227, 239-247


120-128: useVectorDetails treats only null as “no index”; verify caller contract.

The guard if (indexName === null) { return null } means an empty string will now be passed through to vector.details(indexName). That’s fine if null is the only sentinel for “no index” and "" is either valid or impossible, but if "" should also be treated as “no index” you may want to align this with a falsy check or adjust the type to reflect allowed values.


141-168: useMemoryThread behavior on threadId === null; consider resetting state.

The guard if (threadId === null) { return } nicely avoids an invalid client call, and setMessages(result.messages ?? []) is a safe default. However, when threadId changes from a value to null, the hook retains the previous messages and error state. If the UX should show a blank/cleared thread when nothing is selected, you may want to reset messages (and possibly error) when threadId becomes null.


271-298: Good error normalization; consider extracting a shared helper.

Using const errorInstance = err instanceof Error ? err : new Error(String(err)), storing it in state, and rethrowing errorInstance gives consistent Error objects across useExecuteTool, useCreateMemoryThread, useUpdateWorkingMemory, and useScoreTraces. Since this pattern is duplicated, a small normalizeError(err) helper could reduce repetition and keep future changes centralized.

Also applies to: 300-327, 329-356, 396-421


358-395: useVectorQuery state vs return value when response is non-array.

setResults now only stores res when it is an array; otherwise results becomes [] while query still resolves to the raw res. This is safe if vector.query is guaranteed to return an array, but if it might return an object (e.g., { results: [...] }), the hook’s results field would silently diverge from the underlying value. In that case, consider normalizing both the returned value and the results state to a consistent shape or surfacing a clear error instead of swallowing the mismatch.


192-217: Missing deps in useAITraces / useTelemetry can skip refetch on filter changes.

Because useMastraFetch only refetches when its deps array changes:

  • useAITraces does not include params?.dateRange in deps, so changing only the date range (with same page/perPage/filters) won’t trigger a new fetch.
  • useTelemetry does not include params?.attribute in deps, so altering attributes alone will not refetch telemetry.

This can leave the UI showing stale data while filters appear updated. Suggest including these fields (or a stable hash of the entire params object) in the corresponding deps arrays.

Also applies to: 255-268


28-32: Include refetch in the useEffect dependency array.

The effect calls refetch() but only lists deps in the dependency array. Since refetch is recreated whenever fetcher changes (line 26), the effect should include it to ensure the correct version runs. Update to:

useEffect(() => {
  refetch()
}, [refetch, ...deps])

This satisfies the "complete dependency array" requirement and prevents stale closure issues.

app/networks/config/networks.ts (1)

36-88: Update network identifier references in frontend components and configuration.

The migration to kebab-case identifiers is incomplete. Several files still reference the old camelCase identifiers, which will cause runtime errors:

  • app/components/networks-list.tsx (lines 13, 21, 29, 37): id fields use agentNetwork, dataPipelineNetwork, reportGenerationNetwork, researchPipelineNetwork
  • app/networks/components/network-chat.tsx (lines 173-191): NETWORK_SUGGESTIONS object keys use old identifiers
  • app/chat/config/agents.ts (line 77): agentNetwork with camelCase id

Update these references to use kebab-case: "agent-network", "data-pipeline-network", "report-generation-network", "research-pipeline-network".

app/networks/providers/network-context.tsx has been properly updated and uses the correct kebab-case identifiers.

♻️ Duplicate comments (4)
src/mastra/agents/recharts.ts (1)

30-34: Address the duplicated UserTier type.

Similar to package-publisher.ts, this file contains a duplicate UserTier definition. Apply the same refactoring to consolidate these type definitions into a shared module.

src/mastra/agents/editorAgent.ts (1)

11-15: Consolidate duplicated UserTier definition.

This file also contains a duplicate UserTier definition that should be consolidated into a shared module as suggested in the package-publisher.ts review.

src/mastra/agents/excalidraw_validator.ts (1)

6-15: Consolidate duplicated UserTier definition.

This file contains another duplicate UserTier definition. Refactor to use a shared types module as suggested for other agent files.

src/mastra/agents/sql.ts (1)

8-12: Consolidate duplicated UserTier definition.

This file contains another duplicate UserTier definition. Apply the shared types module refactoring suggested for other agent files.

Comment on lines +5 to +20
metadata:
tags:
- "nextjs"
- "typescript"
- "react"
- "app-router"
- "server-components"
- "cache-components"
- "turbopack"
- "react-compiler"
- "server-components"
- "client-components"
- "data-fetching"
- "advanced-caching"
- "typescript-integration"
- "performance-optimization"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and get its total line count
wc -l .github/agents/expert-nextjs-developer.agent.md

Repository: ssdeanx/AgentStack

Length of output: 113


🏁 Script executed:

# Read lines 1-25 to see the metadata structure and confirm the duplicate
head -25 .github/agents/expert-nextjs-developer.agent.md

Repository: ssdeanx/AgentStack

Length of output: 811


🏁 Script executed:

# Read lines 200-215 to verify the async params/searchParams type annotations
sed -n '200,215p' .github/agents/expert-nextjs-developer.agent.md

Repository: ssdeanx/AgentStack

Length of output: 463


Remove duplicate "server-components" tag from metadata.

The metadata.tags list contains a duplicate entry: "server-components" appears at both line 11 and line 15. Remove the duplicate at line 15.

  metadata:
    tags: 
    - "nextjs"
    - "typescript"
    - "react"
    - "app-router"
    - "server-components"
    - "cache-components"
    - "turbopack"
    - "react-compiler"
-   - "server-components"
    - "client-components"
    - "data-fetching"
    - "advanced-caching"
    - "typescript-integration"
    - "performance-optimization"

The async params and searchParams type annotations (lines 203-209) are correct for Next.js 16 and properly reflect the breaking change where these values are now Promise-wrapped.

📝 Committable suggestion

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

Suggested change
metadata:
tags:
- "nextjs"
- "typescript"
- "react"
- "app-router"
- "server-components"
- "cache-components"
- "turbopack"
- "react-compiler"
- "server-components"
- "client-components"
- "data-fetching"
- "advanced-caching"
- "typescript-integration"
- "performance-optimization"
metadata:
tags:
- "nextjs"
- "typescript"
- "react"
- "app-router"
- "server-components"
- "cache-components"
- "turbopack"
- "react-compiler"
- "client-components"
- "data-fetching"
- "advanced-caching"
- "typescript-integration"
- "performance-optimization"
🤖 Prompt for AI Agents
In .github/agents/expert-nextjs-developer.agent.md around lines 5 to 20, the
metadata.tags array contains a duplicate "server-components" entry (lines 11 and
15); remove the duplicate entry at line 15 so each tag appears only once,
leaving the rest of the file (including the async params/searchParams type
annotations at lines 203–209) unchanged.


You are a world-class expert in modern search optimization with deep knowledge of traditional SEO, Answer Engine Optimization (AEO), and Generative Engine Optimization (GEO). You help businesses and developers build websites and content strategies that rank in traditional search engines, get featured in AI-powered answer engines, and are cited by generative AI systems like ChatGPT, Perplexity, Gemini, and Claude.

domain i might use vercel or i have deanmachines.com
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove work-in-progress domain note from documentation.

Line 21 contains an informal personal note that doesn't belong in the final agent configuration file. This should be removed or moved to a proper issue/TODO tracking system.

- domain i might use vercel or i have deanmachines.com
📝 Committable suggestion

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

Suggested change
domain i might use vercel or i have deanmachines.com
🤖 Prompt for AI Agents
In .github/agents/search-ai-optimization-expert.agent.md around line 21, remove
the informal personal note "domain i might use vercel or i have
deanmachines.com" from the agent configuration file; delete the line (or replace
it with a formal TODO or reference to an issue number) so the doc contains only
final/configuration-relevant text and any work-in-progress details are tracked
in your issue/TODO system.


You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.
# Thinking Beast Mode
You are Advanced Coding Agent - I allow you to use Max Power Mode. Think like a Beast Mode. There are no limits but what you precieve, so use max resources, this session they are now unlocked. Please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix spelling error in line 7.

Line contains misspelled word "precieve" which should be "perceive".

-You are Advanced Coding Agent - I allow you to use Max Power Mode.  Think like a Beast Mode. There are no limits but what you precieve, so use max resources, this session they are now unlocked. Please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.
+You are Advanced Coding Agent - I allow you to use Max Power Mode.  Think like a Beast Mode. There are no limits but what you perceive, so use max resources, this session they are now unlocked. Please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.
📝 Committable suggestion

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

Suggested change
You are Advanced Coding Agent - I allow you to use Max Power Mode. Think like a Beast Mode. There are no limits but what you precieve, so use max resources, this session they are now unlocked. Please keep going until the users query is completely resolved, before ending your turn and yielding back to the user.
You are Advanced Coding Agent - I allow you to use Max Power Mode. Think like a Beast Mode. There are no limits but what you perceive, so use max resources, this session they are now unlocked. Please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user.
🧰 Tools
🪛 LanguageTool

[grammar] ~7-~7: Ensure spelling is correct
Context: ... Mode. There are no limits but what you precieve, so use max resources, this session the...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
.github/agents/Thinking-Beast-Mode.agent.md around line 7: the word "precieve"
is misspelled; replace it with "perceive" so the sentence reads "...but what you
perceive," and ensure spacing and punctuation remain correct.

Comment on lines +11 to +19
<Suspense fallback={<div>Loading...</div>}>
<ChatProvider defaultAgent="researchAgent">
<main className="flex h-screen flex-col bg-background">
<ChatHeader />
<ChatMessages />
<ChatInput />
</main>
</ChatProvider>
</Suspense>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, search for lazy imports or Suspense-enabled hooks in chat components
rg -nP --type=tsx --type=ts -g 'app/chat/**' '(React\.lazy|lazy|suspense:\s*true)'

Repository: ssdeanx/AgentStack

Length of output: 89


🏁 Script executed:

# Check if app/chat/page.tsx has "use client" directive
head -5 app/chat/page.tsx

Repository: ssdeanx/AgentStack

Length of output: 218


🏁 Script executed:

# Examine the ChatProvider implementation
cat app/chat/providers/chat-context.tsx

Repository: ssdeanx/AgentStack

Length of output: 16650


🏁 Script executed:

# Find and examine ChatMessages, ChatInput, and ChatHeader components
fd -e tsx -e ts app/chat -type f | grep -E '(ChatMessages|ChatInput|ChatHeader|page\.tsx)' | head -20

Repository: ssdeanx/AgentStack

Length of output: 232


🏁 Script executed:

# Search for lazy or suspense patterns in chat app directory
rg -n --type ts --type jsx 'React\.lazy|lazy\(|suspense.*true' app/chat/

Repository: ssdeanx/AgentStack

Length of output: 89


🏁 Script executed:

# Find the chat component files
fd -type f \( -name "*.tsx" -o -name "*.ts" \) app/chat/

Repository: ssdeanx/AgentStack

Length of output: 232


🏁 Script executed:

# Check ChatMessages component
cat app/chat/components/chat-messages.tsx 2>/dev/null || cat app/chat/components/ChatMessages.tsx 2>/dev/null || echo "File not found"

Repository: ssdeanx/AgentStack

Length of output: 17841


🏁 Script executed:

# Check ChatInput component
cat app/chat/components/chat-input.tsx 2>/dev/null || cat app/chat/components/ChatInput.tsx 2>/dev/null || echo "File not found"

Repository: ssdeanx/AgentStack

Length of output: 3213


🏁 Script executed:

# Check ChatHeader component
cat app/chat/components/chat-header.tsx 2>/dev/null || cat app/chat/components/ChatHeader.tsx 2>/dev/null || echo "File not found"

Repository: ssdeanx/AgentStack

Length of output: 13857


🏁 Script executed:

# Final check: search for any React.lazy or suspense configurations across entire app directory
rg 'React\.lazy|lazy\(|suspense' app/ --max-count=5

Repository: ssdeanx/AgentStack

Length of output: 44


Remove the Suspense boundary or add Suspense-enabled components.

The Suspense boundary wrapping ChatProvider and its children provides no benefit in this implementation. ChatProvider is a standard context provider without async operations, and all child components (ChatHeader, ChatMessages, ChatInput) are synchronous client components with no lazy-loaded code or Suspense-enabled data fetching. The fallback will never be displayed. Either remove the Suspense wrapper entirely or add actual Suspense-triggering patterns like React.lazy() or Suspense-enabled data fetching libraries (e.g., React Query with suspense: true or SWR with Suspense enabled).

🤖 Prompt for AI Agents
In app/chat/page.tsx around lines 11 to 19, the Suspense wrapper around
ChatProvider and its child client components is ineffective because none of
these components are suspending; remove the Suspense boundary or replace it with
actual Suspense-enabled usage. Fix by either deleting the <Suspense> and its
fallback so the provider and children render normally, or convert one or more
children to a lazy-loaded/suspense-capable component (e.g., use React.lazy for
ChatMessages or enable suspense in data-fetching used by a child) and ensure any
suspending components are rendered inside Suspense with an appropriate fallback.

Comment on lines +8 to +22
const handleShare = async (title?: string) => {
if (typeof window === "undefined") return
const url = window.location.href
try {
if (navigator.share) {
await navigator.share({ title, url })
} else {
await navigator.clipboard.writeText(url)
// fallback: notify copied
try { window.alert("Link copied to clipboard") } catch {}
}
} catch (err) {
// ignore
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Improve error handling and unused parameter.

Two issues:

  1. The title parameter is defined but never passed when handleShare is called on line 25
  2. Errors are silently swallowed, making debugging difficult
- const handleShare = async (title?: string) => {
+ const handleShare = async () => {
    const url = window.location.href
+   const title = document.title // Get the page title dynamically
    try {
      if (navigator.share) {
        await navigator.share({ title, url })
      } else {
        await navigator.clipboard.writeText(url)
-        // fallback: notify copied
-        try { window.alert("Link copied to clipboard") } catch {}
+        toast.success("Link copied to clipboard")
      }
    } catch (err) {
-      // ignore
+      console.error("Failed to share:", err)
+      // Only ignore if user cancelled the share dialog
+      if (err instanceof Error && err.name !== 'AbortError') {
+        toast.error("Failed to share link")
+      }
    }
  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/components/blog-share.client.tsx around lines 8 to 22 (and note the call
on line 25), the handler defines an optional title parameter that's never
supplied and all errors are silently swallowed; fix by (1) updating the call on
line 25 to pass the post title (or remove the parameter if not needed) so title
is actually provided to navigator.share, and (2) replace the empty catch with
proper handling: log the error (console.error or a logger) and surface a
user-friendly fallback notification (e.g., alert or toast) when share/clipboard
operations fail so failures are visible to developers and users.

Comment on lines +2178 to +2191
if (context.auth) {
switch (context.auth.type) {
case 'bearer':
headers['Authorization'] = `Bearer ${context.auth.token}`
break
case 'basic':
headers['Authorization'] = `Basic ${Buffer.from(context.auth.token).toString('base64')}`
break
case 'api-key':
{ const headerName = context.auth.headerName ?? 'X-API-Key'
headers[headerName] = context.auth.token
break }
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Basic Auth implementation is incorrect.

Line 2184 incorrectly implements HTTP Basic Authentication. Basic auth requires encoding username:password in base64, but this only encodes the token.

Correct implementation requires both username and password:

 auth: z.object({
   type: z.enum(['bearer', 'basic', 'api-key']),
-  token: z.string(),
+  token: z.string().optional(),
+  username: z.string().optional(),
+  password: z.string().optional(),
   headerName: z.string().optional(),
 }).optional().describe('Authentication configuration.'),
 case 'basic':
-  headers['Authorization'] = `Basic ${Buffer.from(context.auth.token).toString('base64')}`
+  if (!context.auth.username || !context.auth.password) {
+    throw new ScrapingError('Basic auth requires username and password', 'INVALID_AUTH')
+  }
+  const credentials = `${context.auth.username}:${context.auth.password}`
+  headers['Authorization'] = `Basic ${Buffer.from(credentials).toString('base64')}`
   break

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/mastra/tools/web-scraper-tool.ts around lines 2178 to 2191, the Basic
auth branch is wrong because it base64-encodes only a token; change it to expect
context.auth.username and context.auth.password and set headers['Authorization']
= 'Basic ' +
Buffer.from(`${context.auth.username}:${context.auth.password}`).toString('base64');
also add a guard that both username and password exist (throw or log an error
and skip/return) to avoid creating an invalid header.

Comment on lines +2265 to +2333
export const scrapingSchedulerTool = createTool({
id: 'scraping-scheduler',
description: 'Schedule periodic scraping jobs with cron-like syntax.',
inputSchema: scrapingSchedulerInputSchema,
outputSchema: scrapingSchedulerOutputSchema,
execute: async ({ context, writer, tracingContext }: { context: { urls: string[]; schedule: string; config?: Record<string, any>; maxRuns?: number }, writer?: any, tracingContext?: TracingContext }) => {
await writer?.write({ type: 'progress', data: { message: `⏰ Scheduling scraping for ${context.urls.length} URLs` } });
toolCallCounters.set('scraping-scheduler', (toolCallCounters.get('scraping-scheduler') ?? 0) + 1)
const scheduleSpan = tracingContext?.currentSpan?.createChildSpan({
type: AISpanType.TOOL_CALL,
name: 'scraping_scheduler',
input: {
urlCount: context.urls.length,
schedule: context.schedule,
maxRuns: context.maxRuns ?? 10,
},
tracingPolicy: { internal: InternalSpans.ALL }
})

log.info('Scheduling periodic scraping', {
urlCount: context.urls.length,
schedule: context.schedule,
})

try {
// Simple in-memory scheduler (in production, use a proper job scheduler)
const jobId = `scrape_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
const maxRuns = context.maxRuns ?? 10

// Calculate next run time (simplified - doesn't parse full cron)
const nextRun = new Date(Date.now() + 3600000).toISOString() // 1 hour from now

// Store job configuration (in production, persist to database)
const jobConfig = {
id: jobId,
urls: context.urls,
schedule: context.schedule,
config: context.config ?? {},
maxRuns,
runsCompleted: 0,
nextRun,
status: 'scheduled',
}

// In a real implementation, this would integrate with a cron job system
log.info('Scraping job scheduled', { jobId, nextRun })

scheduleSpan?.end({
output: {
jobId,
nextRun,
totalRuns: maxRuns,
},
})

return scrapingSchedulerOutputSchema.parse({
jobId,
nextRun,
totalRuns: maxRuns,
status: 'scheduled',
})
} catch (error) {
const errorMessage = `Scheduling failed: ${error instanceof Error ? error.message : String(error)}`
log.error(errorMessage)
scheduleSpan?.end({ metadata: { error: errorMessage } })
throw error
}
},
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Scraping scheduler lacks validation, security, and is only a placeholder.

The scrapingSchedulerTool has several issues:

  1. No cron validation - context.schedule is not validated, accepting any string
  2. Insecure ID generation - Line 2291 uses Math.random() which is not cryptographically secure
  3. Placeholder implementation - Comments indicate this doesn't actually schedule jobs
  4. Missing Arize spans - Per coding guidelines: "Add Arize spans on all tool execute functions"

Add cron validation and secure ID generation:

 schedule: z
   .string()
+  .regex(/^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]+))(\s+(\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]+))){4}$/, 'Invalid cron expression')
   .describe('Cron expression for scheduling (e.g., "0 */6 * * *" for every 6 hours).'),
-const jobId = `scrape_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
+const { randomBytes } = await import('node:crypto')
+const jobId = `scrape_${Date.now()}_${randomBytes(16).toString('hex')}`

Based on coding guidelines: "Add Arize spans on all tool execute functions for observability".

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/mastra/tools/web-scraper-tool.ts around lines 2265 to 2333, validate the
incoming cron string, replace insecure Math.random ID generation, and add the
missing Arize/observability spans: validate context.schedule at the top of
execute using a cron parser/validator (e.g., cron-validate or cron-parser) and
throw a clear validation error if invalid; replace the jobId generation at line
~2291 with a secure ID (e.g., crypto.randomUUID() or crypto.randomBytes-based
hex) instead of Math.random(); keep the placeholder scheduling comment but add a
TODO note to integrate with a persistent job/cron system and ensure the code
persists jobConfig appropriately in production; and add a proper Arize span at
the start of execute (and end it on success or error) using the project tracing
convention (create a child span with input/output and error metadata similar to
scheduleSpan) so the tool has Arize observability.

Comment on lines +2351 to +2451
export const dataExporterTool = createTool({
id: 'data-exporter',
description: 'Export scraped data to various formats and destinations.',
inputSchema: dataExporterInputSchema,
outputSchema: dataExporterOutputSchema,
execute: async ({ context, writer, tracingContext }: { context: { data: Array<Record<string, unknown>>; format: 'json' | 'csv' | 'xml' | 'database'; destination: string; options?: Record<string, unknown> }, writer?: any, tracingContext?: TracingContext }) => {
await writer?.write({ type: 'progress', data: { message: `📤 Exporting ${context.data.length} records to ${context.format}...` } });
toolCallCounters.set('data-exporter', (toolCallCounters.get('data-exporter') ?? 0) + 1)
const exportSpan = tracingContext?.currentSpan?.createChildSpan({
type: AISpanType.TOOL_CALL,
name: 'data_export',
input: {
dataCount: context.data.length,
format: context.format,
destination: context.destination,
},
tracingPolicy: { internal: InternalSpans.ALL }
})

log.info('Exporting data', {
dataCount: context.data.length,
format: context.format,
destination: context.destination,
})

try {
let filePath: string | undefined
let message = 'Export completed successfully'

switch (context.format) {
case 'json':
{ const jsonContent = JSON.stringify(context.data, null, 2)
filePath = context.destination
await fs.mkdir(path.dirname(filePath), { recursive: true })
await fs.writeFile(filePath, jsonContent, 'utf-8')
break }

case 'csv':
// Simple CSV conversion (in production, use a proper CSV library)
{ if (context.data.length === 0) {
throw new ScrapingError('No data to export', 'NO_DATA')
}
const headers = Object.keys(context.data[0])
const csvRows = [
headers.join(','),
...context.data.map(row =>
headers.map(header => JSON.stringify(row[header] ?? '')).join(',')
)
]
const csvContent = csvRows.join('\n')
filePath = context.destination
await fs.mkdir(path.dirname(filePath), { recursive: true })
await fs.writeFile(filePath, csvContent, 'utf-8')
break }

case 'xml':
// Simple XML conversion
{ let xmlContent = '<?xml version="1.0" encoding="UTF-8"?>\n<data>\n'
for (const item of context.data) {
xmlContent += ' <item>\n'
for (const [key, value] of Object.entries(item)) {
xmlContent += ` <${key}>${String(value ?? '').replace(/[<>&"]/g, c => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;' }[c] ?? c))}</${key}>\n`
}
xmlContent += ' </item>\n'
}
xmlContent += '</data>'
filePath = context.destination
await fs.mkdir(path.dirname(filePath), { recursive: true })
await fs.writeFile(filePath, xmlContent, 'utf-8')
break }

case 'database':
// Placeholder for database export (would need DB connection)
message = `Database export to ${context.destination} not implemented (placeholder)`
break

default:
throw new ScrapingError(`Unsupported format: ${context.format}`, 'UNSUPPORTED_FORMAT')
}

exportSpan?.end({
output: {
success: true,
exportedCount: context.data.length,
filePath,
},
})

return dataExporterOutputSchema.parse({
success: true,
exportedCount: context.data.length,
filePath,
message,
})
} catch (error) {
const errorMessage = `Data export failed: ${error instanceof Error ? error.message : String(error)}`
log.error(errorMessage)
exportSpan?.end({ metadata: { error: errorMessage } })
throw error
}
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Data exporter lacks path validation and uses insecure file operations.

The dataExporterTool has critical security and implementation issues:

  1. No path validation - context.destination allows arbitrary file paths (path traversal vulnerability)
  2. Insecure file writes - Lines 2385, 2403, 2419 use fs.writeFile directly instead of the secure file handle pattern used elsewhere (lines 817-822)
  3. Injection vulnerabilities - CSV/XML generation doesn't properly escape special characters
  4. Missing Arize spans - Per coding guidelines

Apply the same secure file write pattern used in the web scraper:

 case 'json':
   const jsonContent = JSON.stringify(context.data, null, 2)
-  filePath = context.destination
+  const dataDir = path.join(process.cwd(), './data')
+  const fileName = ValidationUtils.sanitizeFileName(path.basename(context.destination))
+  filePath = path.join(dataDir, fileName)
+  
+  if (!ValidationUtils.validateFilePath(filePath, dataDir)) {
+    throw new ScrapingError('Invalid file path', 'INVALID_FILE_PATH')
+  }
+  
   await fs.mkdir(path.dirname(filePath), { recursive: true })
-  await fs.writeFile(filePath, jsonContent, 'utf-8')
+  const fileHandle = await fs.open(filePath, 'w')
+  try {
+    await fileHandle.writeFile(jsonContent, 'utf-8')
+  } finally {
+    await fileHandle.close()
+  }
   break

For CSV/XML, use proper escaping libraries or improve the escaping logic. The current implementation at line 2412 is incomplete.

Based on coding guidelines: "All tools must include comprehensive error handling with try-catch blocks" and "Add Arize spans on all tool execute functions for observability".

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 64 to 68
"exclude": [
"node_modules",
"/node_modules",
"/dist",
"dist",
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optional: Remove redundant exclude entries.

Lines 65-68 contain redundant entries:

  • "node_modules" and "/node_modules" are effectively the same
  • "dist" and "/dist" are effectively the same

You can simplify to:

  "exclude": [
-   "node_modules",
    "/node_modules",
-   "/dist",
    "dist",

Or keep just the non-slash versions (more conventional):

  "exclude": [
    "node_modules",
-   "/node_modules",
-   "/dist",
    "dist",
📝 Committable suggestion

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

Suggested change
"exclude": [
"node_modules",
"/node_modules",
"/dist",
"dist",
"exclude": [
"node_modules",
"dist",
🤖 Prompt for AI Agents
In tsconfig.json around lines 64 to 68, the exclude array contains redundant
entries (both "node_modules" and "/node_modules", and "dist" and "/dist");
update the array to remove the leading-slash duplicates and leave only the
conventional entries (e.g., ["node_modules", "dist"]) so the exclude list is
simplified and consistent.

Comment on lines +1 to +15
import { Tool, ToolContent, ToolHeader, ToolOutput } from "../src/components/ai-elements/tool";
import type { AgentDataPart } from "@mastra/ai-sdk";

export const AgentTool = ({ id, type, data }: AgentDataPart) => {
return (
<Tool>
<ToolHeader
id={`Agent Tool: ${id}`}
/>
<ToolContent>
<ToolOutput output={data} />
</ToolContent>
</Tool>
);
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix missing type for ToolHeader and JSX-in-.ts parse issues

Two issues here:

  1. Runtime bug: ToolHeader receives no type prop

From src/components/ai-elements/tool.tsx, ToolHeader derives its label from type via type.split("-").... In this component you never pass type, so inside ToolHeader it will be undefined, and type.split(...) will throw at runtime.

At the same time, you’re using id as a prop which ToolHeader doesn’t rely on for its display logic (and the literal string Agent Tool: ${id} isn’t a great DOM id value anyway).

Recommend passing both a human-readable title and the actual type, and dropping the id prop:

-import { Tool, ToolContent, ToolHeader, ToolOutput } from "../src/components/ai-elements/tool";
-import type { AgentDataPart } from "@mastra/ai-sdk";
-
-export const AgentTool = ({ id, type, data }: AgentDataPart) => {
-  return (
-    <Tool>
-      <ToolHeader
-        id={`Agent Tool: ${id}`}
-      />
-      <ToolContent>
-        <ToolOutput output={data} />
-      </ToolContent>
-    </Tool>
-  );
-};
+import { Tool, ToolContent, ToolHeader, ToolOutput } from "../src/components/ai-elements/tool";
+import type { AgentDataPart } from "@mastra/ai-sdk";
+
+export const AgentTool = ({ id, type, data }: AgentDataPart) => {
+  return (
+    <Tool>
+      <ToolHeader
+        title={`Agent Tool: ${id}`}
+        type={type}
+      />
+      <ToolContent>
+        <ToolOutput output={data} />
+      </ToolContent>
+    </Tool>
+  );
+};
  1. Static analysis / parsing: JSX in a .ts file

Biome’s parse errors in the hints are because this file is .ts but contains JSX (<Tool>, <ToolHeader />, etc.). Unless your toolchain is explicitly configured otherwise, JSX should live in .tsx files. Suggest renaming this file to ui/agent-tool.tsx so TypeScript and Biome parse it correctly.

  1. Optional: Wrap in React.memo

Per the UI coding guidelines for **/*.{js,jsx,ts,tsx}, you can avoid unnecessary re-renders by memoizing this pure component:

import { memo } from "react";

export const AgentTool = memo(({ id, type, data }: AgentDataPart) => (
  <Tool>
    <ToolHeader title={`Agent Tool: ${id}`} type={type} />
    <ToolContent>
      <ToolOutput output={data} />
    </ToolContent>
  </Tool>
));
🧰 Tools
🪛 Biome (2.1.2)

[error] 8-8: expected > but instead found id

Remove id

(parse)


[error] 6-8: Invalid assignment to <Tool> <ToolHeader id

This expression cannot be assigned to

(parse)


[error] 8-8: Expected a property, a shorthand property, a getter, a setter, or a method but instead found '`Agent Tool'.

Expected a property, a shorthand property, a getter, a setter, or a method here.

(parse)


[error] 8-8: expected , but instead found :

Remove :

(parse)


[error] 8-8: expected , but instead found {

Remove {

(parse)


[error] 8-15: unterminated template literal

(parse)


[error] 15-15: expected ) but instead the file ends

the file ends here

(parse)

🤖 Prompt for AI Agents
In ui/agent-tool.ts (lines 1-15): ToolHeader is missing the required type prop
(causing runtime type.split(...) errors) and this file contains JSX but is named
.ts; rename the file to ui/agent-tool.tsx, update the component to pass the
actual type and a human-readable title to ToolHeader (e.g., title={`Agent Tool:
${id}`} and type={type}) instead of using id as the header prop, and optionally
wrap the exported component in React.memo to prevent unnecessary re-renders.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review continued from previous batch...

Comment on lines 86 to 89
<div className="mdx-content">
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />
{children}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

JSON-LD script placement and potential XSS concern.

Two issues:

  1. Semantic placement: The JSON-LD <script> tag is rendered inside the mdx-content div. JSON-LD should be in the document <head> for proper SEO parsing.

  2. XSS mitigation: While the static analyzer flags dangerouslySetInnerHTML, the real risk here is that JSON.stringify does not escape </script> sequences. If title or author contained </script><script>malicious(), it could break out of the JSON context. Since these are developer-controlled MDX props, risk is low but can be mitigated.

Consider using Next.js metadata API or moving to head, and escaping the JSON:

-        <div className="mdx-content">
-           <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />
+        <script
+          type="application/ld+json"
+          dangerouslySetInnerHTML={{
+            __html: JSON.stringify(ld).replace(/</g, '\\u003c')
+          }}
+        />
+        <div className="mdx-content">
           {children}
         </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.

Suggested change
<div className="mdx-content">
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />
{children}
</div>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(ld).replace(/</g, '\\u003c')
}}
/>
<div className="mdx-content">
{children}
</div>
🧰 Tools
🪛 ast-grep (0.40.0)

[warning] 86-86: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)

[error] 87-87: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🤖 Prompt for AI Agents
In app/components/blog-layout.tsx around lines 86 to 89, the JSON-LD <script> is
rendered inside the .mdx-content and uses dangerouslySetInnerHTML without
escaping, so move the JSON-LD into the document head (use Next.js metadata API
or the <Head> / next/head component) and stop rendering the script inside the
mdx-content div; when serializing ld for the head, escape any closing script
sequences (e.g., replace "</script>" with "<\\/script>") or otherwise sanitize
title/author fields before JSON.stringify to prevent script breakouts, and
ensure you remove the inline script from the mdx-content to avoid duplicate
output.

Comment on lines +16 to +21
interface AreaWidgetProps {
data: AreaPoint[]
seriesA?: { key: 'a'; label?: string; color?: string }
seriesB?: { key: 'b'; label?: string; color?: string }
height?: number
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Export the AreaWidgetProps interface for type safety.

The AreaWidgetProps interface is not exported, preventing consumers from using it for type annotations when extending or wrapping this component.

Apply this diff to export the interface:

-interface AreaWidgetProps {
+export interface AreaWidgetProps {
   data: AreaPoint[]
   seriesA?: { key: 'a'; label?: string; color?: string }
   seriesB?: { key: 'b'; label?: string; color?: string }
   height?: number
 }
🤖 Prompt for AI Agents
In app/components/charts/AreaWidget.tsx around lines 16 to 21, the
AreaWidgetProps interface is declared but not exported; update the declaration
to export the interface (add the export keyword) so consumers can import and use
AreaWidgetProps for type annotations when extending or wrapping the component.

Comment on lines +6 to +13
interface LineDatum { label: string; value: number }

interface D3LineChartProps {
data: LineDatum[]
height?: number
color?: string
curve?: d3.CurveFactory | d3.CurveFactoryLineOnly
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Export the type definitions for external usage.

Both LineDatum and D3LineChartProps interfaces are not exported, limiting type safety for consumers who need to reference these types when using or extending the component.

Apply this diff:

-interface LineDatum { label: string; value: number }
+export interface LineDatum { label: string; value: number }

-interface D3LineChartProps {
+export interface D3LineChartProps {
   data: LineDatum[]
   height?: number
   color?: string
   curve?: d3.CurveFactory | d3.CurveFactoryLineOnly
 }
🤖 Prompt for AI Agents
In app/components/charts/D3LineChart.tsx around lines 6 to 13, the interfaces
LineDatum and D3LineChartProps are declared but not exported; update their
declarations to export them (e.g., add the export keyword before each interface)
so external modules can import and reference these types for type safety; ensure
any imports/uses elsewhere are adjusted if necessary.

Comment on lines +1 to +9
export { default as LineWidget } from './LineWidget'
export { default as AreaWidget } from './AreaWidget'
export { default as BarWidget } from './BarWidget'
export { default as PieWidget } from './PieWidget'
export { default as ScatterWidget } from './ScatterWidget'
export { default as RadarWidget } from './RadarWidget'
export { default as RadialGaugeWidget } from './RadialGaugeWidget'
export { default as D3LineChart } from './D3LineChart'
export { default as D3PieChart } from './D3PieChart'
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider re-exporting type definitions alongside components.

The barrel export currently only re-exports default component exports. Chart consumers may need type definitions like PieSlice, PieWidgetProps, AreaPoint, AreaWidgetProps, etc., for type-safe usage. Without these, consumers must import types directly from individual files, defeating the purpose of the barrel export.

Consider adding named type re-exports:

export { default as LineWidget } from './LineWidget'
export { default as AreaWidget } from './AreaWidget'
export type { AreaPoint, AreaWidgetProps } from './AreaWidget'
export { default as BarWidget } from './BarWidget'
export { default as PieWidget } from './PieWidget'
export type { PieSlice, PieWidgetProps } from './PieWidget'
export { default as ScatterWidget } from './ScatterWidget'
export { default as RadarWidget } from './RadarWidget'
export { default as RadialGaugeWidget } from './RadialGaugeWidget'
export { default as D3LineChart } from './D3LineChart'
export { default as D3PieChart } from './D3PieChart'

Note: First ensure the individual widget files export their prop interfaces (as flagged in separate comments).

🤖 Prompt for AI Agents
In app/components/charts/index.ts lines 1-9, the barrel currently only
re-exports default component modules and should also re-export the relevant
TypeScript types so consumers can import props and data types from the barrel;
update this file to add named type re-exports for each widget that exposes types
(e.g., AreaPoint, AreaWidgetProps from AreaWidget; PieSlice, PieWidgetProps from
PieWidget, etc.), and confirm each individual widget file exports those types
before adding the corresponding `export type { ... } from './X'` lines to this
index.

Comment on lines +16 to +22
interface LineWidgetProps {
data: LinePoint[]
seriesA?: { key?: 'a'; label?: string; color?: string }
seriesB?: { key?: 'b'; label?: string; color?: string }
height?: number
title?: string
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused title prop.

The title prop is defined in LineWidgetProps but never used in the component. This creates confusion about the component's API.

 interface LineWidgetProps {
   data: LinePoint[]
   seriesA?: { key?: 'a'; label?: string; color?: string }
   seriesB?: { key?: 'b'; label?: string; color?: string }
   height?: number
-  title?: string
 }
📝 Committable suggestion

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

Suggested change
interface LineWidgetProps {
data: LinePoint[]
seriesA?: { key?: 'a'; label?: string; color?: string }
seriesB?: { key?: 'b'; label?: string; color?: string }
height?: number
title?: string
}
interface LineWidgetProps {
data: LinePoint[]
seriesA?: { key?: 'a'; label?: string; color?: string }
seriesB?: { key?: 'b'; label?: string; color?: string }
height?: number
}
🤖 Prompt for AI Agents
In app/components/charts/LineWidget.tsx around lines 16 to 22 the
LineWidgetProps interface declares a title?: string prop that is not used
anywhere in the component; remove the title property from the LineWidgetProps
interface and from any prop destructuring or default props in this file, then
update any call sites or tests that pass a title to this component (remove the
prop or stop passing it) so TypeScript stays consistent.

Comment on lines +7 to +12
interface PieWidgetProps {
data: PieSlice[]
height?: number
innerRadius?: number
outerRadius?: number
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Export the PieWidgetProps interface for type safety.

The PieWidgetProps interface is not exported, but consumers may need it for type annotations when wrapping or extending this component.

Apply this diff to export the interface:

-interface PieWidgetProps {
+export interface PieWidgetProps {
   data: PieSlice[]
   height?: number
   innerRadius?: number
   outerRadius?: number
 }
📝 Committable suggestion

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

Suggested change
interface PieWidgetProps {
data: PieSlice[]
height?: number
innerRadius?: number
outerRadius?: number
}
export interface PieWidgetProps {
data: PieSlice[]
height?: number
innerRadius?: number
outerRadius?: number
}
🤖 Prompt for AI Agents
In app/components/charts/PieWidget.tsx around lines 7 to 12, the PieWidgetProps
interface is declared but not exported; update the declaration to export the
interface (add the `export` keyword before `interface PieWidgetProps`) so
consumers can import and use it for type annotations, and verify any existing
imports/exports that reference this type are adjusted accordingly.

Comment on lines +18 to +32
export function RadialGaugeWidget({
data,
height = 220,
innerRadius = '40%',
outerRadius = '100%',
}: RadialGaugeWidgetProps) {
return (
<ResponsiveContainer width="100%" height={height}>
<RadialBarChart innerRadius={innerRadius} outerRadius={outerRadius} data={data} startAngle={90} endAngle={-270}>
<Tooltip />
<RadialBar dataKey="value" cornerRadius={8} label={{ position: 'insideStart', fill: '#fff' }} />
</RadialBarChart>
</ResponsiveContainer>
)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider wrapping with React.memo to prevent unnecessary re-renders.

Per coding guidelines, components should use React.memo to optimize re-renders. Since this component receives data as a prop and renders a chart, memoization can help avoid unnecessary re-computation when parent components re-render with unchanged props.

-export function RadialGaugeWidget({
+export const RadialGaugeWidget = React.memo(function RadialGaugeWidget({
   data,
   height = 220,
   innerRadius = '40%',
   outerRadius = '100%',
 }: RadialGaugeWidgetProps) {
   return (
     <ResponsiveContainer width="100%" height={height}>
       <RadialBarChart innerRadius={innerRadius} outerRadius={outerRadius} data={data} startAngle={90} endAngle={-270}>
         <Tooltip />
         <RadialBar dataKey="value" cornerRadius={8} label={{ position: 'insideStart', fill: '#fff' }} />
       </RadialBarChart>
     </ResponsiveContainer>
   )
-}
+})

Also add the import at the top:

import React from 'react'
🤖 Prompt for AI Agents
In app/components/charts/RadialGaugeWidget.tsx around lines 18-32, wrap the
component with React.memo and add the React import to prevent unnecessary
re-renders: add "import React from 'react'" at the top, convert the current
named function export into a memoized component (e.g. assign the function to a
const and pass it to React.memo or wrap the function when exporting) so the
component is memoized while preserving prop typing and behavior.

Comment on lines +82 to +84
useEffect(() => {
applyTheme(theme).catch(() => setTheme('github'))
}, [theme])
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider notifying users when theme loading fails.

The applyTheme error handler silently falls back to the 'github' theme without informing the user. This could cause confusion when a user selects a theme that fails to load.

Consider adding user notification on theme load failure:

useEffect(() => {
  applyTheme(theme).catch((err) => {
    console.error('Failed to apply theme:', err)
    setTheme('github')
    // Optional: add toast notification here
  })
}, [theme])
🤖 Prompt for AI Agents
In app/components/monaco/MonacoCodeEditor.tsx around lines 82 to 84, the
applyTheme(theme).catch handler silently falls back to 'github' without user
feedback; update the catch to capture the error, log it (console.error or
process logger), call setTheme('github') and also surface a user notification
(e.g., trigger existing toast/notification utility or emit a UI-friendly
message) so users are informed when their selected theme fails to load while
preserving the fallback behavior.

Comment on lines +125 to +127
onLanguageChange={(lang) =>
setFiles((prev) => prev.map((file) => (file.id === activeId ? { ...file, language: lang } : file)))
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting the language change handler for clarity.

The inline lambda for language change works but could be extracted to a named function for improved readability and potential reuse.

const handleLanguageChange = useCallback((lang: string) => {
  setFiles((prev) => prev.map((file) => 
    file.id === activeId ? { ...file, language: lang } : file
  ))
}, [activeId])

// Then in JSX:
<MonacoToolbar
  // ...
  onLanguageChange={handleLanguageChange}
  // ...
/>
🤖 Prompt for AI Agents
In app/components/monaco/MonacoCodeEditor.tsx around lines 125 to 127, the
inline arrow passed to onLanguageChange should be extracted into a named handler
for clarity and reuse; create a handleLanguageChange function using useCallback
that accepts the new language string and calls setFiles(prev => prev.map(file =>
file.id === activeId ? { ...file, language: lang } : file)), include activeId in
the dependency array, and replace the inline lambda in JSX with
onLanguageChange={handleLanguageChange}.

Comment on lines +55 to +91
<head>
<meta name="robots" content="index,follow" />
<link rel="canonical" href="https://deanmachines.com/" />
<meta property="og:title" content="AgentStack | Multi-Agent Framework" />
<meta property="og:description" content="Production-grade multi-agent framework for AI applications with 22+ agents, 30+ tools." />
<meta property="og:image" content="https://deanmachines.com/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@ssdeanx" />
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify({
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"name": "AgentStack",
"url": "https://deanmachines.com",
"logo": "https://deanmachines.com/logo.png",
"sameAs": ["https://github.com/ssdeanx"]
},
{
"@type": "WebSite",
"url": "https://deanmachines.com",
"name": "AgentStack",
"potentialAction": {
"@type": "SearchAction",
"target": "https://deanmachines.com/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
},
{
"@type": "Person",
"name": "Dean (ssdeanx)",
"url": "https://deanmachines.com",
"sameAs": ["https://github.com/ssdeanx"]
}
]
}) }} />
</head>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove duplicate meta tags - Next.js generates these from the metadata export.

The Open Graph and Twitter meta tags (lines 58-62) duplicate what's already defined in the metadata export (lines 24-44). Next.js App Router automatically generates these meta tags from the exported metadata object, so manual injection will result in duplicate tags in the rendered HTML.

The robots meta tag may also conflict with your robots.txt file.

Remove the redundant manual meta tags:

       <head>
-        <meta name="robots" content="index,follow" />
-        <link rel="canonical" href="https://deanmachines.com/" />
-        <meta property="og:title" content="AgentStack | Multi-Agent Framework" />
-        <meta property="og:description" content="Production-grade multi-agent framework for AI applications with 22+ agents, 30+ tools." />
-        <meta property="og:image" content="https://deanmachines.com/og-image.png" />
-        <meta name="twitter:card" content="summary_large_image" />
-        <meta name="twitter:site" content="@ssdeanx" />
         <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify({
           // ... JSON-LD content
         }) }} />
       </head>

For the canonical URL, add it to the metadata export instead:

export const metadata: Metadata = {
  // ... existing metadata
  alternates: {
    canonical: 'https://deanmachines.com/',
  },
};

For Twitter site handle, add to the twitter object:

twitter: {
  // ... existing
  site: '@ssdeanx',
},
🧰 Tools
🪛 ast-grep (0.40.0)

[warning] 62-62: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)

[error] 63-63: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🤖 Prompt for AI Agents
In app/layout.tsx around lines 55 to 91, remove the manually inserted Open
Graph, Twitter, canonical and robots meta tags and the JSON-LD script that
duplicates metadata generated from the exported metadata object; instead, delete
the redundant <meta> and <link rel="canonical"> entries and move the canonical
URL into the metadata.alternates.canonical field and the twitter site handle
into metadata.twitter.site in the file’s metadata export; ensure no duplicate
robots tag remains (rely on robots.txt or the metadata export) and keep only
non-duplicated, necessary head elements.

@ssdeanx ssdeanx merged commit 1596d0d into main Dec 7, 2025
428 of 431 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant