Skip to content

Conversation

@Visual-Studio-Coder
Copy link
Contributor

@Visual-Studio-Coder Visual-Studio-Coder commented Jan 10, 2026

Description

You can now use the AI chat to generate math images of anything. It uses the TikZ (LaTeX derivative) syntax to generate math images with high accuracy.

Screencast

image image

Checklist

- fixed icon
- Add MIT License to the project
- new extension
@raycastbot
Copy link
Collaborator

Congratulations on your new Raycast extension! 🚀

Due to our current reduced availability, the initial review may take up to 10-15 business days.

Once the PR is approved and merged, the extension will be available on our Store.

@Visual-Studio-Coder Visual-Studio-Coder marked this pull request as ready for review January 10, 2026 19:22
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 10, 2026

Greptile Overview

Greptile Summary

This PR adds a new TikZ extension for generating LaTeX diagrams, providing both an AI tool for Raycast AI chat and a manual command with a form interface.

What Changed

New Extension Added:

  • AI tool (generate-tikz-diagram) that compiles TikZ LaTeX code to PNG images
  • Manual command (create-tikz) with form UI for creating diagrams
  • Automatic PDF to PNG conversion using sips
  • Support for common TikZ libraries pre-configured
  • Comprehensive documentation and testing utilities

Core Functionality:

  • Takes TikZ code input, wraps it in LaTeX document structure
  • Compiles using pdflatex to PDF, then converts to PNG
  • Handles both raw TikZ commands and complete LaTeX documents
  • Saves output to different directories based on usage (AI tool vs manual command)

Issues Found

Critical Issues:

  1. eslint.config.js has incorrect import - eslint/config does not export defineConfig, causing lint/build failures
  2. Missing metadata folder - View commands require screenshots in metadata/ directory per store requirements
  3. Missing tool confirmation - AI tool lacks required confirmation export for user approval dialog

Best Practice Violations:

  • Using unlinkSync instead of Raycast's trash() method for file cleanup
  • Incomplete CHANGELOG with placeholder text

Implementation Quality

The core logic is well-structured with proper error handling, comprehensive documentation, and thorough testing utilities. The LaTeX compilation approach is sound with fallback mechanisms. However, the issues above need to be resolved before this can be merged.

Confidence Score: 2/5

  • This PR has critical issues that will prevent the extension from working correctly and passing store requirements
  • Score of 2 reflects three critical blockers: (1) eslint.config.js will cause build failures due to incorrect import, (2) missing metadata folder violates store requirements for view commands, and (3) missing tool confirmation function breaks the AI tool UX pattern. Additionally, using unlinkSync instead of trash() violates Raycast best practices. While the core LaTeX compilation logic is solid and well-documented, these issues must be resolved before merge.
  • Pay close attention to eslint.config.js (will break builds), package.json/metadata (store requirement), and src/tools/generate-tikz-diagram.ts (missing confirmation)

Important Files Changed

File Analysis

Filename Score Overview
extensions/tikz/src/tools/generate-tikz-diagram.ts 2/5 AI tool implementation missing required confirmation function; uses unlinkSync instead of trash(); filename sanitization could be improved
extensions/tikz/src/create-tikz.tsx 3/5 Manual command implementation with form UI; uses unlinkSync instead of trash(); minor filename sanitization improvements needed
extensions/tikz/eslint.config.js 1/5 Incorrect import path - eslint/config does not export defineConfig; will cause build/lint failures
extensions/tikz/package.json 2/5 Extension configuration with view command but missing required metadata folder with screenshots
extensions/tikz/CHANGELOG.md 3/5 Changelog has placeholder date but needs actual feature descriptions for initial version

Copy link
Contributor

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

8 files reviewed, 8 comments

Edit Code Review Agent Settings | Greptile

@@ -0,0 +1,195 @@
import { environment, showToast, Toast } from "@raycast/api";
Copy link
Contributor

Choose a reason for hiding this comment

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

This tool is missing the required export const confirmation function that other tools in the codebase implement. Without this, users won't get a confirmation dialog before the tool executes, which is important for operations that create files.

Looking at similar tools like app-creator/src/tools/create.ts, you should add:

Suggested change
import { environment, showToast, Toast } from "@raycast/api";
import { environment, showToast, Toast, Tool } from "@raycast/api";

And add at the end of the file:

export const confirmation: Tool.Confirmation<Input> = async (input: Input) => {
  return {
    message: `Generate TikZ diagram${input.fileName ? ` "${input.fileName}"` : ""}?\n\`\`\`latex\n${input.tikzCode.slice(0, 200)}${input.tikzCode.length > 200 ? "..." : ""}\n\`\`\``,
  };
};

@@ -0,0 +1,6 @@
const { defineConfig } = require("eslint/config");
Copy link
Contributor

Choose a reason for hiding this comment

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

eslint/config does not export defineConfig. This import path is incorrect for ESLint v9. Looking at the repository pattern used in other recently added extensions, the correct import should be from @eslint/js.

Suggested change
const { defineConfig } = require("eslint/config");
const { defineConfig } = require("@eslint/js");

However, checking other extensions in this codebase, most don't use defineConfig at all - they directly export the config array. Here's the simpler pattern used elsewhere:

