Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
999a620
Fix npm version in gen tool docs
jottakka Feb 17, 2026
9aca853
fixing second bug ...
jottakka Feb 17, 2026
2fe71c9
fixign wrong flagsx
jottakka Feb 17, 2026
8349059
updatint worfklow for better feedback
jottakka Feb 17, 2026
3958c00
fixing matching checks errors
jottakka Feb 17, 2026
934b32a
trying source agnostic compare approach
jottakka Feb 17, 2026
6b29e11
fixing again the workflow...
jottakka Feb 17, 2026
89b29a4
adding faster workflow for testing
jottakka Feb 17, 2026
486fa1d
updating worflow again
jottakka Feb 17, 2026
462693f
updating workflow
jottakka Feb 17, 2026
6012b05
fixing some issues with ordering
jottakka Feb 17, 2026
9836564
adding required all metadate flag
jottakka Feb 18, 2026
d5ad146
[AUTO] Adding MCP Servers docs update (#784)
github-actions[bot] Feb 18, 2026
4a8d9bd
adding as cron job
jottakka Feb 18, 2026
97306d7
ignoring generate jsons from linting checks
jottakka Feb 18, 2026
bedf07a
updating checks
jottakka Feb 18, 2026
e5d1a27
fixing biome errors
jottakka Feb 18, 2026
e3f31c5
minor update in test
jottakka Feb 18, 2026
8dc2d5b
Merge branch 'main' into francisco/gendocsfixversion
jottakka Feb 18, 2026
3962ed2
Revert integrations folder changes
jottakka Feb 18, 2026
ae28f3a
Revert toolkit-docs-generator/data changes
jottakka Feb 18, 2026
d6122d2
removing complex time check
jottakka Feb 18, 2026
b7f9ab7
fixing tests
jottakka Feb 18, 2026
04f95c2
fix issue with matching again ...
jottakka Feb 18, 2026
fae185d
[AUTO] Adding MCP Servers docs update (#787)
github-actions[bot] Feb 18, 2026
79ca4ff
fixing mismatch in components
jottakka Feb 18, 2026
4b4521c
reverting pr changes
jottakka Feb 18, 2026
44108b6
Again ...
jottakka Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions .github/workflows/generate-toolkit-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
repository_dispatch:
types: [porter_deploy_succeeded]
workflow_dispatch:
# 11:00 UTC = 3 AM PST / 4 AM PDT — late enough that DST drift doesn't matter.
schedule:
- cron: "0 11 * * *"

permissions:
contents: write
Expand All @@ -27,8 +30,6 @@ jobs:

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
Expand All @@ -45,11 +46,14 @@ jobs:

- name: Generate toolkit docs
run: |
pnpm start generate \
pnpm dlx tsx src/cli/index.ts generate \
--all \
--skip-unchanged \
--engine-api-url "$ENGINE_API_URL" \
--engine-api-key "$ENGINE_API_KEY" \
--require-complete \
--verbose \
--api-source tool-metadata \
--tool-metadata-url "$ENGINE_API_URL" \
--tool-metadata-key "$ENGINE_API_KEY" \
--llm-provider openai \
--llm-model "$OPENAI_MODEL" \
--llm-api-key "$OPENAI_API_KEY" \
Expand All @@ -62,7 +66,7 @@ jobs:
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL || 'gpt-4o-mini' }}

- name: Sync toolkit sidebar navigation
run: pnpm dlx tsx toolkit-docs-generator/scripts/sync-toolkit-sidebar.ts --prune --verbose
run: pnpm dlx tsx toolkit-docs-generator/scripts/sync-toolkit-sidebar.ts --remove-empty-sections=false --verbose

- name: Check for changes
id: check-changes
Expand All @@ -76,10 +80,12 @@ jobs:
- name: Create pull request
if: steps.check-changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
env:
HUSKY: 0
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: update toolkit docs after Porter deploy"
title: "Update toolkit docs after Porter deploy"
commit-message: "[AUTO] Adding MCP Servers docs update"
title: "[AUTO] Adding MCP Servers docs update"
body: |
This PR was generated after a Porter deploy succeeded.

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ styles/write-good/

