diff --git a/.github/workflows/check-redirects.yml b/.github/workflows/check-redirects.yml new file mode 100644 index 000000000..1482842be --- /dev/null +++ b/.github/workflows/check-redirects.yml @@ -0,0 +1,134 @@ +name: Check Redirects for Deleted Pages + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "app/**/*.md" + - "app/**/*.mdx" + - "next.config.ts" + +permissions: + contents: read + pull-requests: write + +jobs: + check-redirects: + name: Verify Deleted Pages Have Redirects + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history needed for branch comparison + + - name: Fetch base branch + run: git fetch origin ${{ github.base_ref }}:${{ github.base_ref }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: npm install -g pnpm && pnpm install + + - name: Check for missing redirects + id: check + run: | + set -o pipefail + pnpm check-redirects ${{ github.base_ref }} 2>&1 | tee redirect-check-output.txt + continue-on-error: true + + - name: Comment on PR if redirects are missing + if: steps.check.outcome == 'failure' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const output = fs.readFileSync('redirect-check-output.txt', 'utf8'); + + // Extract the missing redirects and suggestions from output + const body = `## 🔗 Missing Redirects Detected + + This PR deletes markdown files that don't have corresponding redirects in \`next.config.ts\`. + + When you delete a page, you must add a redirect to prevent broken links for users who have bookmarked the old URL. + +
+ 📋 View Details + + \`\`\` + ${output} + \`\`\` + +
+ + ### How to fix + + 1. Open \`next.config.ts\` + 2. Find the \`redirects()\` function + 3. Add redirect entries for each deleted file (see suggestions above) + 4. Push the changes + + --- + *This check ensures we maintain URL stability for our documentation.*`; + + // Check if we already commented + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const botComment = comments.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('Missing Redirects Detected') + ); + + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: body + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body + }); + } + + - name: Remove outdated comment if check passes + if: steps.check.outcome == 'success' + uses: actions/github-script@v7 + with: + script: | + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const botComment = comments.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('Missing Redirects Detected') + ); + + if (botComment) { + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + }); + } + + - name: Fail if redirects are missing + if: steps.check.outcome == 'failure' + run: | + echo "❌ Missing redirects for deleted pages. See PR comment for details." + exit 1 diff --git a/.husky/pre-commit b/.husky/pre-commit index 8a2bd82e0..de35e84a2 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -29,6 +29,51 @@ if [ -n "$STAGED_DOCS" ]; then fi fi +# --- Check Redirects (when markdown pages are deleted or renamed) --- +# Detect deleted pages (D status) and renamed pages (R status - old path needs redirect) +DELETED_PAGES=$(git diff --cached --name-status | grep -E "^D.*page\.(md|mdx)$" | cut -f2 || true) +RENAMED_PAGES=$(git diff --cached --name-status | grep -E "^R.*page\.(md|mdx)$" | cut -f2 || true) + +if [ -n "$DELETED_PAGES" ] || [ -n "$RENAMED_PAGES" ]; then + echo "🔗 Detected deleted/renamed page(s), checking for redirects..." + + # Run the TypeScript redirect checker with auto-fix (only checks staged changes) + # This will add redirect entries to next.config.ts if missing + if ! pnpm check-redirects --auto-fix --staged-only 2>&1; then + # Stage next.config.ts if it was modified + if git diff --name-only next.config.ts 2>/dev/null | grep -q "next.config.ts"; then + git add next.config.ts + echo "" + echo "📝 Redirect entries added to next.config.ts and staged." + fi + echo "" + # Check if there are placeholders vs other errors + if grep -q "REPLACE_WITH_NEW_PATH" next.config.ts 2>/dev/null; then + echo "❌ Commit blocked: Please update the placeholder destinations in next.config.ts" + echo " Search for 'REPLACE_WITH_NEW_PATH' and provide actual redirect paths." + else + echo "❌ Commit blocked: Please fix the redirect issues shown above." + fi + exit 1 + fi +fi + +# --- Update Internal Links (when redirects are added) --- +# If next.config.ts is staged, update any internal links pointing to redirected paths +if git diff --cached --name-only | grep -q "next.config.ts"; then + echo "🔗 Updating internal links for new redirects..." + + # Run the TypeScript update script + if pnpm update-links 2>/dev/null; then + # Stage any files that were modified + UPDATED_FILES=$(git diff --name-only -- 'app/**/*.mdx' 'app/**/*.tsx' 'app/**/*.md' 2>/dev/null || true) + if [ -n "$UPDATED_FILES" ]; then + echo "$UPDATED_FILES" | xargs git add + echo "✅ Internal links updated and staged" + fi + fi +fi + # --- Lint Staged (formatting) --- pnpm dlx lint-staged diff --git a/app/_components/tool-footer.tsx b/app/_components/tool-footer.tsx index 749498a0e..bbac5ae9f 100644 --- a/app/_components/tool-footer.tsx +++ b/app/_components/tool-footer.tsx @@ -15,7 +15,7 @@ const ToolFooter: React.FC = ({ pipPackageName }) => (
@@ -24,7 +24,7 @@ const ToolFooter: React.FC = ({ pipPackageName }) => ( description={ "Arcade tools can be self-hosted on your own infrastructure. Learn more about self-hosting." } - href="/home/hosting-overview" + href="/guides/deployment-hosting" icon={Puzzle} title="Self Host Arcade tools" /> diff --git a/app/en/guides/agent-frameworks/_meta.tsx b/app/en/get-started/agent-frameworks/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/_meta.tsx rename to app/en/get-started/agent-frameworks/_meta.tsx diff --git a/app/en/guides/agent-frameworks/crewai/_meta.tsx b/app/en/get-started/agent-frameworks/crewai/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/crewai/_meta.tsx rename to app/en/get-started/agent-frameworks/crewai/_meta.tsx diff --git a/app/en/guides/agent-frameworks/crewai/custom-auth-flow/page.mdx b/app/en/get-started/agent-frameworks/crewai/custom-auth-flow/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/crewai/custom-auth-flow/page.mdx rename to app/en/get-started/agent-frameworks/crewai/custom-auth-flow/page.mdx diff --git a/app/en/guides/agent-frameworks/crewai/use-arcade-tools/page.mdx b/app/en/get-started/agent-frameworks/crewai/use-arcade-tools/page.mdx similarity index 90% rename from app/en/guides/agent-frameworks/crewai/use-arcade-tools/page.mdx rename to app/en/get-started/agent-frameworks/crewai/use-arcade-tools/page.mdx index 3b975f314..acf27603a 100644 --- a/app/en/guides/agent-frameworks/crewai/use-arcade-tools/page.mdx +++ b/app/en/get-started/agent-frameworks/crewai/use-arcade-tools/page.mdx @@ -8,9 +8,9 @@ import ToggleContent from "@/app/_components/toggle-content"; ## Use CrewAI with Arcade -In this guide, we will explore how to integrate Arcade tools into your CrewAI application. Follow the step-by-step instructions below. If a tool requires authorization, an authorization URL will appear in the console, waiting for your approval. This process ensures that only the tools you choose to authorize are executed. +This guide explains how to integrate Arcade tools into your CrewAI application. Follow the step-by-step instructions below. If a tool requires authorization, an authorization URL will appear in the console, waiting for your approval. This process ensures that only the tools you choose to authorize execute. -To tailor the tool authorization flow to meet your application's specific needs, check out the [Custom Auth Flow with CrewAI](/guides/agent-frameworks/crewai/custom-auth-flow) guide. +To tailor the tool authorization flow to meet your application's specific needs, check out the [Custom Auth Flow with CrewAI](/get-started/agent-frameworks/crewai/custom-auth-flow) guide. diff --git a/app/en/guides/agent-frameworks/google-adk/_meta.tsx b/app/en/get-started/agent-frameworks/google-adk/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/google-adk/_meta.tsx rename to app/en/get-started/agent-frameworks/google-adk/_meta.tsx diff --git a/app/en/guides/agent-frameworks/google-adk/overview/page.mdx b/app/en/get-started/agent-frameworks/google-adk/overview/page.mdx similarity index 96% rename from app/en/guides/agent-frameworks/google-adk/overview/page.mdx rename to app/en/get-started/agent-frameworks/google-adk/overview/page.mdx index 6f97f8457..963e91232 100644 --- a/app/en/guides/agent-frameworks/google-adk/overview/page.mdx +++ b/app/en/get-started/agent-frameworks/google-adk/overview/page.mdx @@ -127,7 +127,7 @@ for tool in google_tools: Ready to start building with Arcade and OpenAI Agents? Check out these guides: -- [Using Arcade tools](/guides/agent-frameworks/google-adk/use-arcade-tools) - Learn the basics of using Arcade tools with Google ADK +- [Using Arcade tools](/get-started/agent-frameworks/google-adk/use-arcade-tools) - Learn the basics of using Arcade tools with Google ADK - [Creating custom tools](/guides/create-tools/tool-basics/build-mcp-server) - Build your own tools with the Arcade Tool SDK -Enjoy exploring Arcade and building powerful AI-enabled applications! +Enjoy exploring Arcade and building powerful AI-enabled applications. diff --git a/app/en/guides/agent-frameworks/google-adk/use-arcade-tools/page.mdx b/app/en/get-started/agent-frameworks/google-adk/use-arcade-tools/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/google-adk/use-arcade-tools/page.mdx rename to app/en/get-started/agent-frameworks/google-adk/use-arcade-tools/page.mdx diff --git a/app/en/guides/agent-frameworks/langchain/_meta.tsx b/app/en/get-started/agent-frameworks/langchain/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/langchain/_meta.tsx rename to app/en/get-started/agent-frameworks/langchain/_meta.tsx diff --git a/app/en/guides/agent-frameworks/langchain/auth-langchain-tools/page.mdx b/app/en/get-started/agent-frameworks/langchain/auth-langchain-tools/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/langchain/auth-langchain-tools/page.mdx rename to app/en/get-started/agent-frameworks/langchain/auth-langchain-tools/page.mdx diff --git a/app/en/guides/agent-frameworks/langchain/use-arcade-tools/page.mdx b/app/en/get-started/agent-frameworks/langchain/use-arcade-tools/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/langchain/use-arcade-tools/page.mdx rename to app/en/get-started/agent-frameworks/langchain/use-arcade-tools/page.mdx diff --git a/app/en/guides/agent-frameworks/langchain/use-arcade-with-langchain/page.mdx b/app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/langchain/use-arcade-with-langchain/page.mdx rename to app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain/page.mdx diff --git a/app/en/guides/agent-frameworks/langchain/user-auth-interrupts/page.mdx b/app/en/get-started/agent-frameworks/langchain/user-auth-interrupts/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/langchain/user-auth-interrupts/page.mdx rename to app/en/get-started/agent-frameworks/langchain/user-auth-interrupts/page.mdx diff --git a/app/en/guides/agent-frameworks/mastra/_meta.tsx b/app/en/get-started/agent-frameworks/mastra/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/mastra/_meta.tsx rename to app/en/get-started/agent-frameworks/mastra/_meta.tsx diff --git a/app/en/guides/agent-frameworks/mastra/overview/page.mdx b/app/en/get-started/agent-frameworks/mastra/overview/page.mdx similarity index 87% rename from app/en/guides/agent-frameworks/mastra/overview/page.mdx rename to app/en/get-started/agent-frameworks/mastra/overview/page.mdx index 12ab8b334..53dd45c2a 100644 --- a/app/en/guides/agent-frameworks/mastra/overview/page.mdx +++ b/app/en/get-started/agent-frameworks/mastra/overview/page.mdx @@ -29,5 +29,5 @@ The integration works through three key mechanisms: ### Next Steps -- Learn how to [use Arcade tools](/guides/agent-frameworks/mastra/use-arcade-tools) in a Mastra agent -- Implement [user authentication handling](/guides/agent-frameworks/mastra/user-auth-interrupts) for tools in multi-user applications +- Learn how to [use Arcade tools](/get-started/agent-frameworks/mastra/use-arcade-tools) in a Mastra agent +- Implement [user authentication handling](/get-started/agent-frameworks/mastra/user-auth-interrupts) for tools in multi-user applications diff --git a/app/en/guides/agent-frameworks/mastra/use-arcade-tools/page.mdx b/app/en/get-started/agent-frameworks/mastra/use-arcade-tools/page.mdx similarity index 91% rename from app/en/guides/agent-frameworks/mastra/use-arcade-tools/page.mdx rename to app/en/get-started/agent-frameworks/mastra/use-arcade-tools/page.mdx index da44a2469..ff85034af 100644 --- a/app/en/guides/agent-frameworks/mastra/use-arcade-tools/page.mdx +++ b/app/en/get-started/agent-frameworks/mastra/use-arcade-tools/page.mdx @@ -158,4 +158,4 @@ for await (const chunk of stream.textStream) { -When running your agent for the first time with tools that require user consent (like Google or Github), the agent will return an authorization reponse (e.g., `{ authorization_required: true, url: '...', message: '...' }`). Your agent's instructions should guide it to present this URL to the user. After the user visits this URL and grants permissions, the tool can be used successfully. See the [Managing user authorization](/guides/agent-frameworks/mastra/user-auth-interrupts) guide for more details on handling authentication flows. +When running your agent for the first time with tools that require user consent (like Google or Github), the agent will return an authorization reponse (for example, `{ authorization_required: true, url: '...', message: '...' }`). Your agent's instructions should guide it to present this URL to the user. After the user visits this URL and grants permissions, the tool can be used successfully. See the [Managing user authorization](/get-started/agent-frameworks/mastra/user-auth-interrupts) guide for more details on handling authentication flows. diff --git a/app/en/guides/agent-frameworks/mastra/user-auth-interrupts/page.mdx b/app/en/get-started/agent-frameworks/mastra/user-auth-interrupts/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/mastra/user-auth-interrupts/page.mdx rename to app/en/get-started/agent-frameworks/mastra/user-auth-interrupts/page.mdx diff --git a/app/en/guides/agent-frameworks/openai-agents/_meta.tsx b/app/en/get-started/agent-frameworks/openai-agents/_meta.tsx similarity index 100% rename from app/en/guides/agent-frameworks/openai-agents/_meta.tsx rename to app/en/get-started/agent-frameworks/openai-agents/_meta.tsx diff --git a/app/en/guides/agent-frameworks/openai-agents/overview/page.mdx b/app/en/get-started/agent-frameworks/openai-agents/overview/page.mdx similarity index 95% rename from app/en/guides/agent-frameworks/openai-agents/overview/page.mdx rename to app/en/get-started/agent-frameworks/openai-agents/overview/page.mdx index 73e6b5384..c992e9209 100644 --- a/app/en/guides/agent-frameworks/openai-agents/overview/page.mdx +++ b/app/en/get-started/agent-frameworks/openai-agents/overview/page.mdx @@ -177,8 +177,8 @@ For a full list of available MCP Servers, visit the [Arcade MCP Servers](/resour Ready to start building with Arcade and OpenAI Agents? Check out these guides: -- [Using Arcade tools](/guides/agent-frameworks/openai-agents/use-arcade-tools) - Learn the basics of using Arcade tools with OpenAI Agents -- [Managing user authorization](/guides/agent-frameworks/openai-agents/user-auth-interrupts) - Handle tool authorization efficiently +- [Using Arcade tools](/get-started/agent-frameworks/openai-agents/use-arcade-tools) - Learn the basics of using Arcade tools with OpenAI Agents +- [Managing user authorization](/get-started/agent-frameworks/openai-agents/user-auth-interrupts) - Handle tool authorization efficiently - [Creating custom tools](/guides/create-tools/tool-basics/build-mcp-server) - Build your own tools with the Arcade Tool SDK Enjoy exploring Arcade and building powerful AI-enabled applications! diff --git a/app/en/guides/agent-frameworks/openai-agents/use-arcade-tools/page.mdx b/app/en/get-started/agent-frameworks/openai-agents/use-arcade-tools/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/openai-agents/use-arcade-tools/page.mdx rename to app/en/get-started/agent-frameworks/openai-agents/use-arcade-tools/page.mdx diff --git a/app/en/guides/agent-frameworks/openai-agents/user-auth-interrupts/page.mdx b/app/en/get-started/agent-frameworks/openai-agents/user-auth-interrupts/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/openai-agents/user-auth-interrupts/page.mdx rename to app/en/get-started/agent-frameworks/openai-agents/user-auth-interrupts/page.mdx diff --git a/app/en/guides/agent-frameworks/page.mdx b/app/en/get-started/agent-frameworks/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/page.mdx rename to app/en/get-started/agent-frameworks/page.mdx diff --git a/app/en/guides/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx b/app/en/get-started/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx similarity index 99% rename from app/en/guides/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx rename to app/en/get-started/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx index 9263b36d7..7739ac310 100644 --- a/app/en/guides/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx +++ b/app/en/get-started/agent-frameworks/setup-arcade-with-your-llm-python/page.mdx @@ -313,7 +313,7 @@ With the selection of tools above, you should be able to get the agent to effect ## Next Steps -- Learn more about using Arcade with a [framework](/guides/agent-frameworks) or [MCP client](/guides/tool-calling/mcp-clients). +- Learn more about using Arcade with a [framework](/get-started/agent-frameworks) or [MCP client](/get-started/mcp-clients). - Learn more about how to [build your own MCP Servers](/guides/create-tools/tool-basics/build-mcp-server). ## Example code diff --git a/app/en/guides/agent-frameworks/vercelai/page.mdx b/app/en/get-started/agent-frameworks/vercelai/page.mdx similarity index 100% rename from app/en/guides/agent-frameworks/vercelai/page.mdx rename to app/en/get-started/agent-frameworks/vercelai/page.mdx diff --git a/app/en/guides/tool-calling/mcp-clients/_meta.tsx b/app/en/get-started/mcp-clients/_meta.tsx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/_meta.tsx rename to app/en/get-started/mcp-clients/_meta.tsx diff --git a/app/en/guides/tool-calling/mcp-clients/claude-desktop/page.mdx b/app/en/get-started/mcp-clients/claude-desktop/page.mdx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/claude-desktop/page.mdx rename to app/en/get-started/mcp-clients/claude-desktop/page.mdx diff --git a/app/en/guides/tool-calling/mcp-clients/cursor/page.mdx b/app/en/get-started/mcp-clients/cursor/page.mdx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/cursor/page.mdx rename to app/en/get-started/mcp-clients/cursor/page.mdx diff --git a/app/en/guides/tool-calling/mcp-clients/mcp-client-grid.tsx b/app/en/get-started/mcp-clients/mcp-client-grid.tsx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/mcp-client-grid.tsx rename to app/en/get-started/mcp-clients/mcp-client-grid.tsx diff --git a/app/en/guides/tool-calling/mcp-clients/page.mdx b/app/en/get-started/mcp-clients/page.mdx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/page.mdx rename to app/en/get-started/mcp-clients/page.mdx diff --git a/app/en/guides/tool-calling/mcp-clients/visual-studio-code/page.mdx b/app/en/get-started/mcp-clients/visual-studio-code/page.mdx similarity index 100% rename from app/en/guides/tool-calling/mcp-clients/visual-studio-code/page.mdx rename to app/en/get-started/mcp-clients/visual-studio-code/page.mdx diff --git a/app/en/get-started/quickstarts/call-tool-agent/page.mdx b/app/en/get-started/quickstarts/call-tool-agent/page.mdx index a4cbbc17c..4c2cd73c8 100644 --- a/app/en/get-started/quickstarts/call-tool-agent/page.mdx +++ b/app/en/get-started/quickstarts/call-tool-agent/page.mdx @@ -356,7 +356,7 @@ console.log(respose_send_email.output?.value); ## Next Steps -In this simple example, we call the tool methods directly. In your real applications and agents, you'll likely be letting the LLM decide which tools to call. Learn more about using Arcade with Frameworks in the [Frameworks](/guides/agent-frameworks) section, or [how to build your own tools](/guides/create-tools/tool-basics/build-mcp-server). +In this simple example, we call the tool methods directly. In your real applications and agents, you'll likely be letting the LLM decide which tools to call. Learn more about using Arcade with Frameworks in the [Frameworks](/get-started/agent-frameworks) section, or [how to build your own tools](/guides/create-tools/tool-basics/build-mcp-server). ## Example Code diff --git a/app/en/get-started/quickstarts/call-tool-client/page.mdx b/app/en/get-started/quickstarts/call-tool-client/page.mdx index 591be2d43..67d2b2490 100644 --- a/app/en/get-started/quickstarts/call-tool-client/page.mdx +++ b/app/en/get-started/quickstarts/call-tool-client/page.mdx @@ -6,7 +6,7 @@ description: "Learn how to call a tool in your IDE/MCP Client" import { Steps, Tabs, Callout } from "nextra/components"; import { SignupLink } from "@/app/_components/analytics"; import Image from "next/image"; -import { MCPClientGrid } from "@/app/en/guides/tool-calling/mcp-clients/mcp-client-grid"; +import { MCPClientGrid } from "@/app/en/get-started/mcp-clients/mcp-client-grid"; export const IMAGE_SCALE_FACTOR = 2; export const CREATE_MCP_GATEWAY_DARK_WIDTH = 921; @@ -148,4 +148,7 @@ As you interact with the agent, it will call the tools from the MCP Gateway. You ## Next Steps - Learn more about [MCP Gateways](/guides/create-tools/mcp-gateways). +- Learn how to use MCP Gateways with: + - [Cursor](/get-started/mcp-clients/cursor) + - [Visual Studio Code](/get-started/mcp-clients/visual-studio-code) - Build your own MCP servers with [arcade-mcp](/get-started/quickstarts/mcp-server-quickstart). diff --git a/app/en/guides/_meta.tsx b/app/en/guides/_meta.tsx index bf2e1073b..3c8f69763 100644 --- a/app/en/guides/_meta.tsx +++ b/app/en/guides/_meta.tsx @@ -7,9 +7,6 @@ export const meta: MetaRecord = { "create-tools": { title: "Create tools", }, - "agent-frameworks": { - title: "Agent frameworks", - }, "user-facing-agents": { title: "User-facing agents", }, diff --git a/app/en/guides/create-tools/mcp-gateways/page.mdx b/app/en/guides/create-tools/mcp-gateways/page.mdx index c0d2288da..303c9befe 100644 --- a/app/en/guides/create-tools/mcp-gateways/page.mdx +++ b/app/en/guides/create-tools/mcp-gateways/page.mdx @@ -51,6 +51,6 @@ The options available when configuring an MCP Gateway are: Any MCP client that supports the Streamable HTTP transport can use an Arcade MCP Gateway. To use an Arcade MCP Gateway, you can use the `https://api.arcade.dev/mcp/` URL in your MCP client. Learn how to use MCP Gateways with: -- [Cursor](/guides/tool-calling/mcp-clients/cursor) -- [Claude Desktop](/guides/tool-calling/mcp-clients/claude-desktop) -- [Visual Studio Code](/guides/tool-calling/mcp-clients/visual-studio-code) +- [Cursor](/get-started/mcp-clients/cursor) +- [Claude Desktop](/get-started/mcp-clients/claude-desktop) +- [Visual Studio Code](/get-started/mcp-clients/visual-studio-code) diff --git a/app/en/guides/deployment-hosting/on-prem/page.mdx b/app/en/guides/deployment-hosting/on-prem/page.mdx index db008fbbd..1d46bbc71 100644 --- a/app/en/guides/deployment-hosting/on-prem/page.mdx +++ b/app/en/guides/deployment-hosting/on-prem/page.mdx @@ -284,9 +284,9 @@ You can now test your MCP Server by making requests using the Playground, or an 1. Use an app that supports MCP clients, like AI assistants and IDEs: - - [Visual Studio Code](/guides/tool-calling/mcp-clients/visual-studio-code) - - [Claude Desktop](/guides/tool-calling/mcp-clients/claude-desktop) - - [Cursor](/guides/tool-calling/mcp-clients/cursor) + - [Visual Studio Code](/get-started/mcp-clients/visual-studio-code) + - [Claude Desktop](/get-started/mcp-clients/claude-desktop) + - [Cursor](/get-started/mcp-clients/cursor) 1. Enable your MCP Server from the list of available MCP Servers 1. Verify that the response is correct and you see request logs in your MCP Server diff --git a/app/en/guides/tool-calling/_meta.tsx b/app/en/guides/tool-calling/_meta.tsx index bfef9282b..4afb60e1a 100644 --- a/app/en/guides/tool-calling/_meta.tsx +++ b/app/en/guides/tool-calling/_meta.tsx @@ -7,9 +7,6 @@ export const meta: MetaRecord = { "call-third-party-apis": { title: "Call third-party APIs", }, - "mcp-clients": { - title: "Connect to MCP clients", - }, "custom-apps": { title: "In custom applications", }, diff --git a/app/en/home/landing-page.tsx b/app/en/home/landing-page.tsx index c98712df5..a6cca53bb 100644 --- a/app/en/home/landing-page.tsx +++ b/app/en/home/landing-page.tsx @@ -345,7 +345,7 @@ export function LandingPage() {
The `TrashEmail` tool is currently only available on a self-hosted instance of the Arcade Engine. To learn more about self-hosting, see the [self-hosting - documentation](http://localhost:3000/en/home/deployment/engine-configuration). + documentation](http://localhost:3000/en/guides/deployment-hosting/configure-engine).
diff --git a/next.config.ts b/next.config.ts index 4cd7690c0..784d55f97 100644 --- a/next.config.ts +++ b/next.config.ts @@ -23,29 +23,37 @@ const nextConfig: NextConfig = withLlmsTxt({ withNextra({ async redirects() { return [ + // Moved from guides to get-started + { + source: + "/:locale/guides/agent-frameworks/setup-arcade-with-your-llm-python", + destination: + "/:locale/get-started/agent-frameworks/setup-arcade-with-your-llm-python", + permanent: true, + }, // Old /home/* paths to new structure { source: "/:locale/home/langchain/use-arcade-tools", destination: - "/:locale/guides/agent-frameworks/langchain/use-arcade-tools", + "/:locale/get-started/agent-frameworks/langchain/use-arcade-tools", permanent: true, }, { source: "/:locale/home/langchain/user-auth-interrupts", destination: - "/:locale/guides/agent-frameworks/langchain/user-auth-interrupts", + "/:locale/get-started/agent-frameworks/langchain/user-auth-interrupts", permanent: true, }, { source: "/:locale/home/oai-agents/user-auth-interrupts", destination: - "/:locale/guides/agent-frameworks/openai-agents/user-auth-interrupts", + "/:locale/get-started/agent-frameworks/openai-agents/user-auth-interrupts", permanent: true, }, { source: "/:locale/home/mastra/user-auth-interrupts", destination: - "/:locale/guides/agent-frameworks/mastra/user-auth-interrupts", + "/:locale/get-started/agent-frameworks/mastra/user-auth-interrupts", permanent: true, }, { @@ -60,7 +68,7 @@ const nextConfig: NextConfig = withLlmsTxt({ }, { source: "/:locale/home/agent-frameworks-overview", - destination: "/:locale/guides/agent-frameworks", + destination: "/:locale/get-started/agent-frameworks", permanent: true, }, { @@ -76,7 +84,7 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/guides/agent-frameworks/vercelai/using-arcade-tools", - destination: "/:locale/guides/agent-frameworks/vercelai", + destination: "/:locale/get-started/agent-frameworks/vercelai", permanent: true, }, { @@ -194,13 +202,13 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/home/crewai/custom-auth-flow", destination: - "/:locale/guides/agent-frameworks/crewai/custom-auth-flow", + "/:locale/get-started/agent-frameworks/crewai/custom-auth-flow", permanent: true, }, { source: "/:locale/home/crewai/use-arcade-tools", destination: - "/:locale/guides/agent-frameworks/crewai/use-arcade-tools", + "/:locale/get-started/agent-frameworks/crewai/use-arcade-tools", permanent: true, }, { @@ -254,7 +262,7 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/home/google-adk/use-arcade-tools", destination: - "/:locale/guides/agent-frameworks/google-adk/use-arcade-tools", + "/:locale/get-started/agent-frameworks/google-adk/use-arcade-tools", permanent: true, }, { @@ -265,30 +273,28 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/home/langchain/auth-langchain-tools", destination: - "/:locale/guides/agent-frameworks/langchain/auth-langchain-tools", + "/:locale/get-started/agent-frameworks/langchain/auth-langchain-tools", permanent: true, }, { source: "/:locale/home/mastra/use-arcade-tools", destination: - "/:locale/guides/agent-frameworks/mastra/use-arcade-tools", + "/:locale/get-started/agent-frameworks/mastra/use-arcade-tools", permanent: true, }, { source: "/:locale/home/mcp-clients/claude-desktop", - destination: - "/:locale/guides/tool-calling/mcp-clients/claude-desktop", + destination: "/:locale/get-started/mcp-clients/claude-desktop", permanent: true, }, { source: "/:locale/home/mcp-clients/cursor", - destination: "/:locale/guides/tool-calling/mcp-clients/cursor", + destination: "/:locale/get-started/mcp-clients/cursor", permanent: true, }, { source: "/:locale/home/mcp-clients/visual-studio-code", - destination: - "/:locale/guides/tool-calling/mcp-clients/visual-studio-code", + destination: "/:locale/get-started/mcp-clients/visual-studio-code", permanent: true, }, { @@ -304,7 +310,7 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/home/oai-agents/use-arcade-tools", destination: - "/:locale/guides/agent-frameworks/openai-agents/use-arcade-tools", + "/:locale/get-started/agent-frameworks/openai-agents/use-arcade-tools", permanent: true, }, { @@ -351,8 +357,7 @@ const nextConfig: NextConfig = withLlmsTxt({ }, { source: "/:locale/home/vercelai/using-arcade-tools", - destination: - "/:locale/guides/agent-frameworks/vercelai/using-arcade-tools", + destination: "/:locale/get-started/agent-frameworks/vercelai", permanent: true, }, // MCP servers to integrations @@ -409,7 +414,7 @@ const nextConfig: NextConfig = withLlmsTxt({ }, { source: "/:locale/guides/tool-calling/mcp-client/:client", - destination: "/:locale/guides/tool-calling/mcp-clients/:client", + destination: "/:locale/get-started/mcp-clients/:client", permanent: true, }, { @@ -439,55 +444,55 @@ const nextConfig: NextConfig = withLlmsTxt({ { source: "/:locale/guides/agent-frameworks/crewai/python", destination: - "/:locale/guides/agent-frameworks/crewai/use-arcade-tools", + "/:locale/get-started/agent-frameworks/crewai/use-arcade-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/langchain/python", destination: - "/:locale/guides/agent-frameworks/langchain/use-arcade-tools", + "/:locale/get-started/agent-frameworks/langchain/use-arcade-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/langchain/tools", destination: - "/:locale/guides/agent-frameworks/langchain/auth-langchain-tools", + "/:locale/get-started/agent-frameworks/langchain/auth-langchain-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/mastra/typescript", destination: - "/:locale/guides/agent-frameworks/mastra/use-arcade-tools", + "/:locale/get-started/agent-frameworks/mastra/use-arcade-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/google-adk/python", destination: - "/:locale/guides/agent-frameworks/google-adk/use-arcade-tools", + "/:locale/get-started/agent-frameworks/google-adk/use-arcade-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/openai/python", destination: - "/:locale/guides/agent-frameworks/openai-agents/use-arcade-tools", + "/:locale/get-started/agent-frameworks/openai-agents/use-arcade-tools", permanent: true, }, { source: "/:locale/guides/agent-frameworks/vercel-ai/typescript", - destination: "/:locale/guides/agent-frameworks/vercelai", + destination: "/:locale/get-started/agent-frameworks/vercelai", permanent: true, }, // Old resource paths { source: "/:locale/resources/mastra/user-auth-interrupts", destination: - "/:locale/guides/agent-frameworks/mastra/user-auth-interrupts", + "/:locale/get-started/agent-frameworks/mastra/user-auth-interrupts", permanent: true, }, { source: "/:locale/resources/oai-agents/overview", destination: - "/:locale/guides/agent-frameworks/openai-agents/overview", + "/:locale/get-started/agent-frameworks/openai-agents/overview", permanent: true, }, { @@ -495,6 +500,28 @@ const nextConfig: NextConfig = withLlmsTxt({ destination: "/:locale/guides/create-tools/:path*", permanent: true, }, + // Agent frameworks moved from guides to get-started + { + source: "/:locale/guides/agent-frameworks", + destination: "/:locale/get-started/agent-frameworks", + permanent: true, + }, + { + source: "/:locale/guides/agent-frameworks/:path*", + destination: "/:locale/get-started/agent-frameworks/:path*", + permanent: true, + }, + // MCP clients moved from guides/tool-calling to get-started + { + source: "/:locale/guides/tool-calling/mcp-clients", + destination: "/:locale/get-started/mcp-clients", + permanent: true, + }, + { + source: "/:locale/guides/tool-calling/mcp-clients/:path*", + destination: "/:locale/get-started/mcp-clients/:path*", + permanent: true, + }, ]; }, headers: async () => [ diff --git a/package.json b/package.json index ba7953195..4718c2862 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "vale:fix": "pnpm dlx tsx scripts/vale-fix.ts", "vale:review": "pnpm dlx tsx scripts/vale-style-review.ts", "vale:editorial": "pnpm dlx tsx scripts/vale-editorial.ts", - "vale:sync": "vale sync" + "vale:sync": "vale sync", + "check-redirects": "pnpm dlx tsx scripts/check-redirects.ts", + "update-links": "pnpm dlx tsx scripts/update-internal-links.ts" }, "repository": { "type": "git", diff --git a/public/llms.txt b/public/llms.txt index 9ad1de7c7..caae727fa 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -1,4 +1,4 @@ - + # Arcade @@ -70,9 +70,9 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Arcade for Slack](https://docs.arcade.dev/en/resources/integrations/social-communication/slack/install.md): The documentation page for Arcade for Slack provides users with guidance on integrating Arcade's AI tools into their Slack workspace to enhance team efficiency. It outlines the installation process, functionalities such as sending messages, finding information, and generating content, while also advising on the - [Arcade for Zoom](https://docs.arcade.dev/en/resources/integrations/social-communication/zoom/install.md): The "Arcade for Zoom" documentation page provides users with guidance on integrating Arcade's AI tools with their Zoom accounts to enhance meeting management and information retrieval. It outlines the functionalities available, such as listing upcoming meetings and retrieving invitation details, while also addressing - [Arcade Glossary](https://docs.arcade.dev/en/resources/glossary.md): The Arcade Glossary documentation provides definitions and explanations of key terms and concepts related to the Arcade platform, including agents, tools, and MCP servers. It aims to help users understand the components necessary for building, testing, and deploying applications that utilize large language -- [Arcade with Agent Frameworks and MCP Clients](https://docs.arcade.dev/en/guides/agent-frameworks.md): This documentation page provides guidance on integrating Arcade with various agent frameworks and MCP clients, enabling users to enhance their AI applications with tool-calling capabilities. It features a list of supported agent frameworks, including LangChain, CrewAI, and OpenAI Agents, -- [Arcade with Google ADK](https://docs.arcade.dev/en/guides/agent-frameworks/google-adk/overview.md): This documentation page provides a comprehensive guide on integrating the `google-adk-arcade` package with Arcade, enabling users to enhance their AI agents with various tools such as Google Mail and GitHub. It covers installation, key features, basic usage examples -- [Arcade with OpenAI Agents](https://docs.arcade.dev/en/guides/agent-frameworks/openai-agents/overview.md): This documentation page provides a comprehensive guide for integrating Arcade with the OpenAI Agents library, enabling users to enhance their AI agents with various tools such as Gmail, LinkedIn, and GitHub. It covers installation, key features, basic usage examples, and +- [Arcade with Agent Frameworks and MCP Clients](https://docs.arcade.dev/en/get-started/agent-frameworks.md): This documentation page provides developers with guidance on integrating Arcade with various agent frameworks and MCP clients to enhance their AI applications. It includes authentication procedures, tool loading, and execution instructions, along with code examples and configuration steps for quick implementation. Users can explore specific +- [Arcade with Google ADK](https://docs.arcade.dev/en/get-started/agent-frameworks/google-adk/overview.md): This documentation page provides a comprehensive guide for integrating the `google-adk-arcade` package with the Google ADK library, enabling users to enhance their AI agents with various Arcade tools such as Google Mail and GitHub. It covers installation, key +- [Arcade with OpenAI Agents](https://docs.arcade.dev/en/get-started/agent-frameworks/openai-agents/overview.md): This documentation page provides a comprehensive guide for integrating Arcade with the OpenAI Agents library, enabling users to enhance their AI agents with various tools like Gmail, LinkedIn, and GitHub. It covers installation, key features, basic usage examples, and handling - [ArcadeEngineApi](https://docs.arcade.dev/en/resources/integrations/development/arcade-engine-api.md): The ArcadeEngineApi documentation provides users with a comprehensive guide to the tools available for interacting with the Arcade Engine API, focusing on managing authentication providers, secrets, and worker configurations. It outlines various actions users and LLMs can perform, such as retrieving - [Asana](https://docs.arcade.dev/en/resources/integrations/productivity/asana.md): This documentation page provides users with a comprehensive guide to the Arcade Asana MCP Server, enabling them to build agents and AI applications that interact with Asana tasks, projects, and workspaces. Users can learn how to manage teams, create and update tasks - [Asana Reference](https://docs.arcade.dev/en/resources/integrations/productivity/asana/reference.md): The Asana Reference documentation provides a comprehensive list of enumerations related to tag colors, task sorting options, and sort orders used in the Asana MCP Server. Users can utilize this reference to understand and implement the various color codes and sorting parameters effectively in @@ -82,7 +82,7 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [BoxApi](https://docs.arcade.dev/en/resources/integrations/productivity/box-api.md): The BoxApi documentation provides users with tools to manage and automate various aspects of Box content, including file management, metadata handling, collaboration, document generation, and enterprise operations. It outlines capabilities for interacting with Box's API, enabling users to build applications or - [Brightdata](https://docs.arcade.dev/en/resources/integrations/development/brightdata.md): The Brightdata documentation page provides users with tools and guidance for scraping, searching, and extracting structured data from various websites at scale without being blocked. It outlines specific functionalities such as scraping web pages in Markdown format, performing advanced searches across major search engines, - [Build a Tool](https://docs.arcade.dev/en/guides/create-tools/tool-basics.md): This documentation page provides a comprehensive guide on building custom tools using Arcade's MCP Server framework, enabling users to enhance AI agents with new functionalities. It serves as a starting point for those looking to create their first tool or expand existing capabilities. Users will learn -- [Build an AI Chatbot with Arcade and Vercel AI SDK](https://docs.arcade.dev/en/guides/agent-frameworks/vercelai.md): This documentation page provides a step-by-step guide for building a browser-based AI chatbot using the Vercel AI SDK and Arcade tools, enabling users to interact with Gmail and Slack through a conversational interface. Users will learn how to set up a Next.js +- [Build an AI Chatbot with Arcade and Vercel AI SDK](https://docs.arcade.dev/en/get-started/agent-frameworks/vercelai.md): This documentation page provides a step-by-step guide for building a browser-based AI chatbot using the Vercel AI SDK and Arcade tools to integrate with Gmail and Slack. Users will learn how to set up a Next.js project, handle authentication, and implement - [Build MCP Server QuickStart](https://docs.arcade.dev/en/get-started/quickstarts/mcp-server-quickstart.md): The "Build MCP Server QuickStart" documentation provides a step-by-step guide for users to create and run a custom MCP Server using the Arcade MCP framework. It covers prerequisites, installation instructions, server setup, and how to connect and authorize tools, enabling - [CalendlyApi](https://docs.arcade.dev/en/resources/integrations/productivity/calendly-api.md): The CalendlyApi documentation provides tools and resources for developers to integrate and manage scheduling and event-related tasks within the Calendly platform using OAuth2 authentication. Users can learn how to create, retrieve, and update event types, manage invitees, and handle - [Call a tool in your IDE/MCP Client](https://docs.arcade.dev/en/get-started/quickstarts/call-tool-client.md): This documentation page guides users on how to create and utilize an MCP Gateway in their IDE or MCP Client to streamline the process of calling tools from multiple MCP servers. It covers the steps to set up the gateway, select relevant tools, and connect it to @@ -99,10 +99,10 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Comparative evaluations](https://docs.arcade.dev/en/guides/create-tools/evaluate-tools/comparative-evaluations.md): The "Comparative Evaluations" documentation page guides users in testing and comparing the performance of AI models across different tool implementations using isolated tool registries, known as tracks. It outlines how to set up comparative evaluations, register tools, create test cases, - [Compare MCP Server Types](https://docs.arcade.dev/en/guides/create-tools/tool-basics/compare-server-types.md): This documentation page provides a comparative overview of different MCP server types offered by Arcade, detailing their functionalities based on transport method and deployment options. Users can learn about the capabilities of each server type, including the availability of tools with or without authentication and secrets. - [Confluence](https://docs.arcade.dev/en/resources/integrations/productivity/confluence.md): This documentation page provides a comprehensive overview of the Arcade Confluence MCP Server, which enables users to build agents and AI applications that interact with Confluence. It details various tools available for managing pages, spaces, and attachments, as well as searching for content -- [Connect Arcade to your LLM](https://docs.arcade.dev/en/guides/agent-frameworks/setup-arcade-with-your-llm-python.md): This documentation page provides a step-by-step guide for integrating Arcade's tool-calling capabilities into a Python application that utilizes a Large Language Model (LLM). Users will learn how to create a harness to facilitate interactions between the user, the model, and -- [Connect to MCP Clients](https://docs.arcade.dev/en/guides/tool-calling/mcp-clients.md): This documentation page provides guidance on connecting Arcade MCP servers to various MCP-compatible clients and development environments, enabling users to enhance their agent workflows. +- [Connect Arcade to your LLM](https://docs.arcade.dev/en/get-started/agent-frameworks/setup-arcade-with-your-llm-python.md): This documentation page provides a step-by-step guide for integrating Arcade with a Large Language Model (LLM) using Python. It outlines the necessary prerequisites, including API keys and package installations, and teaches users how to create a harness that facilitates communication between the +- [Connect to MCP Clients](https://docs.arcade.dev/en/get-started/mcp-clients.md): This documentation page provides guidance on connecting MCP servers to various MCP-compatible clients and development environments, enabling users to enhance their agent workflows. - [Contact Us](https://docs.arcade.dev/en/resources/contact-us.md): This documentation page provides users with information on how to connect with the Arcade team for support through various channels. It aims to facilitate communication and assistance for users and their agents. -- [Create a new Mastra project](https://docs.arcade.dev/en/guides/agent-frameworks/mastra/use-arcade-tools.md): This documentation page provides a step-by-step guide for integrating Arcade tools into a new Mastra project, enabling users to leverage these tools within their Mastra applications. It covers prerequisites, project setup, installation of the Arcade client, API key configuration, and +- [Create a new Mastra project](https://docs.arcade.dev/en/get-started/agent-frameworks/mastra/use-arcade-tools.md): This documentation page provides a comprehensive guide for users to create a new Mastra project and integrate Arcade tools into their applications. It covers prerequisites, project setup, installation of the Arcade client, configuration of API keys, and interaction methods with the Mastra agent - [Create an evaluation suite](https://docs.arcade.dev/en/guides/create-tools/evaluate-tools/create-evaluation-suite.md): This documentation page provides a comprehensive guide on creating an evaluation suite to test AI models' tool usage through Arcade. Users will learn how to set up prerequisites, define evaluation files and suites, run evaluations, and interpret results, ensuring accurate tool selection and parameter - [Create an MCP tool with secrets](https://docs.arcade.dev/en/guides/create-tools/tool-basics/create-tool-secrets.md): This documentation page guides users on how to create custom MCP tools that securely handle sensitive information, or "secrets," using the Arcade platform. It covers the process of reading secrets from various sources, such as environment variables and the Arcade Dashboard, and provides - [Creating an MCP Server with Arcade](https://docs.arcade.dev/en/guides/create-tools/tool-basics/build-mcp-server.md): This documentation page provides a comprehensive guide for users to create, test, deploy, and publish a custom MCP Server using the Arcade framework. It details the installation of necessary tools, the scaffolding of a server project, and the setup of environment configurations, @@ -120,7 +120,7 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Environment Variables](https://docs.arcade.dev/en/resources/integrations/social-communication/slack/environment-variables.md): This documentation page provides guidance on configuring environment variables related to Slack API interactions, specifically `SLACK_MAX_CONCURRENT_REQUESTS`, `MAX_PAGINATION_SIZE_LIMIT`, and `MAX_PAGINATION_TIMEOUT_SECONDS`. Users will learn how to adjust these settings - [Evaluate Tools](https://docs.arcade.dev/en/guides/create-tools/evaluate-tools.md): The "Evaluate Tools" documentation page provides guidance on systematically testing and enhancing tools using Arcade's evaluation framework. It helps users validate the performance of their tools after initial development and offers techniques for iterative improvements to ensure reliability in production. - [ExaApi](https://docs.arcade.dev/en/resources/integrations/search/exa-api.md): The ExaApi documentation provides users with a comprehensive guide to utilizing the Exa.ai Search API, enabling them to conduct searches, manage websets, and handle research requests effectively. It outlines various tools available within the API, detailing their functionalities such as -- [Fetch the "ScrapeUrl" tool from the "Firecrawl" MCP Server](https://docs.arcade.dev/en/guides/agent-frameworks/langchain/use-arcade-tools.md): This documentation page provides a comprehensive guide for integrating Arcade tools into LangGraph applications, detailing prerequisites, environment setup, API key configuration, and tool management. Users will learn how to create and manage AI models, configure agents, and stream responses while utilizing code +- [Fetch the "ScrapeUrl" tool from the "Firecrawl" MCP Server](https://docs.arcade.dev/en/get-started/agent-frameworks/langchain/use-arcade-tools.md): This documentation page provides a comprehensive guide on integrating Arcade tools into LangGraph applications, detailing prerequisites, environment setup, API key configuration, and tool management. Users will learn how to create and manage AI models, configure agents, and stream responses while leveraging specific - [Figma](https://docs.arcade.dev/en/resources/integrations/development/figma.md): This documentation page provides users with a comprehensive guide to the Figma MCP Server, enabling interaction with Figma's design files, components, and collaboration features through the Figma REST API. Users can learn to access file structures, manage components, add comments - [FigmaApi](https://docs.arcade.dev/en/resources/integrations/productivity/figma-api.md): The FigmaApi documentation provides a comprehensive guide for developers to utilize tools that enable interaction with the Figma API, facilitating efficient management of design assets and collaboration on projects. Users can learn how to perform various actions such as retrieving Figma files, managing - [Firecrawl](https://docs.arcade.dev/en/resources/integrations/development/firecrawl.md): The Firecrawl documentation provides users with a comprehensive guide to utilizing the Arcade Firecrawl MCP Server, enabling them to build agents and AI applications for scraping, crawling, and mapping websites. It outlines available tools, including functionalities for scraping URLs, crawling websites, @@ -165,9 +165,9 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [HubspotUsersApi](https://docs.arcade.dev/en/resources/integrations/sales/hubspot-users-api.md): The HubspotUsersApi documentation provides users with tools to efficiently manage users and teams within a HubSpot account, including functionalities for retrieving user lists, creating and updating user accounts, and removing users. It offers detailed descriptions of available API tools, along with - [Imgflip](https://docs.arcade.dev/en/resources/integrations/entertainment/imgflip.md): The Imgflip documentation provides users with tools to create and manage memes using the Imgflip API, enabling the development of agents and AI applications. Users can search for meme templates, retrieve popular memes, and create custom memes by adding text to existing templates. - [Imgflip](https://docs.arcade.dev/en/resources/integrations/entertainment/spotify/imgflip.md): The Imgflip documentation page provides users with tools to create and manage memes using the Imgflip API, allowing them to search for meme templates, retrieve popular templates, and create custom memes. It outlines the available features, including a premium search option and customizable -- [Import necessary classes and modules](https://docs.arcade.dev/en/guides/agent-frameworks/langchain/user-auth-interrupts.md): This documentation page guides users in creating a LangGraph workflow that integrates user authorization for specific Arcade tools, ensuring that only authorized tools are accessible to the language model. It provides step-by-step instructions on setting up the necessary environment, installing required packages, and +- [Import necessary classes and modules](https://docs.arcade.dev/en/get-started/agent-frameworks/langchain/user-auth-interrupts.md): This documentation page guides users in creating a LangGraph workflow that incorporates user authorization for specific Arcade tools, ensuring that only authorized tools are accessible to the language model. It provides step-by-step instructions on setting up the environment, defining workflow functions, and compiling - [In Custom Applications](https://docs.arcade.dev/en/guides/tool-calling/custom-apps.md): This documentation page provides guidance on integrating Arcade tools into custom applications, focusing on user authentication, authorization status checking, and managing tool definitions. It serves as a resource for developers building tool-calling interfaces to ensure proper implementation and functionality. -- [Initialize the Arcade client](https://docs.arcade.dev/en/guides/agent-frameworks/google-adk/use-arcade-tools.md): This documentation page provides a comprehensive guide for integrating Arcade tools into Google ADK applications, outlining the necessary prerequisites, setup procedures, and configuration steps. Users will learn how to manage and authorize Arcade tools, create agents, and run them effectively within their applications +- [Initialize the Arcade client](https://docs.arcade.dev/en/get-started/agent-frameworks/google-adk/use-arcade-tools.md): This documentation page provides a comprehensive guide for integrating Arcade tools into Google ADK applications, detailing the necessary prerequisites, environment setup, and configuration steps. Users will learn how to create and manage Arcade tools, authorize them for agents, and run these agents with - [IntercomApi](https://docs.arcade.dev/en/resources/integrations/customer-support/intercom-api.md): The IntercomApi documentation provides a comprehensive guide to tools that enable users to interact with the Intercom platform using OAuth2 authentication. It details various functionalities, such as managing admin information, creating and updating articles, and handling company data, allowing users to - [Jira](https://docs.arcade.dev/en/resources/integrations/productivity/jira.md): This documentation page provides a comprehensive overview of the Jira MCP Server, which enables users and AI applications to efficiently manage Jira issues and projects. It outlines various functionalities such as creating, updating, and searching for issues, managing labels and attachments, and transitioning issues - [Jira Environment Variables](https://docs.arcade.dev/en/resources/integrations/productivity/jira/environment-variables.md): This documentation page provides essential information on configuring Jira environment variables to optimize API interactions, specifically focusing on controlling the maximum concurrent requests, API request timeout, and cache size for improved performance during tool execution. Users will learn how to set numeric string values for these @@ -186,23 +186,23 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Notion](https://docs.arcade.dev/en/resources/integrations/productivity/notion.md): This documentation page provides users with a comprehensive guide to the Arcade Notion MCP Server, which enables the creation and management of agents and AI applications that interact with Notion. Users can learn how to utilize various tools to retrieve page content, create new pages - [Obsidian](https://docs.arcade.dev/en/resources/integrations/productivity/obsidian.md): This documentation page provides an overview of the Arcade Obsidian Toolkit, a community-contributed MCP Sever verified by the Arcade team. It guides users to learn more about the toolkit by directing them to the associated GitHub repository. - [On-premise MCP Servers](https://docs.arcade.dev/en/guides/deployment-hosting/on-prem.md): This documentation page provides guidance on deploying on-premises MCP servers within a hybrid architecture, enabling users to utilize Arcade's cloud infrastructure while maintaining control over their private resources and data security. Users will learn how to set up their MCP servers, create secure tunnels -- [Or set it directly when initializing the client](https://docs.arcade.dev/en/guides/agent-frameworks/openai-agents/use-arcade-tools.md): This documentation page provides a comprehensive guide on integrating Arcade tools into OpenAI Agents applications, detailing the necessary prerequisites, environment setup, and configuration steps. Users will learn how to create and manage Arcade tools, set up agents, handle authentication, and run their +- [Or set it directly when initializing the client](https://docs.arcade.dev/en/get-started/agent-frameworks/openai-agents/use-arcade-tools.md): This documentation page provides a comprehensive guide on integrating Arcade tools into OpenAI Agents applications, detailing the necessary prerequisites, environment setup, and configuration steps. Users will learn how to create and manage Arcade tools, set up agents with these tools, handle authentication, - [Organize your MCP server and tools](https://docs.arcade.dev/en/guides/create-tools/tool-basics/organize-mcp-tools.md): This documentation page provides best practices for organizing your MCP server and tools, including how to define and import tools from separate files and other packages. Users will learn to maintain a clean project structure by keeping tools in a dedicated directory and using decorators effectively. Additionally - [Outlook Calendar](https://docs.arcade.dev/en/resources/integrations/productivity/outlook-calendar.md): The Outlook Calendar documentation page provides users with tools to create, list, and retrieve events in their Outlook Calendar using the Outlook API. It includes detailed descriptions of available tools, such as creating events and fetching event details, along with example code snippets for implementation - [Outlook Mail](https://docs.arcade.dev/en/resources/integrations/productivity/outlook-mail.md): The Outlook Mail documentation page provides users with tools to interact with the Outlook API, enabling them to read, write, and send emails efficiently. It details various functionalities, such as creating drafts, sending emails, and listing messages, along with code examples for - [OutlookMail Reference](https://docs.arcade.dev/en/resources/integrations/productivity/outlook-mail/reference.md): The OutlookMail Reference documentation provides a comprehensive list of enumerations, folder names, email filter properties, and filter operators used in the OutlookMail MCP Server. It helps users understand and utilize these elements effectively when working with OutlookMail tools. This reference is - [page](https://docs.arcade.dev/en/resources/examples.md): This documentation page showcases a collection of example applications that utilize Arcade's tools and MCP servers, providing users with practical implementations and templates for various workflows and agent functionalities. Users can explore detailed descriptions and links to GitHub repositories for each app, enabling them to - [page](https://docs.arcade.dev/en/resources/integrations.md): This documentation page provides a comprehensive registry of all MCP Servers within the Arcade ecosystem, helping users to easily identify and access the available servers. -- [page](https://docs.arcade.dev/en/guides/agent-frameworks/crewai/use-arcade-tools.md): This documentation page provides a comprehensive guide for integrating Arcade tools into CrewAI applications, detailing the necessary prerequisites, environment setup, and configuration steps. Users will learn how to authorize and utilize these tools within their CrewAI agent teams, ensuring tailored functionality for their -- [page](https://docs.arcade.dev/en/guides/agent-frameworks/langchain/auth-langchain-tools.md): This documentation page provides a step-by-step guide on how to authorize existing LangChain tools, such as the `GmailToolkit`, using the Arcade platform. It outlines the necessary prerequisites, installation of required packages, and detailed instructions for the authorization process in -- [page](https://docs.arcade.dev/en/guides/agent-frameworks/mastra/overview.md): This documentation page guides users on integrating Arcade's tool ecosystem with Mastra applications, enabling enhanced functionality for AI agents. It outlines how to access various pre-built tools, simplifies tool management, and details the processes for tool discovery, schema conversion, and execution -- [page](https://docs.arcade.dev/en/guides/agent-frameworks/mastra/user-auth-interrupts.md): This documentation page provides guidance on managing user-specific authorization for Arcade tools within Mastra applications, focusing on dynamic tool loading and per-user authentication flows. It outlines the steps to set up agents and API endpoints, ensuring each user has a secure and tailored experience +- [page](https://docs.arcade.dev/en/get-started/agent-frameworks/crewai/use-arcade-tools.md): This documentation page provides a comprehensive guide on integrating Arcade tools into CrewAI applications, detailing the necessary prerequisites, setup, and configuration steps. Users will learn how to manage tool authorization and effectively utilize these tools within their CrewAI agent teams. Additionally, it +- [page](https://docs.arcade.dev/en/get-started/agent-frameworks/langchain/auth-langchain-tools.md): This documentation page provides a step-by-step guide on how to authorize existing LangChain tools, such as the `GmailToolkit`, using the Arcade platform. It outlines the prerequisites, installation of necessary packages, and detailed instructions for the authorization process in both +- [page](https://docs.arcade.dev/en/get-started/agent-frameworks/mastra/overview.md): This documentation page provides guidance on integrating Arcade's tool ecosystem with Mastra applications, enabling users to enhance their Mastra agents with access to a variety of pre-built tools and simplified tool management. It outlines the key mechanisms for integration, including tool discovery, +- [page](https://docs.arcade.dev/en/get-started/agent-frameworks/mastra/user-auth-interrupts.md): This documentation page provides guidance on managing user-specific authorization for Arcade tools within Mastra applications, focusing on dynamic tool loading and per-user authentication flows. It outlines the necessary steps to configure agents, create API endpoints, and handle tool authorization effectively, ensuring a - [page](https://docs.arcade.dev/en/resources/integrations/productivity/dropbox/reference.md): This documentation page defines the various item categories used in Dropbox, including types such as image, document, PDF, spreadsheet, presentation, audio, video, folder, and paper. It helps users understand the classification of files within the Dropbox system. - [PagerDuty](https://docs.arcade.dev/en/resources/integrations/customer-support/pagerduty.md): This documentation page provides guidance on using the PagerDuty MCP Server, which enables agents to access and manage incidents, on-call information, services, and teams through read-only API tools. It includes details on OAuth configuration, available tools with descriptions, and code - [PagerdutyApi](https://docs.arcade.dev/en/resources/integrations/development/pagerduty-api.md): The PagerDutyApi documentation provides a comprehensive overview of tools that enable users to manage incidents, services, and integrations within the PagerDuty platform using the API. It outlines various functionalities, such as assigning tags, retrieving metrics, and managing add-ons, allowing - [Postgres](https://docs.arcade.dev/en/resources/integrations/databases/postgres.md): This documentation page provides users with a comprehensive guide to the Arcade Postgres MCP Server, which enables agents to interact with PostgreSQL databases in a read-only manner. Users can learn how to discover database schemas, explore table structures, and execute safe SELECT queries - [PosthogApi](https://docs.arcade.dev/en/resources/integrations/development/posthog-api.md): The PosthogApi documentation provides users with tools and guidance for managing and analyzing data within the PostHog platform via its API. It details the necessary configuration, including authentication secrets, and outlines various available tools for retrieving metrics, managing exports, and handling -- [Provide the tool manager callback to the ArcadeToolManager](https://docs.arcade.dev/en/guides/agent-frameworks/crewai/custom-auth-flow.md): This documentation page provides a step-by-step guide on creating a custom authorization flow for executing Arcade tools within a CrewAI agent team. It outlines the prerequisites, environment setup, and configuration needed to implement a tailored approach to tool authorization, allowing for unique interfaces +- [Provide the tool manager callback to the ArcadeToolManager](https://docs.arcade.dev/en/get-started/agent-frameworks/crewai/custom-auth-flow.md): This documentation page provides a comprehensive guide on creating a custom authorization flow for the ArcadeToolManager within a CrewAI agent team. It outlines the necessary prerequisites, setup steps, and code examples to help users implement tailored authorization processes for executing Arcade tools. By - [Providing useful tool errors](https://docs.arcade.dev/en/guides/create-tools/error-handling/useful-tool-errors.md): This documentation page teaches developers how to effectively handle errors when building tools with Arcade MCP, emphasizing the automatic error adaptation feature that reduces boilerplate code. It outlines the error handling philosophy, explains the use of error adapters, and provides guidance on when to raise - [Pylon](https://docs.arcade.dev/en/resources/integrations/customer-support/pylon.md): The Pylon documentation provides agents with the necessary tools and API functionalities to manage issues, contacts, users, and teams within the Pylon MCP Server. Users can learn how to list and search issues, assign ownership, and interact with user and team data - [Reddit](https://docs.arcade.dev/en/resources/integrations/social-communication/reddit.md): This documentation page provides users with a comprehensive guide to the Arcade Reddit MCP Server, which enables the development of agents and AI applications that can interact with Reddit. It details various tools available for actions such as submitting posts, commenting, retrieving content, and checking @@ -217,8 +217,8 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Security](https://docs.arcade.dev/en/guides/security.md): This documentation page provides users with best practices for ensuring the security of MCP servers and Arcade tools, particularly when handling sensitive data or operating in production environments. It also highlights the importance of security in tool development and outlines the resources available for implementing robust security measures - [Security Research Program](https://docs.arcade.dev/en/guides/security/security-research-program.md): The Security Research Program documentation page outlines how users can report security vulnerabilities in Arcade's tools and services, emphasizing the importance of community involvement in enhancing security. It details the types of vulnerabilities sought, the reporting process, and guidelines for responsible disclosure. Additionally, - [Server-Level vs Tool-Level Authorization](https://docs.arcade.dev/en/learn/server-level-vs-tool-level-auth.md): This documentation page explains the differences between server-level authorization (Resource Server auth) and tool-level authorization in Arcade MCP servers, highlighting their roles in securing access to the server and third-party APIs. It provides guidance on when to implement each type of authorization, -- [Set your API key](https://docs.arcade.dev/en/guides/agent-frameworks/openai-agents/user-auth-interrupts.md): This documentation page provides guidance on managing user authorization for Arcade tools within OpenAI Agents applications. It covers obtaining an API key, configuring the environment, handling authorization errors, and ensuring persistence of user authorization. Users will learn how to effectively implement and manage the -- [Setup Arcade with LangChain](https://docs.arcade.dev/en/guides/agent-frameworks/langchain/use-arcade-with-langchain.md): This documentation page provides a comprehensive guide on integrating Arcade tools within LangChain agents, enabling users to build and manage AI agents effectively. It covers the necessary prerequisites, key concepts like agents and interrupts, and detailed steps for setting up a project, importing required +- [Set your API key](https://docs.arcade.dev/en/get-started/agent-frameworks/openai-agents/user-auth-interrupts.md): This documentation page provides a comprehensive guide on managing user authorization for Arcade tools within OpenAI Agents applications. It outlines the steps to obtain an API key, configure the environment, handle authorization errors, and implement a complete authorization flow. Users will learn how to +- [Setup Arcade with LangChain](https://docs.arcade.dev/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain.md): This documentation page guides users on how to integrate Arcade tools into LangChain agents, enabling them to leverage Arcade's capabilities within the LangChain framework. Users will learn to set up their environment, create a LangChain agent, and manage tool authorization and execution - [Sharepoint](https://docs.arcade.dev/en/resources/integrations/productivity/sharepoint.md): This documentation page provides a comprehensive guide for using the SharePoint MCP Server, enabling users to efficiently interact with SharePoint sites and their contents through various tools. Users can learn to retrieve lists, items, pages, and metadata, as well as search for - [Slack](https://docs.arcade.dev/en/resources/integrations/social-communication/slack.md): This documentation page provides users with tools and functionalities to integrate and interact with the Slack platform, enabling efficient management of conversations and user information. It outlines various capabilities, such as retrieving user details, sending messages, and accessing conversation metadata, all aimed at enhancing - [SlackApi](https://docs.arcade.dev/en/resources/integrations/social-communication/slack_api.md): The SlackApi documentation provides a comprehensive guide for administrators and applications to manage and automate various aspects of Slack workspaces, including user management, messaging, channel operations, and file sharing. It outlines key functionalities such as creating teams, managing user profiles, sending @@ -237,10 +237,10 @@ Arcade delivers three core capabilities: Deploy agents even your security team w - [Twitch auth provider](https://docs.arcade.dev/en/resources/integrations/entertainment/twitch.md): The Twitch auth provider documentation page guides users in creating a custom authentication provider to access the Twitch API using their own OAuth 2.0 credentials. It outlines the steps to configure Twitch authentication within the Arcade platform, including creating a Twitch application and integrating it - [Types of Tools](https://docs.arcade.dev/en/guides/create-tools/improve/types-of-tools.md): This documentation page explains the two types of tools offered by Arcade: Optimized tools and Starter tools. It highlights the differences in design and functionality, emphasizing that Optimized tools are tailored for AI-powered chat interfaces to improve performance, while Starter tools provide more - [Understanding `Context` and tools](https://docs.arcade.dev/en/guides/create-tools/tool-basics/runtime-data-access.md): This documentation page explains the `Context` class used in Arcade tools, detailing how to access runtime capabilities and tool-specific data securely. Users will learn how to utilize the `Context` object to retrieve OAuth tokens, secrets, user information, and to log -- [Use Arcade in Cursor](https://docs.arcade.dev/en/guides/tool-calling/mcp-clients/cursor.md): This documentation page provides a step-by-step guide for users to connect Cursor to an Arcade MCP Gateway, enabling the use of Arcade tools within Cursor. It outlines the prerequisites needed for setup, including creating an Arcade account and obtaining an API key, as well +- [Use Arcade in Claude Desktop](https://docs.arcade.dev/en/get-started/mcp-clients/claude-desktop.md): This documentation page provides a step-by-step guide for users to connect Claude Desktop to an Arcade MCP Gateway, enabling them to utilize custom connectors. It outlines the prerequisites for setup, including creating an Arcade account and obtaining an API key, as well as detailed +- [Use Arcade in Cursor](https://docs.arcade.dev/en/get-started/mcp-clients/cursor.md): This documentation page provides a step-by-step guide for connecting Cursor to an Arcade MCP Gateway, enabling users to utilize Arcade tools within the Cursor environment. It outlines the prerequisites for setup, including creating an Arcade account and obtaining an API key, as well as - [Use Arcade in Microsoft Copilot Studio](https://docs.arcade.dev/en/guides/tool-calling/mcp-clients/copilot-studio.md): This documentation page guides users on how to connect Microsoft Copilot Studio to an Arcade MCP Gateway, enabling the integration of Arcade tools within their agents. It outlines the prerequisites, step-by-step instructions for creating or opening an agent, adding an MCP tool, -- [Use Arcade in Visual Studio Code](https://docs.arcade.dev/en/guides/tool-calling/mcp-clients/visual-studio-code.md): This documentation page provides a step-by-step guide for connecting Visual Studio Code to an Arcade MCP Gateway, enabling users to integrate and utilize Arcade tools within the IDE. It outlines the prerequisites for setup, including creating an Arcade account and obtaining an API key, -- [Use Arcade with Claude Desktop](https://docs.arcade.dev/en/guides/tool-calling/mcp-clients/claude-desktop.md): This documentation page is intended to guide users on how to utilize Arcade with Claude Desktop. However, it currently indicates that the content is forthcoming and does not provide any detailed instructions or information at this time. +- [Use Arcade in Visual Studio Code](https://docs.arcade.dev/en/get-started/mcp-clients/visual-studio-code.md): This documentation page provides a step-by-step guide for connecting Visual Studio Code to an Arcade MCP Gateway, enabling users to set up and run an MCP server within the IDE. It outlines prerequisites, setup instructions, and authentication processes to ensure successful integration. By - [VercelApi](https://docs.arcade.dev/en/resources/integrations/development/vercel-api.md): The VercelApi documentation provides a comprehensive guide for users to manage their Vercel projects, domains, and integrations through various API tools. It outlines available functionalities such as creating and managing access groups, handling deployments, and managing DNS records, enabling - [Walmart Search](https://docs.arcade.dev/en/resources/integrations/search/walmart.md): The Walmart Search documentation provides tools for developers to integrate product search and details retrieval from Walmart into their applications. It outlines how to use the `Walmart.SearchProducts` and `Walmart.GetProductDetails` tools, including parameters for customizing searches and retrieving - [WeaviateApi](https://docs.arcade.dev/en/resources/integrations/databases/weaviate-api.md): The WeaviateApi documentation provides users with essential tools and instructions for managing and interacting with the Weaviate vector search engine via its API. It covers authentication requirements, including obtaining API keys, and offers a comprehensive list of available API endpoints for various diff --git a/scripts/check-redirects.ts b/scripts/check-redirects.ts new file mode 100644 index 000000000..093003ea2 --- /dev/null +++ b/scripts/check-redirects.ts @@ -0,0 +1,652 @@ +#!/usr/bin/env npx tsx + +/** + * Check that deleted/renamed markdown files have corresponding redirects in next.config.ts + * + * Usage: + * pnpm check-redirects [--auto-fix] [--staged-only] [base_branch] + * + * Features: + * - Detects deleted AND renamed markdown files without redirects + * - Auto-fix mode: automatically inserts redirect entries into next.config.ts + * - Validates existing redirects for circular references and invalid destinations + * - Collapses redirect chains automatically + * - --staged-only: Only check staged changes (for pre-commit hook) + */ + +import { execSync } from "node:child_process"; +import { existsSync, readFileSync, writeFileSync } from "node:fs"; + +// Colors for terminal output +const colors = { + red: (s: string) => `\x1b[0;31m${s}\x1b[0m`, + green: (s: string) => `\x1b[0;32m${s}\x1b[0m`, + yellow: (s: string) => `\x1b[1;33m${s}\x1b[0m`, + blue: (s: string) => `\x1b[0;34m${s}\x1b[0m`, +}; + +// Parse command line arguments +const args = process.argv.slice(2); +const autoFix = args.includes("--auto-fix"); +const stagedOnly = args.includes("--staged-only"); +const baseBranch = args.find((arg) => !arg.startsWith("--")) || "main"; + +const CONFIG_FILE = "next.config.ts"; + +// Magic number constant for "return [" offset +const RETURN_BRACKET_LENGTH = 8; + +// Top-level regex patterns for performance +const APP_LOCALE_PREFIX_REGEX = /^app\/[a-z]{2}\//; +const PAGE_FILE_SUFFIX_REGEX = /\/?page\.mdx?$/; +const LOCALE_PREFIX_REGEX = /^\/:locale\/?/; +const PAGE_FILE_MATCH_REGEX = /page\.mdx?$/; +const LOCALE_PATH_PREFIX_REGEX = /^\/:locale\//; +const WILDCARD_PATH_REGEX = /\/:path\*.*$/; +const MDX_EXTENSION_REGEX = /\.mdx$/; +const SPECIAL_REGEX_CHARS_REGEX = /[.*+?^${}()|[\]\\]/g; +const REDIRECT_REGEX = + /\{\s*source:\s*["']([^"']+)["']\s*,\s*destination:\s*["']([^"']+)["']/g; +const REVERSED_REDIRECT_REGEX = + /\{\s*destination:\s*["']([^"']+)["']\s*,\s*source:\s*["']([^"']+)["']/g; + +type Redirect = { + source: string; + destination: string; + permanent?: boolean; +}; + +type RedirectChain = { + source: string; + oldDest: string; + newDest: string; +}; + +/** + * Convert file path to URL path + * e.g., app/en/guides/foo/page.mdx -> /:locale/guides/foo + */ +function fileToUrl(filePath: string): string { + const urlPath = filePath + .replace(APP_LOCALE_PREFIX_REGEX, "") + .replace(PAGE_FILE_SUFFIX_REGEX, ""); + + return urlPath ? `/:locale/${urlPath}` : "/:locale"; +} + +/** + * Convert URL path to file path + * e.g., /:locale/guides/foo -> app/en/guides/foo/page.mdx + */ +function urlToFile(urlPath: string): string { + const pathWithoutLocale = urlPath.replace(LOCALE_PREFIX_REGEX, ""); + return pathWithoutLocale + ? `app/en/${pathWithoutLocale}/page.mdx` + : "app/en/page.mdx"; +} + +/** + * Check if a page exists on disk + */ +function pageExists(urlPath: string): boolean { + if (urlPath.includes(":path*") || urlPath.includes(":path")) { + return true; + } + + const filePath = urlToFile(urlPath); + if (existsSync(filePath)) { + return true; + } + + const mdPath = filePath.replace(MDX_EXTENSION_REGEX, ".md"); + if (existsSync(mdPath)) { + return true; + } + + return false; +} + +/** + * Execute regex and collect all matches (avoids assignment in expression) + */ +function collectRegexMatches( + regex: RegExp, + content: string, + sourceIndex: number, + destIndex: number +): Array<{ source: string; destination: string }> { + const results: Array<{ source: string; destination: string }> = []; + regex.lastIndex = 0; + + let match = regex.exec(content); + while (match !== null) { + results.push({ + source: match[sourceIndex], + destination: match[destIndex], + }); + match = regex.exec(content); + } + + return results; +} + +/** + * Parse redirects from next.config.ts + */ +function parseRedirects(content: string): Redirect[] { + const results: Redirect[] = []; + + // Collect standard format: { source: "...", destination: "..." } + const standardMatches = collectRegexMatches(REDIRECT_REGEX, content, 1, 2); + for (const m of standardMatches) { + results.push(m); + } + + // Collect reversed format: { destination: "...", source: "..." } + const reversedMatches = collectRegexMatches( + REVERSED_REDIRECT_REGEX, + content, + 2, + 1 + ); + for (const m of reversedMatches) { + results.push(m); + } + + return results; +} + +/** + * Parse git diff output for deleted and renamed files + */ +function parseGitDiffOutput( + output: string, + deletedFiles: string[], + renamedFromFiles: string[] +): void { + for (const line of output.split("\n")) { + if (!line) { + continue; + } + const parts = line.split("\t"); + const status = parts[0]; + const filePath = parts[1]; + + if (status === "D" && filePath && PAGE_FILE_MATCH_REGEX.test(filePath)) { + deletedFiles.push(filePath); + } else if ( + status?.startsWith("R") && + filePath && + PAGE_FILE_MATCH_REGEX.test(filePath) + ) { + renamedFromFiles.push(filePath); + } + } +} + +/** + * Ensure base branch exists locally + */ +function ensureBranchExists(branch: string): void { + try { + execSync(`git rev-parse --verify ${branch}`, { encoding: "utf-8" }); + } catch { + console.log(`Fetching ${branch} branch...`); + try { + execSync(`git fetch origin ${branch}:${branch}`, { encoding: "utf-8" }); + } catch { + console.error( + colors.red(`ERROR: Could not fetch base branch '${branch}'`) + ); + process.exit(1); + } + } +} + +/** + * Get deleted and renamed files by comparing branches + * @param branch - Base branch to compare against + * @param checkStagedOnly - If true, only check staged changes (for pre-commit hook) + */ +function getDeletedAndRenamedFiles( + branch: string, + checkStagedOnly: boolean +): { + deleted: string[]; + renamedFrom: string[]; +} { + const deletedFiles: string[] = []; + const renamedFromFiles: string[] = []; + + if (checkStagedOnly) { + // Only check staged changes (for pre-commit hook) + try { + const stagedChanges = execSync("git diff --cached --name-status", { + encoding: "utf-8", + }); + parseGitDiffOutput(stagedChanges, deletedFiles, renamedFromFiles); + } catch { + // Ignore errors from diff + } + } else { + // Check committed changes against base branch + ensureBranchExists(branch); + + try { + const committedChanges = execSync( + `git diff --name-status ${branch}...HEAD`, + { + encoding: "utf-8", + } + ); + parseGitDiffOutput(committedChanges, deletedFiles, renamedFromFiles); + } catch { + // Ignore errors from diff + } + + // Also check uncommitted changes (both staged and unstaged) + try { + const uncommittedChanges = execSync("git diff --name-status HEAD", { + encoding: "utf-8", + }); + parseGitDiffOutput(uncommittedChanges, deletedFiles, renamedFromFiles); + } catch { + // Ignore errors from diff + } + } + + return { + deleted: [...new Set(deletedFiles)], + renamedFrom: [...new Set(renamedFromFiles)], + }; +} + +/** + * Check if a wildcard redirect covers a path + */ +function checkWildcardMatch(path: string, redirectList: Redirect[]): boolean { + const pathWithoutLocale = path.replace(LOCALE_PATH_PREFIX_REGEX, ""); + + for (const redirect of redirectList) { + if (redirect.source.includes(":path*")) { + const prefix = redirect.source + .replace(WILDCARD_PATH_REGEX, "") + .replace(LOCALE_PATH_PREFIX_REGEX, ""); + + if ( + pathWithoutLocale.startsWith(`${prefix}/`) || + pathWithoutLocale === prefix + ) { + return true; + } + } + } + + return false; +} + +/** + * Find the final destination in a redirect chain (follows all hops) + * Returns null if the path doesn't redirect anywhere + */ +function findFinalRedirectDestination( + path: string, + redirectList: Redirect[] +): string | null { + const visited = new Set(); + let current = path; + + while (true) { + // Prevent infinite loops from circular redirects + if (visited.has(current)) { + return null; + } + visited.add(current); + + const redirect = redirectList.find((r) => r.source === current); + if (!redirect) { + // No redirect found - if we've moved at all, return current destination + return current === path ? null : current; + } + + current = redirect.destination; + } +} + +/** + * Insert redirect entries into next.config.ts + */ +function insertRedirects(entries: string[]): void { + const content = readFileSync(CONFIG_FILE, "utf-8"); + + const insertPoint = content.indexOf("return ["); + if (insertPoint === -1) { + console.error(colors.red("ERROR: Could not find 'return [' in config")); + process.exit(1); + } + + const beforeReturn = content.substring( + 0, + insertPoint + RETURN_BRACKET_LENGTH + ); + const afterReturn = content.substring(insertPoint + RETURN_BRACKET_LENGTH); + + const newContent = `${beforeReturn}\n // Auto-added redirects for deleted pages\n${entries.join("\n")}${afterReturn}`; + + writeFileSync(CONFIG_FILE, newContent); +} + +/** + * Update a redirect destination in the config + */ +function updateRedirectDestination( + oldDest: string, + newDest: string, + content: string +): string { + const escaped = oldDest.replace(SPECIAL_REGEX_CHARS_REGEX, "\\$&"); + const regex = new RegExp(`destination:\\s*["']${escaped}["']`, "g"); + // Using replacer function to avoid special replacement pattern interpretation + // (e.g., $1, $2, $& in newDest would be incorrectly expanded if using string) + return content.replace(regex, () => `destination: "${newDest}"`); +} + +// ============================================================ +// Main script +// ============================================================ + +console.log("Checking for deleted markdown files without redirects..."); +console.log(`Comparing current branch to: ${baseBranch}`); +console.log(""); + +const configContent = readFileSync(CONFIG_FILE, "utf-8"); +const redirects = parseRedirects(configContent); + +let exitCode = 0; +const invalidRedirects: string[] = []; +const chains: RedirectChain[] = []; + +// ============================================================ +// PART 1: Validate existing redirects +// ============================================================ +console.log(colors.blue(`Validating existing redirects in ${CONFIG_FILE}...`)); +console.log(""); + +for (const redirect of redirects) { + const { source, destination } = redirect; + + if ( + destination.includes("REPLACE_WITH") || + destination.includes("TODO") || + destination.includes("FIXME") + ) { + console.log(colors.red(`✗ Invalid redirect: ${source}`)); + console.log( + colors.yellow(` Destination contains placeholder text: ${destination}`) + ); + invalidRedirects.push(`${source} -> ${destination} (placeholder text)`); + exitCode = 1; + } else if (source === destination) { + console.log(colors.red(`✗ Circular redirect: ${source}`)); + console.log(colors.yellow(" Source and destination are the same!")); + invalidRedirects.push(`${source} -> ${destination} (circular)`); + exitCode = 1; + } else if (!destination.includes(":path")) { + const destWithoutLocale = destination.replace(LOCALE_PATH_PREFIX_REGEX, ""); + if (!(destWithoutLocale.includes(":") || pageExists(destination))) { + const finalDest = findFinalRedirectDestination(destination, redirects); + if (finalDest) { + console.log(colors.yellow(`⚠ Redirect chain detected: ${source}`)); + console.log(colors.blue(` ${source} → ${destination} → ${finalDest}`)); + chains.push({ source, oldDest: destination, newDest: finalDest }); + } else { + console.log(colors.red(`✗ Invalid redirect: ${source}`)); + console.log( + colors.yellow(` Destination does not exist: ${destination}`) + ); + invalidRedirects.push( + `${source} -> ${destination} (destination not found)` + ); + exitCode = 1; + } + } + } +} + +if (invalidRedirects.length === 0 && chains.length === 0) { + console.log(colors.green("✓ All existing redirects are valid.")); +} +console.log(""); + +// ============================================================ +// PART 1b: Auto-fix redirect chains +// ============================================================ +if (chains.length > 0) { + if (autoFix) { + console.log( + colors.blue(`Collapsing ${chains.length} redirect chain(s)...`) + ); + console.log(""); + + let updatedConfig = configContent; + for (const chain of chains) { + console.log(`${colors.green(" ✓")} ${chain.source}`); + console.log(` was: ${chain.oldDest}`); + console.log(` now: ${chain.newDest}`); + + updatedConfig = updateRedirectDestination( + chain.oldDest, + chain.newDest, + updatedConfig + ); + } + + writeFileSync(CONFIG_FILE, updatedConfig); + console.log(""); + console.log(colors.green(`✓ Redirect chains collapsed in ${CONFIG_FILE}`)); + console.log(""); + } else { + console.log( + colors.yellow( + `Found ${chains.length} redirect chain(s) that need collapsing.` + ) + ); + console.log("Run with --auto-fix to collapse them automatically."); + console.log(""); + exitCode = 1; + } +} + +// ============================================================ +// PART 2: Check for deleted/renamed files without redirects +// ============================================================ +const { deleted, renamedFrom } = getDeletedAndRenamedFiles( + baseBranch, + stagedOnly +); +const allDeletedOrRenamed = [...deleted, ...renamedFrom].filter((f) => + f.startsWith("app/") +); + +if (allDeletedOrRenamed.length === 0) { + console.log(colors.green("✓ No deleted or renamed markdown files found.")); + process.exit(exitCode); +} + +console.log("Found deleted/renamed markdown files:"); +for (const file of allDeletedOrRenamed) { + console.log(` ${file}`); +} +console.log(""); + +const missingRedirects: string[] = []; +const suggestedEntries: string[] = []; + +const latestRedirects = parseRedirects(readFileSync(CONFIG_FILE, "utf-8")); + +for (const file of allDeletedOrRenamed) { + const urlPath = fileToUrl(file); + + const hasExactRedirect = latestRedirects.some((r) => r.source === urlPath); + const hasWildcardRedirect = checkWildcardMatch(urlPath, latestRedirects); + + if (hasExactRedirect) { + console.log(colors.green(`✓ Redirect exists for: ${urlPath}`)); + } else if (hasWildcardRedirect) { + console.log( + colors.green(`✓ Redirect exists for: ${urlPath} (via wildcard)`) + ); + } else { + console.log(colors.red(`✗ Missing redirect for: ${urlPath}`)); + missingRedirects.push(urlPath); + + suggestedEntries.push(` { + source: "${urlPath}", + destination: "/:locale/REPLACE_WITH_NEW_PATH", + permanent: true, + },`); + + exitCode = 1; + } +} + +console.log(""); + +// ============================================================ +// PART 3: Report results and optionally auto-fix +// ============================================================ +if (missingRedirects.length > 0) { + if (autoFix) { + console.log( + colors.blue( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log( + colors.blue( + `Auto-fixing: Adding ${missingRedirects.length} redirect(s) to ${CONFIG_FILE}` + ) + ); + console.log( + colors.blue( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log(""); + + insertRedirects(suggestedEntries); + + console.log(colors.green(`✓ Added redirect entries to ${CONFIG_FILE}`)); + console.log(""); + console.log( + colors.red( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log( + colors.red("ACTION REQUIRED: Update placeholder destinations!") + ); + console.log( + colors.red( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log(""); + console.log("Redirect entries were added with placeholder destinations."); + console.log( + "You MUST update 'REPLACE_WITH_NEW_PATH' with actual paths before committing." + ); + console.log(""); + console.log(colors.yellow("Redirects needing destinations:")); + for (const p of missingRedirects) { + console.log(` - ${p} -> /:locale/REPLACE_WITH_NEW_PATH`); + } + console.log(""); + console.log( + `Open ${CONFIG_FILE} and search for 'REPLACE_WITH_NEW_PATH' to find them.` + ); + console.log(""); + + exitCode = 1; + } else { + console.log( + colors.red( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log( + colors.red( + `ERROR: Found ${missingRedirects.length} deleted file(s) without redirects!` + ) + ); + console.log( + colors.red( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log(""); + console.log( + "When you delete a markdown file, you must add a redirect in next.config.ts" + ); + console.log( + "to prevent broken links for users who have bookmarked the old URL." + ); + console.log(""); + console.log(colors.yellow("Missing redirects for:")); + for (const p of missingRedirects) { + console.log(` - ${p}`); + } + console.log(""); + console.log( + colors.yellow( + "Add the following to the redirects array in next.config.ts:" + ) + ); + console.log(""); + for (const entry of suggestedEntries) { + console.log(entry); + } + console.log(""); + } +} + +if (invalidRedirects.length > 0) { + console.log(""); + console.log( + colors.red("══════════════════════════════════════════════════════════════") + ); + console.log( + colors.red( + `ERROR: Found ${invalidRedirects.length} invalid redirect(s) in config!` + ) + ); + console.log( + colors.red("══════════════════════════════════════════════════════════════") + ); + console.log(""); + for (const invalid of invalidRedirects) { + console.log(` - ${invalid}`); + } + console.log(""); + console.log(colors.yellow("How to fix:")); + console.log(" 1. Open next.config.ts"); + console.log(" 2. Find the redirect(s) listed above"); + console.log(" 3. Update the destination to a valid page path"); + console.log(" (Check that the path exists under app/en/)"); +} + +if (exitCode === 0) { + console.log( + colors.green( + "══════════════════════════════════════════════════════════════" + ) + ); + console.log(colors.green("SUCCESS: All redirects are valid!")); + console.log( + colors.green( + "══════════════════════════════════════════════════════════════" + ) + ); +} + +process.exit(exitCode); diff --git a/scripts/update-internal-links.ts b/scripts/update-internal-links.ts new file mode 100644 index 000000000..da10d93c9 --- /dev/null +++ b/scripts/update-internal-links.ts @@ -0,0 +1,281 @@ +#!/usr/bin/env npx tsx + +/** + * Update internal links to use redirect destinations instead of old paths + * + * Usage: + * pnpm update-links [--dry-run] + * + * This script reads redirects from next.config.ts and updates any internal links + * in MDX/TSX files that point to redirected paths. + */ + +import { readFileSync, writeFileSync } from "node:fs"; +import fg from "fast-glob"; + +// Colors for terminal output +const colors = { + red: (s: string) => `\x1b[0;31m${s}\x1b[0m`, + green: (s: string) => `\x1b[0;32m${s}\x1b[0m`, + yellow: (s: string) => `\x1b[1;33m${s}\x1b[0m`, + blue: (s: string) => `\x1b[0;34m${s}\x1b[0m`, +}; + +// Parse command line arguments +const dryRun = process.argv.includes("--dry-run"); + +const CONFIG_FILE = "next.config.ts"; + +// Top-level regex patterns +const LOCALE_PREFIX_REGEX = /^\/:locale/; +const SPECIAL_REGEX_CHARS_REGEX = /[.*+?^${}()|[\]\\]/g; +const REDIRECT_REGEX = + /\{\s*source:\s*["']([^"']+)["']\s*,\s*destination:\s*["']([^"']+)["']/g; +const REVERSED_REDIRECT_REGEX = + /\{\s*destination:\s*["']([^"']+)["']\s*,\s*source:\s*["']([^"']+)["']/g; + +type Redirect = { + source: string; + destination: string; +}; + +/** + * Execute regex and collect all matches (avoids assignment in expression) + */ +function collectRegexMatches( + regex: RegExp, + content: string, + sourceIndex: number, + destIndex: number +): Array<{ source: string; destination: string }> { + const results: Array<{ source: string; destination: string }> = []; + regex.lastIndex = 0; + + let match = regex.exec(content); + while (match !== null) { + results.push({ + source: match[sourceIndex], + destination: match[destIndex], + }); + match = regex.exec(content); + } + + return results; +} + +/** + * Parse redirects from next.config.ts + */ +function parseRedirects(content: string): Redirect[] { + const results: Redirect[] = []; + + // Collect standard format: { source: "...", destination: "..." } + const standardMatches = collectRegexMatches(REDIRECT_REGEX, content, 1, 2); + for (const m of standardMatches) { + results.push(m); + } + + // Collect reversed format: { destination: "...", source: "..." } + const reversedMatches = collectRegexMatches( + REVERSED_REDIRECT_REGEX, + content, + 2, + 1 + ); + for (const m of reversedMatches) { + results.push(m); + } + + return results; +} + +/** + * Filter redirects to only those that can be auto-updated + */ +function getUpdatableRedirects(redirectList: Redirect[]): Redirect[] { + return redirectList.filter((r) => { + if (r.source.includes(":path*") || r.destination.includes(":path*")) { + return false; + } + + const sourceWithoutLocale = r.source.replace(LOCALE_PREFIX_REGEX, ""); + const destWithoutLocale = r.destination.replace(LOCALE_PREFIX_REGEX, ""); + + if (sourceWithoutLocale.includes(":") || destWithoutLocale.includes(":")) { + return false; + } + + if ( + r.destination.includes("REPLACE_WITH") || + r.destination.includes("TODO") + ) { + return false; + } + + return true; + }); +} + +/** + * Convert redirect to link patterns (without :locale prefix) + */ +function redirectToLinkPatterns(redirect: Redirect): { + oldPath: string; + newPath: string; +} { + return { + oldPath: redirect.source.replace(LOCALE_PREFIX_REGEX, ""), + newPath: redirect.destination.replace(LOCALE_PREFIX_REGEX, ""), + }; +} + +/** + * Escape special regex characters + */ +function escapeRegex(str: string): string { + return str.replace(SPECIAL_REGEX_CHARS_REGEX, "\\$&"); +} + +/** + * Update links in file content + */ +function updateLinksInContent( + content: string, + oldPath: string, + newPath: string +): string { + let updated = content; + + // Markdown links: [text](/old-path) -> [text](/new-path) + // Using replacer function to avoid special replacement pattern interpretation + // (e.g., $1, $2, $& in newPath would be incorrectly expanded if using string) + const markdownLinkRegex = new RegExp( + `(\\]\\()${escapeRegex(oldPath)}([)"#\\s])`, + "g" + ); + updated = updated.replace( + markdownLinkRegex, + (_, p1, p2) => `${p1}${newPath}${p2}` + ); + + // JSX href with double quotes: href="/old-path" + const jsxDoubleQuoteRegex = new RegExp( + `(href=")${escapeRegex(oldPath)}(["#])`, + "g" + ); + updated = updated.replace( + jsxDoubleQuoteRegex, + (_, p1, p2) => `${p1}${newPath}${p2}` + ); + + // JSX href with single quotes: href='/old-path' + const jsxSingleQuoteRegex = new RegExp( + `(href=')${escapeRegex(oldPath)}(['#])`, + "g" + ); + updated = updated.replace( + jsxSingleQuoteRegex, + (_, p1, p2) => `${p1}${newPath}${p2}` + ); + + // Paths in backticks (code blocks showing links) + const backtickRegex = new RegExp(`(\`)${escapeRegex(oldPath)}(\`|[#])`, "g"); + updated = updated.replace( + backtickRegex, + (_, p1, p2) => `${p1}${newPath}${p2}` + ); + + return updated; +} + +// ============================================================ +// Main script +// ============================================================ + +if (dryRun) { + console.log( + colors.blue("Running in dry-run mode - no files will be modified") + ); + console.log(""); +} + +console.log(colors.blue(`Parsing redirects from ${CONFIG_FILE}...`)); + +const configContent = readFileSync(CONFIG_FILE, "utf-8"); +const allRedirects = parseRedirects(configContent); +const redirects = getUpdatableRedirects(allRedirects); + +console.log( + `Found ${colors.green(String(redirects.length))} non-wildcard redirects to check` +); +console.log(""); + +if (redirects.length === 0) { + console.log(colors.green("No redirects to process.")); + process.exit(0); +} + +console.log(colors.blue("Scanning files for internal links to update...")); +console.log(""); + +// Find all MDX, MD, and TSX files in app directory +const files = fg.sync(["app/**/*.mdx", "app/**/*.md", "app/**/*.tsx"], { + ignore: ["**/node_modules/**"], +}); + +let updatedCount = 0; + +for (const file of files) { + const originalContent = readFileSync(file, "utf-8"); + let updatedContent = originalContent; + + for (const redirect of redirects) { + const { oldPath, newPath } = redirectToLinkPatterns(redirect); + + if (updatedContent.includes(oldPath)) { + updatedContent = updateLinksInContent(updatedContent, oldPath, newPath); + } + } + + if (updatedContent !== originalContent) { + if (dryRun) { + console.log(`${colors.yellow("Would update:")} ${file}`); + + const lines = originalContent.split("\n"); + const newLines = updatedContent.split("\n"); + for (let i = 0; i < lines.length; i += 1) { + if (lines[i] !== newLines[i]) { + console.log(colors.red(` - ${lines[i].trim()}`)); + console.log(colors.green(` + ${newLines[i].trim()}`)); + } + } + console.log(""); + } else { + writeFileSync(file, updatedContent); + console.log(`${colors.green("Updated:")} ${file}`); + } + updatedCount += 1; + } +} + +console.log(""); +console.log( + colors.blue("========================================================") +); + +if (dryRun) { + console.log( + colors.yellow(`Dry run complete: ${updatedCount} file(s) would be updated`) + ); + console.log("Run without --dry-run to apply changes."); +} else if (updatedCount > 0) { + console.log( + colors.green(`Updated ${updatedCount} file(s) with new link paths`) + ); +} else { + console.log(colors.green("All internal links are up to date!")); +} + +console.log( + colors.blue("========================================================") +);