@tellet/create 0.8.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/README.md +195 -0
- package/dist/ai/generate.d.ts +33 -0
- package/dist/ai/generate.js +108 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +337 -0
- package/dist/scaffold/project.d.ts +44 -0
- package/dist/scaffold/project.js +318 -0
- package/package.json +48 -0
- package/template/Dockerfile +35 -0
- package/template/app/(dashboard)/agents/page.tsx +14 -0
- package/template/app/(dashboard)/conversations/[id]/page.tsx +103 -0
- package/template/app/(dashboard)/conversations/page.tsx +50 -0
- package/template/app/(dashboard)/dashboard/page.tsx +102 -0
- package/template/app/(dashboard)/layout.tsx +15 -0
- package/template/app/(dashboard)/settings/page.tsx +46 -0
- package/template/app/(site)/layout.tsx +3 -0
- package/template/app/(site)/page.tsx +25 -0
- package/template/app/api/chat/route.ts +129 -0
- package/template/app/api/cron/route.ts +29 -0
- package/template/app/api/orchestrator/route.ts +139 -0
- package/template/app/globals.css +30 -0
- package/template/app/layout.tsx +18 -0
- package/template/components/chat/ChatWidget.tsx +109 -0
- package/template/components/chat/Markdown.tsx +136 -0
- package/template/components/dashboard/AgentChat.tsx +192 -0
- package/template/components/dashboard/AgentsListClient.tsx +86 -0
- package/template/components/dashboard/DashboardAgentGrid.tsx +73 -0
- package/template/components/dashboard/OrchestratorChat.tsx +251 -0
- package/template/components/dashboard/Sidebar.tsx +44 -0
- package/template/components/dashboard/StatsCards.tsx +40 -0
- package/template/components/dashboard/Welcome.tsx +139 -0
- package/template/components/sections/Agents.tsx +67 -0
- package/template/components/sections/CTA.tsx +46 -0
- package/template/components/sections/FAQ.tsx +81 -0
- package/template/components/sections/Features.tsx +51 -0
- package/template/components/sections/Footer.tsx +22 -0
- package/template/components/sections/Hero.tsx +86 -0
- package/template/components/sections/Icons.tsx +29 -0
- package/template/components/ui/Button.tsx +26 -0
- package/template/docker-compose.yml +32 -0
- package/template/infra/bin/app.ts +16 -0
- package/template/infra/cdk.json +6 -0
- package/template/infra/lib/tellet-stack.ts +216 -0
- package/template/infra/package.json +20 -0
- package/template/infra/tsconfig.json +16 -0
- package/template/lib/db.ts +37 -0
- package/template/lib/engine/default.ts +227 -0
- package/template/lib/engine/index.ts +17 -0
- package/template/lib/mcp/client.ts +97 -0
- package/template/lib/mcp/knowledge.ts +84 -0
- package/template/lib/mcp/registry.ts +106 -0
- package/template/lib/orchestrator/executor.ts +202 -0
- package/template/lib/orchestrator/tools.ts +245 -0
- package/template/lib/providers/anthropic.ts +41 -0
- package/template/lib/providers/index.ts +36 -0
- package/template/lib/providers/openai.ts +46 -0
- package/template/lib/scheduler.ts +115 -0
- package/template/lib/supabase.ts +30 -0
- package/template/lib/tellet.ts +45 -0
- package/template/lib/utils.ts +6 -0
- package/template/next.config.ts +7 -0
- package/template/public/widget.js +172 -0
- package/template/railway.toml +9 -0
- package/template/tsconfig.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# @tellet/create
|
|
2
|
+
|
|
3
|
+
> The open-source platform for running an Agentic Company.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @tellet/create
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
tellet is a management platform for AI-powered companies. One command generates your AI agent team, website, dashboard, Knowledge Base, and Orchestrator — ready to deploy anywhere.
|
|
10
|
+
|
|
11
|
+
## What you get
|
|
12
|
+
|
|
13
|
+
- **AI Agent Team** — 3-5 agents auto-generated for your business (CS, marketing, sales, ops)
|
|
14
|
+
- **Orchestrator** — Manage your entire company through conversation
|
|
15
|
+
- **Knowledge Base** — pgvector-powered, agents reference it for accurate answers
|
|
16
|
+
- **Dashboard** — Stats, agent chat, conversations, onboarding
|
|
17
|
+
- **Tool Marketplace** — Stripe, Email, GitHub, Slack, Notion via MCP
|
|
18
|
+
- **Embeddable Widget** — One script tag to add AI chat to any website
|
|
19
|
+
- **3-Tier Deployment** — Free (Vercel) / Cloud (Railway) / Enterprise (AWS)
|
|
20
|
+
|
|
21
|
+
## How it works
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npx @tellet/create
|
|
25
|
+
|
|
26
|
+
? New or Connect? → New business or add AI to existing
|
|
27
|
+
? Deployment? → Quick Start / Cloud / Enterprise
|
|
28
|
+
? AI Provider? → Anthropic / OpenAI
|
|
29
|
+
? Company name? → Sunny Coffee
|
|
30
|
+
? Describe your business → We sell specialty coffee...
|
|
31
|
+
|
|
32
|
+
Generating your AI team and website...
|
|
33
|
+
|
|
34
|
+
Your team:
|
|
35
|
+
Barista (customer_support)
|
|
36
|
+
Roaster (marketing)
|
|
37
|
+
Grinder (sales)
|
|
38
|
+
|
|
39
|
+
Your website:
|
|
40
|
+
"Coffee worth waking up for"
|
|
41
|
+
|
|
42
|
+
✓ Project created!
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick start
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Quick Start (Vercel + Supabase, free)
|
|
49
|
+
npx @tellet/create
|
|
50
|
+
cd your-company
|
|
51
|
+
npm install && npm run dev
|
|
52
|
+
|
|
53
|
+
# Cloud (Docker + Railway, $5/mo)
|
|
54
|
+
npx @tellet/create # choose "Cloud"
|
|
55
|
+
cd your-company
|
|
56
|
+
docker compose up # local dev
|
|
57
|
+
railway up # deploy
|
|
58
|
+
|
|
59
|
+
# Enterprise (AWS CDK, $5-15/mo)
|
|
60
|
+
npx @tellet/create # choose "Enterprise"
|
|
61
|
+
cd your-company/infra
|
|
62
|
+
npm install && npx cdk deploy
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Architecture
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
┌─ tellet Platform ─────────────────────────┐
|
|
69
|
+
│ Owner ↔ Orchestrator │
|
|
70
|
+
│ ↕ │
|
|
71
|
+
│ Agent Team (CS · Marketing · Sales · Ops) │
|
|
72
|
+
│ ↕ │
|
|
73
|
+
│ MCP Bridge Layer │
|
|
74
|
+
│ (KB, Stripe, DB, Email, Custom API...) │
|
|
75
|
+
└────────────────────────────────────────────┘
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Project structure
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
your-company/
|
|
82
|
+
├── agents/ # AI agent definitions (auto-generated)
|
|
83
|
+
├── app/
|
|
84
|
+
│ ├── (site)/ # Public website with chat widget
|
|
85
|
+
│ ├── (dashboard)/ # Management dashboard + Orchestrator
|
|
86
|
+
│ └── api/
|
|
87
|
+
│ ├── chat/ # Streaming chat API (tool use)
|
|
88
|
+
│ ├── orchestrator/ # Orchestrator API (tool use loop)
|
|
89
|
+
│ └── cron/ # Scheduled agent tasks
|
|
90
|
+
├── components/
|
|
91
|
+
│ ├── chat/ # ChatWidget, Markdown
|
|
92
|
+
│ ├── dashboard/ # Sidebar, Stats, AgentChat, Orchestrator
|
|
93
|
+
│ └── sections/ # Landing page sections
|
|
94
|
+
├── lib/
|
|
95
|
+
│ ├── engine/ # Agent runtime with tool use agentic loop
|
|
96
|
+
│ ├── providers/ # LLM providers (Anthropic, OpenAI)
|
|
97
|
+
│ ├── mcp/ # MCP client, Knowledge Base, tool registry
|
|
98
|
+
│ ├── orchestrator/ # Orchestrator tools + executor
|
|
99
|
+
│ └── scheduler.ts # Cron/heartbeat agent scheduler
|
|
100
|
+
├── public/widget.js # Embeddable chat widget
|
|
101
|
+
├── tellet.json # Configuration (single source of truth)
|
|
102
|
+
├── Dockerfile # Docker deployment (Cloud/Enterprise)
|
|
103
|
+
├── docker-compose.yml # Local dev with PostgreSQL + pgvector
|
|
104
|
+
├── railway.toml # Railway auto-deploy
|
|
105
|
+
└── infra/ # AWS CDK (Enterprise only)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Orchestrator
|
|
109
|
+
|
|
110
|
+
The Orchestrator is your AI company manager. Talk to it from the dashboard:
|
|
111
|
+
|
|
112
|
+
- "Show my stats" — conversations, messages, costs
|
|
113
|
+
- "Update the website tagline" — modifies site content
|
|
114
|
+
- "Add Stripe to my agents" — installs tools from marketplace
|
|
115
|
+
- "Schedule marketing to post daily at 9am" — sets up cron tasks
|
|
116
|
+
- "Add our refund policy to the Knowledge Base" — agents reference it
|
|
117
|
+
|
|
118
|
+
## Tool Marketplace
|
|
119
|
+
|
|
120
|
+
Connect tools via the Orchestrator or `tellet.json`:
|
|
121
|
+
|
|
122
|
+
| Tool | Package | Use case |
|
|
123
|
+
|------|---------|----------|
|
|
124
|
+
| Stripe | `@stripe/mcp` | Payments, invoices, subscriptions |
|
|
125
|
+
| Email | `resend-mcp` | Send emails, campaigns |
|
|
126
|
+
| GitHub | `@modelcontextprotocol/server-github` | Issues, PRs, repos |
|
|
127
|
+
| Slack | `@anthropic-ai/mcp-server-slack` | Messages, channels |
|
|
128
|
+
| Notion | `@anthropic-ai/mcp-server-notion` | Docs, databases |
|
|
129
|
+
|
|
130
|
+
19,000+ MCP servers available via the [MCP Registry](https://registry.modelcontextprotocol.io/).
|
|
131
|
+
|
|
132
|
+
## Deployment options
|
|
133
|
+
|
|
134
|
+
| Tier | Provider | Cost | Best for |
|
|
135
|
+
|------|----------|------|----------|
|
|
136
|
+
| Quick Start | Vercel + Supabase | $0 | Prototyping, new business |
|
|
137
|
+
| Cloud | Railway / Render / Fly.io | $5-20/mo | Production, startups |
|
|
138
|
+
| Enterprise | AWS CDK (Lambda + RDS) | $5-15/mo | Scale, existing AWS |
|
|
139
|
+
|
|
140
|
+
## Connect mode
|
|
141
|
+
|
|
142
|
+
Already have a business? Use Connect mode:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npx @tellet/create # choose "Connect"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- Skips site generation, keeps dashboard + API
|
|
149
|
+
- Embeddable widget for your existing site:
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<script src="https://your-tellet.com/widget.js"
|
|
153
|
+
data-agent="support"
|
|
154
|
+
data-api="https://your-tellet.com"></script>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Configuration
|
|
158
|
+
|
|
159
|
+
All configuration lives in `tellet.json`:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"company": { "name": "Sunny Coffee", "industry": "Food & Beverage" },
|
|
164
|
+
"mode": "new",
|
|
165
|
+
"llm": { "provider": "anthropic", "defaultModel": "claude-sonnet-4-6" },
|
|
166
|
+
"agents": [
|
|
167
|
+
{ "id": "barista", "role": "customer_support", "tools": ["search_knowledge"] },
|
|
168
|
+
{ "id": "roaster", "role": "marketing", "tools": ["email"] }
|
|
169
|
+
],
|
|
170
|
+
"tools": {
|
|
171
|
+
"search_knowledge": { "type": "builtin" },
|
|
172
|
+
"email": { "type": "mcp", "package": "resend-mcp" }
|
|
173
|
+
},
|
|
174
|
+
"site": { "tagline": "Coffee worth waking up for", "..." : "..." }
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Tech stack
|
|
179
|
+
|
|
180
|
+
- [Next.js 16](https://nextjs.org/) — App framework
|
|
181
|
+
- [PostgreSQL + pgvector](https://github.com/pgvector/pgvector) — Database + vector search
|
|
182
|
+
- [MCP](https://modelcontextprotocol.io/) — Tool integration protocol
|
|
183
|
+
- [Anthropic Claude](https://anthropic.com/) / [OpenAI](https://openai.com/) — AI models
|
|
184
|
+
- [Tailwind CSS 4](https://tailwindcss.com/) — Styling
|
|
185
|
+
- [Framer Motion](https://www.framer.com/motion/) — Animations
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|
|
190
|
+
|
|
191
|
+
## Links
|
|
192
|
+
|
|
193
|
+
- [tellet.com](https://tellet.com) — Website
|
|
194
|
+
- [GitHub](https://github.com/agentic-company/create-tellet) — Source code
|
|
195
|
+
- [npm](https://www.npmjs.com/package/@tellet/create) — Package
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type Provider = "anthropic" | "openai";
|
|
2
|
+
interface GeneratedAgent {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
role: string;
|
|
6
|
+
description: string;
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
model: string;
|
|
9
|
+
}
|
|
10
|
+
interface SiteFeature {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
}
|
|
15
|
+
interface SiteFAQ {
|
|
16
|
+
question: string;
|
|
17
|
+
answer: string;
|
|
18
|
+
}
|
|
19
|
+
interface SiteContent {
|
|
20
|
+
tagline: string;
|
|
21
|
+
subtitle: string;
|
|
22
|
+
features: SiteFeature[];
|
|
23
|
+
faq: SiteFAQ[];
|
|
24
|
+
cta: string;
|
|
25
|
+
}
|
|
26
|
+
export interface GenerateResult {
|
|
27
|
+
industry: string;
|
|
28
|
+
summary: string;
|
|
29
|
+
agents: GeneratedAgent[];
|
|
30
|
+
site: SiteContent;
|
|
31
|
+
}
|
|
32
|
+
export declare function generateAgents(companyName: string, businessDescription: string, provider?: Provider): Promise<GenerateResult>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import OpenAI from "openai";
|
|
3
|
+
function buildSystemPrompt(provider) {
|
|
4
|
+
const modelExamples = provider === "anthropic"
|
|
5
|
+
? 'use "claude-haiku-4-5" for high-volume simple tasks (CS), "claude-sonnet-4-6" for creative/complex tasks (marketing, sales)'
|
|
6
|
+
: 'use "gpt-4.1-mini" for high-volume simple tasks (CS), "gpt-4.1" for creative/complex tasks (marketing, sales)';
|
|
7
|
+
return `You are an AI company architect. Given a business description, generate a team of AI agents AND website content tailored for that specific business.
|
|
8
|
+
|
|
9
|
+
Rules for AGENTS:
|
|
10
|
+
1. Generate 3-5 agents appropriate for the business
|
|
11
|
+
2. Always include a customer_support agent
|
|
12
|
+
3. Each agent needs a unique, memorable name related to the business theme
|
|
13
|
+
4. Each system_prompt must be detailed (200+ words) and specific to THIS business — include the company name, products, customer demographics, tone of voice
|
|
14
|
+
5. Assign appropriate models: ${modelExamples}
|
|
15
|
+
6. The id should be lowercase, no spaces
|
|
16
|
+
|
|
17
|
+
Rules for SITE CONTENT:
|
|
18
|
+
1. tagline: a punchy one-liner (max 8 words) that captures the business value
|
|
19
|
+
2. subtitle: 1-2 sentences expanding on the tagline, mentioning who the business serves
|
|
20
|
+
3. features: 4-6 business features/benefits (NOT technical features). Each needs a title (3-5 words), description (1 sentence), and icon (one of: sparkles, shield, zap, heart, globe, chart, clock, users, star, target)
|
|
21
|
+
4. faq: 4-5 frequently asked questions a customer would ask, with concise answers
|
|
22
|
+
5. cta: a short call-to-action phrase (e.g. "Start your journey today")
|
|
23
|
+
|
|
24
|
+
Output ONLY valid JSON matching this schema:
|
|
25
|
+
{
|
|
26
|
+
"industry": "string",
|
|
27
|
+
"summary": "string — one-line business summary",
|
|
28
|
+
"agents": [
|
|
29
|
+
{
|
|
30
|
+
"id": "string",
|
|
31
|
+
"name": "string",
|
|
32
|
+
"role": "string — one of: customer_support, marketing, sales, operations, development, analytics",
|
|
33
|
+
"description": "string — one sentence",
|
|
34
|
+
"systemPrompt": "string — detailed system prompt",
|
|
35
|
+
"model": "string"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"site": {
|
|
39
|
+
"tagline": "string",
|
|
40
|
+
"subtitle": "string",
|
|
41
|
+
"features": [
|
|
42
|
+
{ "title": "string", "description": "string", "icon": "string" }
|
|
43
|
+
],
|
|
44
|
+
"faq": [
|
|
45
|
+
{ "question": "string", "answer": "string" }
|
|
46
|
+
],
|
|
47
|
+
"cta": "string"
|
|
48
|
+
}
|
|
49
|
+
}`;
|
|
50
|
+
}
|
|
51
|
+
async function generateWithAnthropic(companyName, businessDescription) {
|
|
52
|
+
const client = new Anthropic();
|
|
53
|
+
const message = await client.messages.create({
|
|
54
|
+
model: "claude-sonnet-4-6",
|
|
55
|
+
max_tokens: 8192,
|
|
56
|
+
system: buildSystemPrompt("anthropic"),
|
|
57
|
+
messages: [
|
|
58
|
+
{
|
|
59
|
+
role: "user",
|
|
60
|
+
content: `Company: ${companyName}\n\nBusiness Description: ${businessDescription}`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
return message.content[0].type === "text" ? message.content[0].text : "";
|
|
65
|
+
}
|
|
66
|
+
async function generateWithOpenAI(companyName, businessDescription) {
|
|
67
|
+
const client = new OpenAI();
|
|
68
|
+
const response = await client.chat.completions.create({
|
|
69
|
+
model: "gpt-4.1",
|
|
70
|
+
max_tokens: 8192,
|
|
71
|
+
messages: [
|
|
72
|
+
{ role: "system", content: buildSystemPrompt("openai") },
|
|
73
|
+
{
|
|
74
|
+
role: "user",
|
|
75
|
+
content: `Company: ${companyName}\n\nBusiness Description: ${businessDescription}`,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
return response.choices[0]?.message?.content || "";
|
|
80
|
+
}
|
|
81
|
+
export async function generateAgents(companyName, businessDescription, provider = "anthropic") {
|
|
82
|
+
const text = provider === "openai"
|
|
83
|
+
? await generateWithOpenAI(companyName, businessDescription)
|
|
84
|
+
: await generateWithAnthropic(companyName, businessDescription);
|
|
85
|
+
// Extract JSON from response (handle markdown code blocks)
|
|
86
|
+
const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/) || [null, text];
|
|
87
|
+
const jsonStr = (jsonMatch[1] || text).trim();
|
|
88
|
+
try {
|
|
89
|
+
const result = JSON.parse(jsonStr);
|
|
90
|
+
if (!result.agents || result.agents.length === 0) {
|
|
91
|
+
throw new Error("No agents generated");
|
|
92
|
+
}
|
|
93
|
+
// Ensure site content exists with defaults
|
|
94
|
+
if (!result.site) {
|
|
95
|
+
result.site = {
|
|
96
|
+
tagline: `${companyName} — Powered by AI`,
|
|
97
|
+
subtitle: result.summary || businessDescription,
|
|
98
|
+
features: [],
|
|
99
|
+
faq: [],
|
|
100
|
+
cta: "Get started today",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
throw new Error("Failed to parse AI response. Please try again.");
|
|
107
|
+
}
|
|
108
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { generateAgents } from "./ai/generate.js";
|
|
5
|
+
import { scaffoldProject } from "./scaffold/project.js";
|
|
6
|
+
async function main() {
|
|
7
|
+
console.clear();
|
|
8
|
+
console.log();
|
|
9
|
+
console.log(chalk.bold(` ${chalk.white("tel")}${chalk.yellow("let")} ${chalk.dim("— Build Your AI Company")}`));
|
|
10
|
+
console.log();
|
|
11
|
+
p.intro(chalk.bgHex("#8b5cf6").white(" @tellet/create "));
|
|
12
|
+
// Step 0: New or Connect
|
|
13
|
+
const modeChoice = await p.select({
|
|
14
|
+
message: "What would you like to do?",
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
value: "new",
|
|
18
|
+
label: "New",
|
|
19
|
+
hint: "Build a new AI company from scratch",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: "connect",
|
|
23
|
+
label: "Connect",
|
|
24
|
+
hint: "Add AI agents to your existing business",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
if (p.isCancel(modeChoice)) {
|
|
29
|
+
p.cancel("Setup cancelled.");
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
const mode = modeChoice;
|
|
33
|
+
// Step 1: Company info
|
|
34
|
+
const company = await p.group({
|
|
35
|
+
name: () => p.text({
|
|
36
|
+
message: "What's your company name?",
|
|
37
|
+
placeholder: "Sunny Coffee",
|
|
38
|
+
validate: (v) => (!v ? "Company name is required" : undefined),
|
|
39
|
+
}),
|
|
40
|
+
description: () => p.text({
|
|
41
|
+
message: "Describe your business (what you do, who your customers are, what help you need):",
|
|
42
|
+
placeholder: "We sell specialty coffee subscriptions. Customers are coffee enthusiasts aged 25-45...",
|
|
43
|
+
validate: (v) => !v || v.length < 20
|
|
44
|
+
? "Please provide at least a few sentences"
|
|
45
|
+
: undefined,
|
|
46
|
+
}),
|
|
47
|
+
}, {
|
|
48
|
+
onCancel: () => {
|
|
49
|
+
p.cancel("Setup cancelled.");
|
|
50
|
+
process.exit(0);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
// Step 2: Deployment tier
|
|
54
|
+
const tierChoice = await p.select({
|
|
55
|
+
message: "Deployment mode:",
|
|
56
|
+
options: [
|
|
57
|
+
{
|
|
58
|
+
value: "quickstart",
|
|
59
|
+
label: "Quick Start",
|
|
60
|
+
hint: "Vercel + Supabase — free, instant deploy",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: "cloud",
|
|
64
|
+
label: "Cloud",
|
|
65
|
+
hint: "Railway / Render / Fly.io — Docker, $5-20/mo",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
value: "enterprise",
|
|
69
|
+
label: "Enterprise",
|
|
70
|
+
hint: "AWS CDK — auto-provision Lambda + RDS + CloudFront",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
if (p.isCancel(tierChoice)) {
|
|
75
|
+
p.cancel("Setup cancelled.");
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
const tier = tierChoice;
|
|
79
|
+
// Step 3: Choose AI provider
|
|
80
|
+
const providerChoice = await p.select({
|
|
81
|
+
message: "Choose your AI provider:",
|
|
82
|
+
options: [
|
|
83
|
+
{
|
|
84
|
+
value: "anthropic",
|
|
85
|
+
label: "Anthropic (Claude)",
|
|
86
|
+
hint: "recommended — also powers the Orchestrator",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
value: "openai",
|
|
90
|
+
label: "OpenAI (GPT)",
|
|
91
|
+
hint: "uses gpt-4.1 for generation",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
if (p.isCancel(providerChoice)) {
|
|
96
|
+
p.cancel("Setup cancelled.");
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
const provider = providerChoice;
|
|
100
|
+
// Step 4: Get API key
|
|
101
|
+
const envKey = provider === "anthropic"
|
|
102
|
+
? process.env.ANTHROPIC_API_KEY
|
|
103
|
+
: process.env.OPENAI_API_KEY;
|
|
104
|
+
const envName = provider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
|
|
105
|
+
const keyPrefix = provider === "anthropic" ? "sk-ant-" : "sk-";
|
|
106
|
+
const keyPlaceholder = provider === "anthropic" ? "sk-ant-..." : "sk-...";
|
|
107
|
+
let apiKey = envKey || "";
|
|
108
|
+
if (!apiKey) {
|
|
109
|
+
const keyInput = await p.text({
|
|
110
|
+
message: `Your ${provider === "anthropic" ? "Anthropic" : "OpenAI"} API key:`,
|
|
111
|
+
placeholder: keyPlaceholder,
|
|
112
|
+
validate: (v) => !v || !v.startsWith(keyPrefix)
|
|
113
|
+
? `Please enter a valid key (starts with ${keyPrefix})`
|
|
114
|
+
: undefined,
|
|
115
|
+
});
|
|
116
|
+
if (p.isCancel(keyInput)) {
|
|
117
|
+
p.cancel("Setup cancelled.");
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
apiKey = keyInput;
|
|
121
|
+
process.env[envName] = apiKey;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
p.log.info(chalk.dim(`Using ${envName} from environment.`));
|
|
125
|
+
}
|
|
126
|
+
// Orchestrator always needs Anthropic
|
|
127
|
+
let anthropicKey = "";
|
|
128
|
+
if (provider === "anthropic") {
|
|
129
|
+
anthropicKey = apiKey;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const existingKey = process.env.ANTHROPIC_API_KEY || "";
|
|
133
|
+
if (existingKey) {
|
|
134
|
+
anthropicKey = existingKey;
|
|
135
|
+
p.log.info(chalk.dim("Using ANTHROPIC_API_KEY for Orchestrator."));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
p.log.info(chalk.dim("The Orchestrator requires an Anthropic API key (Claude tool use)."));
|
|
139
|
+
const orchKeyInput = await p.text({
|
|
140
|
+
message: "Anthropic API key for Orchestrator:",
|
|
141
|
+
placeholder: "sk-ant-...",
|
|
142
|
+
validate: (v) => !v || !v.startsWith("sk-ant-")
|
|
143
|
+
? "Please enter a valid Anthropic key (starts with sk-ant-)"
|
|
144
|
+
: undefined,
|
|
145
|
+
});
|
|
146
|
+
if (p.isCancel(orchKeyInput)) {
|
|
147
|
+
p.cancel("Setup cancelled.");
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
anthropicKey = orchKeyInput;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Step 5: Generate agents + site content
|
|
154
|
+
const s = p.spinner();
|
|
155
|
+
s.start("Generating your AI team and website...");
|
|
156
|
+
let agents;
|
|
157
|
+
try {
|
|
158
|
+
agents = await generateAgents(company.name, company.description, provider);
|
|
159
|
+
s.stop("Your AI team is ready!");
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
s.stop("Failed to generate agents.");
|
|
163
|
+
p.log.error(err instanceof Error ? err.message : "Check your API key");
|
|
164
|
+
p.cancel("Setup failed.");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
// Step 6: Show agents + site preview
|
|
168
|
+
p.log.info(chalk.bold("Meet your team:"));
|
|
169
|
+
console.log();
|
|
170
|
+
for (const agent of agents.agents) {
|
|
171
|
+
console.log(` ${chalk.hex("#8b5cf6").bold(agent.name)} ${chalk.dim(`(${agent.role})`)}`);
|
|
172
|
+
console.log(` ${chalk.dim(agent.description)}`);
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
if (agents.site && mode === "new") {
|
|
176
|
+
p.log.info(chalk.bold("Your website:"));
|
|
177
|
+
console.log(` ${chalk.hex("#f59e0b")(agents.site.tagline)}`);
|
|
178
|
+
console.log(` ${chalk.dim(agents.site.subtitle)}`);
|
|
179
|
+
console.log();
|
|
180
|
+
}
|
|
181
|
+
const confirm = await p.confirm({
|
|
182
|
+
message: "Looks good?",
|
|
183
|
+
initialValue: true,
|
|
184
|
+
});
|
|
185
|
+
if (p.isCancel(confirm) || !confirm) {
|
|
186
|
+
p.cancel("Setup cancelled.");
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
// Step 7a: Connect mode — website URL for KB
|
|
190
|
+
let websiteUrl = "";
|
|
191
|
+
if (mode === "connect") {
|
|
192
|
+
const urlInput = await p.text({
|
|
193
|
+
message: "Your existing website URL (for Knowledge Base crawling):",
|
|
194
|
+
placeholder: "https://my-business.com",
|
|
195
|
+
});
|
|
196
|
+
if (!p.isCancel(urlInput) && urlInput) {
|
|
197
|
+
websiteUrl = urlInput;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Step 7b: Infrastructure setup (tier-dependent)
|
|
201
|
+
let supabaseUrl = "";
|
|
202
|
+
let supabaseKey = "";
|
|
203
|
+
if (tier === "quickstart") {
|
|
204
|
+
p.log.info(`${chalk.bold("Supabase setup")} ${chalk.dim("(free tier works fine)")}\n` +
|
|
205
|
+
` ${chalk.dim("1.")} Create a project at ${chalk.cyan("https://supabase.com/dashboard/new")}\n` +
|
|
206
|
+
` ${chalk.dim("2.")} Go to Settings → API to find your URL and keys`);
|
|
207
|
+
const supabase = await p.group({
|
|
208
|
+
url: () => p.text({
|
|
209
|
+
message: "Your Supabase project URL:",
|
|
210
|
+
placeholder: "https://xxx.supabase.co",
|
|
211
|
+
validate: (v) => !v || !v.includes("supabase")
|
|
212
|
+
? "Please enter a valid Supabase URL"
|
|
213
|
+
: undefined,
|
|
214
|
+
}),
|
|
215
|
+
key: () => p.text({
|
|
216
|
+
message: "Your Supabase publishable key (anon/public):",
|
|
217
|
+
placeholder: "sb_publishable_...",
|
|
218
|
+
validate: (v) => (!v ? "Key is required" : undefined),
|
|
219
|
+
}),
|
|
220
|
+
}, {
|
|
221
|
+
onCancel: () => {
|
|
222
|
+
p.cancel("Setup cancelled.");
|
|
223
|
+
process.exit(0);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
supabaseUrl = supabase.url;
|
|
227
|
+
supabaseKey = supabase.key;
|
|
228
|
+
}
|
|
229
|
+
else if (tier === "cloud") {
|
|
230
|
+
p.log.info(chalk.dim("Cloud mode: PostgreSQL runs in Docker. No Supabase needed."));
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
p.log.info(`${chalk.bold("AWS Enterprise setup")}\n` +
|
|
234
|
+
` ${chalk.dim("Requires:")} AWS CLI configured + CDK bootstrapped\n` +
|
|
235
|
+
` ${chalk.dim("Cost:")} ~$5-15/mo (Lambda + RDS free tier)`);
|
|
236
|
+
}
|
|
237
|
+
// Step 8: Scaffold project
|
|
238
|
+
s.start("Creating your project...");
|
|
239
|
+
try {
|
|
240
|
+
const projectDir = await scaffoldProject({
|
|
241
|
+
company: {
|
|
242
|
+
name: company.name,
|
|
243
|
+
description: company.description,
|
|
244
|
+
industry: agents.industry,
|
|
245
|
+
},
|
|
246
|
+
agents: agents.agents,
|
|
247
|
+
site: agents.site,
|
|
248
|
+
provider,
|
|
249
|
+
tier,
|
|
250
|
+
mode,
|
|
251
|
+
websiteUrl,
|
|
252
|
+
infra: {
|
|
253
|
+
anthropicKey,
|
|
254
|
+
openaiKey: provider === "openai" ? apiKey : undefined,
|
|
255
|
+
supabaseUrl,
|
|
256
|
+
supabaseKey,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
s.stop("Project created!");
|
|
260
|
+
const slug = company.name
|
|
261
|
+
.toLowerCase()
|
|
262
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
263
|
+
.replace(/^-|-$/g, "");
|
|
264
|
+
const widgetSnippet = mode === "connect"
|
|
265
|
+
? [
|
|
266
|
+
``,
|
|
267
|
+
`${chalk.bold("Embed in your existing site:")}`,
|
|
268
|
+
`${chalk.cyan('<script src="https://YOUR_URL/widget.js"')}`,
|
|
269
|
+
`${chalk.cyan(' data-agent="' + agents.agents[0].id + '"')}`,
|
|
270
|
+
`${chalk.cyan(' data-api="https://YOUR_URL"></script>')}`,
|
|
271
|
+
]
|
|
272
|
+
: [];
|
|
273
|
+
if (tier === "quickstart") {
|
|
274
|
+
p.note([
|
|
275
|
+
`cd ${slug}`,
|
|
276
|
+
`npm install`,
|
|
277
|
+
`npm run dev ${chalk.dim("→ http://localhost:3000")}`,
|
|
278
|
+
``,
|
|
279
|
+
`Dashboard: ${chalk.dim("/dashboard")}`,
|
|
280
|
+
`Orchestrator: ${chalk.dim("floating button in dashboard")}`,
|
|
281
|
+
`Agents: ${chalk.dim(`${agents.agents.length} active`)}`,
|
|
282
|
+
...widgetSnippet,
|
|
283
|
+
].join("\n"), mode === "connect" ? "Your AI agents are ready" : "Your AI company is ready");
|
|
284
|
+
p.outro(`Deploy: ${chalk.cyan("vercel deploy")}`);
|
|
285
|
+
}
|
|
286
|
+
else if (tier === "cloud") {
|
|
287
|
+
p.note([
|
|
288
|
+
`cd ${slug}`,
|
|
289
|
+
``,
|
|
290
|
+
`${chalk.bold("Local development:")}`,
|
|
291
|
+
`docker compose up ${chalk.dim("→ http://localhost:3000")}`,
|
|
292
|
+
``,
|
|
293
|
+
`${chalk.bold("Deploy to Railway:")}`,
|
|
294
|
+
`railway login`,
|
|
295
|
+
`railway init`,
|
|
296
|
+
`railway add --plugin postgresql`,
|
|
297
|
+
`railway up`,
|
|
298
|
+
``,
|
|
299
|
+
`Dashboard: ${chalk.dim("/dashboard")}`,
|
|
300
|
+
`Orchestrator: ${chalk.dim("floating button in dashboard")}`,
|
|
301
|
+
`Agents: ${chalk.dim(`${agents.agents.length} active`)}`,
|
|
302
|
+
].join("\n"), "Your AI company is ready");
|
|
303
|
+
p.outro(`Or deploy to ${chalk.cyan("Render")}, ${chalk.cyan("Fly.io")}, or any Docker host`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
p.note([
|
|
307
|
+
`cd ${slug}`,
|
|
308
|
+
``,
|
|
309
|
+
`${chalk.bold("Local development:")}`,
|
|
310
|
+
`docker compose up ${chalk.dim("→ http://localhost:3000")}`,
|
|
311
|
+
``,
|
|
312
|
+
`${chalk.bold("Deploy to AWS:")}`,
|
|
313
|
+
`cd infra`,
|
|
314
|
+
`npm install`,
|
|
315
|
+
`npx cdk bootstrap ${chalk.dim("(first time only)")}`,
|
|
316
|
+
`npx cdk deploy ${chalk.dim("→ CloudFront URL in output")}`,
|
|
317
|
+
``,
|
|
318
|
+
`${chalk.bold("Update API keys:")}`,
|
|
319
|
+
`aws secretsmanager put-secret-value \\`,
|
|
320
|
+
` --secret-id ${slug}/api-keys \\`,
|
|
321
|
+
` --secret-string '{"ANTHROPIC_API_KEY":"sk-ant-..."}'`,
|
|
322
|
+
``,
|
|
323
|
+
`Dashboard: ${chalk.dim("/dashboard")}`,
|
|
324
|
+
`Orchestrator: ${chalk.dim("floating button in dashboard")}`,
|
|
325
|
+
`Agents: ${chalk.dim(`${agents.agents.length} active`)}`,
|
|
326
|
+
`Est. cost: ${chalk.dim("$5-15/mo")}`,
|
|
327
|
+
].join("\n"), "Your AI company is ready (AWS)");
|
|
328
|
+
p.outro(`Run ${chalk.cyan("cd infra && npx cdk deploy")} to provision AWS infrastructure`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
s.stop("Failed to create project.");
|
|
333
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
main().catch(console.error);
|