# Toolkit overview input files
toolkit-docs-generator/overview-input/
toolkit-docs-generator-verification/logs/

# Generated toolkit markdown (built at build time, not committed)
public/toolkit-markdown/
53 changes: 36 additions & 17 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ if git diff --cached --name-only | grep -q "next.config.ts"; then
fi

# --- Lint Staged (formatting) ---
pnpm dlx lint-staged
pnpm exec lint-staged

# --- Stash + Format ---
# Skip this block during merge/rebase: git stash --keep-index destroys
Expand All @@ -150,17 +150,43 @@ STAGED_HASH=$(git diff --cached | sha256sum | cut -d' ' -f1)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
PARTIALLY_STAGED=$(git diff --name-only)

# If a file is both staged and unstaged, stash/pop can produce conflicts.
# In that case rely on lint-staged only, which already ran above.
if [ -n "$PARTIALLY_STAGED" ] && [ -n "$STAGED_FILES" ]; then
for file in $PARTIALLY_STAGED; do
if [ -f "$file" ] && echo "$STAGED_FILES" | grep -qxF "$file"; then
echo "⏭️ Skipping stash+format (partially staged files detected)"
exit 0
fi
done
fi

# Stash unstaged changes to preserve working directory
# --keep-index keeps staged changes in working tree
git stash push --quiet --keep-index --message "pre-commit-stash" || true
STASHED=$?
STASH_CREATED=false
STASH_MESSAGE="pre-commit-stash-$$-$(date +%s)"
if ! git diff --quiet; then
git stash push --quiet --keep-index --message "$STASH_MESSAGE"
TOP_STASH_SUBJECT="$(git stash list -1 --format='%s' || true)"
case "$TOP_STASH_SUBJECT" in
*"$STASH_MESSAGE")
STASH_CREATED=true
;;
esac
fi

# Run formatter on the staged files
pnpm dlx ultracite fix
FORMAT_EXIT_CODE=$?
if [ -n "$STAGED_FILES" ]; then
for file in $STAGED_FILES; do
if [ -f "$file" ]; then
pnpm exec ultracite fix "$file"
fi
done
fi
FORMAT_EXIT_CODE=0

# Restore working directory state
if [ $STASHED -eq 0 ]; then
if [ "$STASH_CREATED" = true ]; then
# Re-stage the formatted files
if [ -n "$STAGED_FILES" ]; then
echo "$STAGED_FILES" | while IFS= read -r file; do
Expand All @@ -171,17 +197,10 @@ if [ $STASHED -eq 0 ]; then
fi

# Restore unstaged changes
git stash pop --quiet || true

