@tellet/create 0.9.0 → 0.12.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 +151 -135
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +54 -0
- package/dist/commands/agent.d.ts +1 -0
- package/dist/commands/agent.js +156 -0
- package/dist/commands/build.d.ts +1 -0
- package/dist/commands/build.js +14 -0
- package/dist/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.js +117 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +15 -0
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/mcp.js +4 -0
- package/dist/commands/shared.d.ts +69 -0
- package/dist/commands/shared.js +73 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +53 -0
- package/dist/index.js +8 -336
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +25 -0
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +264 -0
- package/dist/scaffold/project.js +1 -1
- package/dist/scaffold-flow.d.ts +1 -0
- package/dist/scaffold-flow.js +402 -0
- package/dist/setup/deps.d.ts +4 -0
- package/dist/setup/deps.js +24 -0
- package/dist/setup/env.d.ts +12 -0
- package/dist/setup/env.js +26 -0
- package/dist/setup/supabase.d.ts +36 -0
- package/dist/setup/supabase.js +207 -0
- package/package.json +5 -4
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
/** Check if the Supabase CLI is installed and accessible. */
|
|
5
|
+
export function hasSupabaseCLI() {
|
|
6
|
+
try {
|
|
7
|
+
execFileSync("supabase", ["--version"], { stdio: "ignore" });
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Check if Docker is running (required for `supabase start`). */
|
|
15
|
+
export function hasDocker() {
|
|
16
|
+
try {
|
|
17
|
+
execFileSync("docker", ["info"], { stdio: "ignore", timeout: 5000 });
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse `supabase status` output to extract local dev credentials.
|
|
26
|
+
* The output format is like:
|
|
27
|
+
* API URL: http://127.0.0.1:54321
|
|
28
|
+
* anon key: eyJ...
|
|
29
|
+
* service_role key: eyJ...
|
|
30
|
+
*/
|
|
31
|
+
function parseSupabaseStatus(output) {
|
|
32
|
+
const urlMatch = output.match(/API URL:\s*(http\S+)/);
|
|
33
|
+
const anonMatch = output.match(/anon key:\s*(\S+)/);
|
|
34
|
+
const serviceMatch = output.match(/service_role key:\s*(\S+)/);
|
|
35
|
+
if (!urlMatch || !anonMatch)
|
|
36
|
+
return null;
|
|
37
|
+
return {
|
|
38
|
+
url: urlMatch[1],
|
|
39
|
+
anonKey: anonMatch[1],
|
|
40
|
+
serviceRoleKey: serviceMatch?.[1],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Run supabase CLI command in a directory, returning stdout.
|
|
45
|
+
*/
|
|
46
|
+
function runSupabase(args, cwd) {
|
|
47
|
+
return execFileSync("supabase", args, {
|
|
48
|
+
cwd,
|
|
49
|
+
encoding: "utf-8",
|
|
50
|
+
timeout: 120_000,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run supabase CLI with live stdio (visible to user).
|
|
55
|
+
* Returns the exit code.
|
|
56
|
+
*/
|
|
57
|
+
function runSupabaseLive(args, cwd) {
|
|
58
|
+
const result = spawnSync("supabase", args, {
|
|
59
|
+
cwd,
|
|
60
|
+
stdio: "inherit",
|
|
61
|
+
timeout: 300_000,
|
|
62
|
+
});
|
|
63
|
+
return result.status ?? 1;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Initialize Supabase in the project directory.
|
|
67
|
+
* Creates supabase/config.toml if not already present.
|
|
68
|
+
*/
|
|
69
|
+
export function supabaseInit(projectDir) {
|
|
70
|
+
try {
|
|
71
|
+
runSupabase(["init", "--with-intellij-settings=false", "--with-vscode-settings=false"], projectDir);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Start local Supabase (Docker containers).
|
|
80
|
+
* Returns credentials on success, null on failure.
|
|
81
|
+
*/
|
|
82
|
+
export async function supabaseStartLocal(projectDir) {
|
|
83
|
+
p.log.info(chalk.dim("Starting local Supabase (this may take a minute on first run)..."));
|
|
84
|
+
const code = runSupabaseLive(["start"], projectDir);
|
|
85
|
+
if (code !== 0) {
|
|
86
|
+
p.log.error("Failed to start local Supabase.");
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
p.log.success("Local Supabase is running!");
|
|
90
|
+
// Extract credentials from status
|
|
91
|
+
try {
|
|
92
|
+
const output = runSupabase(["status"], projectDir);
|
|
93
|
+
return parseSupabaseStatus(output);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Link to a remote Supabase project.
|
|
101
|
+
* Prompts for project ref, runs `supabase link`.
|
|
102
|
+
*/
|
|
103
|
+
export async function supabaseLinkRemote(projectDir) {
|
|
104
|
+
const refInput = await p.text({
|
|
105
|
+
message: "Supabase project ref (from Dashboard → Settings → General):",
|
|
106
|
+
placeholder: "abcdefghijklmnopqrst",
|
|
107
|
+
validate: (v) => !v || v.length < 10
|
|
108
|
+
? "Please enter a valid project ref"
|
|
109
|
+
: undefined,
|
|
110
|
+
});
|
|
111
|
+
if (p.isCancel(refInput))
|
|
112
|
+
return false;
|
|
113
|
+
p.log.info(chalk.dim("Linking to Supabase project (follow the prompts below)..."));
|
|
114
|
+
const code = runSupabaseLive(["link", "--project-ref", refInput], projectDir);
|
|
115
|
+
if (code !== 0) {
|
|
116
|
+
p.log.error("Failed to link project.");
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
p.log.success("Linked to Supabase project!");
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Push migrations to the database.
|
|
124
|
+
*/
|
|
125
|
+
export async function supabasePushMigrations(projectDir) {
|
|
126
|
+
p.log.info(chalk.dim("Applying database migrations..."));
|
|
127
|
+
const code = runSupabaseLive(["db", "push"], projectDir);
|
|
128
|
+
if (code !== 0) {
|
|
129
|
+
p.log.error("Migration push failed.");
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
p.log.success("Migrations applied!");
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Full Supabase setup flow for quickstart tier.
|
|
137
|
+
* Returns credentials or null if user chose manual setup.
|
|
138
|
+
*/
|
|
139
|
+
export async function setupSupabase(projectDir) {
|
|
140
|
+
const cliAvailable = hasSupabaseCLI();
|
|
141
|
+
const dockerAvailable = hasDocker();
|
|
142
|
+
if (!cliAvailable) {
|
|
143
|
+
p.log.info(chalk.dim("Supabase CLI not found. Install it for automated setup:\n" +
|
|
144
|
+
" brew install supabase/tap/supabase\n" +
|
|
145
|
+
" — or —\n" +
|
|
146
|
+
" npx supabase --version"));
|
|
147
|
+
return { credentials: null, method: "manual" };
|
|
148
|
+
}
|
|
149
|
+
// Build options based on what's available
|
|
150
|
+
const options = [];
|
|
151
|
+
if (dockerAvailable) {
|
|
152
|
+
options.push({
|
|
153
|
+
value: "local",
|
|
154
|
+
label: "Local development",
|
|
155
|
+
hint: "supabase start — runs Postgres + Auth locally via Docker",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
options.push({
|
|
159
|
+
value: "remote",
|
|
160
|
+
label: "Remote project",
|
|
161
|
+
hint: "Link to an existing Supabase project",
|
|
162
|
+
}, {
|
|
163
|
+
value: "manual",
|
|
164
|
+
label: "Manual setup",
|
|
165
|
+
hint: "I'll enter the URL and key myself",
|
|
166
|
+
});
|
|
167
|
+
if (!dockerAvailable) {
|
|
168
|
+
p.log.info(chalk.dim("Docker not detected — local Supabase requires Docker Desktop."));
|
|
169
|
+
}
|
|
170
|
+
const choice = await p.select({
|
|
171
|
+
message: "Supabase setup:",
|
|
172
|
+
options,
|
|
173
|
+
});
|
|
174
|
+
if (p.isCancel(choice)) {
|
|
175
|
+
return { credentials: null, method: "manual" };
|
|
176
|
+
}
|
|
177
|
+
const method = choice;
|
|
178
|
+
if (method === "manual") {
|
|
179
|
+
return { credentials: null, method: "manual" };
|
|
180
|
+
}
|
|
181
|
+
// Initialize supabase in project
|
|
182
|
+
const inited = supabaseInit(projectDir);
|
|
183
|
+
if (!inited) {
|
|
184
|
+
p.log.error("Failed to initialize Supabase in the project directory.");
|
|
185
|
+
return { credentials: null, method: "manual" };
|
|
186
|
+
}
|
|
187
|
+
if (method === "local") {
|
|
188
|
+
const creds = await supabaseStartLocal(projectDir);
|
|
189
|
+
if (creds) {
|
|
190
|
+
// Apply migrations to local DB
|
|
191
|
+
await supabasePushMigrations(projectDir);
|
|
192
|
+
}
|
|
193
|
+
return { credentials: creds, method: "local" };
|
|
194
|
+
}
|
|
195
|
+
// Remote
|
|
196
|
+
const linked = await supabaseLinkRemote(projectDir);
|
|
197
|
+
if (linked) {
|
|
198
|
+
const pushConfirm = await p.confirm({
|
|
199
|
+
message: "Apply database migrations now?",
|
|
200
|
+
initialValue: true,
|
|
201
|
+
});
|
|
202
|
+
if (!p.isCancel(pushConfirm) && pushConfirm) {
|
|
203
|
+
await supabasePushMigrations(projectDir);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { credentials: null, method: "remote" };
|
|
207
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellet/create",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.12.0",
|
|
4
|
+
"description": "AI agents that run your business — create, manage, and deploy. One CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"create
|
|
8
|
-
"
|
|
7
|
+
"create": "dist/index.js",
|
|
8
|
+
"tellet": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@anthropic-ai/sdk": "^0.80.0",
|
|
44
44
|
"@clack/prompts": "^1.1.0",
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
46
|
"chalk": "^5.6.2",
|
|
46
47
|
"fs-extra": "^11.3.4",
|
|
47
48
|
"openai": "^6.32.0"
|