Suggested change
const { defineConfig } = require("eslint/config");
const raycastConfig = require("@raycast/eslint-config");
module.exports = raycastConfig;


// Generate unique filename
const timestamp = Date.now();
const baseName = input.fileName?.replace(/[^a-z0-9]/gi, "_") || "diagram";
Copy link
Contributor

Choose a reason for hiding this comment

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

Potential security issue: The fileName parameter is sanitized with a simple regex replacement, but it's not validated before being used in file operations. If fileName is undefined or becomes an empty string after sanitization, this could lead to file path issues.

The expression input.fileName?.replace(/[^a-z0-9]/gi, "_") returns undefined if fileName is not provided, but the || "diagram" fallback only applies if the value is falsy. This is working correctly, but could be clearer.

More importantly, the sanitized filename is not validated for length or for becoming an empty string after sanitization (e.g., if someone passes only special characters like "!@#$%"). Consider adding validation:

Suggested change
const baseName = input.fileName?.replace(/[^a-z0-9]/gi, "_") || "diagram";
const baseName = (input.fileName?.replace(/[^a-z0-9]/gi, "_").substring(0, 100) || "diagram") || "diagram";


// Generate filename
const timestamp = Date.now();
const baseName = values.fileName?.trim().replace(/[^a-z0-9]/gi, "_") || "diagram";
Copy link
Contributor

Choose a reason for hiding this comment

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

Same filename sanitization issue as in the tool file. The regex replacement could result in an empty string if only special characters are provided, though the || "diagram" fallback handles it. Consider adding explicit validation and length limiting for consistency:

Suggested change
const baseName = values.fileName?.trim().replace(/[^a-z0-9]/gi, "_") || "diagram";
const baseName = (values.fileName?.trim().replace(/[^a-z0-9]/gi, "_").substring(0, 100) || "diagram") || "diagram";

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +8 to +18
"platforms": [
"macOS"
],
"categories": [
"Design Tools",
"Data",
"Media",
"Fun",
"Developer Tools",
"Web"
],
Copy link
Contributor

Choose a reason for hiding this comment

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

This extension has a view-type command ("create-tikz" with "mode": "view") and therefore requires a metadata/ folder with Raycast-styled screenshots.

The metadata folder is missing. You need to add a metadata/ directory with at least one screenshot showing the command UI in action. See other extensions like app-creator/metadata/ for examples.

Comment on lines +157 to +160
if (existsSync(pdfFilePath)) unlinkSync(pdfFilePath);
if (existsSync(texFilePath)) unlinkSync(texFilePath);
if (existsSync(logFilePath)) unlinkSync(logFilePath);
if (existsSync(auxFilePath)) unlinkSync(auxFilePath);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using unlinkSync to delete files goes against best practices. You should use Raycast's built-in trash() method instead, which is safer and cross-platform compatible.

Suggested change
if (existsSync(pdfFilePath)) unlinkSync(pdfFilePath);
if (existsSync(texFilePath)) unlinkSync(texFilePath);
if (existsSync(logFilePath)) unlinkSync(logFilePath);
if (existsSync(auxFilePath)) unlinkSync(auxFilePath);
import { trash } from "@raycast/api";
// Then in the cleanup section:
if (existsSync(pdfFilePath)) await trash(pdfFilePath);
if (existsSync(texFilePath)) await trash(texFilePath);
if (existsSync(logFilePath)) await trash(logFilePath);
if (existsSync(auxFilePath)) await trash(auxFilePath);

Note: This will require changing the cleanup block to be async or moving it to a separate async function.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +170 to +173
if (existsSync(pdfFilePath)) unlinkSync(pdfFilePath);
if (existsSync(texFilePath)) unlinkSync(texFilePath);
if (existsSync(logFilePath)) unlinkSync(logFilePath);
if (existsSync(auxFilePath)) unlinkSync(auxFilePath);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using unlinkSync to delete files goes against best practices. You should use Raycast's built-in trash() method instead.

Suggested change
if (existsSync(pdfFilePath)) unlinkSync(pdfFilePath);
if (existsSync(texFilePath)) unlinkSync(texFilePath);
if (existsSync(logFilePath)) unlinkSync(logFilePath);
if (existsSync(auxFilePath)) unlinkSync(auxFilePath);
import { trash } from "@raycast/api";
// Then in the cleanup section:
if (existsSync(pdfFilePath)) await trash(pdfFilePath);
if (existsSync(texFilePath)) await trash(texFilePath);
if (existsSync(logFilePath)) await trash(logFilePath);
if (existsSync(auxFilePath)) await trash(auxFilePath);

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@@ -0,0 +1,3 @@
# TikZ Changelog

## [Initial Version] - {PR_MERGE_DATE} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

The CHANGELOG is incomplete and needs to document the actual changes being introduced. Currently it just has a placeholder {PR_MERGE_DATE}.

For an initial version, you should at minimum describe what the extension does:

Suggested change
## [Initial Version] - {PR_MERGE_DATE}
## [Initial Version] - 2025-01-XX
### Added
- AI tool for generating TikZ diagrams from LaTeX code
- Manual command for creating TikZ diagrams with form interface
- Support for PDF and PNG output formats
- Automatic LaTeX document wrapper handling
- Common TikZ libraries pre-configured

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Extension new extension Label for PRs with new extensions platform: macOS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants