Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ one tree rather than beside the source.
| `apps/dev-tools-help-docs` | [.claude/apps/dev-tools-help-docs/CLAUDE.md](.claude/apps/dev-tools-help-docs/CLAUDE.md) |
| `apps/vscode-cloud` | [.claude/apps/vscode-cloud/CLAUDE.md](.claude/apps/vscode-cloud/CLAUDE.md) |
| `packages/about-system-info` | [.claude/packages/about-system-info/CLAUDE.md](.claude/packages/about-system-info/CLAUDE.md) |
| `packages/ask-ai-button` | [.claude/packages/ask-ai-button/CLAUDE.md](.claude/packages/ask-ai-button/CLAUDE.md) |
| `packages/api2ai-mcp-generator` | [.claude/packages/api2ai-mcp-generator/CLAUDE.md](.claude/packages/api2ai-mcp-generator/CLAUDE.md) |
| `packages/cloudflare-to-claude-fix` | [.claude/packages/cloudflare-to-claude-fix/CLAUDE.md](.claude/packages/cloudflare-to-claude-fix/CLAUDE.md) |
| `packages/code-tree-graph` | [.claude/packages/code-tree-graph/CLAUDE.md](.claude/packages/code-tree-graph/CLAUDE.md) |
Expand Down
1 change: 1 addition & 0 deletions .claude/architecture/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ name is what turbo filters and `--skill` flags use.
| Directory | npm name | What it owns |
| --- | --- | --- |
| `about-system-info` | `about-system` | Cross-platform CLI printing CPU/memory/disk/uptime/IP/ISP as one emoji line; also a desktop app under `native/` |
| `ask-ai-button` | `ask-ai-button` | Ask AI dropdown / floating button / inline panel for docs pages: sends the page (link or pasted Markdown) plus a question to Claude, ChatGPT, Gemini, Perplexity and more, or copies it. Spun out of `template-fumadocs` |
| `api2ai-mcp-generator` | `api2ai` | Generates MCP servers from any OpenAPI spec (mcp-use); HTTP/SSE/Streamable transports, inspector UI, Zod validation |
| `cloudflare-to-claude-fix` | `cloudflare-to-claude-fix` | Workers Queue consumer that fires a Claude Code routine when a Workers build fails |
| `code-tree-graph` | `code-tree-graph` | Fumadocs/Next components: `DependencyGraph` (Mermaid from AST), `FileTreeView`, `TypeTable` — all from a local parser, no external service |
Expand Down
32 changes: 32 additions & 0 deletions .claude/packages/ask-ai-button/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# CLAUDE.md — `ask-ai-button`

**skill:** [`skills/ask-ai-button`](../../../skills/ask-ai-button/SKILL.md)
· **runner:** Vitest (jsdom) · **build:** Vite library + `vite-plugin-dts`

"Ask AI about this page" for docs sites: `AskAIButton` (dropdown or FAB),
`AskAIPanel` (inline), `CopyPageButton`. Spun out of
`starter-templates/template-fumadocs/components/fumadocs/ai/`.

## Rules

- **Provider URLs are public API.** A changed query parameter silently empties
every prompt for that provider. Only change one after checking it opens with
the prompt filled in, and keep the encode-everything test passing.
- **`window.open` must stay synchronous in the click handler.** Content is
prefetched for exactly this reason; an `await` before the open gets the tab
blocked as a popup.
- **No Tailwind, no CSS import.** Styles live in `src/styles.ts` and are
injected at runtime; class names (`aai-*`) and `--aai-*` variables are public
surface.
- The bundle keeps its `"use client"` banner (`vite.config.ts`) so Next.js
server components can render it.

## Layout

`src/AskAIButton.tsx` (trigger, FAB, CopyPageButton) · `src/AskAIPanel.tsx`
(the panel) · `src/providers.tsx` · `src/prompt.ts` · `src/clipboard.ts` ·
`src/styles.ts` · `src/icons.tsx` · `demo/` (`bun run dev`)