# Restore partial staging if files were partially staged
if [ -n "$PARTIALLY_STAGED" ]; then
for file in $PARTIALLY_STAGED; do
if [ -f "$file" ] && echo "$STAGED_FILES" | grep -q "^$file$"; then
# File was partially staged - need to unstage the unstaged parts
git restore --staged "$file" 2>/dev/null || true
git add -p "$file" < /dev/null 2>/dev/null || git add "$file"
fi
done
if ! git stash pop --quiet; then
echo "❌ Failed to restore stashed changes during pre-commit."
echo " Resolve conflicts, then re-stage files and commit again."
exit 1
fi
else
# No stash was created, just re-add the formatted files
Expand Down
18 changes: 9 additions & 9 deletions app/_components/toolkit-docs/components/toolkit-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,15 @@ export function ToolkitPage({ data }: ToolkitPageProps) {
<h1 className="mb-6 font-bold text-4xl text-foreground tracking-tight">
{data.label}
</h1>
<ToolkitHeader
auth={data.auth}
description={data.description}
id={data.id}
label={data.label}
metadata={metadata}
toolStats={toolStats}
version={data.version}
/>
<DocumentationChunkRenderer
chunks={documentationChunks}
location="header"
Expand All @@ -593,15 +602,6 @@ export function ToolkitPage({ data }: ToolkitPageProps) {
location="description"
position="before"
/>
<ToolkitHeader
auth={data.auth}
description={data.description}
id={data.id}
label={data.label}
metadata={metadata}
toolStats={toolStats}
version={data.version}
/>
<DocumentationChunkRenderer
chunks={documentationChunks}
location="description"
Expand Down
80 changes: 57 additions & 23 deletions app/_lib/toolkit-static-params.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { readdir, readFile } from "node:fs/promises";
import { createRequire } from "node:module";
import { join } from "node:path";
import { TOOLKITS as DESIGN_SYSTEM_TOOLKITS } from "@arcadeai/design-system";
import { pathToFileURL } from "node:url";
import { readToolkitData, readToolkitIndex } from "./toolkit-data";
import { getToolkitSlug, normalizeToolkitId } from "./toolkit-slug";

Expand Down Expand Up @@ -31,6 +32,45 @@ export type ToolkitRouteEntry = {
category: IntegrationCategory;
};

const require = createRequire(import.meta.url);
let cachedDesignSystemToolkits: ToolkitCatalogEntry[] | null = null;

const isToolkitCatalogEntry = (
value: unknown
): value is ToolkitCatalogEntry => {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
return false;
}
const entry = value as Record<string, unknown>;
return typeof entry.id === "string";
};

const loadDesignSystemToolkits = async (): Promise<ToolkitCatalogEntry[]> => {
if (cachedDesignSystemToolkits) {
return cachedDesignSystemToolkits;
}

try {
const designSystemEntry = require.resolve("@arcadeai/design-system");
const designSystem = (await import(
pathToFileURL(designSystemEntry).href
)) as {
TOOLKITS?: unknown;
};
const toolkits = Array.isArray(designSystem.TOOLKITS)
? designSystem.TOOLKITS
: [];

cachedDesignSystemToolkits = toolkits.flatMap((toolkit) =>
isToolkitCatalogEntry(toolkit) ? [toolkit] : []
);
} catch {
cachedDesignSystemToolkits = [];
}

return cachedDesignSystemToolkits;
};

function normalizeCategory(
value: string | null | undefined
): IntegrationCategory {
Expand Down Expand Up @@ -98,42 +138,35 @@ const listToolkitRoutesFromDataDir = async (options?: {
return [...unique.values()];
};

const shouldReadToolkitData = (entry?: ToolkitCatalogEntry): boolean => {
if (!entry) {
return true;
}

// Read toolkit data if we need a docsLink or hidden flag.
return (
typeof entry.docsLink === "undefined" ||
typeof entry.isHidden === "undefined"
);
};

const resolveToolkitRoute = async (
toolkit: { id: string; category?: string },
catalogByNormalizedId: Map<string, ToolkitCatalogEntry>,
dataDir?: string
): Promise<ToolkitRouteEntry | null> => {
const normalizedId = normalizeToolkitId(toolkit.id);
const catalogEntry = catalogByNormalizedId.get(normalizedId);
const data = shouldReadToolkitData(catalogEntry)
? await readToolkitData(toolkit.id, dataDir ? { dataDir } : undefined)
: null;
// Always read the JSON file — it is the source of truth for category, docsLink,
// and isHidden. The design system catalog is only used as a fallback for
// visibility when the JSON file is absent.
const data = await readToolkitData(
toolkit.id,
dataDir ? { dataDir } : undefined
);

const isHidden = catalogEntry?.isHidden ?? data?.metadata?.isHidden ?? false;
const isHidden = data?.metadata?.isHidden ?? catalogEntry?.isHidden ?? false;
if (isHidden) {
return null;
}

const slug = getToolkitSlug({
id: catalogEntry?.id ?? toolkit.id,
docsLink: catalogEntry?.docsLink ?? data?.metadata?.docsLink,
id: toolkit.id,
docsLink: data?.metadata?.docsLink ?? catalogEntry?.docsLink,
});
// Prefer the full JSON data file's category over the index.json summary,
// because the index may have stale/incorrect categories.
// JSON file is the source of truth for category. The generator is responsible
// for writing the correct value; the design system catalog and index.json are
// only used as a last resort when the JSON is missing.
const category = normalizeCategory(
catalogEntry?.category ?? data?.metadata?.category ?? toolkit.category
data?.metadata?.category ?? catalogEntry?.category ?? toolkit.category
);
return { toolkitId: slug, category };
};
Expand All @@ -150,7 +183,8 @@ export async function listToolkitRoutes(options?: {
return await listToolkitRoutesFromDataDir(options);
}

const toolkitsCatalog = options?.toolkitsCatalog ?? DESIGN_SYSTEM_TOOLKITS;
const toolkitsCatalog =
options?.toolkitsCatalog ?? (await loadDesignSystemToolkits());
const catalogByNormalizedId = new Map(
toolkitsCatalog.map((toolkit) => [normalizeToolkitId(toolkit.id), toolkit])
);
Expand Down
2 changes: 2 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
"!build",
"!node_modules",
"!public",
"!toolkit-docs-generator/data/toolkits",
"!toolkit-docs-generator/data/toolkits",
"!scripts",
"!agents",
"!.vscode",
Expand Down
30 changes: 30 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { createRequire } from "node:module";
import type { NextConfig } from "next";
import nextra from "nextra";
import { withLlmsTxt } from "./lib/next-plugin-llmstxt";
import { remarkGlossary } from "./lib/remark-glossary";

const require = createRequire(import.meta.url);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure why we are adding all of these.

const designSystemMainPath = require.resolve("@arcadeai/design-system");
const designSystemUtilsPath = require.resolve(
"@arcadeai/design-system/lib/utils"
);
const designSystemVariablesPath = require.resolve(
"@arcadeai/design-system/assets/variables.css"
);
const designSystemArcadeLogoPath = require.resolve(
"@arcadeai/design-system/assets/images/arcade-logo"
);

// Set up Nextra with its configuration
const withNextra = nextra({
defaultShowCopyCode: true,
Expand Down Expand Up @@ -844,6 +857,23 @@ const nextConfig: NextConfig = withLlmsTxt({
},
];
},
webpack: (config) => {
config.resolve ??= {};
config.resolve.alias ??= {};

if (typeof config.resolve.alias === "object") {
config.resolve.alias["@arcadeai/design-system$"] = designSystemMainPath;
config.resolve.alias["@arcadeai/design-system/lib/utils"] =
designSystemUtilsPath;
config.resolve.alias["@arcadeai/design-system/assets/variables.css"] =
designSystemVariablesPath;
config.resolve.alias[
"@arcadeai/design-system/assets/images/arcade-logo"
] = designSystemArcadeLogoPath;
}

return config;
},
headers: async () => [
{
source: "/(.*)",
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"dev": "next dev --webpack",
"build": "pnpm run toolkit-markdown && next build --webpack && pnpm run custompagefind",
"start": "next start",
"lint": "pnpm dlx ultracite check",
"format": "pnpm dlx ultracite fix",
"lint": "pnpm exec ultracite check",
"format": "pnpm exec ultracite fix",
"prepare": "husky install",
"toolkit-markdown": "pnpm dlx tsx toolkit-docs-generator/scripts/generate-toolkit-markdown.ts",
"postbuild": "if [ \"$SKIP_POSTBUILD\" != \"true\" ]; then pnpm run generate:markdown && pnpm run custompagefind; fi",
Expand Down Expand Up @@ -42,7 +42,7 @@
},
"homepage": "https://arcade.dev/",
"dependencies": {
"@arcadeai/design-system": "^3.26.1",
"@arcadeai/design-system": "^3.27.7",
"@mdx-js/mdx": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@next/third-parties": "16.0.1",
Expand Down Expand Up @@ -112,7 +112,7 @@
},
"lint-staged": {
"!(examples)/**/*.{js,jsx,ts,tsx,json,jsonc,css,scss,md,mdx}": [
"pnpm dlx ultracite fix "
"pnpm exec ultracite fix"
]
},
"packageManager": "pnpm@10.11.0",
Expand Down
Loading