#
tokens: 33154/50000 8/90 files (page 2/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 2. Use http://codebase.md/alfonsograziano/node-code-sandbox-mcp?page={x} to view the full context.

# Directory Structure

```
├── .commitlintrc
├── .env.sample
├── .github
│   └── workflows
│       ├── docker.yaml
│       ├── publish-node-chartjs-canvas.yaml
│       ├── publish-on-npm.yaml
│       └── test.yaml
├── .gitignore
├── .husky
│   ├── commit-msg
│   └── pre-commit
├── .lintstagedrc
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── .vscode
│   ├── extensions.json
│   ├── mcp.json
│   └── settings.json
├── assets
│   └── images
│       └── website_homepage.png
├── Dockerfile
├── eslint.config.js
├── evals
│   ├── auditClient.ts
│   ├── basicEvals.json
│   ├── evals.json
│   └── index.ts
├── examples
│   ├── docker.js
│   ├── ephemeral.js
│   ├── ephemeralWithDependencies.js
│   ├── ephemeralWithFiles.js
│   ├── playwright.js
│   └── simpleSandbox.js
├── images
│   └── node-chartjs-canvas
│       └── Dockerfile
├── NODE_GUIDELINES.md
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── config.ts
│   ├── containerUtils.ts
│   ├── dockerUtils.ts
│   ├── linterUtils.ts
│   ├── logger.ts
│   ├── runUtils.ts
│   ├── server.ts
│   ├── snapshotUtils.ts
│   ├── tools
│   │   ├── exec.ts
│   │   ├── getDependencyTypes.ts
│   │   ├── initialize.ts
│   │   ├── runJs.ts
│   │   ├── runJsEphemeral.ts
│   │   ├── searchNpmPackages.ts
│   │   └── stop.ts
│   ├── types.ts
│   └── utils.ts
├── test
│   ├── execInSandbox.test.ts
│   ├── getDependencyTypes.test.ts
│   ├── initialize.test.ts
│   ├── initializeSandbox.test.ts
│   ├── runJs-cache.test.ts
│   ├── runJs.test.ts
│   ├── runJsEphemeral.test.ts
│   ├── runJsListenOnPort.test.ts
│   ├── runMCPClient.test.ts
│   ├── sandbox.test.ts
│   ├── searchNpmPackages.test.ts
│   ├── snapshotUtils.test.ts
│   ├── stopSandbox.test.ts
│   ├── unit
│   │   └── linterUtils.test.ts
│   ├── utils.test.ts
│   └── utils.ts
├── tsconfig.build.json
├── tsconfig.json
├── USE_CASE.md
├── vitest.config.ts
└── website
    ├── .gitignore
    ├── index.html
    ├── LICENSE.md
    ├── package-lock.json
    ├── package.json
    ├── postcss.config.js
    ├── public
    │   └── images
    │       ├── client.png
    │       ├── graph-gpt_markdown.png
    │       ├── graph-gpt_reference_section.png
    │       ├── graph-gpt.png
    │       ├── js_ai.jpeg
    │       └── simple_agent.jpeg
    ├── src
    │   ├── App.tsx
    │   ├── Components
    │   │   ├── Footer.tsx
    │   │   ├── GettingStarted.tsx
    │   │   └── Header.tsx
    │   ├── index.css
    │   ├── main.tsx
    │   ├── pages
    │   │   ├── GraphGPT.tsx
    │   │   ├── Home.tsx
    │   │   ├── NodeMCPServer.tsx
    │   │   └── TinyAgent.tsx
    │   ├── polyfills.ts
    │   ├── useCases.ts
    │   └── vite-env.d.ts
    ├── tailwind.config.js
    ├── tsconfig.json
    ├── tsconfig.node.json
    ├── vite-env.d.ts
    └── vite.config.ts
```

# Files

--------------------------------------------------------------------------------
/test/unit/linterUtils.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { lintAndRefactorCode } from '../../src/linterUtils.ts';
import { ESLint } from 'eslint';

vi.mock('eslint', () => {
  const ESLint = vi.fn();
  ESLint.prototype.lintText = vi.fn();
  return { ESLint };
});

// Get a typed reference to the mocked class and its method
const mockedESLint = vi.mocked(ESLint);
const mockedLintText = vi.mocked(ESLint.prototype.lintText);

describe('lintAndRefactorCode', () => {
  beforeEach(() => {
    // Clear mock history before each test
    mockedESLint.mockClear();
    mockedLintText.mockClear();
  });

  it('should return original code and no errors for clean code', async () => {
    const code = `const x = 1;`;
    mockedLintText.mockResolvedValue([
      {
        messages: [],
        output: undefined, // No fixes, so output is undefined
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(code);

    expect(fixedCode).toBe(code);
    expect(errorReport).toBeNull();
    expect(mockedLintText).toHaveBeenCalledWith(code);
  });

  it('should return fixed code and no errors for auto-fixable issues', async () => {
    const originalCode = `var x=1`;
    const expectedFixedCode = `const x = 1;`;
    mockedLintText.mockResolvedValue([
      {
        messages: [], // Assuming no remaining errors after fix
        output: expectedFixedCode,
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(originalCode);

    expect(fixedCode).toBe(expectedFixedCode);
    expect(errorReport).toBeNull();
    expect(mockedLintText).toHaveBeenCalledWith(originalCode);
  });

  it('should return an error report for non-fixable errors', async () => {
    const codeWithErrors = `const x = y;`; // ReferenceError
    const errorMessages = [
      {
        severity: 2 as const,
        line: 1,
        column: 11,
        message: "'y' is not defined.",
        ruleId: 'no-undef',
      },
    ];
    mockedLintText.mockResolvedValue([
      {
        messages: errorMessages,
        output: undefined, // No fixes applied
        errorCount: 1,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } =
      await lintAndRefactorCode(codeWithErrors);

    expect(fixedCode).toBe(codeWithErrors);
    expect(errorReport).not.toBeNull();
    expect(errorReport).toBe("L1:11: 'y' is not defined. (no-undef)");
    expect(mockedLintText).toHaveBeenCalledWith(codeWithErrors);
  });

  it('should return fixed code and an error report for mixed issues', async () => {
    const originalCode = `var x=y`; // fixable `var` and `spacing`, unfixable `y`
    const partiallyFixedCode = `const x = y;`;
    const errorMessages = [
      {
        severity: 2 as const,
        line: 1,
        column: 9,
        message: "'y' is not defined.",
        ruleId: 'no-undef',
      },
    ];
    mockedLintText.mockResolvedValue([
      {
        messages: errorMessages,
        output: partiallyFixedCode,
        errorCount: 1,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(originalCode);

    expect(fixedCode).toBe(partiallyFixedCode);
    expect(errorReport).not.toBeNull();
    expect(errorReport).toBe("L1:9: 'y' is not defined. (no-undef)");
    expect(mockedLintText).toHaveBeenCalledWith(originalCode);
  });

  it('should auto-fix `let` to `const` for non-reassigned variables', async () => {
    const originalCode = `let x = 5; console.log(x);`;
    const expectedFixedCode = `const x = 5; console.log(x);`;
    mockedLintText.mockResolvedValue([
      {
        messages: [],
        output: expectedFixedCode,
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(originalCode);

    expect(fixedCode).toBe(expectedFixedCode);
    expect(errorReport).toBeNull();
    expect(mockedLintText).toHaveBeenCalledWith(originalCode);
  });

  it('should auto-fix to use object shorthand', async () => {
    const originalCode = `const name = 'test'; const obj = { name: name };`;
    const expectedFixedCode = `const name = 'test'; const obj = { name };`;
    mockedLintText.mockResolvedValue([
      {
        messages: [],
        output: expectedFixedCode,
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(originalCode);

    expect(fixedCode).toBe(expectedFixedCode);
    expect(errorReport).toBeNull();
    expect(mockedLintText).toHaveBeenCalledWith(originalCode);
  });

  it('should auto-fix to use template literals', async () => {
    const originalCode = `const name = 'world'; const greeting = 'Hello ' + name;`;
    const expectedFixedCode =
      "const name = 'world'; const greeting = `Hello ${name}`;";
    mockedLintText.mockResolvedValue([
      {
        messages: [],
        output: expectedFixedCode,
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } = await lintAndRefactorCode(originalCode);

    expect(fixedCode).toBe(expectedFixedCode);
    expect(errorReport).toBeNull();
    expect(mockedLintText).toHaveBeenCalledWith(originalCode);
  });

  it('should report an error for using == instead of ===', async () => {
    const codeWithErrors = `if (x == 1) {}`;
    const errorMessages = [
      {
        severity: 2 as const,
        line: 1,
        column: 5,
        message: "Expected '===' and instead saw '=='.",
        ruleId: 'eqeqeq',
      },
    ];
    mockedLintText.mockResolvedValue([
      {
        messages: errorMessages,
        output: codeWithErrors, // No fix applied
        errorCount: 1,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        usedDeprecatedRules: [],
        filePath: '',
        suppressedMessages: [],
        fatalErrorCount: 0,
      },
    ]);

    const { fixedCode, errorReport } =
      await lintAndRefactorCode(codeWithErrors);

    expect(fixedCode).toBe(codeWithErrors);
    expect(errorReport).not.toBeNull();
    expect(errorReport).toBe(
      "L1:5: Expected '===' and instead saw '=='. (eqeqeq)"
    );
    expect(mockedLintText).toHaveBeenCalledWith(codeWithErrors);
  });
});

```

--------------------------------------------------------------------------------
/test/runJs.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import * as tmp from 'tmp';
import { z } from 'zod';
import runJs, { argSchema } from '../src/tools/runJs.ts';
import initializeSandbox from '../src/tools/initialize.ts';
import stopSandbox from '../src/tools/stop.ts';
import type { McpContentText } from '../src/types.ts';

describe('argSchema', () => {
  it('should accept code and container_id and set defaults', () => {
    const parsed = z.object(argSchema).parse({
      code: "console.log('hi');",
      container_id: 'dummy',
    });
    expect(parsed.container_id).toBe('dummy');
    expect(parsed.dependencies).toEqual([]);
    expect(parsed.code).toBe("console.log('hi');");
  });
});

describe('runJs basic execution', () => {
  let containerId: string;
  let tmpDir: tmp.DirResult;

  beforeEach(async () => {
    tmpDir = tmp.dirSync({ unsafeCleanup: true });
    process.env.FILES_DIR = tmpDir.name;

    const result = await initializeSandbox({});
    if (result.content[0].type === 'text') {
      containerId = result.content[0].text;
    } else {
      throw new Error("Expected the first content item to be of type 'text'");
    }
  });

  afterEach(() => {
    tmpDir.removeCallback();
    delete process.env.FILES_DIR;

    if (containerId) {
      stopSandbox({ container_id: containerId });
    }
  });

  it('should run simple JS in container', async () => {
    const result = await runJs({
      container_id: containerId,
      code: `console.log("Hello from runJs")`,
    });

    expect(result).toBeDefined();
    expect(result.content.length).toBeGreaterThan(0);

    const output = result.content[0];
    expect(output.type).toBe('text');
    if (output.type === 'text') {
      expect(output.text).toContain('Hello from runJs');
    }
  });

  it('should generate telemetry', async () => {
    const result = await runJs({
      container_id: containerId,
      code: "console.log('Hello telemetry!');",
    });

    const telemetryItem = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Telemetry:')
    );

    expect(telemetryItem).toBeDefined();
    if (telemetryItem?.type === 'text') {
      const telemetry = JSON.parse(
        telemetryItem.text.replace('Telemetry:\n', '')
      );

      expect(telemetry).toHaveProperty('installTimeMs');
      expect(typeof telemetry.installTimeMs).toBe('number');
      expect(telemetry).toHaveProperty('runTimeMs');
      expect(typeof telemetry.runTimeMs).toBe('number');
      expect(telemetry).toHaveProperty('installOutput');
      expect(typeof telemetry.installOutput).toBe('string');
    } else {
      throw new Error("Expected telemetry item to be of type 'text'");
    }
  });
  it('should write and retrieve a file', async () => {
    const result = await runJs({
      container_id: containerId,
      code: `
        import fs from 'fs/promises';
        await fs.writeFile('./files/hello test.txt', 'Hello world!');
        console.log('Saved hello test.txt');
      `,
    });

    // Assert stdout contains the save confirmation
    const stdoutEntry = result.content.find(
      (c) => c.type === 'text' && c.text.includes('Saved hello test.txt')
    );
    expect(stdoutEntry).toBeDefined();

    // Assert the change list mentions the created file
    const changeList = result.content.find(
      (c) =>
        c.type === 'text' &&
        c.text.includes('List of changed files') &&
        c.text.includes('- hello test.txt was created')
    );
    expect(changeList).toBeDefined();

    // Assert the resource entry has the correct text and URI
    const resourceEntry = result.content.find(
      (c) =>
        c.type === 'resource' &&
        'text' in c.resource &&
        c.resource.text === 'hello test.txt'
    );
    expect(resourceEntry).toBeDefined();
    if (resourceEntry?.type === 'resource') {
      // The URI should include the filename (URL-encoded)
      expect(resourceEntry.resource.uri).toContain('hello%20test.txt');
    }
  });

  it('should skip npm install if no dependencies are provided', async () => {
    const result = await runJs({
      container_id: containerId,
      code: "console.log('No deps');",
      dependencies: [],
    });

    const telemetryItem = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Telemetry:')
    );

    expect(telemetryItem).toBeDefined();
    if (telemetryItem?.type === 'text') {
      const telemetry = JSON.parse(
        telemetryItem.text.replace('Telemetry:\n', '')
      );

      expect(telemetry.installTimeMs).toBe(0);
      expect(telemetry.installOutput).toBe(
        'Skipped npm install (no dependencies)'
      );
    }
  });

  it('should install lodash and use it', async () => {
    const result = await runJs({
      container_id: containerId,
      code: `
        import _ from 'lodash';
        console.log(_.join(['Hello', 'lodash'], ' '));
      `,
      dependencies: [{ name: 'lodash', version: '^4.17.21' }],
    });

    const stdout = result.content.find((c) => c.type === 'text');
    expect(stdout).toBeDefined();
    if (stdout?.type === 'text') {
      expect(stdout.text).toContain('Hello lodash');
    }
  });

  it('should hang indefinitely until a timeout error gets triggered', async () => {
    //Simulating a 10 seconds timeout
    process.env.RUN_SCRIPT_TIMEOUT = '10000';
    const result = await runJs({
      container_id: containerId,
      code: `
        (async () => {
          console.log("🕒 Hanging for 20 seconds…");
          await new Promise((resolve) => setTimeout(resolve, 20_000));
          console.log("✅ Done waiting 20 seconds, exiting now.");
        })();
      `,
    });

    //Cleanup
    delete process.env.RUN_SCRIPT_TIMEOUT;

    const execError = result.content.find(
      (item) =>
        item.type === 'text' && item.text.startsWith('Error during execution:')
    );
    expect(execError).toBeDefined();
    expect((execError as McpContentText).text).toContain('ETIMEDOUT');

    const telemetryText = result.content.find(
      (item) => item.type === 'text' && item.text.startsWith('Telemetry:')
    );
    expect(telemetryText).toBeDefined();
  }, 20_000);

  it('should report execution error for runtime exceptions', async () => {
    const result = await runJs({
      container_id: containerId,
      code: `throw new Error('boom');`,
    });

    expect(result).toBeDefined();
    expect(result.content).toBeDefined();

    const execError = result.content.find(
      (item) =>
        item.type === 'text' && item.text.startsWith('Error during execution:')
    );
    expect(execError).toBeDefined();
    expect((execError as McpContentText).text).toContain('Error: boom');

    const telemetryText = result.content.find(
      (item) => item.type === 'text' && item.text.startsWith('Telemetry:')
    );
    expect(telemetryText).toBeDefined();
  });

  it('should auto-fix linting issues and run the corrected code', async () => {
    const result = await runJs({
      container_id: containerId,
      // This code has fixable issues: `var` instead of `const`, and extra spacing.
      code: `var msg = "hello auto-fixed world"  ; console.log(msg)`,
    });

    // 1. Check that no linting report was returned, as it should be auto-fixed.
    const lintReport = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Linting issues found')
    );
    expect(lintReport).toBeUndefined();

    // 2. Check that the execution was successful and the output is correct.
    const execOutput = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Node.js process output:')
    );
    expect(execOutput).toBeDefined();
    if (execOutput?.type === 'text') {
      expect(execOutput.text).toContain('hello auto-fixed world');
    }

    // 3. Check that there was no execution error.
    const execError = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Error during execution:')
    );
    expect(execError).toBeUndefined();
  });

  it('should report unfixable linting issues and the subsequent execution error', async () => {
    const result = await runJs({
      container_id: containerId,
      // This code has an unfixable issue: using an undefined variable.
      code: `console.log(someUndefinedVariable);`,
    });

    expect(result).toBeDefined();

    // 1. Check that a linting report was returned.
    const lintReport = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Linting issues found')
    );
    expect(lintReport).toBeDefined();
    if (lintReport?.type === 'text') {
      expect(lintReport.text).toContain(
        "'someUndefinedVariable' is not defined."
      );
      expect(lintReport.text).toContain('(no-undef)');
    }

    // 2. Check that the execution also failed and was reported.
    const execError = result.content.find(
      (c) => c.type === 'text' && c.text.startsWith('Error during execution:')
    );
    expect(execError).toBeDefined();
    if (execError?.type === 'text') {
      expect(execError.text).toContain(
        'ReferenceError: someUndefinedVariable is not defined'
      );
    }
  });
}, 10_000);

describe('Command injection prevention', () => {
  beforeEach(() => {
    vi.doMock('node:child_process', () => ({
      execFileSync: vi.fn(() => Buffer.from('')),
      execFile: vi.fn(() => Buffer.from('')),
    }));
  });

  afterEach(() => {
    vi.resetModules();
    vi.resetAllMocks();
    vi.restoreAllMocks();
  });

  const dangerousIds = [
    '$(touch /tmp/pwned)',
    '`touch /tmp/pwned`',
    'bad;id',
    'js-sbx-123 && rm -rf /',
    'js-sbx-123 | echo hacked',
    'js-sbx-123 > /tmp/pwned',
    'js-sbx-123 $(id)',
    'js-sbx-123; echo pwned',
    'js-sbx-123`echo pwned`',
    'js-sbx-123/../../etc/passwd',
    'js-sbx-123\nrm -rf /',
    '',
    ' ',
    'js-sbx-123$',
    'js-sbx-123#',
  ];

  dangerousIds.forEach((payload) => {
    it(`should reject dangerous container_id: "${payload}"`, async () => {
      const { default: runJs } = await import('../src/tools/runJs.ts');
      const childProcess = await import('node:child_process');
      const result = await runJs({
        container_id: payload,
        code: 'console.log("test")',
      });
      expect(result).toEqual({
        content: [
          {
            type: 'text',
            text: 'Invalid container ID',
          },
        ],
      });
      const execFileSyncCall = vi.mocked(childProcess.execFileSync).mock.calls;
      expect(execFileSyncCall.length).toBe(0);
    });
  });
});

```

--------------------------------------------------------------------------------
/website/src/pages/NodeMCPServer.tsx:
--------------------------------------------------------------------------------

```typescript
import React, { useEffect, useState } from 'react';
import {
  X,
  Terminal,
  ShieldCheck,
  Cpu,
  Package,
  Code,
  Settings,
  Server,
  Star,
} from 'lucide-react';

import { UseCase, useCases } from '../useCases';
import GettingStarted from '../Components/GettingStarted';
import Footer from '../Components/Footer';
import Header from '../Components/Header';

interface Feature {
  title: string;
  description: string;
  icon: React.ElementType;
}

// Extract unique categories
const allCategories: string[] = [
  ...new Set(useCases.flatMap((u) => u.category)),
].sort();

const features: Feature[] = [
  {
    title: 'Ephemeral Containers',
    description:
      'Run JavaScript in isolated Docker containers that clean up automatically after execution.',
    icon: Terminal,
  },
  {
    title: 'Secure Execution',
    description:
      'Sandboxed execution with CPU/memory limits and safe, controlled environments.',
    icon: ShieldCheck,
  },
  {
    title: 'Detached Mode',
    description:
      'Keep containers alive after execution to host servers or persistent processes.',
    icon: Cpu,
  },
  {
    title: 'Optimized Docker Images',
    description:
      'Use prebuilt Docker images with popular dependencies already installed—perfect for advanced use cases like Playwright, Chart.js, and more.',
    icon: Package,
  },
  {
    title: 'NPM Dependencies',
    description:
      'Install dependencies on-the-fly per job using package name and version.',
    icon: Settings,
  },
  {
    title: 'Multi-Tool Support',
    description:
      'Use ephemeral runs or long-lived sandbox sessions, depending on your use case.',
    icon: Server,
  },
];

const App: React.FC = () => {
  const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
  const [modalOpen, setModalOpen] = useState<boolean>(false);
  const [selectedCase, setSelectedCase] = useState<UseCase | null>(null);

  const toggleCategory = (cat: string) => {
    setSelectedCategories((prev) =>
      prev.includes(cat) ? prev.filter((c) => c !== cat) : [...prev, cat]
    );
  };

  const openModal = (useCase: UseCase) => {
    setSelectedCase(useCase);
    setModalOpen(true);
  };

  const closeModal = () => {
    setModalOpen(false);
    setSelectedCase(null);
  };

  useEffect(() => {
    if (modalOpen) {
      document.body.classList.add('overflow-hidden');
    } else {
      document.body.classList.remove('overflow-hidden');
    }

    return () => {
      document.body.classList.remove('overflow-hidden');
    };
  }, [modalOpen]);

  const filteredCases =
    selectedCategories.length === 0
      ? useCases
      : useCases.filter((u) =>
          u.category.some((c) => selectedCategories.includes(c))
        );

  const gridBg: React.CSSProperties = {
    backgroundImage:
      'linear-gradient(to right, rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.03) 1px, transparent 1px)',
    backgroundSize: '20px 20px',
  };

  return (
    <div style={gridBg} className="min-h-screen bg-gray-50 text-gray-900">
      {/* Header */}
      <Header />

      {/* Hero Section */}
      <header className="max-w-6xl mx-auto text-center py-16">
        <h1 className="text-5xl font-extrabold mb-4">
          🐢🚀 Node.js Sandbox MCP Server
        </h1>
        {/* Compact MCP Info Banner */}
        <div className="max-w-3xl mx-auto mb-8 px-4 py-3 bg-green-50 border border-green-200 text-sm rounded-lg flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 text-center sm:text-left">
          <div className="text-gray-800">
            🧠 MCP is a protocol that lets AI models access tools and data
            through a standardized interface.
          </div>
          <a
            href="https://modelcontextprotocol.io/"
            target="_blank"
            rel="noopener noreferrer"
            className="text-green-700 font-medium hover:underline"
          >
            Learn more →
          </a>
        </div>

        <p className="text-lg text-gray-700 mb-8">
          Run JavaScript in secure, disposable Docker containers via the Model
          Context Protocol (MCP). Automatic dependency installation included.
        </p>

        <div className="flex flex-col sm:flex-row justify-center gap-4 px-4 sm:px-0">
          <a
            href="#use-cases"
            className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition text-center"
          >
            Explore Use Cases
          </a>
          <a
            href="https://github.com/alfonsograziano/node-code-sandbox-mcp"
            target="_blank"
            rel="noopener noreferrer"
            className="flex items-center justify-center gap-2 px-6 py-3 bg-white border border-gray-300 text-gray-800 rounded-lg hover:bg-gray-100 transition"
          >
            <Star size={16} className="text-yellow-500" fill="yellow" /> Star on
            GitHub
          </a>
          <div className="relative">
            <a
              href="https://hub.docker.com/r/mcp/node-code-sandbox"
              target="_blank"
              rel="noopener noreferrer"
              className="flex items-center justify-center gap-2 px-6 py-3 bg-white border border-gray-300 text-gray-800 rounded-lg hover:bg-gray-100 transition"
            >
              <Package size={16} className="text-blue-500" /> Docker Hub
            </a>
            <div className="absolute -top-2 -right-2 bg-green-500 text-white text-xs font-bold px-2 py-1 rounded-full shadow-lg">
              10K+
            </div>
          </div>
        </div>
      </header>

      {/* Features */}
      <section id="features" className="max-w-6xl mx-auto">
        <h2 className="text-3xl font-bold text-center mb-8">Core Features</h2>
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
          {features.map(({ title, description, icon: Icon }, i) => (
            <div
              key={i}
              className="bg-white bg-opacity-80 p-6 rounded-xl shadow-md"
            >
              <Icon width={32} height={32} className="text-green-600 mb-4" />
              <h3 className="text-xl font-semibold mb-2">{title}</h3>
              <p className="text-gray-700">{description}</p>
            </div>
          ))}
        </div>
      </section>

      {/* Getting Started Section */}
      <GettingStarted />

      {/* Contribute Section */}
      <section id="contribute" className="max-w-4xl mx-auto my-10">
        <div className="bg-green-50 border border-green-200 p-6 rounded-xl shadow-md">
          <h2 className="text-2xl font-bold mb-2">
            🤝 Want to contribute to Node.js + AI?
          </h2>
          <p className="text-gray-800 mb-4">
            Brilliant! If you want to help, I’m opening a few issues on my new
            MCP server project. Since the project is still in its early stages,
            it’s the <strong>perfect time to jump in</strong> and become a core
            collaborator. 🚀
          </p>
          <p className="text-gray-800 mb-4">
            If you're excited about bringing <strong>Node.js</strong> into the
            world of <strong>AI applications</strong>, leave a comment or DM me,
            I'd love to have a chat!
          </p>
          <a
            href="https://github.com/alfonsograziano/node-code-sandbox-mcp/issues"
            target="_blank"
            rel="noopener noreferrer"
            className="inline-block px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition"
          >
            View Open Issues →
          </a>
        </div>
      </section>

      {/* Use Cases Grid */}
      <section id="use-cases" className="max-w-6xl mx-auto py-8">
        <h2 className="text-3xl font-bold text-center mb-8">Use Cases</h2>
        <p className="text-center text-gray-600 max-w-3xl mx-auto mb-8">
          Discover powerful, real-world examples you can run in seconds. From
          file generation to web scraping and AI workflows—this sandbox unlocks
          serious JavaScript potential in isolated containers.
        </p>

        <section id="filter" className="max-w-6xl mx-auto py-8">
          <h3 className="text-2xl font-semibold mb-4">Filter by Category</h3>
          <div className="flex flex-wrap gap-2">
            {allCategories.map((cat) => (
              <button
                key={cat}
                onClick={() => toggleCategory(cat)}
                className={`flex items-center gap-1 px-3 py-1 rounded-full text-sm font-medium transition-all ${
                  selectedCategories.includes(cat)
                    ? 'bg-green-600 text-white'
                    : 'bg-white border border-gray-300 text-gray-800 hover:bg-gray-100'
                }`}
              >
                <span>{cat}</span>
              </button>
            ))}
          </div>
        </section>

        <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
          {filteredCases.map((u, index) => (
            <div
              key={index}
              onClick={() => openModal(u)}
              className="bg-white bg-opacity-80 p-6 rounded-xl shadow hover:shadow-lg cursor-pointer transition"
            >
              <h3 className="text-xl font-semibold mb-2 flex items-center gap-2">
                {u.title}
              </h3>
              <p className="text-gray-700 mb-4">{u.description}</p>
              <div className="flex flex-wrap gap-2">
                {u.category.map((cat) => (
                  <span
                    key={cat}
                    className="flex items-center gap-1 bg-green-100 text-green-800 px-2 py-1 rounded-full text-xs"
                  >
                    <span>{cat}</span>
                  </span>
                ))}
              </div>
            </div>
          ))}
        </div>
      </section>

      {/* Modal */}
      {modalOpen && selectedCase && (
        <div
          className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50"
          onClick={closeModal}
        >
          <div
            className="bg-white rounded-xl w-full max-w-3xl max-h-[90vh] overflow-y-auto"
            onClick={(e) => e.stopPropagation()}
          >
            <div className="sticky top-0 bg-white p-4 flex justify-between items-center border-b">
              <h2 className="text-2xl font-bold">{selectedCase.title}</h2>
              <button
                onClick={closeModal}
                aria-label="Close"
                className="p-2 hover:bg-gray-100 rounded-full"
              >
                <X size={20} />
              </button>
            </div>
            <div className="p-6">
              <div className="flex flex-wrap gap-2 mb-4">
                {selectedCase.category.map((cat) => (
                  <span
                    key={cat}
                    className="flex items-center gap-1 bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm"
                  >
                    <span>{cat}</span>
                  </span>
                ))}
              </div>
              <div className="mb-6">
                <h3 className="flex items-center gap-2 text-lg font-semibold mb-2 text-gray-800">
                  <Code size={20} /> Prompt for AI
                </h3>
                <pre className="bg-gray-100 rounded-lg p-4 whitespace-pre-wrap text-sm text-gray-800">
                  {selectedCase.prompt}
                </pre>
              </div>
              <div>
                <h3 className="text-lg font-semibold mb-2 text-gray-800">
                  Expected Result
                </h3>
                <div className="bg-gray-100 rounded-lg p-4 text-sm text-gray-800">
                  {selectedCase.result}
                </div>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Footer */}
      <Footer />
    </div>
  );
};

export default App;

```

--------------------------------------------------------------------------------
/website/src/useCases.ts:
--------------------------------------------------------------------------------

```typescript
export const categories = {
  FILE_GENERATION: '📄 File Generation',
  IMAGES: '🖼️ Images',
  DEVELOPMENT: '💻 Development',
  TESTING: '🧪 Testing',
  DATA: '📊 Data',
  WEB: '🌐 Web',
  SCRAPING: '🕷️ Scraping',
  EDUCATION: '🎓 Education',
  API: '🔌 API',
  CONVERSION: '🔄 Conversion',
  DATA_VISUALIZATION: '📈 Data Visualization',
  AI: '🤖 AI',
  MATH: '➗ Math',
  FILE_PROCESSING: '📄 File Processing',
  AUTOMATION: '⚙️ Automation',
  SIMULATION: '🧪 Simulation',
  FUN: '🎉 Fun & Games',
  SECURITY: '🔐 Security',
  AUDIO: '🔊 Audio',
} as const;

export type CategoryKey = keyof typeof categories;
export interface UseCase {
  title: string;
  description: string;
  category: string[];
  prompt: string;
  result: string;
  prerequisites?: string;
}

export const useCases: UseCase[] = [
  {
    title: 'Generate a QR Code',
    description: 'Create a QR code from a URL and save it as an image file.',
    category: [categories.FILE_GENERATION, categories.IMAGES],
    prompt: `Create a Node.js script that installs the 'qrcode' package, generates a QR code for the URL "https://nodejs.org/en", and saves it to a file named "qrcode.png".`,
    result:
      'An image file "qrcode.png" will be generated in the output folder, containing the QR code.',
  },
  {
    title: 'Test Regular Expressions',
    description:
      'Create and test a complex regular expression with unit tests.',
    category: [categories.DEVELOPMENT, categories.TESTING],
    prompt: `Create a Node.js script that defines a complex regular expression to match valid mathematical expressions with nested parentheses (e.g. ((2+3)_(4-5))). The regex should support +, -, _, /, numbers, and nesting up to 4 levels. Write at least 10 unit tests, throwing errors if validation fails. Comment the regex logic.`,
    result:
      'Console output confirming all regex test cases passed and regex logic validated.',
  },
  {
    title: 'Create CSV with Random Data',
    description: 'Generate a CSV file with random names, numbers, and emails.',
    category: [categories.FILE_GENERATION, categories.DATA],
    prompt:
      'Create and execute a js script which generates 200 items in a csv. The CSV has full name, random number and random (but valid) email. Write it in a file called "fake_data.csv"',
    result:
      'A CSV file "fake_data.csv" with 200 rows of randomized data will appear in the output.',
  },
  {
    title: 'Scrape a Webpage Title',
    description: 'Fetch a webpage, save HTML, and extract the title.',
    category: [categories.WEB, categories.SCRAPING],
    prompt: `Use Node.js with the "cheerio" package to fetch https://example.com, save the HTML to "example.html", and extract the content of the <title> tag. Log it to the console.`,
    result:
      'A file "example.html" will be saved and the page title will be printed to the console.',
  },
  {
    title: 'Create a PDF Report',
    description: 'Generate a playful JavaScript tutorial for kids as a PDF.',
    category: [categories.FILE_GENERATION, categories.EDUCATION],
    prompt:
      'Create a JavaScript script with Node.js that generates a PDF file containing a fun "Getting Started with JavaScript" tutorial for a 10-year-old kid.\n\nThe tutorial should be simple, playful, and colorful, explaining basic concepts like console.log(), variables, and how to write your first small program.\nSave the PDF as getting-started-javascript.pdf with fs\n\nTip: Use `pdf-lib` or `pdfkit` for creating the PDF.',
    result:
      'A child-friendly PDF tutorial named "getting-started-javascript.pdf" will be created.',
  },
  {
    title: 'Fetch an API and Save to JSON',
    description: 'Fetch GitHub API data and save it locally.',
    category: [categories.WEB, categories.API, categories.FILE_GENERATION],
    prompt: `Create a Node.js script that fetches repository data from https://api.github.com/repos/nodejs/node and saves the name, description, and star count to a file called "nodejs_info.json".`,
    result:
      'A JSON file "nodejs_info.json" will be saved with details from the Node.js GitHub repository.',
  },
  {
    title: 'Markdown to HTML Converter',
    description: 'Convert Markdown content to HTML using a library.',
    category: [categories.FILE_GENERATION, categories.CONVERSION],
    prompt: `Use Node.js and the "marked" package to convert the following Markdown to HTML and save it to "content_converted.html":\n\n# Welcome to My Page\n\nThis is a simple page created from **Markdown**!\n\n- Learn JavaScript\n- Learn Markdown\n- Build Cool Stuff 🚀`,
    result:
      'The HTML version of the Markdown content will be saved in "content_converted.html".',
  },
  {
    title: 'Generate Random Data',
    description: 'Generate fake user data and save to JSON.',
    category: [categories.FILE_GENERATION, categories.DATA],
    prompt: `Use Node.js with the "@faker-js/faker" package to create a list of 100 fake users (name, email, address) and save to "fake_users.json".`,
    result:
      'A JSON file "fake_users.json" containing 100 fake users will be saved.',
  },
  {
    title: 'Evaluate Complex Math Expression',
    description: 'Use math.js to evaluate a very complex expression.',
    category: [categories.DEVELOPMENT, categories.MATH],
    prompt: `Use Node.js and the "mathjs" package to evaluate the following expression accurately: ((5 + 8) * (15 / 3) - (9 - (4 * 6)) + (10 / (2 + 6))) ^ 2 + sqrt(64) - factorial(6) + (24 / (5 + 7 * (3 ^ 2))) + log(1000) * sin(30 * pi / 180) - cos(60 * pi / 180) + tan(45 * pi / 180) + (4 ^ 3 - 2 ^ (5 - 2)) * (sqrt(81) / 9).`,
    result: 'The result of the full expression will be logged to the console.',
  },
  {
    title: 'Take a Screenshot with Playwright',
    description: 'Launch Chromium and save a screenshot.',
    category: [categories.WEB, categories.IMAGES],
    prompt: `Use Node.js with the "playwright" package and use the optimized Docker image to launch a Chromium browser, visit https://example.com, and save a screenshot to "screenshot_test.png".`,
    result:
      'A PNG screenshot named "screenshot_test.png" will be saved to the output.',
  },
  {
    title: 'Generate a Chart',
    description: 'Create a revenue chart using Chart.js.',
    category: [categories.DATA_VISUALIZATION, categories.IMAGES],
    prompt:
      'Write a JavaScript script that generates a bar chart using chartjs-node-canvas.\nThe chart should show Monthly Revenue Growth for the first 6 months of the year.\nUse the following data:\n\n-January: $12,000\n-February: $15,500\n-March: $14,200\n-April: $18,300\n-May: $21,000\n-June: $24,500\n\nAdd the following details:\n\n-Title: "Monthly Revenue Growth (2025)"\n-X-axis label: "Month"\n-Y-axis label: "Revenue (USD)"\n-Save the resulting chart as chart.png.',
    result:
      'An image file "chart.png" with the rendered revenue chart will be generated.',
  },
  {
    title: 'Summarize a Long Article',
    description: 'Extract Wikipedia article text and summarize it.',
    category: [categories.WEB, categories.AI, categories.SCRAPING],
    prompt: `Fetch and extract plain text from https://en.wikipedia.org/wiki/Node.js. Strip HTML tags and send the text to an AI to summarize in bullet points (max 300 words).`,
    result:
      'A bullet-point summary of the Node.js Wikipedia page will be returned via AI.',
  },
  {
    title: 'Refactor and Optimize JS Code',
    description: 'Refactor a loop-based function using modern JS.',
    category: [categories.DEVELOPMENT, categories.TESTING],
    prompt:
      "Here's an unoptimized JavaScript function:\n```javascript\nfunction getUniqueValues(arr) {\n  let result = [];\n  for (let i = 0; i < arr.length; i++) {\n    let exists = false;\n    for (let j = 0; j < result.length; j++) {\n      if (arr[i] === result[j]) {\n        exists = true;\n        break;\n      }\n    }\n    if (!exists) {\n      result.push(arr[i]);\n    }\n  }\n  return result;\n}\n```\n\nPlease refactor and optimize this function for performance and readability. Then, write and run basic tests with the Node.js test runner to make sure it works (covering common and edge cases). As soon as all tests pass, return only the refactored function.",
    result:
      'A clean, optimized function using modern JS and tests will be logged.',
  },
  {
    title: 'Create a Mock Book API',
    description: 'Build an API from a schema with mock data.',
    category: [categories.WEB, categories.API, categories.DEVELOPMENT],
    prompt: `
Here is a JSON Schema describing a "Book" entity:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Book",
  "type": "object",
  "required": ["title", "author", "isbn"],
  "properties": {
    "title": {
      "type": "string",
      "minLength": 1
    },
    "author": {
      "type": "string",
      "minLength": 1
    },
    "isbn": {
      "type": "string",
      "pattern": "^(97(8|9))?\\d{9}(\\d|X)$"
    },
    "publishedYear": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2100
    },
    "genres": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "available": {
      "type": "boolean",
      "default": true
    }
  },
  "additionalProperties": false
}

Using this schema:

1. Generate **mock data** for at least 5 different books.
2. Create a simple **Node.js REST API** (you can use Express or Fastify) that:
   - Serves a GET /books endpoint on **port 5007**, which returns all mock books.
   - Serves a GET /books/:isbn endpoint that returns a single book matching the provided ISBN (or a 404 if not found).
3. Run the server and print a message like:  
   "Mock Book API is running on http://localhost:5007"`,
    result:
      'A local API will be running with endpoints to fetch all or individual mock books.',
  },
  {
    title: 'File Manipulation',
    description: 'Read, filter, and write a JSON file.',
    category: [categories.FILE_PROCESSING, categories.DATA],
    prerequisites:
      ' Create in your mounted folder a file called "books.json" with this content:\n\n```json\n[\n  { "id": 1, "title": "The Silent Code", "author": "Jane Doe" },\n  { "id": 2, "title": "Refactoring Legacy", "author": "John Smith" },\n  { "id": 3, "title": "Async in Action", "author": "Jane Doe" },\n  { "id": 4, "title": "The Pragmatic Stack", "author": "Emily Ray" },\n  { "id": 5, "title": "Systems Unboxed", "author": "Mark Lee" }\n]\n```',
    prompt: `Create a Node.js script to read "books.json", filter books by author "Jane Doe", and save them to "books_filtered.json".`,
    result:
      'A new file "books_filtered.json" will contain only books written by Jane Doe.',
  },
  {
    title: 'Simulate Dice Rolls for a Game',
    description: 'Run thousands of dice rolls and calculate probabilities.',
    category: [categories.SIMULATION, categories.FUN],
    prompt: `Write a Node.js script that simulates 100,000 rolls of two six-sided dice. Count and print the probability of each possible sum (2 to 12), rounded to 4 decimals.`,
    result: 'Console output showing empirical probabilities for each dice sum.',
  },
  {
    title: 'Create a Password Strength Checker',
    description:
      'Use zxcvbn to analyze password strength and suggest improvements.',
    category: [categories.SECURITY, categories.DEVELOPMENT],
    prompt: `Install and use the "zxcvbn" package to check the strength of this password "?p{4t5#z+oJh", and provide suggestions for improvement. Print the feedback to the console.`,
    result: 'Console logs show password strength score and actionable tips.',
  },
  {
    title: 'Explore NPM Package API Surface',
    description:
      'Analyze and extract the top-level functions, types, and exports of any npm package.',
    category: [categories.DEVELOPMENT, categories.AI],
    prompt: `Explore and explain the surface API and exported types of the npm package "lodash".`,
    result:
      'Console output summarizing the functions, classes, and type exports of lodash, including usage hints.',
  },
  {
    title: 'Create Dependency Tree Diagram',
    description:
      'Visualize a local Node.js project’s internal dependency tree.',
    category: [categories.DATA, categories.DEVELOPMENT],
    prompt: `Run madge on the local ./src directory and output the dependency graph as a JSON or SVG.`,
    result:
      'An image or JSON structure representing the project’s internal module dependencies.',
  },
  {
    title: 'Convert CSV to JSON',
    description: 'Read a CSV file and output a clean, structured JSON version.',
    category: [categories.FILE_PROCESSING, categories.CONVERSION],
    prompt: `Read the file "data.csv", convert it to JSON format, and save it as "data.json".`,
    result:
      'File "data.json" created with structured data matching the CSV rows.',
  },
  {
    title: 'Markdown Slide Deck Generator',
    description: 'Convert a markdown document into HTML slides.',
    category: [categories.FILE_GENERATION, categories.EDUCATION],
    prompt: `Take "slides.md" and use "reveal.js" to generate an HTML slide deck in "slides.html".`,
    result:
      'An interactive slide deck HTML file is saved and ready to present.',
  },
  {
    title: 'Generate a Changelog',
    description:
      'Fetch the Git diff between two tags or branches and automatically generate a Markdown changelog.',
    category: [
      categories.AUTOMATION,
      categories.DEVELOPMENT,
      categories.FILE_GENERATION,
    ],
    prompt: `Write a Node.js script that uses the GitHub API to get the commit diff between v1.0.2 and master of the repo "alfonsograziano/node-code-sandbox-mcp". Summarize the changes and generate a Markdown changelog for the upcoming v1.1 release.`,
    result:
      'A Markdown changelog with categorized features, fixes, and improvements based on commit history and diff.',
  },
  {
    title: 'Generate a PR Description from a Diff',
    description:
      'Fetch and analyze the file changes in a GitHub PR and generate a structured PR description in Markdown.',
    category: [categories.AUTOMATION, categories.DEVELOPMENT],
    prompt: `Use the GitHub API to fetch the diff from PR #71 on the "alfonsograziano/node-code-sandbox-mcp" repository. Analyze what was changed, added, or removed, and create a well-formatted PR description with sections like "What’s Changed", "Why", and "Additional Context".`,
    result:
      'A ready-to-use Markdown PR description summarizing the intent and scope of the pull request.',
  },
];

```

--------------------------------------------------------------------------------
/website/src/pages/GraphGPT.tsx:
--------------------------------------------------------------------------------

```typescript
import React from 'react';
import {
  Brain,
  GitBranch,
  Zap,
  Play,
  Github,
  CheckCircle,
  Database,
  Layers,
  Users,
  ExternalLink,
} from 'lucide-react';
import Footer from '../Components/Footer';
import Header from '../Components/Header';

const GraphGPT: React.FC = () => {
  const gridBg: React.CSSProperties = {
    backgroundImage:
      'linear-gradient(to right, rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.03) 1px, transparent 1px)',
    backgroundSize: '20px 20px',
  };

  const features = [
    {
      icon: GitBranch,
      title: 'Non-linear Conversations',
      description:
        'Create multiple conversation branches from any point in your interaction',
    },
    {
      icon: Layers,
      title: 'Visual Graph Interface',
      description:
        'Intuitive node-based conversation management using React Flow',
    },
    {
      icon: Zap,
      title: 'Real-time Streaming',
      description: 'Live markdown rendering as the AI responds',
    },
    {
      icon: Brain,
      title: 'Contextual Branching',
      description: 'Create new nodes from specific parts of AI responses',
    },
    {
      icon: Database,
      title: 'Conversation Persistence',
      description: 'Save and manage multiple conversation graphs',
    },
    {
      icon: Users,
      title: 'Interactive Node Management',
      description:
        'Click to activate conversation paths, drag to reposition nodes',
    },
  ];

  return (
    <div style={gridBg} className="min-h-screen bg-gray-50 text-gray-900">
      {/* Header */}
      <Header />

      {/* Hero Section */}
      <header className="relative overflow-hidden">
        <div className="max-w-6xl mx-auto px-6 py-20 text-center">
          <h1 className="text-4xl md:text-6xl font-extrabold mb-6 leading-tight">
            GraphGPT
            <span className="block text-3xl md:text-4xl font-normal text-gray-600 mt-4">
              A graph-based interface for LLM interactions
            </span>
          </h1>

          <p className="text-lg md:text-xl text-gray-700 mb-8 max-w-3xl mx-auto">
            Mirror human thinking patterns with non-linear conversations.
            Instead of linear chat, explore multiple conversation paths
            simultaneously, creating a visual knowledge graph of your AI
            interactions.
          </p>

          <div className="flex flex-col sm:flex-row gap-4 justify-center mb-12">
            <a
              href="https://github.com/alfonsograziano/graph-gpt"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-green-600 text-white rounded-lg hover:bg-green-700 transition text-lg font-semibold"
            >
              <Github size={20} />
              View on GitHub
            </a>
            <a
              href="https://www.youtube.com/watch?v=AGMuGlKxO3w"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white border border-gray-300 text-gray-800 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
            >
              <Play size={20} />
              Watch Demo
            </a>
          </div>

          {/* Hero Image */}
          <div className="relative max-w-4xl mx-auto">
            <div className="bg-gradient-to-r from-purple-400 to-blue-500 rounded-2xl p-2 shadow-2xl">
              <img
                src="/images/graph-gpt.png"
                alt="GraphGPT Demo Interface - Interactive graph visualization of AI conversations with nodes and branches"
                className="w-full h-auto rounded-xl shadow-lg"
              />
            </div>
          </div>
        </div>
      </header>

      {/* Demo Video Section */}
      <section className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-12">
            <h2 className="text-3xl md:text-4xl font-bold mb-6">
              📹 See GraphGPT in Action
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Watch how GraphGPT transforms traditional linear conversations
              into dynamic, explorative knowledge graphs.
            </p>
          </div>

          <div className="relative max-w-4xl mx-auto">
            <div className="bg-gradient-to-r from-red-500 to-pink-500 rounded-2xl p-2 shadow-2xl">
              <div className="bg-black rounded-xl overflow-hidden">
                <iframe
                  width="100%"
                  height="400"
                  src="https://www.youtube.com/embed/AGMuGlKxO3w"
                  title="GraphGPT Demo Video"
                  frameBorder="0"
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                  allowFullScreen
                  className="w-full aspect-video rounded-lg"
                ></iframe>
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* Key Features Section */}
      <section className="py-20 bg-gray-50">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-6">
              🌟 Key Features
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Experience the future of AI conversations with these powerful
              features
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
            {features.map((feature, index) => (
              <div
                key={index}
                className="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition"
              >
                <feature.icon
                  width={32}
                  height={32}
                  className="text-purple-600 mb-4"
                />
                <h3 className="text-xl font-semibold mb-3">{feature.title}</h3>
                <p className="text-gray-600">{feature.description}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Reference Parts of Conversation Section */}
      <section className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-6">
              🔗 Reference Parts of a Conversation
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Link new chat inputs to specific parts of your conversation for
              more contextual and focused AI interactions
            </p>
          </div>

          <div className="bg-gradient-to-br from-blue-50 to-purple-50 rounded-2xl p-8 md:p-12">
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
              <div>
                <h3 className="text-2xl md:text-3xl font-bold mb-6 text-gray-900">
                  Contextual Branching
                </h3>
                <p className="text-lg text-gray-700 mb-6">
                  Select any part of your conversation and create a new branch
                  from that specific point. This allows you to explore different
                  directions while maintaining the context of your original
                  discussion.
                </p>
                <div className="space-y-4">
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-blue-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Click on any message to create a branch
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-blue-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Maintain conversation context automatically
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-blue-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Explore multiple conversation paths simultaneously
                    </span>
                  </div>
                </div>
              </div>

              {/* Reference Parts Screenshot */}
              <div className="bg-white rounded-xl shadow-lg">
                <img
                  src="/images/graph-gpt_reference_section.png"
                  alt="GraphGPT Reference Parts - Visual demonstration of contextual branching and conversation referencing"
                  className="w-full h-auto rounded-lg"
                />
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* Markdown Support Section */}
      <section className="py-20 bg-gray-50">
        <div className="max-w-6xl mx-auto px-6">
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
            {/* Markdown Support Screenshot */}
            <div className="bg-white rounded-xl shadow-lg">
              <img
                src="/images/graph-gpt_markdown.png"
                alt="GraphGPT Markdown Support - Real-time markdown rendering demonstration with code highlighting and formatting"
                className="w-full h-auto rounded-lg"
              />
            </div>

            <div>
              <div>
                <h2 className="text-3xl md:text-4xl font-bold mb-6">
                  📝 Markdown Support
                </h2>
                <p className="text-lg text-gray-600 max-w-2xl mx-auto">
                  Rich text formatting and real-time rendering for enhanced
                  conversation readability and structure
                </p>
              </div>

              <p className="text-lg text-gray-700 mb-6">
                GraphGPT supports full Markdown formatting, allowing you to
                create structured, readable conversations with headers, lists,
                code blocks, and more. All formatting is rendered in real-time
                as the AI responds.
              </p>
              <div className="space-y-4">
                <div className="flex items-center gap-3">
                  <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                    <CheckCircle size={16} className="text-green-600" />
                  </div>
                  <span className="text-gray-700 font-medium">
                    Real-time markdown rendering
                  </span>
                </div>
                <div className="flex items-center gap-3">
                  <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                    <CheckCircle size={16} className="text-green-600" />
                  </div>
                  <span className="text-gray-700 font-medium">
                    Code syntax highlighting
                  </span>
                </div>
                <div className="flex items-center gap-3">
                  <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                    <CheckCircle size={16} className="text-green-600" />
                  </div>
                  <span className="text-gray-700 font-medium">
                    Tables, lists, and formatting support
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* Quick Start Section */}
      <section className="py-20 bg-gradient-to-br from-blue-50 to-indigo-100">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-6">
              🚀 Quick Start
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Get GraphGPT running on your machine in just a few steps
            </p>
          </div>

          <div className="bg-white rounded-2xl shadow-lg p-8 md:p-12">
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
              {/* Prerequisites */}
              <div>
                <h3 className="text-2xl font-bold mb-6">Prerequisites</h3>
                <div className="space-y-4">
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Node.js v20+
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      MongoDB (local with Docker, or cloud instance)
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      OpenAI API key
                    </span>
                  </div>
                </div>
              </div>

              {/* Installation Steps */}
              <div>
                <h3 className="text-2xl font-bold mb-6">Installation</h3>
                <div className="space-y-4">
                  <div className="bg-gray-900 rounded-lg p-4 overflow-x-auto">
                    <code className="text-green-400 text-sm whitespace-nowrap">
                      git clone https://github.com/alfonsograziano/graph-gpt.git
                      <br />
                      cd graph-gpt
                      <br />
                      npm install
                    </code>
                  </div>
                  <div className="bg-gray-900 rounded-lg p-4 overflow-x-auto">
                    <code className="text-green-400 text-sm whitespace-nowrap">
                      cp .env.example .env.local
                      <br /># Add your OpenAI API key and MongoDB URI
                    </code>
                  </div>
                  <div className="bg-gray-900 rounded-lg p-4 overflow-x-auto">
                    <code className="text-green-400 text-sm whitespace-nowrap">
                      npm run start:mongodb
                      <br />
                      npm run dev
                    </code>
                  </div>
                </div>
              </div>
            </div>

            <div className="mt-12 text-center">
              <a
                href="https://github.com/alfonsograziano/graph-gpt"
                target="_blank"
                rel="noopener noreferrer"
                className="inline-flex items-center gap-2 px-8 py-4 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition text-lg font-semibold"
              >
                <Github size={20} />
                Get Started on GitHub
                <ExternalLink size={16} />
              </a>
            </div>
          </div>
        </div>
      </section>

      {/* Contributing Section */}
      <section className="py-20 bg-white">
        <div className="max-w-4xl mx-auto px-6 text-center">
          <h2 className="text-3xl md:text-4xl font-bold mb-6">
            🤝 Contributing
          </h2>
          <p className="text-lg text-gray-600 mb-8">
            We welcome contributions! Please feel free to open a PR or an issue
            to request features :D
          </p>
          <div className="flex justify-center">
            <a
              href="https://github.com/alfonsograziano/graph-gpt"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-6 py-3 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition"
            >
              <Github size={20} />
              Contribute on GitHub
            </a>
          </div>
        </div>
      </section>

      {/* CTA Section */}
      <section className="py-20 bg-gradient-to-r from-purple-600 to-blue-600 text-white">
        <div className="max-w-4xl mx-auto px-6 text-center">
          <h2 className="text-3xl md:text-4xl font-bold mb-6">
            Ready to Transform Your AI Conversations?
          </h2>
          <p className="text-xl mb-8 opacity-90">
            Experience the future of AI interaction with GraphGPT's innovative
            graph-based conversation interface.
          </p>
          <div className="flex flex-col sm:flex-row gap-4 justify-center">
            <a
              href="https://github.com/alfonsograziano/graph-gpt"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white text-purple-600 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
            >
              <Github size={20} />
              View on GitHub
            </a>
            <a
              href="https://www.youtube.com/watch?v=AGMuGlKxO3w"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-transparent border-2 border-white text-white rounded-lg hover:bg-white hover:text-purple-600 transition text-lg font-semibold"
            >
              <Play size={20} />
              Watch Demo
            </a>
          </div>
        </div>
      </section>

      {/* Footer */}
      <Footer />
    </div>
  );
};

export default GraphGPT;

```

--------------------------------------------------------------------------------
/website/src/pages/TinyAgent.tsx:
--------------------------------------------------------------------------------

```typescript
import React from 'react';
import {
  Brain,
  Code,
  Shield,
  Terminal,
  ArrowRight,
  CheckCircle,
  Play,
  Github,
  Database,
  FileText,
  Cpu,
  Server,
  HardDrive,
  Search,
  GitBranch,
  Package,
  Globe,
  ArrowUpRight,
  Settings,
} from 'lucide-react';
import Footer from '../Components/Footer';
import Header from '../Components/Header';

const TinyAgent: React.FC = () => {
  const gridBg: React.CSSProperties = {
    backgroundImage:
      'linear-gradient(to right, rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.03) 1px, transparent 1px)',
    backgroundSize: '20px 20px',
  };

  const features = [
    {
      icon: Brain,
      title: 'Intelligent Agent',
      description: 'LLM-powered agent with context-aware decision making',
      color: 'from-green-500 to-green-700',
    },
    {
      icon: Server,
      title: 'Server-Client Architecture',
      description:
        'Once the server is running, multiple clients can be used to interact with the agent',
      color: 'from-green-500 to-green-700',
    },
    {
      icon: Search,
      title: 'RAG System',
      description:
        'Automatic file indexing of your workspace and retrieval with semantic search',
      color: 'from-green-500 to-green-700',
    },
    {
      icon: Terminal,
      title: 'Built-in Tools',
      description:
        'Integrated MCP servers including code interpreter and Playwright',
      color: 'from-green-500 to-green-700',
    },
    {
      icon: Shield,
      title: 'Node.js Sandbox',
      description: 'Safe code execution environment for dynamic tool creation',
      color: 'from-green-500 to-green-700',
    },
    {
      icon: Globe,
      title: 'Smart Web Content Fetching',
      description:
        'Fetch and extract clean, LLM-optimized text content from webpages.',
      color: 'from-green-500 to-green-700',
    },
  ];

  const architecture = [
    {
      title: 'Server',
      description:
        'Handles RAG operations, memory storage, MCP server management, and tool execution',
      icon: Server,
      features: [
        'File indexing',
        'Vector search',
        'Memory storage',
        'Tool registry',
      ],
    },
    {
      title: 'Client',
      description:
        'Provides command line interface, goal setting, tool invocation, and memory context management',
      icon: Cpu,
      features: [
        'User interaction',
        'Task management',
        'Tool handling',
        'Context management',
      ],
    },
  ];

  const tools = [
    {
      title: 'Code Interpreter',
      description:
        'Execute Node.js code in a sandboxed environment with resource limits',
      icon: Code,
      benefits: ['Safe execution', 'Resource limits', 'Dynamic tools'],
    },
    {
      title: 'Playwright Integration',
      description:
        'Web automation and scraping with browser control and interaction',
      icon: Globe,
      benefits: ['Web automation', 'Browser control', 'Screenshot analysis'],
    },
    {
      title: 'Filesystem Access',
      description: 'File reading, writing, and manipulation operations',
      icon: FileText,
      benefits: [
        'File operations',
        'Directory traversal',
        'Content manipulation',
      ],
    },
  ];

  const quickStart = [
    {
      step: '1',
      title: 'Prerequisites',
      description: 'Node.js 18+, PostgreSQL with pgvector, OpenAI API key',
      icon: CheckCircle,
    },
    {
      step: '2',
      title: 'Installation',
      description: 'Run npm install to get all dependencies',
      icon: Package,
    },
    {
      step: '3',
      title: 'Configuration',
      description: 'Set API keys and configure agent settings',
      icon: Settings,
    },
    {
      step: '4',
      title: 'Run',
      description: 'Start server and client processes',
      icon: Play,
    },
  ];

  return (
    <div style={gridBg} className="min-h-screen bg-gray-50 text-gray-900">
      {/* Header */}
      <Header />

      {/* Hero Section */}
      <header className="relative overflow-hidden">
        <div className="max-w-6xl mx-auto px-6 py-20 grid grid-cols-1 md:grid-cols-2 items-center gap-12">
          {/* Left Column - Content */}
          <div className="text-center md:text-left order-2 md:order-1">
            <h1 className="text-4xl md:text-6xl font-extrabold mb-6 leading-tight">
              <span className="block text-transparent bg-clip-text bg-gradient-to-r from-green-600 to-green-700 leading-[1.2]">
                Tiny Agent
              </span>

              <span className="block text-3xl md:text-4xl font-normal text-gray-600 mt-1">
                A cute agent written in TypeScript
              </span>
            </h1>

            <p className="text-lg md:text-xl text-gray-700 mb-8 max-w-2xl">
              An opinionated AI agent that comes with "batteries included":
              built-in tools, RAG capabilities, memory persistence, and powerful
              integrations.
            </p>

            <div className="flex flex-col sm:flex-row gap-4 justify-center md:justify-start mb-12">
              <a
                href="https://github.com/alfonsograziano/meta-tiny-agents"
                target="_blank"
                rel="noopener noreferrer"
                className="inline-flex items-center gap-2 px-8 py-4 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-lg hover:from-green-700 hover:to-green-800 transition-all text-lg font-semibold shadow-lg hover:shadow-xl transform hover:-translate-y-1"
              >
                <Github size={20} />
                View on GitHub
              </a>
              <a
                href="#features"
                className="inline-flex items-center gap-2 px-8 py-4 bg-white border border-gray-300 text-gray-800 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
              >
                <ArrowRight size={20} />
                Explore Features
              </a>
            </div>
          </div>

          {/* Right Column - Image */}
          <div className="flex justify-center md:justify-end order-1 md:order-2">
            <img
              src="/images/client.png"
              alt="Client illustration"
              className="max-w-full h-auto rounded-2xl shadow-xl"
            />
          </div>
        </div>
      </header>

      {/* Features Section */}
      <section id="features" className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Everything You Need, Built Right In
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              No need to hunt for tools or build integrations - everything is
              already included and designed to work together seamlessly
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
            {features.map((feature, index) => (
              <div
                key={index}
                className={`group relative p-6 rounded-xl border-2 transition-all duration-300 hover:shadow-xl transform hover:-translate-y-2 border-gray-200 bg-white hover:border-green-200`}
              >
                <div
                  className={`w-12 h-12 rounded-lg bg-gradient-to-r ${feature.color} flex items-center justify-center mb-4 group-hover:scale-110 transition-transform`}
                >
                  <feature.icon size={24} className="text-white" />
                </div>
                <h3 className="text-xl font-semibold mb-2">{feature.title}</h3>
                <p className="text-gray-600">{feature.description}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Architecture Section */}
      <section className="py-20 bg-gray-50">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Scalable Architecture
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Built for production with server-client separation and intelligent
              resource management
            </p>
          </div>

          <div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
            {architecture.map((arch, index) => (
              <div
                key={index}
                className="bg-white p-8 rounded-xl shadow-lg border border-gray-200"
              >
                <div className="flex items-center gap-4 mb-6">
                  <div className="w-12 h-12 bg-gradient-to-r from-green-500 to-green-700 rounded-lg flex items-center justify-center">
                    <arch.icon size={24} className="text-white" />
                  </div>
                  <h3 className="text-2xl font-bold">{arch.title}</h3>
                </div>
                <p className="text-gray-600 mb-6">{arch.description}</p>
                <ul className="space-y-2">
                  {arch.features.map((feature, idx) => (
                    <li
                      key={idx}
                      className="flex items-center gap-2 text-gray-700"
                    >
                      <CheckCircle size={16} className="text-green-500" />
                      {feature}
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Tools Section */}
      <section className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Built-in Tools & Capabilities
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Comprehensive toolset for AI development and automation
            </p>
          </div>

          <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
            {tools.map((tool, index) => (
              <div
                key={index}
                className="bg-gradient-to-br from-gray-50 to-white p-6 rounded-xl border border-gray-200 hover:shadow-lg transition-all duration-300"
              >
                <div className="w-12 h-12 bg-gradient-to-r from-green-500 to-green-700 rounded-lg flex items-center justify-center mb-4">
                  <tool.icon size={24} className="text-white" />
                </div>
                <h3 className="text-xl font-semibold mb-3">{tool.title}</h3>
                <p className="text-gray-600 mb-4">{tool.description}</p>
                <ul className="space-y-2">
                  {tool.benefits.map((benefit, idx) => (
                    <li
                      key={idx}
                      className="flex items-center gap-2 text-sm text-gray-600"
                    >
                      <ArrowRight size={14} className="text-purple-500" />
                      {benefit}
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Quick Start Section */}
      <section className="py-20 bg-gradient-to-br from-green-50 to-green-100">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Get Started in Minutes
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Simple setup process to get your AI agent running quickly
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
            {quickStart.map((step, index) => (
              <div
                key={index}
                className="bg-white p-6 rounded-xl shadow-lg border border-gray-200 text-center"
              >
                <div className="w-16 h-16 bg-gradient-to-r from-green-500 to-green-700 rounded-full flex items-center justify-center mx-auto mb-4">
                  <span className="text-white font-bold text-xl">
                    {step.step}
                  </span>
                </div>
                <h3 className="text-lg font-semibold mb-2">{step.title}</h3>
                <p className="text-gray-600 text-sm">{step.description}</p>
              </div>
            ))}
          </div>

          <div className="text-center mt-12">
            <a
              href="https://github.com/alfonsograziano/meta-tiny-agents"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-lg hover:from-green-700 hover:to-green-800 transition-all text-lg font-semibold shadow-lg hover:shadow-xl transform hover:-translate-y-1"
            >
              <Github size={20} />
              Start Building
              <ArrowUpRight size={20} />
            </a>
          </div>
        </div>
      </section>

      {/* RAG & Memory Section */}
      <section className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
            <div>
              <h2 className="text-3xl md:text-4xl font-bold mb-6">
                Advanced RAG & Memory System
              </h2>
              <p className="text-lg text-gray-600 mb-8">
                Tiny Agent automatically indexes your workspace and provides
                intelligent context retrieval for seamless AI workflows.
              </p>

              <div className="space-y-4">
                <div className="flex items-start gap-3">
                  <div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center mt-1">
                    <CheckCircle size={14} className="text-white" />
                  </div>
                  <div>
                    <h4 className="font-semibold">Automatic File Indexing</h4>
                    <p className="text-gray-600 text-sm">
                      Files are automatically processed and indexed for semantic
                      search
                    </p>
                  </div>
                </div>

                <div className="flex items-start gap-3">
                  <div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center mt-1">
                    <CheckCircle size={14} className="text-white" />
                  </div>
                  <div>
                    <h4 className="font-semibold">Vector Storage</h4>
                    <p className="text-gray-600 text-sm">
                      Uses pgvector for efficient similarity search and
                      retrieval
                    </p>
                  </div>
                </div>

                <div className="flex items-start gap-3">
                  <div className="w-6 h-6 bg-purple-500 rounded-full flex items-center justify-center mt-1">
                    <CheckCircle size={14} className="text-white" />
                  </div>
                  <div>
                    <h4 className="font-semibold">Memory Persistence</h4>
                    <p className="text-gray-600 text-sm">
                      Memories survive restarts and are stored as semantic
                      vectors
                    </p>
                  </div>
                </div>
              </div>
            </div>

            <div className="relative">
              <div className="bg-gradient-to-br from-green-100 to-green-200 p-8 rounded-2xl">
                <div className="space-y-4">
                  <div className="bg-white p-4 rounded-lg shadow-sm">
                    <div className="flex items-center gap-2 mb-2">
                      <Search size={16} className="text-purple-500" />
                      <span className="font-mono text-sm text-gray-600">
                        RAG Query
                      </span>
                    </div>
                    <p className="text-sm text-gray-800">
                      Find relevant context for AI tasks
                    </p>
                  </div>

                  <div className="bg-white p-4 rounded-lg shadow-sm">
                    <div className="flex items-center gap-2 mb-2">
                      <Database size={16} className="text-blue-500" />
                      <span className="font-mono text-sm text-gray-600">
                        Vector Search
                      </span>
                    </div>
                    <p className="text-sm text-gray-800">
                      Semantic similarity matching
                    </p>
                  </div>

                  <div className="bg-white p-4 rounded-lg shadow-sm">
                    <div className="flex items-center gap-2 mb-2">
                      <HardDrive size={16} className="text-green-500" />
                      <span className="font-mono text-sm text-gray-600">
                        Memory Store
                      </span>
                    </div>
                    <p className="text-sm text-gray-800">
                      Persistent context across sessions
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* CTA Section */}
      <section className="py-20 bg-gradient-to-r from-green-600 to-green-700">
        <div className="max-w-4xl mx-auto px-6 text-center">
          <h2 className="text-3xl md:text-4xl font-bold text-white mb-6">
            Ready to Build AI Agents the Right Way?
          </h2>
          <p className="text-xl text-green-100 mb-8">
            Skip the setup headaches and start building with our opinionated,
            batteries-included framework
          </p>

          <div className="flex flex-col sm:flex-row gap-4 justify-center">
            <a
              href="https://github.com/alfonsograziano/meta-tiny-agents"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white text-green-600 rounded-lg hover:bg-gray-100 transition text-lg font-semibold shadow-lg"
            >
              <Github size={20} />
              Star on GitHub
            </a>
            <a
              href="https://github.com/alfonsograziano/meta-tiny-agents"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-8 py-4 border-2 border-white text-white rounded-lg hover:bg-white hover:text-green-600 transition text-lg font-semibold"
            >
              <GitBranch size={20} />
              Fork & Contribute
            </a>
          </div>
        </div>
      </section>

      {/* Footer */}
      <Footer />
    </div>
  );
};

export default TinyAgent;

```

--------------------------------------------------------------------------------
/test/runJsEphemeral.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as tmp from 'tmp';
import { z } from 'zod';
import runJsEphemeral, { argSchema } from '../src/tools/runJsEphemeral.ts';
import { DEFAULT_NODE_IMAGE, PLAYWRIGHT_IMAGE } from '../src/utils.ts';
import { describeIfLocal } from './utils.ts';
import type {
  McpContentImage,
  McpContentResource,
  McpContentText,
  McpContentTextResource,
} from '../src/types.ts';

let tmpDir: tmp.DirResult;

describe('runJsEphemeral', () => {
  beforeEach(() => {
    tmpDir = tmp.dirSync({ unsafeCleanup: true });
    process.env.FILES_DIR = tmpDir.name;
  });

  afterEach(() => {
    tmpDir.removeCallback();
    delete process.env.FILES_DIR;
  });
  describe('argSchema', () => {
    it('should use default values for image and dependencies', () => {
      const parsed = z.object(argSchema).parse({ code: 'console.log(1);' });
      expect(parsed.image).toBe(DEFAULT_NODE_IMAGE);
      expect(parsed.dependencies).toEqual([]);
      expect(parsed.code).toBe('console.log(1);');
    });

    it('should accept valid custom image and dependencies', () => {
      const input = {
        image: DEFAULT_NODE_IMAGE,
        dependencies: [
          { name: 'lodash', version: '^4.17.21' },
          { name: 'axios', version: '^1.0.0' },
        ],
        code: "console.log('hi');",
      };
      const parsed = z.object(argSchema).parse(input);
      expect(parsed.image).toBe(DEFAULT_NODE_IMAGE);
      expect(parsed.dependencies.length).toBe(2);
      expect(parsed.dependencies[0]).toEqual({
        name: 'lodash',
        version: '^4.17.21',
      });
      expect(parsed.code).toBe("console.log('hi');");
    });
  });

  describe('should run runJsEphemeral', () => {
    it('shoud run runJsEphemeral base', async () => {
      const result = await runJsEphemeral({
        code: "console.log('Hello, world!');",
        dependencies: [],
      });
      expect(result).toBeDefined();
      expect(result.content).toBeDefined();
      expect(result.content.length).toBeGreaterThan(0);
      expect(result.content[0].type).toBe('text');

      if (result.content[0].type === 'text') {
        expect(result.content[0].text).toContain('Hello, world!');
      } else {
        throw new Error("Expected content type to be 'text'");
      }
    });

    it('should generate telemetry', async () => {
      const result = await runJsEphemeral({
        code: "console.log('Hello telemetry!');",
        dependencies: [],
      });

      const telemetryItem = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Telemetry:')
      );
      expect(telemetryItem).toBeDefined();
      if (telemetryItem?.type === 'text') {
        const telemetry = JSON.parse(
          telemetryItem.text.replace('Telemetry:\n', '')
        );
        expect(telemetry).toHaveProperty('installTimeMs');
        expect(typeof telemetry.installTimeMs).toBe('number');
        expect(telemetry).toHaveProperty('runTimeMs');
        expect(typeof telemetry.runTimeMs).toBe('number');
        expect(telemetry).toHaveProperty('installOutput');
        expect(typeof telemetry.installOutput).toBe('string');
      } else {
        throw new Error("Expected telemetry item to be of type 'text'");
      }
    });

    it('should hang indefinitely until a timeout error gets triggered', async () => {
      //Simulating a 10 seconds timeout
      process.env.RUN_SCRIPT_TIMEOUT = '10000';
      const result = await runJsEphemeral({
        code: `
          (async () => {
            console.log("🕒 Hanging for 20 seconds…");
            await new Promise((resolve) => setTimeout(resolve, 20_000));
            console.log("✅ Done waiting 20 seconds, exiting now.");
          })();
           `,
      });

      //Cleanup
      delete process.env.RUN_SCRIPT_TIMEOUT;

      const execError = result.content.find(
        (item) =>
          item.type === 'text' &&
          item.text.startsWith('Error during execution:')
      );
      expect(execError).toBeDefined();
      expect((execError as McpContentText).text).toContain('ETIMEDOUT');

      const telemetryText = result.content.find(
        (item) => item.type === 'text' && item.text.startsWith('Telemetry:')
      );
      expect(telemetryText).toBeDefined();
    }, 20_000);

    it('should report execution error for runtime exceptions', async () => {
      const result = await runJsEphemeral({
        code: `throw new Error('boom');`,
      });

      expect(result).toBeDefined();
      expect(result.content).toBeDefined();

      // should hit our "other errors" branch
      const execError = result.content.find(
        (item) =>
          item.type === 'text' &&
          (item as McpContentText).text.startsWith('Error during execution:')
      );
      expect(execError).toBeDefined();
      expect((execError as McpContentText).text).toContain('Error: boom');

      // telemetry should still be returned
      const telemetryText = result.content.find(
        (item) =>
          item.type === 'text' &&
          (item as McpContentText).text.startsWith('Telemetry:')
      );
      expect(telemetryText).toBeDefined();
    });

    it('should skip npm install if no dependencies are provided', async () => {
      const result = await runJsEphemeral({
        code: "console.log('No deps');",
        dependencies: [],
      });

      const telemetryItem = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Telemetry:')
      );

      expect(telemetryItem).toBeDefined();
      if (telemetryItem?.type === 'text') {
        const telemetry = JSON.parse(
          telemetryItem.text.replace('Telemetry:\n', '')
        );

        expect(telemetry.installTimeMs).toBe(0);
        expect(telemetry.installOutput).toBe(
          'Skipped npm install (no dependencies)'
        );
      }
    });

    it('should generate a valid QR code resource', async () => {
      const result = await runJsEphemeral({
        code: `
          import fs from 'fs';
          import qrcode from 'qrcode';
    
          const url = 'https://nodejs.org/en';
          const outputFile = './files/qrcode.png';
    
          qrcode.toFile(outputFile, url, {
            type: 'png',
          }, function(err) {
            if (err) throw err;
            console.log('QR code saved as PNG!');
          });
        `,
        dependencies: [
          {
            name: 'qrcode',
            version: '^1.5.3',
          },
        ],
      });

      expect(result).toBeDefined();
      expect(result.content).toBeDefined();

      // Find process output
      const processOutput = result.content.find(
        (item) =>
          item.type === 'text' &&
          item.text.startsWith('Node.js process output:')
      );
      expect(processOutput).toBeDefined();
      expect((processOutput as McpContentText).text).toContain(
        'QR code saved as PNG!'
      );

      // Find QR image
      const imageResource = result.content.find(
        (item) => item.type === 'image' && item.mimeType === 'image/png'
      );
      expect(imageResource).toBeDefined();
    }, 15_000);

    it('should save a hello.txt file and return it as a resource', async () => {
      const result = await runJsEphemeral({
        code: `
          import fs from 'fs/promises';
          await fs.writeFile('./files/hello test.txt', 'Hello world!');
          console.log('Saved hello test.txt');
        `,
      });

      expect(result).toBeDefined();
      expect(result.content).toBeDefined();

      // Find process output
      const processOutput = result.content.find(
        (item) =>
          item.type === 'text' &&
          item.text.startsWith('Node.js process output:')
      );
      expect(processOutput).toBeDefined();
      expect((processOutput as McpContentText).text).toContain(
        'Saved hello test.txt'
      );

      // Find file change info
      const changeInfo = result.content.find(
        (item) =>
          item.type === 'text' && item.text.startsWith('List of changed files:')
      );
      expect(changeInfo).toBeDefined();
      expect((changeInfo as McpContentText).text).toContain(
        '- hello test.txt was created'
      );

      // Find the resource
      const resource = result.content.find((item) => item.type === 'resource');
      expect(resource).toBeDefined();
      expect((resource as McpContentResource).resource.mimeType).toBe(
        'text/plain'
      );
      expect((resource as McpContentResource).resource.uri).toContain(
        'hello%20test.txt'
      );
      expect((resource as McpContentResource).resource.uri).toContain(
        'file://'
      );
      if ('text' in (resource as McpContentResource).resource) {
        expect((resource as McpContentTextResource).resource.text).toBe(
          'hello test.txt'
        );
      } else {
        throw new Error("Expected resource to have a 'text' property");
      }

      // Find telemetry info
      const telemetry = result.content.find(
        (item) => item.type === 'text' && item.text.startsWith('Telemetry:')
      );
      expect(telemetry).toBeDefined();
      expect((telemetry as McpContentText).text).toContain('"installTimeMs"');
      expect((telemetry as McpContentText).text).toContain('"runTimeMs"');
    });
  }, 10_000);

  describe('runJsEphemeral error handling', () => {
    it('should return an execution error and telemetry when the code throws', async () => {
      const result = await runJsEphemeral({
        code: "throw new Error('Test error');",
      });

      const execError = result.content.find(
        (item) =>
          item.type === 'text' &&
          item.text.startsWith('Error during execution:')
      );
      expect(execError).toBeDefined();
      expect((execError as McpContentText).text).toContain('Test error');

      const telemetryText = result.content.find(
        (item) => item.type === 'text' && item.text.startsWith('Telemetry:')
      );
      expect(telemetryText).toBeDefined();
    });
  });

  describe('runJsEphemeral multiple file outputs', () => {
    it('should handle saving both text and JPEG files correctly', async () => {
      const base64 =
        '/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxISEhUSEhIVFhUVFRUVFRUVFRUVFRUVFRUWFhUVFRUYHSggGBolGxUVITEhJSkrLi4uFx8zODMsNygtLisBCgoKDg0OGhAQGy0lHyYtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLf/AABEIAJ8BPgMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAEBgIDBQABB//EADkQAAIBAgQDBgQEBQUBAAAAAAECAwQRAAUSITFBBhTiUWEHFDJxgZEjQrHB0RUjYnLw8RUz/8QAGQEAAgMBAAAAAAAAAAAAAAAAAwQBAgAF/8QAJBEAAgEEAgEFAAAAAAAAAAAAAQIDBBESITFBBRMiUYGh/9oADAMBAAIRAxEAPwD9YKKKAP/Z';

      const result = await runJsEphemeral({
        code: `
          import fs from 'fs/promises';
          await fs.writeFile('./files/foo.txt', 'Hello Foo');
          const img = Buffer.from('${base64}', 'base64');
          await fs.writeFile('./files/bar.jpg', img);
          console.log('Done writing foo.txt and bar.jpg');
        `,
      });

      expect(result).toBeDefined();
      expect(result.content).toBeDefined();

      // stdout
      const stdout = result.content.find(
        (c) =>
          c.type === 'text' &&
          c.text.includes('Done writing foo.txt and bar.jpg')
      );
      expect(stdout).toBeDefined();
      expect((stdout as McpContentText).text).toContain(
        'Done writing foo.txt and bar.jpg'
      );

      // resource names (foo.txt and bar.jpg)
      const savedResourceNames = result.content
        .filter((c) => c.type === 'resource')
        .map((c) => (c as McpContentTextResource).resource.text);

      expect(savedResourceNames).toEqual(
        expect.arrayContaining(['foo.txt', 'bar.jpg'])
      );

      // JPEG image check
      const jpegImage = result.content.find(
        (c) => c.type === 'image' && c.mimeType === 'image/jpeg'
      );
      expect(jpegImage).toBeDefined();
    });
  });

  describe('runJsEphemeral screenshot with Playwright', () => {
    it('should take a screenshot of example.com using Playwright and the Playwright image', async () => {
      process.env.RUN_SCRIPT_TIMEOUT = '80000';

      const playwrightVersion =
        PLAYWRIGHT_IMAGE.match(/:v(\d+\.\d+\.\d+)/)?.[1];
      if (!playwrightVersion) {
        throw new Error(
          `Could not extract Playwright version from image: ${PLAYWRIGHT_IMAGE}`
        );
      }

      const result = await runJsEphemeral({
        code: `
            import { chromium } from 'playwright';
    
            (async () => {
              const browser = await chromium.launch({ args: ['--no-sandbox'] });
              const page = await browser.newPage();
              await page.goto('https://example.com', { timeout: 70000 });
              await page.screenshot({ path: './files/example_screenshot.png' });
              await browser.close();
              console.log('Screenshot saved');
            })();
          `,
        dependencies: [
          {
            name: 'playwright',
            version: `^${playwrightVersion}`,
          },
        ],
        image: PLAYWRIGHT_IMAGE,
      });

      // Cleanup
      delete process.env.RUN_SCRIPT_TIMEOUT;

      expect(result).toBeDefined();
      expect(result.content).toBeDefined();

      // stdout check
      const output = result.content.find(
        (item) => item.type === 'text' && item.text.includes('Screenshot saved')
      );
      expect(output).toBeDefined();
      expect((output as McpContentText).text).toContain('Screenshot saved');

      // PNG image resource check
      const image = result.content.find(
        (item) => item.type === 'image' && item.mimeType === 'image/png'
      );
      expect(image).toBeDefined();
    }, 100_000);
  });

  describe('runJsEphemeral linting', () => {
    it('should auto-fix linting issues and run the corrected code', async () => {
      const result = await runJsEphemeral({
        // This code has fixable issues: `var` instead of `const`, and extra spacing.
        code: `var msg = "hello auto-fixed world"  ; console.log(msg)`,
      });

      // 1. Check that no linting report was returned, as it should be auto-fixed.
      const lintReport = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Linting issues found')
      );
      expect(lintReport).toBeUndefined();

      // 2. Check that the execution was successful and the output is correct.
      const execOutput = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Node.js process output:')
      );
      expect(execOutput).toBeDefined();
      if (execOutput?.type === 'text') {
        expect(execOutput.text).toContain('hello auto-fixed world');
      }

      // 3. Check that there was no execution error.
      const execError = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Error during execution:')
      );
      expect(execError).toBeUndefined();
    });

    it('should report unfixable linting issues and the subsequent execution error', async () => {
      const result = await runJsEphemeral({
        // This code has an unfixable issue: using an undefined variable.
        code: `console.log(someUndefinedVariable);`,
      });

      expect(result).toBeDefined();

      // 1. Check that a linting report was returned.
      const lintReport = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Linting issues found')
      );
      expect(lintReport).toBeDefined();
      if (lintReport?.type === 'text') {
        expect(lintReport.text).toContain(
          "'someUndefinedVariable' is not defined."
        );
        expect(lintReport.text).toContain('(no-undef)');
      }

      // 2. Check that the execution also failed and was reported.
      const execError = result.content.find(
        (c) => c.type === 'text' && c.text.startsWith('Error during execution:')
      );
      expect(execError).toBeDefined();
      if (execError?.type === 'text') {
        expect(execError.text).toContain(
          'ReferenceError: someUndefinedVariable is not defined'
        );
      }
    });
  });

  // Skipping this on the CI as it requires a lot of resources
  // and an image that is not available in the CI environment
  describeIfLocal(
    'runJsEphemeral generate charts',
    () => {
      it('should correctly generate a chart', async () => {
        const result = await runJsEphemeral({
          code: `
          import { ChartJSNodeCanvas } from 'chartjs-node-canvas';
          import fs from 'fs';
  
          const width = 800;
          const height = 400;
          const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height });
  
          const data = {
            labels: ['January', 'February', 'March', 'April', 'May', 'June'],
            datasets: [{
              label: 'Monthly Revenue Growth (2025)',
              data: [12000, 15500, 14200, 18300, 21000, 24500],
              backgroundColor: 'rgba(75, 192, 192, 0.6)',
              borderColor: 'rgba(75, 192, 192, 1)',
              borderWidth: 1
            }]
          };
  
          const config = {
            type: 'bar',
            data: data,
            options: {
              responsive: true,
              plugins: {
                legend: {
                  display: true,
                  position: 'top',
                },
                title: {
                  display: true,
                  text: 'Monthly Revenue Growth (2025)',
                }
              },
              scales: {
                x: {
                  title: {
                    display: true,
                    text: 'Month'
                  }
                },
                y: {
                  title: {
                    display: true,
                    text: 'Revenue (USD)'
                  },
                  beginAtZero: true
                }
              }
            }
          };
  
          async function generateChart() {
            const image = await chartJSNodeCanvas.renderToBuffer(config);
            fs.writeFileSync('./files/chart_test.png', image);
            console.log('Chart saved as chart.png');
          }
  
          generateChart();
        `,
          image: 'alfonsograziano/node-chartjs-canvas:latest',
        });

        expect(result).toBeDefined();
        expect(result.content).toBeDefined();

        const output = result.content.find(
          (item) =>
            item.type === 'text' &&
            typeof item.text === 'string' &&
            item.text.includes('Chart saved as chart.png')
        );
        expect(output).toBeDefined();
        expect((output as { type: 'text'; text: string }).text).toContain(
          'Chart saved as chart.png'
        );

        const image = result.content.find(
          (item) =>
            item.type === 'image' &&
            'mimeType' in item &&
            item.mimeType === 'image/png'
        );
        expect(image).toBeDefined();
        expect((image as McpContentImage).mimeType).toBe('image/png');
      });

      it('should still be able to add new dependencies with the node-chartjs-canvas image', async () => {
        const result = await runJsEphemeral({
          code: `
          import _ from 'lodash';
          console.log('_.chunk([1,2,3,4,5], 2):', _.chunk([1,2,3,4,5], 2));
        `,
          dependencies: [{ name: 'lodash', version: '^4.17.21' }],
          image: 'alfonsograziano/node-chartjs-canvas:latest',
        });

        expect(result).toBeDefined();
        expect(result.content).toBeDefined();

        const output = result.content.find(
          (item) =>
            item.type === 'text' &&
            typeof item.text === 'string' &&
            item.text.includes('[ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]')
        );
        expect(output).toBeDefined();
        expect((output as McpContentText).text).toContain(
          '[ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]'
        );
      });

      it('should generate a Mermaid sequence diagram SVG file', async () => {
        const result = await runJsEphemeral({
          code: `
            import fs from "fs";
            import { run } from "@mermaid-js/mermaid-cli";
      
            const diagramDefinition = \`
            sequenceDiagram
                participant App as Application
                participant KC as Keycloak
                participant IDP as Identity Provider
      
                %% Initial Sign-In
                App->>KC: "Go authenticate!"
                KC->>App: Redirect to Keycloak login
                KC->>IDP: "Which IDP? (MyGovID / EntraID)"
                IDP-->>KC: ID Token + Refresh Token (1 day)
                KC-->>App: KC Tokens (1 day)
      
                %% After 24 Hours
                App->>KC: Request new tokens (expired refresh token)
                alt KC session still active (<14 days)
                    KC-->>App: New tokens (1 day)
                else KC session expired (>14 days)
                    KC->>IDP: Redirect to reauthenticate
                    IDP-->>KC: Fresh ID + Refresh Tokens
                    KC-->>App: New KC Tokens (1 day)
                end
            \`;
      
            fs.writeFileSync("./files/authDiagram.mmd", diagramDefinition, "utf8");
            console.log("Mermaid definition saved to authDiagram.mmd");
      
            console.time("test");
            await run("./files/authDiagram.mmd", "./files/output.svg", {
              puppeteerConfig: { args: ['--no-sandbox'] },
            });
            console.timeEnd("test");
            console.log("Diagram generated as output.svg");
          `,
          dependencies: [
            { name: '@mermaid-js/mermaid-cli', version: '^11.4.2' },
          ],
          image: 'alfonsograziano/node-chartjs-canvas:latest',
        });

        // Ensure result exists
        expect(result).toBeDefined();
        expect(result.content).toBeDefined();

        // Validate Mermaid diagram creation log
        const logOutput = result.content.find(
          (item) =>
            item.type === 'text' &&
            item.text.includes('Diagram generated as output.svg')
        );
        expect(logOutput).toBeDefined();

        // Validate .mmd file was created
        const mmdFile = result.content.find(
          (item) =>
            item.type === 'resource' &&
            item.resource?.uri?.endsWith('authDiagram.mmd')
        );
        expect(mmdFile).toBeDefined();

        // Validate that the SVG file was generated and returned as a resource
        const svgFile = result.content.find(
          (item) =>
            item.type === 'resource' &&
            item.resource?.uri?.endsWith('output.svg')
        );
        expect(svgFile).toBeDefined();
      });
    },
    50_000
  );
});

```

--------------------------------------------------------------------------------
/website/src/pages/Home.tsx:
--------------------------------------------------------------------------------

```typescript
import React from 'react';
import { Link } from 'react-router-dom';
import {
  Brain,
  Code,
  Zap,
  Shield,
  Rocket,
  Terminal,
  ArrowRight,
  CheckCircle,
  Play,
  Github,
  GitBranch,
} from 'lucide-react';
import Footer from '../Components/Footer';
import Header from '../Components/Header';

const Home: React.FC = () => {
  const gridBg: React.CSSProperties = {
    backgroundImage:
      'linear-gradient(to right, rgba(0,0,0,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.03) 1px, transparent 1px)',
    backgroundSize: '20px 20px',
  };

  const features = [
    {
      icon: Brain,
      title: 'AI-First Development',
      description:
        'Build intelligent applications with JavaScript-first AI tools and frameworks',
    },
    {
      icon: Zap,
      title: 'Rapid Prototyping',
      description:
        'Quickly iterate and test AI features with our sandboxed development environment',
    },
    {
      icon: Shield,
      title: 'Enterprise Security',
      description:
        'Production-ready security practices for AI applications in regulated industries',
    },
    {
      icon: Rocket,
      title: 'Scalable Architecture',
      description:
        'Design patterns and best practices for AI systems that grow with your business',
    },
  ];

  const tools = [
    {
      title: 'Node.js Sandbox MCP',
      description:
        'Run JavaScript in secure Docker containers with automatic dependency management',
      category: 'Development Tools',
      link: '/mcp',
      icon: Terminal,
    },
    {
      title: 'Tiny Agent Framework',
      description:
        'Intelligent AI agent framework with RAG capabilities and memory persistence',
      category: 'AI Development',
      link: '/tiny-agent',
      icon: Brain,
    },
    {
      title: 'GraphGPT',
      description:
        'Graph-based interface for LLM interactions that mirrors human thinking patterns',
      category: 'AI Interface',
      link: '/graph-gpt',
      icon: GitBranch,
    },
  ];

  return (
    <div style={gridBg} className="min-h-screen bg-gray-50 text-gray-900">
      {/* Header */}
      <Header />

      {/* Hero Section */}
      <header className="relative overflow-hidden">
        <div className="max-w-6xl mx-auto px-6 py-20 text-center">
          <h1 className="text-4xl md:text-6xl font-extrabold mb-6 leading-tight">
            Build the Future of
            <span className="block text-green-600">AI-Powered Apps</span>
            <span className="block text-3xl md:text-4xl font-normal text-gray-600 mt-4">
              with JavaScript
            </span>
          </h1>

          <p className="text-lg md:text-xl text-gray-700 mb-8 max-w-3xl mx-auto">
            Your comprehensive toolkit for building intelligent applications.
            From AI integration to production deployment, we've got everything
            you need to succeed in the AI revolution.
          </p>

          <div className="flex flex-col sm:flex-row gap-4 justify-center mb-12">
            <Link
              to="/mcp"
              className="inline-flex items-center gap-2 px-8 py-4 bg-green-600 text-white rounded-lg hover:bg-green-700 transition text-lg font-semibold"
            >
              <Play size={20} />
              Try Our Sandbox
            </Link>
            <a
              href="#tools"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white border border-gray-300 text-gray-800 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
            >
              <Code size={20} />
              Explore Tools
            </a>
          </div>

          {/* Hero Image */}
          <div className="relative max-w-4xl mx-auto">
            <div className="bg-gradient-to-r from-green-400 to-blue-500 rounded-2xl p-2 shadow-2xl">
              <img
                src="/images/js_ai.jpeg"
                alt="JavaScript AI Development - Showcase of AI-powered development workflow with modern tools and frameworks"
                className="w-full h-auto rounded-xl shadow-lg"
              />
            </div>
          </div>
        </div>
      </header>

      {/* Why JavaScript for AI Section - Expanded */}
      <section className="py-20 bg-gradient-to-b from-gray-50 to-white">
        <div className="max-w-6xl mx-auto px-6">
          {/* Section Header */}
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-5xl font-bold mb-6">
              Why JavaScript for AI Development?
            </h2>
            <p className="text-lg md:text-xl text-gray-600 max-w-4xl mx-auto">
              While Python dominates model training, JavaScript excels at
              building the applications that users actually interact with.
              Here's why JS is the perfect choice for AI-powered apps.
            </p>
          </div>

          {/* Main Value Proposition */}
          <div className="bg-white rounded-2xl shadow-lg p-8 md:p-12 mb-16">
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
              <div>
                <h3 className="text-2xl md:text-3xl font-bold mb-6 text-gray-900">
                  Build Where Users Are
                </h3>
                <p className="text-lg text-gray-700 mb-6">
                  JavaScript runs everywhere your users are - browsers, mobile
                  apps, servers, and edge computing. While Python trains the
                  models, JavaScript delivers the experience.
                </p>
                <div className="space-y-4">
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Frontend AI interfaces that users love
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Real-time AI responses with WebSockets
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
                      <CheckCircle size={16} className="text-green-600" />
                    </div>
                    <span className="text-gray-700 font-medium">
                      Edge AI deployment for low latency
                    </span>
                  </div>
                </div>
              </div>

              {/* Code Example Image */}
              <div className="bg-gray-900 rounded-xl">
                <img
                  src="/images/simple_agent.jpeg"
                  alt="Simple AI Agent Code Example - JavaScript AI chat interface implementation in React"
                  className="w-full h-auto rounded-lg shadow-lg"
                />
              </div>
            </div>
          </div>

          {/* AI Use Cases Grid */}
          <div className="mb-16">
            <h3 className="text-2xl md:text-3xl font-bold text-center mb-12">
              What You Can Build with JavaScript AI
            </h3>
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
              {/* RAG Applications */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">🔍</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">RAG Applications</h4>
                <p className="text-gray-600 mb-4">
                  Build intelligent search and question-answering systems that
                  combine your data with AI models.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> LangChain.js, Vector DBs, OpenAI API
                </div>
              </div>

              {/* AI Agents */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">🤖</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">AI Agents</h4>
                <p className="text-gray-600 mb-4">
                  Create autonomous agents that can browse the web, use tools,
                  and complete complex multi-step tasks.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> Playwright, Puppeteer, Function
                  Calling
                </div>
              </div>

              {/* Real-time AI Chat */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">💬</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">
                  Real-time AI Chat
                </h4>
                <p className="text-gray-600 mb-4">
                  Build responsive chat interfaces with streaming responses,
                  typing indicators, and rich media support.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> WebSockets, Server-Sent Events, React
                </div>
              </div>

              {/* AI-Powered APIs */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">⚡</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">AI-Powered APIs</h4>
                <p className="text-gray-600 mb-4">
                  Create intelligent backends that process natural language,
                  generate content, and make smart decisions.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> Express.js, Fastify, Serverless
                </div>
              </div>

              {/* Browser AI */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-red-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">🌐</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">Browser AI</h4>
                <p className="text-gray-600 mb-4">
                  Run AI models directly in the browser with WebAssembly,
                  enabling privacy-first AI applications.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> ONNX.js, TensorFlow.js, WebAssembly
                </div>
              </div>

              {/* AI Automation */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="w-12 h-12 bg-yellow-100 rounded-lg flex items-center justify-center mb-4">
                  <span className="text-2xl">🔄</span>
                </div>
                <h4 className="text-xl font-semibold mb-3">AI Automation</h4>
                <p className="text-gray-600 mb-4">
                  Automate workflows with AI-driven decision making, from
                  content generation to data processing.
                </p>
                <div className="text-sm text-gray-500">
                  <strong>Tools:</strong> Node.js, Cron Jobs, Webhooks
                </div>
              </div>
            </div>
          </div>

          {/* JavaScript AI Advantages */}
          <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 mb-16">
            <div className="bg-gradient-to-br from-green-50 to-blue-50 rounded-2xl p-8">
              <h3 className="text-2xl font-bold mb-6 text-gray-900">
                🚀 JavaScript AI Superpowers
              </h3>
              <div className="space-y-6">
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    Async by Nature
                  </h4>
                  <p className="text-gray-600">
                    JavaScript's async/await makes it perfect for AI API calls,
                    streaming responses, and handling multiple concurrent AI
                    operations without blocking the UI.
                  </p>
                </div>
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    JSON Native
                  </h4>
                  <p className="text-gray-600">
                    AI APIs speak JSON, and JavaScript speaks JSON natively. No
                    parsing overhead, no type conversion - just seamless data
                    flow.
                  </p>
                </div>
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    Real-time Ready
                  </h4>
                  <p className="text-gray-600">
                    WebSockets, Server-Sent Events, and WebRTC are built into
                    the ecosystem. Perfect for streaming AI responses and
                    collaborative AI features.
                  </p>
                </div>
              </div>
            </div>

            <div className="bg-gradient-to-br from-purple-50 to-pink-50 rounded-2xl p-8">
              <h3 className="text-2xl font-bold mb-6 text-gray-900">
                🌍 Ecosystem Advantages
              </h3>
              <div className="space-y-6">
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    2M+ NPM Packages
                  </h4>
                  <p className="text-gray-600">
                    The largest package ecosystem in the world includes
                    countless AI libraries, integrations, and tools ready to use
                    in your projects.
                  </p>
                </div>
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    Universal Deployment
                  </h4>
                  <p className="text-gray-600">
                    Deploy anywhere: Vercel, Netlify, AWS Lambda, Cloudflare
                    Workers, or traditional servers. One codebase, infinite
                    possibilities.
                  </p>
                </div>
                <div>
                  <h4 className="font-semibold text-lg mb-2 text-gray-800">
                    Developer Velocity
                  </h4>
                  <p className="text-gray-600">
                    Hot reload, excellent debugging, TypeScript support, and the
                    best developer tools mean you can iterate on AI features
                    incredibly fast.
                  </p>
                </div>
              </div>
            </div>
          </div>

          {/* AI Integration Examples */}
          <div className="bg-white rounded-2xl shadow-lg p-8 md:p-12 mb-16">
            <h3 className="text-2xl md:text-3xl font-bold text-center mb-12">
              Popular AI Integrations in JavaScript
            </h3>
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
              <div className="text-center p-4">
                <div className="w-16 h-16 bg-gradient-to-r from-green-400 to-green-600 rounded-2xl flex items-center justify-center mx-auto mb-4">
                  <span className="text-white text-2xl font-bold">🤖</span>
                </div>
                <h4 className="font-semibold mb-2">OpenAI</h4>
                <p className="text-sm text-gray-600">GPT-4, DALL-E, Whisper</p>
                <a
                  href="https://github.com/openai/openai-node"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-xs text-green-600 hover:underline"
                >
                  openai-node
                </a>
              </div>
              <div className="text-center p-4">
                <div className="w-16 h-16 bg-gradient-to-r from-blue-400 to-blue-600 rounded-2xl flex items-center justify-center mx-auto mb-4">
                  <span className="text-white text-2xl font-bold">🧠</span>
                </div>
                <h4 className="font-semibold mb-2">Anthropic</h4>
                <p className="text-sm text-gray-600">
                  Claude, Constitutional AI
                </p>
                <a
                  href="https://github.com/anthropics-ai/anthropic-sdk-typescript"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-xs text-blue-600 hover:underline"
                >
                  anthropic-sdk
                </a>
              </div>
              <div className="text-center p-4">
                <div className="w-16 h-16 bg-gradient-to-r from-purple-400 to-purple-600 rounded-2xl flex items-center justify-center mx-auto mb-4">
                  <span className="text-white text-2xl font-bold">🔗</span>
                </div>
                <h4 className="font-semibold mb-2">LangChain</h4>
                <p className="text-sm text-gray-600">Agents, Chains, Tools</p>
                <a
                  href="https://github.com/langchain-ai/langchainjs"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-xs text-purple-600 hover:underline"
                >
                  langchainjs
                </a>
              </div>
              <div className="text-center p-4">
                <div className="w-16 h-16 bg-gradient-to-r from-orange-400 to-orange-600 rounded-2xl flex items-center justify-center mx-auto mb-4">
                  <span className="text-white text-2xl font-bold">📊</span>
                </div>
                <h4 className="font-semibold mb-2">Vector DBs</h4>
                <p className="text-sm text-gray-600">
                  Pinecone, Weaviate, Chroma
                </p>
                <a
                  href="https://github.com/pinecone-io/pinecone-js"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-xs text-orange-600 hover:underline"
                >
                  pinecone-js
                </a>
              </div>
            </div>
          </div>

          {/* JavaScript AI Frameworks & Tools */}
          <div className="bg-gradient-to-br from-gray-50 to-blue-50 rounded-2xl p-8 md:p-12 mb-16">
            <h3 className="text-2xl md:text-3xl font-bold text-center mb-12">
              JavaScript AI Frameworks & Tools
            </h3>
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
              {/* Vercel AI SDK */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-black rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">▲</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">Vercel AI SDK</h4>
                    <p className="text-sm text-gray-500">
                      Streaming AI responses
                    </p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  Build AI-powered streaming text and chat UIs with React,
                  Svelte, Vue, and more.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full">
                    React/Next.js
                  </span>
                  <a
                    href="https://github.com/vercel/ai"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    GitHub →
                  </a>
                </div>
              </div>

              {/* TensorFlow.js */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-orange-500 rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">TF</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">TensorFlow.js</h4>
                    <p className="text-sm text-gray-500">
                      Browser ML framework
                    </p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  Run machine learning models directly in the browser with
                  JavaScript.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-orange-100 text-orange-700 px-2 py-1 rounded-full">
                    ML/AI
                  </span>
                  <a
                    href="https://github.com/tensorflow/tfjs"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    GitHub →
                  </a>
                </div>
              </div>

              {/* Hugging Face */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-yellow-500 rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">🤗</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">Hugging Face</h4>
                    <p className="text-sm text-gray-500">Transformers.js</p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  Run transformer models in the browser with zero dependencies.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-yellow-100 text-yellow-700 px-2 py-1 rounded-full">
                    NLP
                  </span>
                  <a
                    href="https://github.com/xenova/transformers.js"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    GitHub →
                  </a>
                </div>
              </div>

              {/* AutoGen */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-purple-500 rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">🤖</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">Mastra</h4>
                    <p className="text-sm text-gray-500">
                      TypeScript Agent Framework
                    </p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  The TypeScript Agent Framework from the Gatsby team. Build AI
                  agents with modern JavaScript.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-purple-100 text-purple-700 px-2 py-1 rounded-full">
                    Agents
                  </span>
                  <a
                    href="https://mastra.ai/"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    Website →
                  </a>
                </div>
              </div>

              {/* ChromaDB */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-green-500 rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">📊</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">ChromaDB</h4>
                    <p className="text-sm text-gray-500">Vector database</p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  Embedding database for AI applications with JavaScript client.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-green-100 text-green-700 px-2 py-1 rounded-full">
                    Vector DB
                  </span>
                  <a
                    href="https://docs.trychroma.com/docs/overview/introduction#javascripttypescript"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    Docs →
                  </a>
                </div>
              </div>

              {/* BMAD-METHOD */}
              <div className="bg-white rounded-xl p-6 shadow-md hover:shadow-lg transition">
                <div className="flex items-center gap-3 mb-4">
                  <div className="w-12 h-12 bg-blue-500 rounded-lg flex items-center justify-center">
                    <span className="text-white text-xl font-bold">🚀</span>
                  </div>
                  <div>
                    <h4 className="text-lg font-semibold">BMAD-METHOD™</h4>
                    <p className="text-sm text-gray-500">
                      Universal AI Agent Framework
                    </p>
                  </div>
                </div>
                <p className="text-gray-600 mb-4">
                  Universal AI Agent Framework with Agentic Planning and
                  Context-Engineered Development for any domain.
                </p>
                <div className="flex items-center justify-between">
                  <span className="text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded-full">
                    AI Agents
                  </span>
                  <a
                    href="https://github.com/bmad-code-org/bmad-method"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sm text-blue-600 hover:underline"
                  >
                    GitHub →
                  </a>
                </div>
              </div>
            </div>
          </div>

          {/* Comparison Section */}
          <div className="bg-gradient-to-r from-gray-900 to-gray-800 rounded-2xl p-8 md:p-12 text-white mb-16">
            <h3 className="text-2xl md:text-3xl font-bold text-center mb-8">
              Python vs JavaScript in AI Development
            </h3>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
              <div className="bg-white/10 rounded-xl p-6">
                <h4 className="text-xl font-semibold mb-4 text-yellow-400">
                  🐍 Python's Domain
                </h4>
                <ul className="space-y-3 text-gray-300">
                  <li>• Model training & fine-tuning</li>
                  <li>• Data science & research</li>
                  <li>• Deep learning frameworks</li>
                  <li>• Scientific computing</li>
                  <li>• ML experimentation</li>
                </ul>
              </div>
              <div className="bg-white/10 rounded-xl p-6">
                <h4 className="text-xl font-semibold mb-4 text-green-400">
                  ⚡ JavaScript's Domain
                </h4>
                <ul className="space-y-3 text-gray-300">
                  <li>• User-facing AI applications</li>
                  <li>• Real-time AI interactions</li>
                  <li>• AI-powered web & mobile apps</li>
                  <li>• Agent orchestration</li>
                  <li>• Production AI deployment</li>
                </ul>
              </div>
            </div>
            <div className="text-center mt-8">
              <p className="text-lg text-gray-300">
                <strong className="text-white">The Perfect Partnership:</strong>{' '}
                Train in Python, Deploy in JavaScript
              </p>
            </div>
          </div>

          {/* Call to Action */}
          <div className="text-center bg-gradient-to-r from-green-600 to-blue-600 rounded-2xl p-8 md:p-12 text-white">
            <h3 className="text-2xl md:text-3xl font-bold mb-4">
              Ready to Build AI Apps with JavaScript?
            </h3>
            <p className="text-lg mb-8 opacity-90 max-w-2xl mx-auto">
              Join thousands of developers who are already building the future
              of AI applications with the language they know and love.
            </p>
            <Link
              to="/mcp"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white text-green-600 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
            >
              <Terminal size={20} />
              Start Building Now
            </Link>
          </div>
        </div>
      </section>

      {/* Features Section */}
      <section className="py-20">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Everything You Need to Build AI Apps
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              From development tools to production best practices, we've curated
              the essential resources for modern AI development with JavaScript.
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
            {features.map((feature, index) => (
              <div
                key={index}
                className="bg-white bg-opacity-80 p-6 rounded-xl shadow-md hover:shadow-lg transition"
              >
                <feature.icon
                  width={32}
                  height={32}
                  className="text-green-600 mb-4"
                />
                <h3 className="text-xl font-semibold mb-2">{feature.title}</h3>
                <p className="text-gray-700">{feature.description}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Tools Section */}
      <section id="tools" className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6">
          <div className="text-center mb-16">
            <h2 className="text-3xl md:text-4xl font-bold mb-4">
              Essential AI Development Tools
            </h2>
            <p className="text-lg text-gray-600 max-w-2xl mx-auto">
              Discover the tools that will accelerate your AI development
              journey
            </p>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
            {tools.map((tool, index) => (
              <div
                key={index}
                className="bg-gray-50 p-6 rounded-xl border border-gray-200 hover:border-green-300 transition"
              >
                <div className="flex items-start gap-4">
                  <div className="p-3 bg-green-100 rounded-lg">
                    <tool.icon size={24} className="text-green-600" />
                  </div>
                  <div className="flex-1">
                    <div className="flex items-center gap-2 mb-2">
                      <span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">
                        {tool.category}
                      </span>
                    </div>
                    <h3 className="text-xl font-semibold mb-2">{tool.title}</h3>
                    <p className="text-gray-600 mb-4">{tool.description}</p>
                    {tool.link ? (
                      <Link
                        to={tool.link}
                        className="inline-flex items-center gap-2 text-green-600 hover:text-green-700 font-medium"
                      >
                        Learn More <ArrowRight size={16} />
                      </Link>
                    ) : (
                      <span className="inline-flex items-center gap-2 text-gray-400 font-medium">
                        Coming Soon <ArrowRight size={16} />
                      </span>
                    )}
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Community Section */}
      <section className="py-20 bg-white">
        <div className="max-w-6xl mx-auto px-6 text-center">
          <h2 className="text-3xl md:text-4xl font-bold mb-6">
            Join the AI JavaScript Community
          </h2>
          <p className="text-lg text-gray-600 mb-8 max-w-2xl mx-auto">
            Connect with developers, share knowledge, and stay updated with the
            latest AI development trends and tools.
          </p>

          <div className="flex justify-center">
            <a
              href="https://github.com/alfonsograziano/node-code-sandbox-mcp"
              target="_blank"
              rel="noopener noreferrer"
              className="inline-flex items-center gap-2 px-6 py-3 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition"
            >
              <Github size={20} />
              GitHub Community
            </a>
          </div>
        </div>
      </section>

      {/* CTA Section */}
      <section className="py-20 bg-gradient-to-r from-green-600 to-blue-600 text-white">
        <div className="max-w-4xl mx-auto px-6 text-center">
          <h2 className="text-3xl md:text-4xl font-bold mb-6">
            Ready to Build the Future?
          </h2>
          <p className="text-xl mb-8 opacity-90">
            Start your AI development journey with our comprehensive toolkit and
            community support.
          </p>
          <div className="flex justify-center">
            <Link
              to="/mcp"
              className="inline-flex items-center gap-2 px-8 py-4 bg-white text-green-600 rounded-lg hover:bg-gray-100 transition text-lg font-semibold"
            >
              <Terminal size={20} />
              Try Our Sandbox
            </Link>
          </div>
        </div>
      </section>

      {/* Footer */}
      <Footer />
    </div>
  );
};

export default Home;

```
Page 2/2FirstPrevNextLast