```bash
cd packages/ask-ai-button && bun run typecheck && bun run test && bun run build
```
1 change: 1 addition & 0 deletions .github/scripts/sync-package-readmes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const SKILLS_SOURCE = 'https://github.com/OpenSourceAGI/dev-tools-starter-agent'
const SKILLS_BY_PACKAGE = {
'about-system-info': ['about-system'],
'api2ai-mcp-generator': ['api2ai'],
'ask-ai-button': ['ask-ai-button'],
'cloudflare-to-claude-fix': ['cloudflare-to-claude-fix'],
'code-tree-graph': ['code-tree-graph'],
'create-cloud-db': ['create-cloud-db'],
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
include:
- package: about-system-info
- package: api2ai-mcp-generator
- package: ask-ai-button
- package: cloudflare-to-claude-fix
- package: code-tree-graph
- package: create-cloud-db
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
[![npm downloads](https://img.shields.io/npm/dm/code-tree-graph.svg)](https://www.npmjs.com/package/code-tree-graph) **[code-tree-graph](packages/code-tree-graph/)** - Interactive code dependency graph and file tree components for Fumadocs + Next.js. `DependencyGraph` renders a pan/zoom Mermaid flowchart from full AST analysis, `FileTreeView` a searchable table with export/JSDoc metadata and GitHub deep links, and `TypeTable` collapsible property tables — all from a local TypeScript/JS parser, no external service.
`npm install code-tree-graph` · `bun add code-tree-graph`

[![npm downloads](https://img.shields.io/npm/dm/ask-ai-button.svg)](https://www.npmjs.com/package/ask-ai-button) **[ask-ai-button](packages/ask-ai-button/)** - "Ask AI about this page" for docs sites, as a dropdown, a floating action button or an inline panel. The visitor types a question and picks Claude, ChatGPT, Gemini, Perplexity, Grok, Copilot, Le Chat, T3 Chat, Brave, QwkSearch or Cursor; a new tab opens with the page (as a link or as pasted Markdown) and the question pre-filled. Also copies the prompt or the page Markdown, takes custom URL or API providers, and picks up Fumadocs theme colors with no CSS import.
`npm install ask-ai-button` · `bun add ask-ai-button`

[![npm downloads](https://img.shields.io/npm/dm/create-cloud-db.svg)](https://www.npmjs.com/package/create-cloud-db) **[create-cloud-db](packages/create-cloud-db/)** - Interactive CLI that creates a Turso edge database and writes `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` directly into your `.env` file. Handles Turso login, database creation, token generation, and env-file patching in one command.
`npx create-cloud-db [db-name]` · `npm install -g create-cloud-db`

Expand Down
5 changes: 5 additions & 0 deletions apps/dev-tools-help-docs/scripts/sync-readme-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ const PACKAGES: Entry[] = [
title: 'manage-storage',
icon: 'HardDrive',
},
{
dir: 'packages/ask-ai-button',
title: 'ask-ai-button',
icon: 'Sparkles',
},
{
dir: 'packages/react-app-store-buttons',
title: 'react-app-store-buttons',
Expand Down
3 changes: 3 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ flag_management:
- name: react-app-store-buttons
paths:
- packages/react-app-store-buttons/
- name: ask-ai-button
paths:
- packages/ask-ai-button/

comment:
layout: "header, diff, flags, files"
Expand Down
176 changes: 176 additions & 0 deletions packages/ask-ai-button/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<p align="center">
<img src="https://i.imgur.com/5lsiepL.png" width="300" >
<br />
<b>💍One Code to rule them all — and in the cloud compile them. </b>
</p>

<!-- template-git-repo:badges:start -->
<p align="center">
<a href="https://1computer.online/docs/packages/ask-ai-button"><img src="https://img.shields.io/badge/Docs-blue?logo=ReadTheDocs&logoColor=white" alt="Documentation" /></a>
<br />
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/stargazers"><img src="https://img.shields.io/github/stars/OpenSourceAGI/dev-tools-starter-agent" alt="GitHub Stars" /></a>
<a href="https://www.npmjs.com/package/ask-ai-button"><img src="https://img.shields.io/npm/dm/ask-ai-button.svg" alt="NPM Monthly Downloads" /></a>
<a href="https://www.npmjs.com/package/ask-ai-button"><img src="https://img.shields.io/npm/v/ask-ai-button.svg" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/ask-ai-button"><img src="https://img.shields.io/npm/dt/ask-ai-button.svg" alt="NPM Total Downloads" /></a>
<a href="https://www.npmjs.com/package/ask-ai-button"><img src="https://img.shields.io/npm/types/ask-ai-button" alt="TypeScript types" /></a>
<a href="https://packagephobia.com/result?p=ask-ai-button"><img src="https://packagephobia.com/badge?p=ask-ai-button" alt="Install size" /></a>
<a href="https://app.codecov.io/gh/OpenSourceAGI/dev-tools-starter-agent/flags"><img src="https://img.shields.io/codecov/c/github/OpenSourceAGI/dev-tools-starter-agent?flag=ask-ai-button&label=ask-ai-button%20coverage&logo=codecov&logoColor=white" alt="Coverage" /></a>
<br />
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/issues"><img src="https://img.shields.io/github/issues/OpenSourceAGI/dev-tools-starter-agent?logo=github" alt="GitHub Issues" /></a>
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/pulls"><img src="https://img.shields.io/github/issues-pr/OpenSourceAGI/dev-tools-starter-agent?logo=github&label=PRs" alt="Open Pull Requests" /></a>
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/pulls?q=is%3Apr+is%3Aclosed"><img src="https://img.shields.io/github/issues-pr-closed/OpenSourceAGI/dev-tools-starter-agent?logo=github&label=PRs%20merged&color=8957e5" alt="Merged Pull Requests" /></a>
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/discussions"><img src="https://img.shields.io/github/discussions/OpenSourceAGI/dev-tools-starter-agent" alt="GitHub Discussions" /></a>
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/commits/master/"><img src="https://img.shields.io/github/last-commit/OpenSourceAGI/dev-tools-starter-agent.svg" alt="GitHub last commit" /></a>
<br />
<a href="https://stackblitz.com/github/OpenSourceAGI/dev-tools-starter-agent/tree/master/packages/ask-ai-button"><img height="20px" src="https://developer.stackblitz.com/img/open_in_stackblitz.svg" alt="Open in StackBlitz" /></a>
<img src="https://img.shields.io/badge/Bun-14151A?logo=bun&logoColor=white" alt="Bun" /> <img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/badge/React-20232A?logo=react&logoColor=white" alt="React" /> <img src="https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=white" alt="Vite" /> <img src="https://img.shields.io/badge/Vitest-6E9F18?logo=vitest&logoColor=white" alt="Vitest" />
</p>
<!-- template-git-repo:badges:end -->

<!-- skills:install:start -->
**🤖 Agent skill** — `npx skills@latest add https://github.com/OpenSourceAGI/dev-tools-starter-agent --skill ask-ai-button` ([what it covers](../../skills/ask-ai-button/SKILL.md))
<!-- skills:install:end -->


# ask-ai-button

An **Ask AI** button for docs sites. The visitor types a question, picks a
model, and a new tab opens in Claude, ChatGPT, Gemini, Perplexity, Grok,
Copilot, Le Chat, T3 Chat, Brave, QwkSearch or Cursor with the prompt already
filled in: the current page (as a link or as pasted Markdown) plus their
question. They can also just copy the prompt, or copy the page as Markdown.

Ships as a **dropdown** for a page header, a **floating action button**, or an
**inline panel**. Self-styled — no Tailwind or CSS import needed — and it picks
up Fumadocs' theme colors automatically.

Spun out of the Ask AI dropdown and copy button in
[`starter-templates/template-fumadocs`](../../starter-templates/template-fumadocs/).

## Install

```bash
bun add ask-ai-button # or: npm install ask-ai-button
```

`react` and `react-dom` 18+ are peers.

## Usage

```tsx
import { AskAIButton, CopyPageButton } from "ask-ai-button";

// Dropdown, e.g. under a Fumadocs page title
<div className="flex gap-2">
<CopyPageButton markdownUrl={`${page.url}.mdx`} />
<AskAIButton
markdownUrl={`${page.url}.mdx`}
title={page.data.title}
githubUrl={`https://github.com/me/repo/blob/main/content/docs/${page.path}`}
/>
</div>

// Floating action button, once in your layout
<AskAIButton variant="fab" position="bottom-right" />

// Inline panel, anywhere in the page
<AskAIPanel markdownUrl="/docs/intro.mdx" inline />
```

The components are client components (the bundle starts with `"use client"`),
so they can be rendered straight from a Next.js server component.

### What gets sent

The panel has a **Link to page / Include page text** toggle:

| Mode | Prompt |
| --- | --- |
| `link` *(default with `markdownUrl`)* | `Read https://site/docs/intro.mdx, <question>` — the model fetches the page |
| `content` | The page's Markdown pasted between `<page>` tags, then the question |

In `content` mode the text comes from `markdownUrl`, or from `getContent()` if
you pass one, or from the page's `<article>`/`<main>` text when neither is set.
If a pasted page would make the URL longer than `maxUrlLength` (default 8000),
the tab opens with the `link` prompt and the full prompt is put on the
clipboard so the visitor can paste it.

`Ctrl/⌘ + Enter` in the message box sends to the first provider.

### Choosing providers

```tsx
<AskAIButton providers={["claude", "chatgpt", "perplexity"]} />
```

Built-in IDs: `claude`, `chatgpt`, `gemini`, `perplexity`, `grok`, `copilot`,
`mistral`, `t3chat`, `brave`, `qwksearch`, `cursor`. Mix them with your own:

```tsx
<AskAIButton
providers={[
"claude",
// Any chat UI that takes a prompt in its URL
{ id: "phind", title: "Phind", getHref: (p) => `https://www.phind.com/search?q=${encodeURIComponent(p)}` },
// Or your own API / in-page chat — no tab is opened
{ id: "api", title: "Our assistant", onSelect: (prompt, page) => fetch("/api/ask", { method: "POST", body: prompt }) },
]}
/>
```

A provider without an `icon` shows its site's favicon.

## Props

`AskAIButton` takes every `AskAIPanel` prop plus the trigger props.

| Prop | Default | |
| --- | --- | --- |
| `markdownUrl` | — | Raw Markdown/MDX of the page. Relative URLs resolve against the current page. |
| `pageUrl` | `location.href` | The page being asked about. |
| `title` | — | Named in the prompt and shown in the panel header. |
| `githubUrl` | — | Adds a GitHub link. |
| `providers` | all built-ins | IDs and/or `AIProvider` objects, in order. |
| `defaultMode` | `link` if `markdownUrl`, else `content` | Starting mode. |
| `showModeToggle` | `true` | Show the link/content toggle. |
| `getContent` | — | Supply the page text yourself. |
| `promptTemplate` | `buildPrompt` | `(input) => string` to change the wording. |
| `maxUrlLength` | `8000` | URL length before falling back to the link prompt. |
| `placeholder`, `heading` | — | Text in the panel. `heading={null}` hides the header. |
| `onSend` | — | `({ provider, prompt, href })` after each send — for analytics. |
| `injectStyles` | `true` | Set `false` if you ship `askAIButtonCss` yourself. |
| `variant` | `dropdown` | `dropdown` or `fab`. |
| `label`, `icon` | `"Ask AI"`, sparkle | Trigger content. `label={null}` gives an icon-only FAB. |
| `align` | `start` | Dropdown: panel aligns to the trigger's `start` or `end` edge. |
| `position` | `bottom-right` | FAB: `bottom-right` or `bottom-left`. |
| `open`, `defaultOpen`, `onOpenChange` | — | Controlled or uncontrolled open state. |

Helpers exported for building your own UI: `buildPrompt`,
`resolveProviderTarget`, `resolveProviders`, `AI_PROVIDERS`, `fetchMarkdown`,
`copyText`, `copyPendingText`, and the brand icons.

## Theming

Every class is prefixed `aai-`. Colors come from CSS variables that default to
Fumadocs' `--color-fd-*` tokens and fall back to a neutral palette, with a dark
palette under `.dark` or `[data-theme="dark"]`:

```css
.aai-root {
--aai-primary: #7c3aed;
--aai-radius: 1rem;
}
```

The stylesheet is injected once as `<style id="ask-ai-button-styles">`. To ship
it yourself (for a strict CSP), pass `injectStyles={false}` and render
`askAIButtonCss` where you want it.

## Develop

```bash
cd packages/ask-ai-button
bun run dev # demo page at demo/
bun run test
bun run build
```
27 changes: 27 additions & 0 deletions packages/ask-ai-button/demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ask-ai-button demo</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 2rem;
max-width: 48rem;
}
.row {
display: flex;
gap: 0.5rem;
align-items: center;
padding-bottom: 1.5rem;
border-bottom: 1px solid #e5e7eb;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="./main.tsx"></script>
</body>
</html>
50 changes: 50 additions & 0 deletions packages/ask-ai-button/demo/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { AskAIButton, AskAIPanel, CopyPageButton } from "../src";

const markdownUrl = "./sample.md";

function App() {
return (
<article>
<h1>Getting started</h1>
<div className="row">
<CopyPageButton markdownUrl={markdownUrl} />
<AskAIButton
markdownUrl={markdownUrl}
title="Getting started"
githubUrl="https://github.com/OpenSourceAGI/dev-tools-starter-agent"
providers={[
"claude",
"chatgpt",
"gemini",
"perplexity",
"grok",
"copilot",
{
id: "api",
title: "My API",
onSelect: (prompt) => alert(`POST /api/ask\n\n${prompt}`),
},
]}
/>
</div>
<p>
Install the package, then render the button in your docs page header.
</p>
<h2>Inline panel</h2>
<AskAIPanel markdownUrl={markdownUrl} title="Getting started" inline />
<AskAIButton
variant="fab"
markdownUrl={markdownUrl}
title="Getting started"
/>
</article>
);
}

createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
3 changes: 3 additions & 0 deletions packages/ask-ai-button/demo/public/sample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Getting started

Install the package, then render the button in your docs page header.
Loading
Loading