kaddidlehopper 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/add-ons/ai/assets/AGENTS.md.append +24 -0
- package/add-ons/ai/info.json +11 -17
- package/add-ons/db/assets/AGENTS.md.append +22 -0
- package/add-ons/db/info.json +10 -10
- package/add-ons/forms/assets/AGENTS.md.append +13 -0
- package/add-ons/forms/info.json +6 -10
- package/dist/agents-md.js +103 -0
- package/dist/cli.js +3 -0
- package/dist/types/agents-md.d.ts +5 -0
- package/examples/ai-chat/assets/AGENTS.md.append +24 -0
- package/examples/ai-chat/info.json +11 -11
- package/examples/blog/assets/AGENTS.md.append +18 -0
- package/examples/blog/info.json +25 -29
- package/examples/calculator/assets/AGENTS.md.append +9 -0
- package/examples/calculator/info.json +8 -8
- package/examples/dashboard/assets/AGENTS.md.append +12 -0
- package/examples/dashboard/info.json +7 -8
- package/examples/ecommerce/assets/AGENTS.md.append +22 -0
- package/examples/ecommerce/info.json +24 -27
- package/examples/events/assets/AGENTS.md.append +21 -0
- package/examples/events/info.json +46 -60
- package/examples/marketing/assets/AGENTS.md.append +15 -0
- package/examples/marketing/info.json +17 -23
- package/examples/portfolio/assets/AGENTS.md.append +21 -0
- package/examples/portfolio/info.json +37 -44
- package/examples/resume/assets/AGENTS.md.append +19 -0
- package/examples/resume/info.json +24 -15
- package/examples/saas/assets/AGENTS.md.append +9 -0
- package/examples/saas/info.json +9 -13
- package/examples/survey/assets/AGENTS.md.append +9 -0
- package/examples/survey/info.json +7 -8
- package/package.json +1 -1
- package/project/base/AGENTS.md +86 -0
- package/project/info.json +17 -0
- package/src/agents-md.ts +139 -0
- package/src/cli.ts +4 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
### AI Integration
|
|
2
|
+
|
|
3
|
+
Multi-provider AI chat with fallback chain:
|
|
4
|
+
|
|
5
|
+
1. Anthropic Claude (preferred)
|
|
6
|
+
2. OpenAI GPT-4o
|
|
7
|
+
3. Google Gemini
|
|
8
|
+
4. Ollama (local)
|
|
9
|
+
|
|
10
|
+
**Tools available to AI:**
|
|
11
|
+
- `getWeather` - Get the current weather for a city. Returns temperature, condition, and humidity.
|
|
12
|
+
|
|
13
|
+
## Environment Variables
|
|
14
|
+
|
|
15
|
+
For AI functionality, set one or more:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
ANTHROPIC_API_KEY=...
|
|
19
|
+
OPENAI_API_KEY=...
|
|
20
|
+
GOOGLE_GENERATIVE_AI_API_KEY=...
|
|
21
|
+
OLLAMA_BASE_URL=...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The application uses the first available provider in the fallback chain.
|
package/add-ons/ai/info.json
CHANGED
|
@@ -6,22 +6,16 @@
|
|
|
6
6
|
"modes": ["file-router"],
|
|
7
7
|
"type": "add-on",
|
|
8
8
|
"priority": 20,
|
|
9
|
-
"routes": [
|
|
10
|
-
|
|
11
|
-
"icon": "MessagesSquare",
|
|
12
|
-
"url": "/chat",
|
|
13
|
-
"name": "Chat",
|
|
14
|
-
"path": "src/routes/chat.tsx",
|
|
15
|
-
"jsName": "ChatPage"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
"integrations": [
|
|
19
|
-
{
|
|
20
|
-
"type": "header-user",
|
|
21
|
-
"path": "src/components/AIAssistant.tsx",
|
|
22
|
-
"jsName": "AIAssistant"
|
|
23
|
-
}
|
|
24
|
-
],
|
|
9
|
+
"routes": [{"icon": "MessagesSquare", "url": "/chat", "name": "Chat", "path": "src/routes/chat.tsx", "jsName": "ChatPage"}],
|
|
10
|
+
"integrations": [{"type": "header-user", "path": "src/components/AIAssistant.tsx", "jsName": "AIAssistant"}],
|
|
25
11
|
"dependsOn": [],
|
|
26
|
-
"variables": []
|
|
12
|
+
"variables": [],
|
|
13
|
+
"packageFileDescriptions": {
|
|
14
|
+
"src/lib/ai-hook.ts": "useAIChat hook: useChat with fetchServerSentEvents connection to /api/chat.",
|
|
15
|
+
"src/routes/chat.tsx": "Chat page route (/chat): Weather Chat UI with messages, input form, send/stop.",
|
|
16
|
+
"src/routes/api.chat.ts": "POST handler for /api/chat: multi-provider AI (Anthropic, OpenAI, Gemini, Ollama) with getWeather tool and SSE streaming.",
|
|
17
|
+
"src/lib/weather-tools.ts": "TanStack AI getWeather tool definition; server returns mock temperature, condition, humidity for a city.",
|
|
18
|
+
"src/routes/chat.css": "Chat page styles: prose/markdown, scrollbar, message animations.",
|
|
19
|
+
"src/components/AIAssistant.tsx": "Pop-up AI assistant component for header; toggleable chat panel with useAIChat."
|
|
20
|
+
}
|
|
27
21
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
### Netlify DB Integration
|
|
2
|
+
|
|
3
|
+
Guestbook demo powered by Netlify DB (Neon Postgres) with Drizzle ORM.
|
|
4
|
+
|
|
5
|
+
**Setup:**
|
|
6
|
+
1. Link project: `netlify login` then `netlify init`
|
|
7
|
+
2. Provision database: `netlify db init` (creates Neon Postgres, sets `DATABASE_URL`)
|
|
8
|
+
3. Push schema: `npx drizzle-kit push` (creates `guestbook` table from `src/db/schema.ts`)
|
|
9
|
+
4. Run locally: `netlify dev` (visit `/db-example`)
|
|
10
|
+
|
|
11
|
+
**Key files:**
|
|
12
|
+
- `src/db/schema.ts` - Guestbook table (id, name, message, createdAt)
|
|
13
|
+
- `src/server/guestbook.functions.ts` - Server functions: `getEntries`, `addEntry`
|
|
14
|
+
- `drizzle.config.ts` - Drizzle Kit config for migrations
|
|
15
|
+
|
|
16
|
+
**Dependencies:** drizzle-orm, @neondatabase/serverless, drizzle-kit
|
|
17
|
+
|
|
18
|
+
## Environment Variables
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
DATABASE_URL=... # Auto-set by netlify db init; pull with netlify env:pull
|
|
22
|
+
```
|
package/add-ons/db/info.json
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
"modes": ["file-router"],
|
|
7
7
|
"type": "add-on",
|
|
8
8
|
"priority": 20,
|
|
9
|
-
"routes": [
|
|
10
|
-
{
|
|
11
|
-
"icon": "Database",
|
|
12
|
-
"url": "/db-example",
|
|
13
|
-
"name": "DB Example",
|
|
14
|
-
"path": "src/routes/db-example.tsx",
|
|
15
|
-
"jsName": "DBExample"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
9
|
+
"routes": [{"icon": "Database", "url": "/db-example", "name": "DB Example", "path": "src/routes/db-example.tsx", "jsName": "DBExample"}],
|
|
18
10
|
"integrations": [],
|
|
19
11
|
"dependsOn": [],
|
|
20
|
-
"variables": []
|
|
12
|
+
"variables": [],
|
|
13
|
+
"packageFileDescriptions": {
|
|
14
|
+
"DB-SETUP.md": "Setup guide: link to Netlify, run netlify db init, configure DATABASE_URL.",
|
|
15
|
+
"src/routes/db-example.tsx": "Guestbook route (/db-example): form to add entries, list from getEntries/addEntry.",
|
|
16
|
+
"src/server/guestbook.functions.ts": "Server functions: getEntries (list), addEntry (create) for guestbook via Drizzle.",
|
|
17
|
+
"src/db/index.ts": "Drizzle + Neon client; exports db and schema.",
|
|
18
|
+
"src/db/schema.ts": "Guestbook table schema: id, name, message, createdAt.",
|
|
19
|
+
"drizzle.config.ts": "Drizzle Kit config for migrations; postgres, schema path, DATABASE_URL."
|
|
20
|
+
}
|
|
21
21
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### Netlify Forms Integration
|
|
2
|
+
|
|
3
|
+
Signup form powered by Netlify Forms with honeypot spam protection. No server-side code required.
|
|
4
|
+
|
|
5
|
+
**How it works:**
|
|
6
|
+
- Form submissions are handled by Netlify at build/deploy
|
|
7
|
+
- Add `data-netlify="true"` to the form
|
|
8
|
+
- Spam protection: `netlify-honeypot="bot-field"` + hidden input with `name="bot-field"`
|
|
9
|
+
- `public/form-example.html` declares the form (hidden) so Netlify detects it during build
|
|
10
|
+
|
|
11
|
+
**Route:** `/form-example` - Signup form (name, email)
|
|
12
|
+
|
|
13
|
+
No environment variables required. Works after deploy to Netlify.
|
package/add-ons/forms/info.json
CHANGED
|
@@ -6,16 +6,12 @@
|
|
|
6
6
|
"modes": ["file-router"],
|
|
7
7
|
"type": "add-on",
|
|
8
8
|
"priority": 20,
|
|
9
|
-
"routes": [
|
|
10
|
-
{
|
|
11
|
-
"icon": "FormInput",
|
|
12
|
-
"url": "/form-example",
|
|
13
|
-
"name": "Form Example",
|
|
14
|
-
"path": "src/routes/form-example.tsx",
|
|
15
|
-
"jsName": "FormExample"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
9
|
+
"routes": [{"icon": "FormInput", "url": "/form-example", "name": "Form Example", "path": "src/routes/form-example.tsx", "jsName": "FormExample"}],
|
|
18
10
|
"integrations": [],
|
|
19
11
|
"dependsOn": [],
|
|
20
|
-
"variables": []
|
|
12
|
+
"variables": [],
|
|
13
|
+
"packageFileDescriptions": {
|
|
14
|
+
"src/routes/form-example.tsx": "Form example route (/form-example): Netlify Forms signup with honeypot spam protection.",
|
|
15
|
+
"public/form-example.html": "Static HTML form declaration for Netlify Forms; name, email, bot-field."
|
|
16
|
+
}
|
|
21
17
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { dirname, join, relative } from 'node:path';
|
|
2
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const PLACEHOLDER = '[[[DIRECTORY STRUCTURE]]]';
|
|
5
|
+
const IGNORED_DIRS = new Set([
|
|
6
|
+
'node_modules',
|
|
7
|
+
'.git',
|
|
8
|
+
'dist',
|
|
9
|
+
'dist-ssr',
|
|
10
|
+
'.netlify',
|
|
11
|
+
'.tanstack',
|
|
12
|
+
'.DS_Store',
|
|
13
|
+
]);
|
|
14
|
+
function buildDescriptionLookup(descriptions) {
|
|
15
|
+
const lookup = new Map();
|
|
16
|
+
for (const [key, desc] of Object.entries(descriptions)) {
|
|
17
|
+
const normalizedKey = key.replace(/\\/g, '/');
|
|
18
|
+
lookup.set(normalizedKey, desc);
|
|
19
|
+
if (normalizedKey.endsWith('.ejs')) {
|
|
20
|
+
lookup.set(normalizedKey.slice(0, -4), desc);
|
|
21
|
+
}
|
|
22
|
+
if (normalizedKey.startsWith('_dot_')) {
|
|
23
|
+
lookup.set('.' + normalizedKey.slice(5), desc);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return lookup;
|
|
27
|
+
}
|
|
28
|
+
async function loadFileDescriptions(addOnDescriptions) {
|
|
29
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
30
|
+
const infoPath = join(packageRoot, 'project', 'info.json');
|
|
31
|
+
const lookup = new Map();
|
|
32
|
+
try {
|
|
33
|
+
const info = await readFile(infoPath, 'utf-8');
|
|
34
|
+
const { packageFileDescriptions } = JSON.parse(info);
|
|
35
|
+
if (packageFileDescriptions) {
|
|
36
|
+
for (const [key, desc] of buildDescriptionLookup(packageFileDescriptions)) {
|
|
37
|
+
lookup.set(key, desc);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// No info.json or invalid, continue
|
|
43
|
+
}
|
|
44
|
+
if (addOnDescriptions) {
|
|
45
|
+
for (const addOn of addOnDescriptions) {
|
|
46
|
+
if (addOn.packageFileDescriptions) {
|
|
47
|
+
for (const [key, desc] of buildDescriptionLookup(addOn.packageFileDescriptions)) {
|
|
48
|
+
lookup.set(key, desc);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return lookup;
|
|
54
|
+
}
|
|
55
|
+
async function buildFileTree(dirPath, rootPath, descriptions, prefix = '') {
|
|
56
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
57
|
+
const filtered = entries
|
|
58
|
+
.filter((e) => !e.name.startsWith('.') || e.name === '.gitignore')
|
|
59
|
+
.filter((e) => !IGNORED_DIRS.has(e.name))
|
|
60
|
+
.sort((a, b) => {
|
|
61
|
+
// Directories first, then files; alphabetically within each
|
|
62
|
+
if (a.isDirectory() !== b.isDirectory()) {
|
|
63
|
+
return a.isDirectory() ? -1 : 1;
|
|
64
|
+
}
|
|
65
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
|
|
66
|
+
});
|
|
67
|
+
const lines = [];
|
|
68
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
69
|
+
const entry = filtered[i];
|
|
70
|
+
const isLastEntry = i === filtered.length - 1;
|
|
71
|
+
const connector = isLastEntry ? '└── ' : '├── ';
|
|
72
|
+
const fullPath = join(dirPath, entry.name);
|
|
73
|
+
const relPath = relative(rootPath, fullPath).replace(/\\/g, '/');
|
|
74
|
+
const description = descriptions.get(relPath);
|
|
75
|
+
const suffix = description ? ` # ${description}` : '';
|
|
76
|
+
lines.push(`${prefix}${connector}${entry.name}${suffix}`);
|
|
77
|
+
if (entry.isDirectory()) {
|
|
78
|
+
const childPrefix = prefix + (isLastEntry ? ' ' : '│ ');
|
|
79
|
+
const childLines = await buildFileTree(join(dirPath, entry.name), rootPath, descriptions, childPrefix);
|
|
80
|
+
lines.push(...childLines);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return lines;
|
|
84
|
+
}
|
|
85
|
+
export async function generateAgentsMd(targetDir, _projectName, chosenAddOns) {
|
|
86
|
+
const agentsMdPath = join(targetDir, 'AGENTS.md');
|
|
87
|
+
let content;
|
|
88
|
+
try {
|
|
89
|
+
content = await readFile(agentsMdPath, 'utf-8');
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// No AGENTS.md template, skip
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!content.includes(PLACEHOLDER)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const descriptions = await loadFileDescriptions(chosenAddOns);
|
|
99
|
+
const treeLines = await buildFileTree(targetDir, targetDir, descriptions);
|
|
100
|
+
const tree = treeLines.length > 0 ? treeLines.join('\n') : '(empty)';
|
|
101
|
+
const updatedContent = content.replace(PLACEHOLDER, tree);
|
|
102
|
+
await writeFile(agentsMdPath, updatedContent, 'utf-8');
|
|
103
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Command, InvalidArgumentError } from 'commander';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import validatePackageName from 'validate-npm-package-name';
|
|
6
6
|
import { SUPPORTED_PACKAGE_MANAGERS, createApp, createDefaultEnvironment, finalizeAddOns, getAllAddOns, getFrameworkByName, getPackageManager, DEFAULT_PACKAGE_MANAGER, populateAddOnOptionsDefaults, } from '@tanstack/cta-engine';
|
|
7
|
+
import { generateAgentsMd } from './agents-md.js';
|
|
7
8
|
// Utility functions
|
|
8
9
|
function sanitizePackageName(name) {
|
|
9
10
|
return name
|
|
@@ -248,6 +249,8 @@ export function cli({ name, appName, defaultFramework, forcedMode, forcedAddOns
|
|
|
248
249
|
}
|
|
249
250
|
}
|
|
250
251
|
}
|
|
252
|
+
// Generate an AGENTS.md file in the root of the project
|
|
253
|
+
await generateAgentsMd(targetDir, resolvedProjectName, chosenAddOns);
|
|
251
254
|
});
|
|
252
255
|
program.parse();
|
|
253
256
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
### AI Integration
|
|
2
|
+
|
|
3
|
+
Multi-provider AI chat with fallback chain:
|
|
4
|
+
|
|
5
|
+
1. Anthropic Claude (preferred)
|
|
6
|
+
2. OpenAI GPT-4o
|
|
7
|
+
3. Google Gemini
|
|
8
|
+
4. Ollama (local)
|
|
9
|
+
|
|
10
|
+
**Tools available to AI:**
|
|
11
|
+
- `getWeather` - Get the current weather for a city. Returns temperature, condition, and humidity.
|
|
12
|
+
|
|
13
|
+
## Environment Variables
|
|
14
|
+
|
|
15
|
+
For AI functionality, set one or more:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
ANTHROPIC_API_KEY=...
|
|
19
|
+
OPENAI_API_KEY=...
|
|
20
|
+
GOOGLE_GENERATIVE_AI_API_KEY=...
|
|
21
|
+
OLLAMA_BASE_URL=...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The application uses the first available provider in the fallback chain.
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
"priority": 10,
|
|
8
8
|
"link": "",
|
|
9
9
|
"routes": [
|
|
10
|
-
{
|
|
11
|
-
|
|
12
|
-
"path": "src/routes/index.tsx",
|
|
13
|
-
"jsName": "Home"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"url": "/api/chat",
|
|
17
|
-
"path": "src/routes/api.chat.ts",
|
|
18
|
-
"jsName": "ChatAPI"
|
|
19
|
-
}
|
|
10
|
+
{"url": "/", "path": "src/routes/index.tsx", "jsName": "Home"},
|
|
11
|
+
{"url": "/api/chat", "path": "src/routes/api.chat.ts", "jsName": "ChatAPI"}
|
|
20
12
|
],
|
|
21
13
|
"integrations": [],
|
|
22
14
|
"dependsOn": [],
|
|
23
|
-
"variables": []
|
|
15
|
+
"variables": [],
|
|
16
|
+
"packageFileDescriptions": {
|
|
17
|
+
"src/styles.css": "Global styles: Tailwind, highlight.js theme, custom scrollbar, prose/markdown styles for chat UI.",
|
|
18
|
+
"src/lib/weather-tools.ts": "TanStack AI tool definition for getWeather; server implementation returns mock temperature, condition, humidity for a city.",
|
|
19
|
+
"src/lib/ai-hook.ts": "useAIChat hook: useChat with fetchServerSentEvents connection to /api/chat.",
|
|
20
|
+
"src/routes/api.chat.ts": "POST handler for /api/chat: multi-provider AI (Anthropic, OpenAI, Gemini, Ollama) with getWeather tool and SSE streaming.",
|
|
21
|
+
"src/routes/index.tsx": "Home route: Weather Chat UI with messages list, input form, send/stop, Streamdown markdown rendering.",
|
|
22
|
+
"src/routes/__root.tsx": "Root layout: HTML shell, Weather Chat header, styles, TanStack Devtools."
|
|
23
|
+
}
|
|
24
24
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
### Content Collections
|
|
2
|
+
|
|
3
|
+
Markdown files in `content/posts/` are type-safe blog posts:
|
|
4
|
+
|
|
5
|
+
- Frontmatter validated against Zod schemas in `content-collections.ts`
|
|
6
|
+
- Imported as typed array: `import { allPosts } from 'content-collections'`
|
|
7
|
+
- Each post has: `title`, `summary`, `categories[]`, `slug`, `image`, `date`, `content`
|
|
8
|
+
|
|
9
|
+
### VacayAssistant AI Integration
|
|
10
|
+
|
|
11
|
+
**Tools available to AI:**
|
|
12
|
+
- `getCurrentBlogPost` - Get full content and metadata of the current blog post by slug
|
|
13
|
+
- `getAllBlogPosts` - List all posts with titles, summaries, categories
|
|
14
|
+
- `searchBlogPosts` - Search posts by title, summary, or categories
|
|
15
|
+
|
|
16
|
+
## Environment Variables
|
|
17
|
+
|
|
18
|
+
For AI: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OLLAMA_BASE_URL (same as ai add-on).
|
package/examples/blog/info.json
CHANGED
|
@@ -7,37 +7,33 @@
|
|
|
7
7
|
"priority": 10,
|
|
8
8
|
"link": "",
|
|
9
9
|
"routes": [
|
|
10
|
-
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"jsName": "BlogHome"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"url": "/posts/$slug",
|
|
17
|
-
"path": "src/routes/posts.$slug.tsx",
|
|
18
|
-
"jsName": "BlogPost"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"url": "/category/$category",
|
|
22
|
-
"path": "src/routes/category.$category.tsx",
|
|
23
|
-
"jsName": "BlogCategory"
|
|
24
|
-
}
|
|
25
|
-
],
|
|
26
|
-
"integrations": [
|
|
27
|
-
{
|
|
28
|
-
"type": "vite-plugin",
|
|
29
|
-
"import": "import contentCollections from '@content-collections/vite'",
|
|
30
|
-
"code": "contentCollections()"
|
|
31
|
-
}
|
|
10
|
+
{"url": "/", "path": "src/routes/index.tsx", "jsName": "BlogHome"},
|
|
11
|
+
{"url": "/posts/$slug", "path": "src/routes/posts.$slug.tsx", "jsName": "BlogPost"},
|
|
12
|
+
{"url": "/category/$category", "path": "src/routes/category.$category.tsx", "jsName": "BlogCategory"}
|
|
32
13
|
],
|
|
14
|
+
"integrations": [{"type": "vite-plugin", "import": "import contentCollections from '@content-collections/vite'", "code": "contentCollections()"}],
|
|
33
15
|
"dependsOn": [],
|
|
34
16
|
"variables": [],
|
|
35
|
-
"bareBones": {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
"bareBones": {"deleteFiles": ["public/jungle.jpg", "public/mountains.jpg", "public/snorkeling.jpg", "public/waterfall.jpg"]},
|
|
18
|
+
"packageFileDescriptions": {
|
|
19
|
+
"content-collections.ts": "Content Collections config: posts schema (title, summary, categories, slug, image, date).",
|
|
20
|
+
"content/posts/beach.md": "Blog post: beach adventure.",
|
|
21
|
+
"content/posts/jungle.md.ejs": "Blog post template: jungle adventure.",
|
|
22
|
+
"content/posts/mountains.md.ejs": "Blog post template: mountains adventure.",
|
|
23
|
+
"content/posts/snorkeling.md.ejs": "Blog post template: snorkeling adventure.",
|
|
24
|
+
"content/posts/waterfall.md.ejs": "Blog post template: waterfall adventure.",
|
|
25
|
+
"src/styles.css": "Global styles: Tailwind, prose, highlight.js.",
|
|
26
|
+
"src/routes/index.tsx": "Blog home: post list, VacayAssistant.",
|
|
27
|
+
"src/routes/posts.$slug.tsx": "Post detail route: single post by slug.",
|
|
28
|
+
"src/routes/category.$category.tsx": "Category route: posts filtered by category.",
|
|
29
|
+
"src/routes/api.blog-chat.ts": "POST handler for blog AI chat with getPostBySlug, getAllBlogPosts tools.",
|
|
30
|
+
"src/routes/__root.tsx": "Root layout: Header, styles, TanStack Devtools.",
|
|
31
|
+
"src/lib/utils.ts": "cn() helper for conditional Tailwind class merging.",
|
|
32
|
+
"src/lib/blog-tools.ts": "AI tools: getPostBySlug, getAllBlogPosts, getPostsByCategory for VacayAssistant.",
|
|
33
|
+
"src/lib/blog-ai-hook.ts": "useBlogChat hook for /api/blog-chat.",
|
|
34
|
+
"src/components/ui/card.tsx": "Card UI component.",
|
|
35
|
+
"src/components/blog-posts.tsx": "Blog post list/card display component.",
|
|
36
|
+
"src/components/VacayAssistant.tsx": "AI assistant for blog Q&A.",
|
|
37
|
+
"src/components/Header.tsx": "Site header with nav."
|
|
42
38
|
}
|
|
43
39
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
### Calculator Component
|
|
2
|
+
|
|
3
|
+
iOS-style calculator built with React `useReducer` for state management.
|
|
4
|
+
|
|
5
|
+
**State pattern:** `display`, `previousValue`, `operation`, `overwrite`
|
|
6
|
+
|
|
7
|
+
**Actions:** ADD_DIGIT, CHOOSE_OPERATION, EVALUATE, CLEAR, DELETE_DIGIT, PERCENT, TOGGLE_SIGN
|
|
8
|
+
|
|
9
|
+
No special dependencies beyond base TanStack Start. Pure React + Tailwind CSS.
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
"type": "example",
|
|
7
7
|
"priority": 10,
|
|
8
8
|
"link": "",
|
|
9
|
-
"routes": [
|
|
10
|
-
{
|
|
11
|
-
"url": "/",
|
|
12
|
-
"path": "src/routes/index.tsx",
|
|
13
|
-
"jsName": "Home"
|
|
14
|
-
}
|
|
15
|
-
],
|
|
9
|
+
"routes": [{"url": "/", "path": "src/routes/index.tsx", "jsName": "Home"}],
|
|
16
10
|
"integrations": [],
|
|
17
11
|
"dependsOn": [],
|
|
18
|
-
"variables": []
|
|
12
|
+
"variables": [],
|
|
13
|
+
"packageFileDescriptions": {
|
|
14
|
+
"src/routes/index.tsx": "Home route: renders Calculator component.",
|
|
15
|
+
"src/routes/__root.tsx": "Root layout: HTML shell, styles.",
|
|
16
|
+
"src/components/Calculator.tsx": "iOS-style calculator: digits, operations, evaluate, clear, percent.",
|
|
17
|
+
"src/components/Header.tsx": "Header component."
|
|
18
|
+
}
|
|
19
19
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
### Chart.js Dashboard
|
|
2
|
+
|
|
3
|
+
Analytics dashboard with Chart.js and react-chartjs-2.
|
|
4
|
+
|
|
5
|
+
**Dependencies:** chart.js, react-chartjs-2
|
|
6
|
+
|
|
7
|
+
**Chart types:**
|
|
8
|
+
- Bar - Revenue by month
|
|
9
|
+
- Line - User growth
|
|
10
|
+
- Doughnut - Sales by category
|
|
11
|
+
|
|
12
|
+
**Setup:** Register Chart.js components before use (CategoryScale, LinearScale, BarElement, LineElement, PointElement, ArcElement, Title, Tooltip, Legend, Filler).
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
"type": "example",
|
|
7
7
|
"priority": 10,
|
|
8
8
|
"link": "",
|
|
9
|
-
"routes": [
|
|
10
|
-
{
|
|
11
|
-
"url": "/",
|
|
12
|
-
"path": "src/routes/index.tsx",
|
|
13
|
-
"jsName": "Home"
|
|
14
|
-
}
|
|
15
|
-
],
|
|
9
|
+
"routes": [{"url": "/", "path": "src/routes/index.tsx", "jsName": "Home"}],
|
|
16
10
|
"integrations": [],
|
|
17
11
|
"dependsOn": [],
|
|
18
|
-
"variables": []
|
|
12
|
+
"variables": [],
|
|
13
|
+
"packageFileDescriptions": {
|
|
14
|
+
"src/routes/index.tsx": "Dashboard home: Bar, Line, Doughnut charts (revenue, users, sales).",
|
|
15
|
+
"src/routes/__root.tsx": "Root layout: Header, styles.",
|
|
16
|
+
"src/components/Header.tsx": "Header component."
|
|
17
|
+
}
|
|
19
18
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
### Ecommerce Integration
|
|
2
|
+
|
|
3
|
+
Motorcycle ecommerce site with Stripe checkout and AI shopping assistant.
|
|
4
|
+
|
|
5
|
+
**Stripe checkout:**
|
|
6
|
+
- `createCheckoutSession` server function in `src/lib/stripe.server.ts`
|
|
7
|
+
- BuyButton component redirects to Stripe Checkout
|
|
8
|
+
- Routes: `/checkout/success`, `/checkout/cancel`
|
|
9
|
+
|
|
10
|
+
**AI tools available:**
|
|
11
|
+
- `getMotorcycles` - Get all motorcycles from catalog
|
|
12
|
+
- `recommendMotorcycle` - Display motorcycle recommendation card (MUST use for recommendations; do not write recommendations manually)
|
|
13
|
+
|
|
14
|
+
**Dependencies:** stripe, @tanstack/ai, streamdown
|
|
15
|
+
|
|
16
|
+
## Environment Variables
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
STRIPE_SECRET_KEY=... # Required for checkout
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For AI assistant: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OLLAMA_BASE_URL (same as ai add-on).
|
|
@@ -7,34 +7,31 @@
|
|
|
7
7
|
"priority": 10,
|
|
8
8
|
"link": "",
|
|
9
9
|
"routes": [
|
|
10
|
-
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"url": "/motorcycles/$motorcycleId",
|
|
18
|
-
"path": "src/routes/motorcycles/$motorcycleId.tsx",
|
|
19
|
-
"jsName": "MotorcycleDetail"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"url": "/checkout/success",
|
|
23
|
-
"path": "src/routes/checkout/success.tsx",
|
|
24
|
-
"jsName": "CheckoutSuccess"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"url": "/checkout/cancel",
|
|
28
|
-
"path": "src/routes/checkout/cancel.tsx",
|
|
29
|
-
"jsName": "CheckoutCancel"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"url": "/api/motorcycle-chat",
|
|
33
|
-
"path": "src/routes/api.motorcycle-chat.ts",
|
|
34
|
-
"jsName": "MotorcycleChatAPI"
|
|
35
|
-
}
|
|
10
|
+
{"url": "/", "name": "Home", "path": "src/routes/index.tsx", "jsName": "MotorcyclesIndex"},
|
|
11
|
+
{"url": "/motorcycles/$motorcycleId", "path": "src/routes/motorcycles/$motorcycleId.tsx", "jsName": "MotorcycleDetail"},
|
|
12
|
+
{"url": "/checkout/success", "path": "src/routes/checkout/success.tsx", "jsName": "CheckoutSuccess"},
|
|
13
|
+
{"url": "/checkout/cancel", "path": "src/routes/checkout/cancel.tsx", "jsName": "CheckoutCancel"},
|
|
14
|
+
{"url": "/api/motorcycle-chat", "path": "src/routes/api.motorcycle-chat.ts", "jsName": "MotorcycleChatAPI"}
|
|
36
15
|
],
|
|
37
16
|
"integrations": [],
|
|
38
17
|
"dependsOn": [],
|
|
39
|
-
"variables": []
|
|
18
|
+
"variables": [],
|
|
19
|
+
"packageFileDescriptions": {
|
|
20
|
+
"src/routes/index.tsx": "Motorcycle catalog home with MotorcycleAIAssistant.",
|
|
21
|
+
"src/routes/motorcycles/$motorcycleId.tsx": "Motorcycle detail page with BuyButton, recommendation.",
|
|
22
|
+
"src/routes/checkout/success.tsx": "Stripe checkout success page.",
|
|
23
|
+
"src/routes/checkout/cancel.tsx": "Stripe checkout cancel page.",
|
|
24
|
+
"src/routes/api.motorcycle-chat.ts": "POST handler for motorcycle AI chat with getMotorcycles, recommendMotorcycle tools.",
|
|
25
|
+
"src/routes/__root.tsx": "Root layout: Header, styles.",
|
|
26
|
+
"src/styles.css": "Global styles: Tailwind, prose.",
|
|
27
|
+
"src/data/motorcycles.ts": "Motorcycle catalog data.",
|
|
28
|
+
"src/lib/motorcycle-tools.ts": "AI tools: getMotorcycles, recommendMotorcycle.",
|
|
29
|
+
"src/lib/motorcycle-ai-hook.ts": "useMotorcycleChat hook for /api/motorcycle-chat.",
|
|
30
|
+
"src/lib/stripe.server.ts": "Stripe server utilities for checkout.",
|
|
31
|
+
"src/store/motorcycle-assistant.ts": "Zustand store for assistant open state.",
|
|
32
|
+
"src/components/Header.tsx": "Header with nav.",
|
|
33
|
+
"src/components/MotorcycleAIAssistant.tsx": "AI shopping assistant component.",
|
|
34
|
+
"src/components/MotorcycleRecommendation.tsx": "Motorcycle recommendation card display.",
|
|
35
|
+
"src/components/BuyButton.tsx": "Stripe checkout button component."
|
|
36
|
+
}
|
|
40
37
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
### Conference Site Integration
|
|
2
|
+
|
|
3
|
+
Pastry conference website with Content Collections (speakers, talks) and Remy AI assistant.
|
|
4
|
+
|
|
5
|
+
**Content Collections:**
|
|
6
|
+
- `speakers` - name, title, specialty, restaurant, headshot, awards
|
|
7
|
+
- `talks` - title, speaker, duration, topics, image
|
|
8
|
+
- Schemas in `content-collections.ts`
|
|
9
|
+
|
|
10
|
+
**AI tools available (RemyAssistant):**
|
|
11
|
+
- `getSpeakerBySlug` - Get speaker profile by slug
|
|
12
|
+
- `getTalkBySlug` - Get talk details by slug
|
|
13
|
+
- `getAllSpeakers` - List all speakers
|
|
14
|
+
- `getAllTalks` - List all talks
|
|
15
|
+
- `getSchedule` - Get full schedule
|
|
16
|
+
|
|
17
|
+
**Components:** HeroCarousel (background images), RemyAssistant (conference Q&A)
|
|
18
|
+
|
|
19
|
+
## Environment Variables
|
|
20
|
+
|
|
21
|
+
For AI: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, or OLLAMA_BASE_URL (same as ai add-on).
|