create-better-t-stack 3.11.0-bun-compile-opentui.9db6a48 → 3.11.0-bun-compile-opentui.d1f8ac1
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/package.json +10 -7
- package/src/api.ts +1 -1
- package/src/cli.ts +1 -3
- package/src/helpers/addons/addons-setup.ts +4 -9
- package/src/helpers/addons/fumadocs-setup.ts +18 -50
- package/src/helpers/addons/ruler-setup.ts +42 -55
- package/src/helpers/addons/starlight-setup.ts +1 -2
- package/src/helpers/addons/tauri-setup.ts +1 -2
- package/src/helpers/addons/tui-setup.ts +5 -34
- package/src/helpers/addons/ultracite-setup.ts +19 -120
- package/src/helpers/addons/wxt-setup.ts +5 -42
- package/src/helpers/core/create-project.ts +2 -2
- package/src/helpers/core/db-setup.ts +11 -6
- package/src/helpers/database-providers/mongodb-atlas-setup.ts +31 -65
- package/src/helpers/database-providers/neon-setup.ts +26 -95
- package/src/helpers/database-providers/prisma-postgres-setup.ts +28 -62
- package/src/helpers/database-providers/supabase-setup.ts +22 -47
- package/src/helpers/database-providers/turso-setup.ts +69 -112
- package/src/utils/logger.ts +19 -3
- package/src/utils/project-directory.ts +52 -63
- package/src/utils/sponsors.ts +7 -8
- package/src/helpers/core/command-handlers.ts +0 -354
- package/src/utils/render-title.ts +0 -48
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.11.0-bun-compile-opentui.
|
|
3
|
+
"version": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"better-auth",
|
|
@@ -68,13 +68,16 @@
|
|
|
68
68
|
"prepublishOnly": "echo 'Build binaries separately before publishing'"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@better-t-stack/types": "3.11.0-bun-compile-opentui.
|
|
71
|
+
"@better-t-stack/types": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
72
|
+
"@clack/prompts": "^1.0.0-alpha.8",
|
|
72
73
|
"@opentui/core": "^0.1.62",
|
|
73
74
|
"@opentui/react": "^0.1.62",
|
|
74
75
|
"commander": "^14.0.2",
|
|
76
|
+
"consola": "^3.4.2",
|
|
75
77
|
"fs-extra": "^11.3.3",
|
|
76
78
|
"handlebars": "^4.7.8",
|
|
77
79
|
"jsonc-parser": "^3.3.1",
|
|
80
|
+
"picocolors": "^1.1.1",
|
|
78
81
|
"react": "^19.1.0",
|
|
79
82
|
"tinyglobby": "^0.2.15",
|
|
80
83
|
"ts-morph": "^27.0.2",
|
|
@@ -90,11 +93,11 @@
|
|
|
90
93
|
"typescript": "^5.9.3"
|
|
91
94
|
},
|
|
92
95
|
"optionalDependencies": {
|
|
93
|
-
"@better-t-stack/cli-darwin-arm64": "3.11.0-bun-compile-opentui.
|
|
94
|
-
"@better-t-stack/cli-darwin-x64": "3.11.0-bun-compile-opentui.
|
|
95
|
-
"@better-t-stack/cli-linux-arm64": "3.11.0-bun-compile-opentui.
|
|
96
|
-
"@better-t-stack/cli-linux-x64": "3.11.0-bun-compile-opentui.
|
|
97
|
-
"@better-t-stack/cli-windows-x64": "3.11.0-bun-compile-opentui.
|
|
96
|
+
"@better-t-stack/cli-darwin-arm64": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
97
|
+
"@better-t-stack/cli-darwin-x64": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
98
|
+
"@better-t-stack/cli-linux-arm64": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
99
|
+
"@better-t-stack/cli-linux-x64": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
100
|
+
"@better-t-stack/cli-windows-x64": "3.11.0-bun-compile-opentui.d1f8ac1",
|
|
98
101
|
"@opentui/core-darwin-arm64": "0.1.63",
|
|
99
102
|
"@opentui/core-darwin-x64": "0.1.63",
|
|
100
103
|
"@opentui/core-linux-arm64": "0.1.63",
|
package/src/api.ts
CHANGED
|
@@ -173,7 +173,7 @@ export async function create(options: CreateOptions = {}): Promise<CreateResult>
|
|
|
173
173
|
console.warn = () => {};
|
|
174
174
|
|
|
175
175
|
try {
|
|
176
|
-
await createProject(config
|
|
176
|
+
await createProject(config);
|
|
177
177
|
} finally {
|
|
178
178
|
console.log = originalLog;
|
|
179
179
|
console.info = originalInfo;
|
package/src/cli.ts
CHANGED
|
@@ -86,9 +86,7 @@ program
|
|
|
86
86
|
// Create project in logs panel
|
|
87
87
|
console.log("\nCreating project...\n");
|
|
88
88
|
|
|
89
|
-
await createProject(config
|
|
90
|
-
manualDb: options.manualDb as boolean,
|
|
91
|
-
});
|
|
89
|
+
await createProject(config);
|
|
92
90
|
|
|
93
91
|
const reproducibleCommand = generateReproducibleCommand(config);
|
|
94
92
|
console.log(`\n✓ Project created at: ${config.projectDir}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import fs from "fs-extra";
|
|
3
3
|
import pc from "picocolors";
|
|
4
|
+
import { log } from "../../utils/logger";
|
|
4
5
|
import type { Frontend, ProjectConfig } from "../../types";
|
|
5
6
|
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
6
7
|
import { setupFumadocs } from "./fumadocs-setup";
|
|
@@ -31,15 +32,9 @@ export async function setupAddons(config: ProjectConfig, isAddCommand = false) {
|
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
if (isAddCommand) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
${pc.dim("Replace:")} ${pc.yellow('"pnpm --filter web dev"')} ${pc.dim(
|
|
38
|
-
"→",
|
|
39
|
-
)} ${pc.green('"turbo -F web dev"')}
|
|
40
|
-
|
|
41
|
-
${pc.cyan("Docs:")} ${pc.underline("https://turborepo.com/docs")}
|
|
42
|
-
`);
|
|
35
|
+
log.info(
|
|
36
|
+
`Update your package.json scripts: Replace "pnpm -r dev" → "turbo dev", Replace "pnpm --filter web dev" → "turbo -F web dev". Docs: https://turborepo.com/docs`,
|
|
37
|
+
);
|
|
43
38
|
}
|
|
44
39
|
}
|
|
45
40
|
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { isCancel, log, select, spinner } from "@clack/prompts";
|
|
3
|
-
import consola from "consola";
|
|
4
2
|
import { $ } from "bun";
|
|
5
3
|
import fs from "fs-extra";
|
|
6
4
|
import pc from "picocolors";
|
|
7
5
|
import type { ProjectConfig } from "../../types";
|
|
8
|
-
import { exitCancelled } from "../../utils/errors";
|
|
9
6
|
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
7
|
+
import { log } from "../../utils/logger";
|
|
10
8
|
|
|
11
9
|
type FumadocsTemplate =
|
|
12
10
|
| "next-mdx"
|
|
@@ -15,53 +13,24 @@ type FumadocsTemplate =
|
|
|
15
13
|
| "react-router-spa"
|
|
16
14
|
| "tanstack-start";
|
|
17
15
|
|
|
18
|
-
const
|
|
19
|
-
"next-mdx":
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
label: "React Router: MDX Remote",
|
|
31
|
-
hint: "Template for React Router with MDX remote",
|
|
32
|
-
value: "react-router",
|
|
33
|
-
},
|
|
34
|
-
"react-router-spa": {
|
|
35
|
-
label: "React Router: SPA",
|
|
36
|
-
hint: "Template for React Router SPA",
|
|
37
|
-
value: "react-router-spa",
|
|
38
|
-
},
|
|
39
|
-
"tanstack-start": {
|
|
40
|
-
label: "Tanstack Start: MDX Remote",
|
|
41
|
-
hint: "Template for Tanstack Start with MDX remote",
|
|
42
|
-
value: "tanstack-start",
|
|
43
|
-
},
|
|
44
|
-
} as const;
|
|
45
|
-
|
|
46
|
-
export async function setupFumadocs(config: ProjectConfig) {
|
|
16
|
+
const TEMPLATE_VALUES: Record<FumadocsTemplate, string> = {
|
|
17
|
+
"next-mdx": "+next+fuma-docs-mdx",
|
|
18
|
+
waku: "waku",
|
|
19
|
+
"react-router": "react-router",
|
|
20
|
+
"react-router-spa": "react-router-spa",
|
|
21
|
+
"tanstack-start": "tanstack-start",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export async function setupFumadocs(
|
|
25
|
+
config: ProjectConfig,
|
|
26
|
+
template: FumadocsTemplate = "next-mdx",
|
|
27
|
+
) {
|
|
47
28
|
const { packageManager, projectDir } = config;
|
|
48
29
|
|
|
49
30
|
try {
|
|
50
31
|
log.info("Setting up Fumadocs...");
|
|
51
32
|
|
|
52
|
-
const
|
|
53
|
-
message: "Choose a template",
|
|
54
|
-
options: Object.entries(TEMPLATES).map(([key, template]) => ({
|
|
55
|
-
value: key as FumadocsTemplate,
|
|
56
|
-
label: template.label,
|
|
57
|
-
hint: template.hint,
|
|
58
|
-
})),
|
|
59
|
-
initialValue: "next-mdx",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
63
|
-
|
|
64
|
-
const templateArg = TEMPLATES[template].value;
|
|
33
|
+
const templateArg = TEMPLATE_VALUES[template];
|
|
65
34
|
|
|
66
35
|
const commandWithArgs = `create-fumadocs-app@latest fumadocs --template ${templateArg} --src --pm ${packageManager} --no-git`;
|
|
67
36
|
|
|
@@ -70,8 +39,7 @@ export async function setupFumadocs(config: ProjectConfig) {
|
|
|
70
39
|
const appsDir = path.join(projectDir, "apps");
|
|
71
40
|
await fs.ensureDir(appsDir);
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
s.start("Running Fumadocs create command...");
|
|
42
|
+
log.step("Running Fumadocs create command...");
|
|
75
43
|
|
|
76
44
|
await $`${{ raw: fumadocsInitCommand }}`.cwd(appsDir).env({ CI: "true" });
|
|
77
45
|
|
|
@@ -89,11 +57,11 @@ export async function setupFumadocs(config: ProjectConfig) {
|
|
|
89
57
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
90
58
|
}
|
|
91
59
|
|
|
92
|
-
|
|
60
|
+
log.success("Fumadocs setup complete!");
|
|
93
61
|
} catch (error) {
|
|
94
|
-
log.error(
|
|
62
|
+
log.error("Failed to set up Fumadocs");
|
|
95
63
|
if (error instanceof Error) {
|
|
96
|
-
|
|
64
|
+
log.error(error.message);
|
|
97
65
|
}
|
|
98
66
|
}
|
|
99
67
|
}
|
|
@@ -1,13 +1,43 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { autocompleteMultiselect, isCancel, log, spinner } from "@clack/prompts";
|
|
3
2
|
import { $ } from "bun";
|
|
4
3
|
import fs from "fs-extra";
|
|
5
4
|
import pc from "picocolors";
|
|
6
5
|
import type { ProjectConfig } from "../../types";
|
|
7
|
-
import { exitCancelled } from "../../utils/errors";
|
|
8
6
|
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import { log } from "../../utils/logger";
|
|
8
|
+
|
|
9
|
+
type RulerAgent =
|
|
10
|
+
| "amp"
|
|
11
|
+
| "copilot"
|
|
12
|
+
| "claude"
|
|
13
|
+
| "codex"
|
|
14
|
+
| "cursor"
|
|
15
|
+
| "windsurf"
|
|
16
|
+
| "cline"
|
|
17
|
+
| "aider"
|
|
18
|
+
| "firebase"
|
|
19
|
+
| "gemini-cli"
|
|
20
|
+
| "junie"
|
|
21
|
+
| "kilocode"
|
|
22
|
+
| "opencode"
|
|
23
|
+
| "crush"
|
|
24
|
+
| "zed"
|
|
25
|
+
| "qwen"
|
|
26
|
+
| "amazonqcli"
|
|
27
|
+
| "augmentcode"
|
|
28
|
+
| "firebender"
|
|
29
|
+
| "goose"
|
|
30
|
+
| "jules"
|
|
31
|
+
| "kiro"
|
|
32
|
+
| "openhands"
|
|
33
|
+
| "roo"
|
|
34
|
+
| "trae"
|
|
35
|
+
| "warp";
|
|
36
|
+
|
|
37
|
+
export async function setupRuler(
|
|
38
|
+
config: ProjectConfig,
|
|
39
|
+
agents: RulerAgent[] = ["cursor", "claude"],
|
|
40
|
+
) {
|
|
11
41
|
const { packageManager, projectDir } = config;
|
|
12
42
|
|
|
13
43
|
try {
|
|
@@ -17,54 +47,12 @@ export async function setupRuler(config: ProjectConfig) {
|
|
|
17
47
|
|
|
18
48
|
if (!(await fs.pathExists(rulerDir))) {
|
|
19
49
|
log.error(
|
|
20
|
-
|
|
21
|
-
"Ruler template directory not found. Please ensure ruler addon is properly installed.",
|
|
22
|
-
),
|
|
50
|
+
"Ruler template directory not found. Please ensure ruler addon is properly installed.",
|
|
23
51
|
);
|
|
24
52
|
return;
|
|
25
53
|
}
|
|
26
54
|
|
|
27
|
-
|
|
28
|
-
amp: { label: "AMP" },
|
|
29
|
-
copilot: { label: "GitHub Copilot" },
|
|
30
|
-
claude: { label: "Claude Code" },
|
|
31
|
-
codex: { label: "OpenAI Codex CLI" },
|
|
32
|
-
cursor: { label: "Cursor" },
|
|
33
|
-
windsurf: { label: "Windsurf" },
|
|
34
|
-
cline: { label: "Cline" },
|
|
35
|
-
aider: { label: "Aider" },
|
|
36
|
-
firebase: { label: "Firebase Studio" },
|
|
37
|
-
"gemini-cli": { label: "Gemini CLI" },
|
|
38
|
-
junie: { label: "Junie" },
|
|
39
|
-
kilocode: { label: "Kilo Code" },
|
|
40
|
-
opencode: { label: "OpenCode" },
|
|
41
|
-
crush: { label: "Crush" },
|
|
42
|
-
zed: { label: "Zed" },
|
|
43
|
-
qwen: { label: "Qwen" },
|
|
44
|
-
amazonqcli: { label: "Amazon Q CLI" },
|
|
45
|
-
augmentcode: { label: "AugmentCode" },
|
|
46
|
-
firebender: { label: "Firebender" },
|
|
47
|
-
goose: { label: "Goose" },
|
|
48
|
-
jules: { label: "Jules" },
|
|
49
|
-
kiro: { label: "Kiro" },
|
|
50
|
-
openhands: { label: "Open Hands" },
|
|
51
|
-
roo: { label: "RooCode" },
|
|
52
|
-
trae: { label: "Trae AI" },
|
|
53
|
-
warp: { label: "Warp" },
|
|
54
|
-
} as const;
|
|
55
|
-
|
|
56
|
-
const selectedEditors = await autocompleteMultiselect({
|
|
57
|
-
message: "Select AI assistants for Ruler",
|
|
58
|
-
options: Object.entries(EDITORS).map(([key, v]) => ({
|
|
59
|
-
value: key,
|
|
60
|
-
label: v.label,
|
|
61
|
-
})),
|
|
62
|
-
required: false,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (isCancel(selectedEditors)) return exitCancelled("Operation cancelled");
|
|
66
|
-
|
|
67
|
-
if (selectedEditors.length === 0) {
|
|
55
|
+
if (agents.length === 0) {
|
|
68
56
|
log.info("No AI assistants selected. To apply rules later, run:");
|
|
69
57
|
log.info(
|
|
70
58
|
pc.cyan(
|
|
@@ -79,29 +67,28 @@ export async function setupRuler(config: ProjectConfig) {
|
|
|
79
67
|
|
|
80
68
|
let updatedConfig = currentConfig;
|
|
81
69
|
|
|
82
|
-
const defaultAgentsLine = `default_agents = [${
|
|
70
|
+
const defaultAgentsLine = `default_agents = [${agents.map((agent) => `"${agent}"`).join(", ")}]`;
|
|
83
71
|
updatedConfig = updatedConfig.replace(/default_agents = \[\]/, defaultAgentsLine);
|
|
84
72
|
|
|
85
73
|
await fs.writeFile(configFile, updatedConfig);
|
|
86
74
|
|
|
87
75
|
await addRulerScriptToPackageJson(projectDir, packageManager);
|
|
88
76
|
|
|
89
|
-
|
|
90
|
-
s.start("Applying rules with Ruler...");
|
|
77
|
+
log.step("Applying rules with Ruler...");
|
|
91
78
|
|
|
92
79
|
try {
|
|
93
80
|
const rulerApplyCmd = getPackageExecutionCommand(
|
|
94
81
|
packageManager,
|
|
95
|
-
`@intellectronica/ruler@latest apply --agents ${
|
|
82
|
+
`@intellectronica/ruler@latest apply --agents ${agents.join(",")} --local-only`,
|
|
96
83
|
);
|
|
97
84
|
await $`${{ raw: rulerApplyCmd }}`.cwd(projectDir).env({ CI: "true" });
|
|
98
85
|
|
|
99
|
-
|
|
86
|
+
log.success("Applied rules with Ruler");
|
|
100
87
|
} catch {
|
|
101
|
-
|
|
88
|
+
log.error("Failed to apply rules");
|
|
102
89
|
}
|
|
103
90
|
} catch (error) {
|
|
104
|
-
log.error(
|
|
91
|
+
log.error("Failed to set up Ruler");
|
|
105
92
|
if (error instanceof Error) {
|
|
106
93
|
console.error(pc.red(error.message));
|
|
107
94
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import consola from "consola";
|
|
3
2
|
import { $ } from "bun";
|
|
4
3
|
import fs from "fs-extra";
|
|
5
4
|
import pc from "picocolors";
|
|
@@ -38,7 +37,7 @@ export async function setupStarlight(config: ProjectConfig) {
|
|
|
38
37
|
} catch (error) {
|
|
39
38
|
log.error("Failed to set up Starlight docs");
|
|
40
39
|
if (error instanceof Error) {
|
|
41
|
-
|
|
40
|
+
log.error(error.message);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { consola } from "consola";
|
|
3
2
|
import { $ } from "bun";
|
|
4
3
|
import fs from "fs-extra";
|
|
5
4
|
import pc from "picocolors";
|
|
@@ -83,7 +82,7 @@ export async function setupTauri(config: ProjectConfig) {
|
|
|
83
82
|
} catch (error) {
|
|
84
83
|
log.error("Failed to set up Tauri");
|
|
85
84
|
if (error instanceof Error) {
|
|
86
|
-
|
|
85
|
+
log.error(error.message);
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
}
|
|
@@ -1,47 +1,19 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { isCancel, log, select, spinner } from "@clack/prompts";
|
|
3
2
|
import { $ } from "bun";
|
|
4
3
|
import fs from "fs-extra";
|
|
5
4
|
import pc from "picocolors";
|
|
6
5
|
import type { ProjectConfig } from "../../types";
|
|
7
|
-
import { exitCancelled } from "../../utils/errors";
|
|
8
6
|
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
7
|
+
import { log } from "../../utils/logger";
|
|
9
8
|
|
|
10
9
|
type TuiTemplate = "core" | "react" | "solid";
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
core: {
|
|
14
|
-
label: "Core",
|
|
15
|
-
hint: "Basic OpenTUI template",
|
|
16
|
-
},
|
|
17
|
-
react: {
|
|
18
|
-
label: "React",
|
|
19
|
-
hint: "React-based OpenTUI template",
|
|
20
|
-
},
|
|
21
|
-
solid: {
|
|
22
|
-
label: "Solid",
|
|
23
|
-
hint: "SolidJS-based OpenTUI template",
|
|
24
|
-
},
|
|
25
|
-
} as const;
|
|
26
|
-
|
|
27
|
-
export async function setupTui(config: ProjectConfig) {
|
|
11
|
+
export async function setupTui(config: ProjectConfig, template: TuiTemplate = "react") {
|
|
28
12
|
const { packageManager, projectDir } = config;
|
|
29
13
|
|
|
30
14
|
try {
|
|
31
15
|
log.info("Setting up OpenTUI...");
|
|
32
16
|
|
|
33
|
-
const template = await select<TuiTemplate>({
|
|
34
|
-
message: "Choose a template",
|
|
35
|
-
options: Object.entries(TEMPLATES).map(([key, template]) => ({
|
|
36
|
-
value: key as TuiTemplate,
|
|
37
|
-
label: template.label,
|
|
38
|
-
hint: template.hint,
|
|
39
|
-
})),
|
|
40
|
-
initialValue: "core",
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
44
|
-
|
|
45
17
|
const commandWithArgs = `create-tui@latest --template ${template} --no-git --no-install tui`;
|
|
46
18
|
|
|
47
19
|
const tuiInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
|
|
@@ -49,14 +21,13 @@ export async function setupTui(config: ProjectConfig) {
|
|
|
49
21
|
const appsDir = path.join(projectDir, "apps");
|
|
50
22
|
await fs.ensureDir(appsDir);
|
|
51
23
|
|
|
52
|
-
|
|
53
|
-
s.start("Running OpenTUI create command...");
|
|
24
|
+
log.step("Running OpenTUI create command...");
|
|
54
25
|
|
|
55
26
|
await $`${{ raw: tuiInitCommand }}`.cwd(appsDir).env({ CI: "true" });
|
|
56
27
|
|
|
57
|
-
|
|
28
|
+
log.success("OpenTUI setup complete!");
|
|
58
29
|
} catch (error) {
|
|
59
|
-
log.error(
|
|
30
|
+
log.error("Failed to set up OpenTUI");
|
|
60
31
|
if (error instanceof Error) {
|
|
61
32
|
console.error(pc.red(error.message));
|
|
62
33
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { autocompleteMultiselect, group, log, multiselect, spinner } from "@clack/prompts";
|
|
2
1
|
import { $ } from "bun";
|
|
3
2
|
import pc from "picocolors";
|
|
4
3
|
import type { ProjectConfig } from "../../types";
|
|
5
4
|
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
6
|
-
import { exitCancelled } from "../../utils/errors";
|
|
7
5
|
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
8
6
|
import { setupBiome } from "./addons-setup";
|
|
7
|
+
import { log } from "../../utils/logger";
|
|
9
8
|
|
|
10
9
|
type UltraciteEditor = "vscode" | "zed";
|
|
11
10
|
type UltraciteAgent =
|
|
@@ -30,80 +29,11 @@ type UltraciteAgent =
|
|
|
30
29
|
|
|
31
30
|
type UltraciteHook = "cursor" | "claude";
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
label: "Zed",
|
|
39
|
-
},
|
|
40
|
-
} as const;
|
|
41
|
-
|
|
42
|
-
const AGENTS = {
|
|
43
|
-
"vscode-copilot": {
|
|
44
|
-
label: "VS Code Copilot",
|
|
45
|
-
},
|
|
46
|
-
cursor: {
|
|
47
|
-
label: "Cursor",
|
|
48
|
-
},
|
|
49
|
-
windsurf: {
|
|
50
|
-
label: "Windsurf",
|
|
51
|
-
},
|
|
52
|
-
zed: {
|
|
53
|
-
label: "Zed",
|
|
54
|
-
},
|
|
55
|
-
claude: {
|
|
56
|
-
label: "Claude",
|
|
57
|
-
},
|
|
58
|
-
codex: {
|
|
59
|
-
label: "Codex",
|
|
60
|
-
},
|
|
61
|
-
kiro: {
|
|
62
|
-
label: "Kiro",
|
|
63
|
-
},
|
|
64
|
-
cline: {
|
|
65
|
-
label: "Cline",
|
|
66
|
-
},
|
|
67
|
-
amp: {
|
|
68
|
-
label: "Amp",
|
|
69
|
-
},
|
|
70
|
-
aider: {
|
|
71
|
-
label: "Aider",
|
|
72
|
-
},
|
|
73
|
-
"firebase-studio": {
|
|
74
|
-
label: "Firebase Studio",
|
|
75
|
-
},
|
|
76
|
-
"open-hands": {
|
|
77
|
-
label: "Open Hands",
|
|
78
|
-
},
|
|
79
|
-
"gemini-cli": {
|
|
80
|
-
label: "Gemini CLI",
|
|
81
|
-
},
|
|
82
|
-
junie: {
|
|
83
|
-
label: "Junie",
|
|
84
|
-
},
|
|
85
|
-
augmentcode: {
|
|
86
|
-
label: "AugmentCode",
|
|
87
|
-
},
|
|
88
|
-
"kilo-code": {
|
|
89
|
-
label: "Kilo Code",
|
|
90
|
-
},
|
|
91
|
-
goose: {
|
|
92
|
-
label: "Goose",
|
|
93
|
-
},
|
|
94
|
-
"roo-code": {
|
|
95
|
-
label: "Roo Code",
|
|
96
|
-
},
|
|
97
|
-
} as const;
|
|
98
|
-
|
|
99
|
-
const HOOKS = {
|
|
100
|
-
cursor: {
|
|
101
|
-
label: "Cursor",
|
|
102
|
-
},
|
|
103
|
-
claude: {
|
|
104
|
-
label: "Claude",
|
|
105
|
-
},
|
|
106
|
-
} as const;
|
|
32
|
+
export type UltraciteOptions = {
|
|
33
|
+
editors?: UltraciteEditor[];
|
|
34
|
+
agents?: UltraciteAgent[];
|
|
35
|
+
hooks?: UltraciteHook[];
|
|
36
|
+
};
|
|
107
37
|
|
|
108
38
|
function getFrameworksFromFrontend(frontend: string[]): string[] {
|
|
109
39
|
const frameworkMap: Record<string, string> = {
|
|
@@ -130,53 +60,23 @@ function getFrameworksFromFrontend(frontend: string[]): string[] {
|
|
|
130
60
|
return Array.from(frameworks);
|
|
131
61
|
}
|
|
132
62
|
|
|
133
|
-
export async function setupUltracite(
|
|
63
|
+
export async function setupUltracite(
|
|
64
|
+
config: ProjectConfig,
|
|
65
|
+
hasHusky: boolean,
|
|
66
|
+
options: UltraciteOptions = {},
|
|
67
|
+
) {
|
|
134
68
|
const { packageManager, projectDir, frontend } = config;
|
|
135
69
|
|
|
70
|
+
// Use defaults if not provided
|
|
71
|
+
const editors = options.editors ?? ["vscode"];
|
|
72
|
+
const agents = options.agents ?? ["cursor", "claude"];
|
|
73
|
+
const hooks = options.hooks ?? [];
|
|
74
|
+
|
|
136
75
|
try {
|
|
137
76
|
log.info("Setting up Ultracite...");
|
|
138
77
|
|
|
139
78
|
await setupBiome(projectDir);
|
|
140
79
|
|
|
141
|
-
const result = await group(
|
|
142
|
-
{
|
|
143
|
-
editors: () =>
|
|
144
|
-
multiselect<UltraciteEditor>({
|
|
145
|
-
message: "Choose editors",
|
|
146
|
-
options: Object.entries(EDITORS).map(([key, editor]) => ({
|
|
147
|
-
value: key as UltraciteEditor,
|
|
148
|
-
label: editor.label,
|
|
149
|
-
})),
|
|
150
|
-
required: true,
|
|
151
|
-
}),
|
|
152
|
-
agents: () =>
|
|
153
|
-
autocompleteMultiselect<UltraciteAgent>({
|
|
154
|
-
message: "Choose agents",
|
|
155
|
-
options: Object.entries(AGENTS).map(([key, agent]) => ({
|
|
156
|
-
value: key as UltraciteAgent,
|
|
157
|
-
label: agent.label,
|
|
158
|
-
})),
|
|
159
|
-
required: true,
|
|
160
|
-
}),
|
|
161
|
-
hooks: () =>
|
|
162
|
-
autocompleteMultiselect<UltraciteHook>({
|
|
163
|
-
message: "Choose hooks",
|
|
164
|
-
options: Object.entries(HOOKS).map(([key, hook]) => ({
|
|
165
|
-
value: key as UltraciteHook,
|
|
166
|
-
label: hook.label,
|
|
167
|
-
})),
|
|
168
|
-
}),
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
onCancel: () => {
|
|
172
|
-
exitCancelled("Operation cancelled");
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
const editors = result.editors as UltraciteEditor[];
|
|
178
|
-
const agents = result.agents as UltraciteAgent[];
|
|
179
|
-
const hooks = result.hooks as UltraciteHook[];
|
|
180
80
|
const frameworks = getFrameworksFromFrontend(frontend);
|
|
181
81
|
|
|
182
82
|
const ultraciteArgs = ["init", "--pm", packageManager];
|
|
@@ -206,8 +106,7 @@ export async function setupUltracite(config: ProjectConfig, hasHusky: boolean) {
|
|
|
206
106
|
|
|
207
107
|
const ultraciteInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
|
|
208
108
|
|
|
209
|
-
|
|
210
|
-
s.start("Running Ultracite init command...");
|
|
109
|
+
log.step("Running Ultracite init command...");
|
|
211
110
|
|
|
212
111
|
await $`${{ raw: ultraciteInitCommand }}`.cwd(projectDir).env({ CI: "true" });
|
|
213
112
|
|
|
@@ -218,9 +117,9 @@ export async function setupUltracite(config: ProjectConfig, hasHusky: boolean) {
|
|
|
218
117
|
});
|
|
219
118
|
}
|
|
220
119
|
|
|
221
|
-
|
|
120
|
+
log.success("Ultracite setup successfully!");
|
|
222
121
|
} catch (error) {
|
|
223
|
-
log.error(
|
|
122
|
+
log.error("Failed to set up Ultracite");
|
|
224
123
|
if (error instanceof Error) {
|
|
225
124
|
console.error(pc.red(error.message));
|
|
226
125
|
}
|