create-better-fullstack 2.1.5 → 2.1.7
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/dist/{add-handler-BNSL6HdM.mjs → add-handler-ztNjzoMN.mjs} +52 -6
- package/dist/addons-setup-DnLjAzTw.mjs +7 -0
- package/dist/{addons-setup-CyrP1IV-.mjs → addons-setup-LaAj43NP.mjs} +10 -24
- package/dist/analytics-DVltG11u.mjs +170 -0
- package/dist/{errors-Cyol8zbN.mjs → bts-config-DQVWvPDs.mjs} +72 -149
- package/dist/cli.mjs +2 -2
- package/dist/{templates-CnTOtKjm.mjs → config-processing-D9-F2Us9.mjs} +57 -2
- package/dist/{doctor-DBoq7bZ9.mjs → doctor-a4ca3SMd.mjs} +3 -2
- package/dist/errors-ns_o2OKg.mjs +86 -0
- package/dist/{file-formatter-B3dsev2l.mjs → file-formatter-gvmrpd-g.mjs} +78 -6
- package/dist/gen-CCClL7Ve.mjs +274 -0
- package/dist/{generated-checks-C8hn9w2i.mjs → generated-checks-BV9jol5h.mjs} +1 -1
- package/dist/index.d.mts +162 -64
- package/dist/index.mjs +17 -8
- package/dist/{install-dependencies-CgNh-aOy.mjs → install-dependencies-RoUyaE8o.mjs} +80 -21
- package/dist/mcp-492OkjcS.mjs +11 -0
- package/dist/mcp-entry.mjs +205 -30
- package/dist/prompt-environment-BR0Kkw2W.mjs +26 -0
- package/dist/registry-DSf2CEaU.mjs +408 -0
- package/dist/{run-BYse4yJy.mjs → run-D9I7NdES.mjs} +2081 -464
- package/dist/run-buK4aZS8.mjs +15 -0
- package/dist/scaffold-manifest-DGRyepdb.mjs +4 -0
- package/dist/scaffold-manifest-Dyi0voqE.mjs +135 -0
- package/dist/update-DJ8CI5KW.mjs +401 -0
- package/package.json +3 -3
- package/dist/addons-setup-DyMm42a5.mjs +0 -5
- package/dist/mcp-CsW3i66c.mjs +0 -6
- package/dist/run-_cf_sFwM.mjs +0 -10
- /package/dist/{update-deps-D5OG0KmJ.mjs → update-deps-aD-iQw4U.mjs} +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { a as updateBtsConfig, r as readBtsConfig, v as getDefaultConfig } from "./bts-config-DQVWvPDs.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
|
-
import { t as
|
|
5
|
-
import "./
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
4
|
+
import { c as isSilent, l as runWithContextAsync, n as UserCancelledError, t as CLIError } from "./errors-ns_o2OKg.mjs";
|
|
5
|
+
import "./prompt-environment-BR0Kkw2W.mjs";
|
|
6
|
+
import { i as trackEvent, r as maybeShowTelemetryNotice } from "./analytics-DVltG11u.mjs";
|
|
7
|
+
import "./file-formatter-gvmrpd-g.mjs";
|
|
8
|
+
import { c as applyDependencyVersionChannel, t as installDependencies, u as getAddonsToAdd } from "./install-dependencies-RoUyaE8o.mjs";
|
|
9
|
+
import "./scaffold-manifest-Dyi0voqE.mjs";
|
|
10
|
+
import { t as setupAddons } from "./addons-setup-LaAj43NP.mjs";
|
|
11
|
+
import { o as applyStackUpdate, u as planStackUpdate } from "./mcp-entry.mjs";
|
|
8
12
|
import { intro, log, outro } from "@clack/prompts";
|
|
9
13
|
import pc from "picocolors";
|
|
10
14
|
import fs from "fs-extra";
|
|
@@ -55,6 +59,13 @@ function logStackUpdateSummary(plan, dryRun) {
|
|
|
55
59
|
const envCount = countEnvChanges(plan);
|
|
56
60
|
if (envCount > 0) log.info(pc.dim(`Env vars: ${formatCount(envCount, "addition")}`));
|
|
57
61
|
for (const adjustment of plan.compatibilityAdjustments) log.info(pc.dim(`Adjusted: ${adjustment}`));
|
|
62
|
+
if (plan.architectureChanges.length > 0) {
|
|
63
|
+
const swaps = plan.architectureChanges.map((change) => `${change.key}: ${change.from} -> ${change.to}`).join(", ");
|
|
64
|
+
log.warn(pc.yellow(`Architecture change: ${swaps}`));
|
|
65
|
+
log.info(pc.dim("Data and schema are NOT migrated automatically. Migration checklist:"));
|
|
66
|
+
for (const step of plan.migrationSteps) log.info(pc.dim(` - ${step}`));
|
|
67
|
+
if (dryRun && plan.requiresArchitectureAck) log.warn(pc.yellow("Re-run with --acknowledge-architecture-change to apply this architecture change."));
|
|
68
|
+
}
|
|
58
69
|
for (const blocker of plan.manualReviewBlockers) log.warn(pc.yellow(`Manual review: ${blocker}`));
|
|
59
70
|
}
|
|
60
71
|
function buildAddonSetupConfig(projectDir, projectName, currentConfig, plan, addonsToSetup) {
|
|
@@ -116,12 +127,47 @@ async function runStackUpdateAdd(input, projectDir, projectName, currentConfig,
|
|
|
116
127
|
setupWarnings: setupWarnings.length > 0 ? setupWarnings : void 0
|
|
117
128
|
};
|
|
118
129
|
}
|
|
130
|
+
const ADD_FEATURE_KEYS = new Set([
|
|
131
|
+
"addons",
|
|
132
|
+
"webDeploy",
|
|
133
|
+
"serverDeploy",
|
|
134
|
+
"packageManager"
|
|
135
|
+
]);
|
|
136
|
+
async function trackAddEvent(input, options, outcome) {
|
|
137
|
+
if (input.dryRun) return;
|
|
138
|
+
const request = buildStackUpdateRequest(input);
|
|
139
|
+
const stackPayload = { ...request };
|
|
140
|
+
if (outcome.addedAddons !== void 0) if (outcome.addedAddons.length > 0) stackPayload.addons = outcome.addedAddons;
|
|
141
|
+
else delete stackPayload.addons;
|
|
142
|
+
await trackEvent(Object.keys(request).some((key) => !ADD_FEATURE_KEYS.has(key)) ? "stack_updated" : "feature_added", stackPayload, {
|
|
143
|
+
source: options.telemetrySource ?? (options.silent ? "programmatic" : Object.keys(request).length > 0 ? "cli-flags" : "cli-interactive"),
|
|
144
|
+
success: outcome.success,
|
|
145
|
+
errorName: outcome.errorName,
|
|
146
|
+
durationMs: outcome.durationMs
|
|
147
|
+
});
|
|
148
|
+
}
|
|
119
149
|
async function addHandler(input, options = {}) {
|
|
120
150
|
const { silent = false } = options;
|
|
151
|
+
const startTime = Date.now();
|
|
121
152
|
return runWithContextAsync({ silent }, async () => {
|
|
122
153
|
try {
|
|
123
|
-
|
|
154
|
+
const result = await addHandlerInternal(input);
|
|
155
|
+
await maybeShowTelemetryNotice();
|
|
156
|
+
await trackAddEvent(input, options, {
|
|
157
|
+
success: result.success,
|
|
158
|
+
durationMs: Date.now() - startTime,
|
|
159
|
+
addedAddons: result.addedAddons
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
124
162
|
} catch (error) {
|
|
163
|
+
if (!(error instanceof UserCancelledError)) {
|
|
164
|
+
await maybeShowTelemetryNotice();
|
|
165
|
+
await trackAddEvent(input, options, {
|
|
166
|
+
success: false,
|
|
167
|
+
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
168
|
+
durationMs: Date.now() - startTime
|
|
169
|
+
});
|
|
170
|
+
}
|
|
125
171
|
if (error instanceof UserCancelledError) {
|
|
126
172
|
if (isSilent()) return {
|
|
127
173
|
success: false,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { r as readBtsConfig } from "./bts-config-DQVWvPDs.mjs";
|
|
3
|
+
import { c as isSilent, r as exitCancelled } from "./errors-ns_o2OKg.mjs";
|
|
4
|
+
import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
|
|
3
5
|
import { autocompleteMultiselect, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
|
|
4
6
|
import pc from "picocolors";
|
|
5
7
|
import fs from "fs-extra";
|
|
@@ -7,28 +9,6 @@ import path from "node:path";
|
|
|
7
9
|
import consola from "consola";
|
|
8
10
|
import { $ } from "execa";
|
|
9
11
|
|
|
10
|
-
//#region src/utils/prompt-environment.ts
|
|
11
|
-
function hasOwnProperty(value, property) {
|
|
12
|
-
return Object.prototype.hasOwnProperty.call(value, property);
|
|
13
|
-
}
|
|
14
|
-
function resolveCiValue(environment) {
|
|
15
|
-
if (environment && hasOwnProperty(environment, "ci")) return environment.ci;
|
|
16
|
-
return process.env.CI;
|
|
17
|
-
}
|
|
18
|
-
function isCiEnvironment(value) {
|
|
19
|
-
if (!value) return false;
|
|
20
|
-
const normalizedValue = value.trim().toLowerCase();
|
|
21
|
-
return normalizedValue !== "" && normalizedValue !== "0" && normalizedValue !== "false";
|
|
22
|
-
}
|
|
23
|
-
function canPromptInteractively(environment = {}) {
|
|
24
|
-
const silent = environment.silent ?? isSilent();
|
|
25
|
-
const stdinIsTTY = environment.stdinIsTTY ?? process.stdin.isTTY === true;
|
|
26
|
-
const stdoutIsTTY = environment.stdoutIsTTY ?? process.stdout.isTTY === true;
|
|
27
|
-
const ci = resolveCiValue(environment);
|
|
28
|
-
return !silent && stdinIsTTY && stdoutIsTTY && !isCiEnvironment(ci);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
12
|
//#region src/utils/add-package-deps.ts
|
|
33
13
|
const addPackageDependency = async (opts) => {
|
|
34
14
|
const { dependencies = [], devDependencies = [], customDependencies = {}, customDevDependencies = {}, projectDir } = opts;
|
|
@@ -396,6 +376,12 @@ function getRecommendedMcpServers(config) {
|
|
|
396
376
|
name: "polar",
|
|
397
377
|
target: "https://mcp.polar.sh/mcp/polar-mcp"
|
|
398
378
|
});
|
|
379
|
+
if (config.payments === "revenuecat") servers.push({
|
|
380
|
+
key: "revenuecat",
|
|
381
|
+
label: "RevenueCat",
|
|
382
|
+
name: "revenuecat",
|
|
383
|
+
target: "https://mcp.revenuecat.ai/mcp"
|
|
384
|
+
});
|
|
399
385
|
return servers;
|
|
400
386
|
}
|
|
401
387
|
function filterAgentsForScope(scope) {
|
|
@@ -1332,4 +1318,4 @@ async function setupLefthook(projectDir) {
|
|
|
1332
1318
|
}
|
|
1333
1319
|
|
|
1334
1320
|
//#endregion
|
|
1335
|
-
export {
|
|
1321
|
+
export { getPackageExecutionArgs as n, addPackageDependency as r, setupAddons as t };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { m as getLatestCLIVersion } from "./bts-config-DQVWvPDs.mjs";
|
|
3
|
+
import { t as canPromptInteractively } from "./prompt-environment-BR0Kkw2W.mjs";
|
|
4
|
+
import { log } from "@clack/prompts";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import envPaths from "env-paths";
|
|
7
|
+
import fs from "fs-extra";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
|
|
11
|
+
//#region src/utils/telemetry-settings.ts
|
|
12
|
+
const paths = envPaths("better-fullstack", { suffix: "" });
|
|
13
|
+
const SETTINGS_FILE = "telemetry.json";
|
|
14
|
+
function getSettingsPath() {
|
|
15
|
+
return path.join(paths.data, SETTINGS_FILE);
|
|
16
|
+
}
|
|
17
|
+
function emptySettings() {
|
|
18
|
+
return {
|
|
19
|
+
version: 1,
|
|
20
|
+
noticeShown: false
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function readTelemetrySettings() {
|
|
24
|
+
const settingsPath = getSettingsPath();
|
|
25
|
+
if (!await fs.pathExists(settingsPath)) return emptySettings();
|
|
26
|
+
try {
|
|
27
|
+
const data = await fs.readJson(settingsPath);
|
|
28
|
+
if (!data || typeof data !== "object") return emptySettings();
|
|
29
|
+
return {
|
|
30
|
+
version: typeof data.version === "number" ? data.version : 1,
|
|
31
|
+
enabled: typeof data.enabled === "boolean" ? data.enabled : void 0,
|
|
32
|
+
noticeShown: data.noticeShown === true,
|
|
33
|
+
machineId: typeof data.machineId === "string" ? data.machineId : void 0
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
return emptySettings();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function writeTelemetrySettings(settings) {
|
|
40
|
+
await fs.ensureDir(paths.data);
|
|
41
|
+
await fs.writeJson(getSettingsPath(), settings, { spaces: 2 });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The user's explicit persisted preference, or `undefined` when they never chose.
|
|
45
|
+
*/
|
|
46
|
+
async function getPersistedTelemetryPreference() {
|
|
47
|
+
return (await readTelemetrySettings()).enabled;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Persist an explicit opt-in/opt-out. Choosing a preference also marks the
|
|
51
|
+
* first-run notice as shown so it never appears afterwards.
|
|
52
|
+
*/
|
|
53
|
+
async function setTelemetryPreference(enabled) {
|
|
54
|
+
const settings = await readTelemetrySettings();
|
|
55
|
+
settings.enabled = enabled;
|
|
56
|
+
settings.noticeShown = true;
|
|
57
|
+
await writeTelemetrySettings(settings);
|
|
58
|
+
}
|
|
59
|
+
async function hasTelemetryNoticeBeenShown() {
|
|
60
|
+
return (await readTelemetrySettings()).noticeShown;
|
|
61
|
+
}
|
|
62
|
+
async function markTelemetryNoticeShown() {
|
|
63
|
+
const settings = await readTelemetrySettings();
|
|
64
|
+
settings.noticeShown = true;
|
|
65
|
+
await writeTelemetrySettings(settings);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The persisted anonymous machine ID, created on first use. Returns
|
|
69
|
+
* `undefined` if it cannot be persisted (telemetry then simply omits it).
|
|
70
|
+
*/
|
|
71
|
+
async function getOrCreateMachineId() {
|
|
72
|
+
try {
|
|
73
|
+
const settings = await readTelemetrySettings();
|
|
74
|
+
if (settings.machineId) return settings.machineId;
|
|
75
|
+
settings.machineId = randomUUID();
|
|
76
|
+
await writeTelemetrySettings(settings);
|
|
77
|
+
return settings.machineId;
|
|
78
|
+
} catch {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/utils/analytics.ts
|
|
85
|
+
const CONVEX_INGEST_URL = "https://curious-elephant-653.convex.site/api/analytics/ingest";
|
|
86
|
+
/**
|
|
87
|
+
* Whether telemetry is explicitly overridden at runtime.
|
|
88
|
+
*
|
|
89
|
+
* Only `BTS_TELEMETRY_DISABLED` is a runtime override: `BTS_TELEMETRY` is inlined
|
|
90
|
+
* by the bundler at build time (see tsdown.config.ts) and therefore acts as a
|
|
91
|
+
* build-time default, not a runtime switch.
|
|
92
|
+
*/
|
|
93
|
+
function hasTelemetryEnvOverride() {
|
|
94
|
+
return process.env.BTS_TELEMETRY_DISABLED !== void 0;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Resolve whether telemetry is enabled.
|
|
98
|
+
*
|
|
99
|
+
* Precedence: runtime env override (`BTS_TELEMETRY_DISABLED`) > persisted
|
|
100
|
+
* preference > default. The default honors the build-time `BTS_TELEMETRY` flag
|
|
101
|
+
* (inlined by the bundler, "0" by default) and falls back to enabled when the
|
|
102
|
+
* flag is unset (e.g. running from source).
|
|
103
|
+
*
|
|
104
|
+
* `BTS_TELEMETRY` is intentionally evaluated last: the bundler replaces it with
|
|
105
|
+
* a literal, so an early `!== undefined` check would always short-circuit and
|
|
106
|
+
* make the persisted preference unreachable in the shipped CLI.
|
|
107
|
+
*/
|
|
108
|
+
async function isTelemetryEnabled() {
|
|
109
|
+
const disabled = process.env.BTS_TELEMETRY_DISABLED;
|
|
110
|
+
if (disabled !== void 0) return disabled !== "1";
|
|
111
|
+
const persisted = await getPersistedTelemetryPreference();
|
|
112
|
+
if (persisted !== void 0) return persisted;
|
|
113
|
+
const buildDefault = "1";
|
|
114
|
+
return buildDefault === void 0 ? true : buildDefault === "1";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Print a one-time notice describing the anonymous telemetry the CLI collects
|
|
118
|
+
* and how to opt out, then remember that it was shown so it never repeats.
|
|
119
|
+
*
|
|
120
|
+
* No-ops when telemetry is explicitly configured via env var, when a persisted
|
|
121
|
+
* preference already exists, when the notice was already shown, when telemetry
|
|
122
|
+
* is disabled by the build default, or when the CLI is not running interactively
|
|
123
|
+
* (CI / silent / non-TTY).
|
|
124
|
+
*/
|
|
125
|
+
async function maybeShowTelemetryNotice() {
|
|
126
|
+
if (hasTelemetryEnvOverride()) return;
|
|
127
|
+
if (!canPromptInteractively()) return;
|
|
128
|
+
if (await getPersistedTelemetryPreference() !== void 0) return;
|
|
129
|
+
if (await hasTelemetryNoticeBeenShown()) return;
|
|
130
|
+
if (!await isTelemetryEnabled()) return;
|
|
131
|
+
log.info(`${pc.bold("Anonymous usage telemetry is enabled.")}\n${pc.dim("We collect your selected stack options (e.g. frontend, backend, database),")}\n${pc.dim("scaffold outcome (success, duration), CLI version, Node.js version, OS")}\n${pc.dim("platform, and a random anonymous install ID — never project names, file")}\n${pc.dim("paths, or any personal data.")}\nOpt out anytime with ${pc.cyan("create-better-fullstack telemetry disable")} or ${pc.cyan("BTS_TELEMETRY_DISABLED=1")}.`);
|
|
132
|
+
try {
|
|
133
|
+
await markTelemetryNoticeShown();
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
136
|
+
async function sendConvexEvent(payload) {
|
|
137
|
+
try {
|
|
138
|
+
await fetch(CONVEX_INGEST_URL, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: { "Content-Type": "application/json" },
|
|
141
|
+
body: JSON.stringify(payload)
|
|
142
|
+
});
|
|
143
|
+
} catch {}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Send one telemetry event. `config` may be a full ProjectConfig or any
|
|
147
|
+
* partial stack snapshot (e.g. the parts added by `add`); PII-ish fields
|
|
148
|
+
* are always stripped before sending.
|
|
149
|
+
*/
|
|
150
|
+
async function trackEvent(eventType, config, outcome = {}, disableAnalytics = false) {
|
|
151
|
+
if (disableAnalytics || !await isTelemetryEnabled()) return;
|
|
152
|
+
const { projectName: _projectName, projectDir: _projectDir, relativePath: _relativePath, ...safeConfig } = config;
|
|
153
|
+
try {
|
|
154
|
+
await sendConvexEvent({
|
|
155
|
+
...safeConfig,
|
|
156
|
+
eventType,
|
|
157
|
+
...outcome,
|
|
158
|
+
machineId: await getOrCreateMachineId(),
|
|
159
|
+
cli_version: getLatestCLIVersion(),
|
|
160
|
+
node_version: typeof process !== "undefined" ? process.version : "",
|
|
161
|
+
platform: typeof process !== "undefined" ? process.platform : ""
|
|
162
|
+
});
|
|
163
|
+
} catch {}
|
|
164
|
+
}
|
|
165
|
+
async function trackProjectCreation(config, disableAnalytics = false, outcome = {}) {
|
|
166
|
+
await trackEvent("project_created", config, outcome, disableAnalytics);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { trackProjectCreation as a, trackEvent as i, isTelemetryEnabled as n, getPersistedTelemetryPreference as o, maybeShowTelemetryNotice as r, setTelemetryPreference as s, hasTelemetryEnvOverride as t };
|
|
@@ -1,20 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as __reExport } from "./chunk-CCII7kTE.mjs";
|
|
3
|
-
import { cancel } from "@clack/prompts";
|
|
4
|
-
import pc from "picocolors";
|
|
5
3
|
import fs from "fs-extra";
|
|
6
4
|
import path from "node:path";
|
|
7
5
|
import * as JSONC from "jsonc-parser";
|
|
8
6
|
import { createCliDefaultProjectConfigBase } from "@better-fullstack/types";
|
|
9
7
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
11
|
-
import consola from "consola";
|
|
12
8
|
|
|
13
9
|
//#region src/types.ts
|
|
14
10
|
var types_exports = {};
|
|
15
11
|
import * as import__better_fullstack_types from "@better-fullstack/types";
|
|
16
12
|
__reExport(types_exports, import__better_fullstack_types);
|
|
17
13
|
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/utils/get-package-manager.ts
|
|
16
|
+
const getUserPkgManager = () => {
|
|
17
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
18
|
+
if (userAgent?.startsWith("pnpm")) return "pnpm";
|
|
19
|
+
if (userAgent?.startsWith("bun")) return "bun";
|
|
20
|
+
if (userAgent?.startsWith("yarn")) return "yarn";
|
|
21
|
+
return "npm";
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/constants.ts
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const distPath = path.dirname(__filename);
|
|
28
|
+
const PKG_ROOT = path.join(distPath, "../");
|
|
29
|
+
const BUILDER_URL = "https://better-fullstack-web.vercel.app/new";
|
|
30
|
+
const DEFAULT_CONFIG_BASE = createCliDefaultProjectConfigBase(getUserPkgManager());
|
|
31
|
+
function getDefaultConfig() {
|
|
32
|
+
return {
|
|
33
|
+
...DEFAULT_CONFIG_BASE,
|
|
34
|
+
projectDir: path.resolve(process.cwd(), DEFAULT_CONFIG_BASE.projectName),
|
|
35
|
+
packageManager: getUserPkgManager(),
|
|
36
|
+
frontend: [...DEFAULT_CONFIG_BASE.frontend],
|
|
37
|
+
addons: [...DEFAULT_CONFIG_BASE.addons],
|
|
38
|
+
examples: [...DEFAULT_CONFIG_BASE.examples],
|
|
39
|
+
rustLibraries: [...DEFAULT_CONFIG_BASE.rustLibraries],
|
|
40
|
+
pythonAi: [...DEFAULT_CONFIG_BASE.pythonAi],
|
|
41
|
+
javaLibraries: [...DEFAULT_CONFIG_BASE.javaLibraries],
|
|
42
|
+
javaTestingLibraries: [...DEFAULT_CONFIG_BASE.javaTestingLibraries],
|
|
43
|
+
aiDocs: [...DEFAULT_CONFIG_BASE.aiDocs]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const DEFAULT_CONFIG = getDefaultConfig();
|
|
47
|
+
/**
|
|
48
|
+
* Default UI library for each frontend framework
|
|
49
|
+
* Falls back based on what's compatible
|
|
50
|
+
*/
|
|
51
|
+
const DEFAULT_UI_LIBRARY_BY_FRONTEND = {
|
|
52
|
+
"tanstack-router": "shadcn-ui",
|
|
53
|
+
"react-router": "shadcn-ui",
|
|
54
|
+
"react-vite": "shadcn-ui",
|
|
55
|
+
"tanstack-start": "shadcn-ui",
|
|
56
|
+
next: "shadcn-ui",
|
|
57
|
+
vinext: "shadcn-ui",
|
|
58
|
+
nuxt: "daisyui",
|
|
59
|
+
svelte: "daisyui",
|
|
60
|
+
solid: "daisyui",
|
|
61
|
+
"solid-start": "daisyui",
|
|
62
|
+
astro: "daisyui",
|
|
63
|
+
qwik: "daisyui",
|
|
64
|
+
angular: "daisyui",
|
|
65
|
+
redwood: "daisyui",
|
|
66
|
+
fresh: "daisyui",
|
|
67
|
+
"native-bare": "none",
|
|
68
|
+
"native-uniwind": "none",
|
|
69
|
+
"native-unistyles": "none",
|
|
70
|
+
none: "none"
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/utils/get-latest-cli-version.ts
|
|
75
|
+
const getLatestCLIVersion = () => {
|
|
76
|
+
const packageJsonPath = path.join(PKG_ROOT, "package.json");
|
|
77
|
+
return fs.readJSONSync(packageJsonPath).version ?? "1.0.0";
|
|
78
|
+
};
|
|
79
|
+
|
|
18
80
|
//#endregion
|
|
19
81
|
//#region src/utils/graph-summary.ts
|
|
20
82
|
const FRONTEND_LABELS = {
|
|
@@ -167,71 +229,6 @@ function getGraphBackendDeployInstructions(config) {
|
|
|
167
229
|
}
|
|
168
230
|
}
|
|
169
231
|
|
|
170
|
-
//#endregion
|
|
171
|
-
//#region src/utils/get-package-manager.ts
|
|
172
|
-
const getUserPkgManager = () => {
|
|
173
|
-
const userAgent = process.env.npm_config_user_agent;
|
|
174
|
-
if (userAgent?.startsWith("pnpm")) return "pnpm";
|
|
175
|
-
if (userAgent?.startsWith("bun")) return "bun";
|
|
176
|
-
if (userAgent?.startsWith("yarn")) return "yarn";
|
|
177
|
-
return "npm";
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
//#endregion
|
|
181
|
-
//#region src/constants.ts
|
|
182
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
183
|
-
const distPath = path.dirname(__filename);
|
|
184
|
-
const PKG_ROOT = path.join(distPath, "../");
|
|
185
|
-
const DEFAULT_CONFIG_BASE = createCliDefaultProjectConfigBase(getUserPkgManager());
|
|
186
|
-
function getDefaultConfig() {
|
|
187
|
-
return {
|
|
188
|
-
...DEFAULT_CONFIG_BASE,
|
|
189
|
-
projectDir: path.resolve(process.cwd(), DEFAULT_CONFIG_BASE.projectName),
|
|
190
|
-
packageManager: getUserPkgManager(),
|
|
191
|
-
frontend: [...DEFAULT_CONFIG_BASE.frontend],
|
|
192
|
-
addons: [...DEFAULT_CONFIG_BASE.addons],
|
|
193
|
-
examples: [...DEFAULT_CONFIG_BASE.examples],
|
|
194
|
-
rustLibraries: [...DEFAULT_CONFIG_BASE.rustLibraries],
|
|
195
|
-
pythonAi: [...DEFAULT_CONFIG_BASE.pythonAi],
|
|
196
|
-
javaLibraries: [...DEFAULT_CONFIG_BASE.javaLibraries],
|
|
197
|
-
javaTestingLibraries: [...DEFAULT_CONFIG_BASE.javaTestingLibraries],
|
|
198
|
-
aiDocs: [...DEFAULT_CONFIG_BASE.aiDocs]
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
const DEFAULT_CONFIG = getDefaultConfig();
|
|
202
|
-
/**
|
|
203
|
-
* Default UI library for each frontend framework
|
|
204
|
-
* Falls back based on what's compatible
|
|
205
|
-
*/
|
|
206
|
-
const DEFAULT_UI_LIBRARY_BY_FRONTEND = {
|
|
207
|
-
"tanstack-router": "shadcn-ui",
|
|
208
|
-
"react-router": "shadcn-ui",
|
|
209
|
-
"react-vite": "shadcn-ui",
|
|
210
|
-
"tanstack-start": "shadcn-ui",
|
|
211
|
-
next: "shadcn-ui",
|
|
212
|
-
vinext: "shadcn-ui",
|
|
213
|
-
nuxt: "daisyui",
|
|
214
|
-
svelte: "daisyui",
|
|
215
|
-
solid: "daisyui",
|
|
216
|
-
"solid-start": "daisyui",
|
|
217
|
-
astro: "daisyui",
|
|
218
|
-
qwik: "daisyui",
|
|
219
|
-
angular: "daisyui",
|
|
220
|
-
redwood: "daisyui",
|
|
221
|
-
fresh: "daisyui",
|
|
222
|
-
"native-bare": "none",
|
|
223
|
-
"native-uniwind": "none",
|
|
224
|
-
"native-unistyles": "none",
|
|
225
|
-
none: "none"
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
//#endregion
|
|
229
|
-
//#region src/utils/get-latest-cli-version.ts
|
|
230
|
-
const getLatestCLIVersion = () => {
|
|
231
|
-
const packageJsonPath = path.join(PKG_ROOT, "package.json");
|
|
232
|
-
return fs.readJSONSync(packageJsonPath).version ?? "1.0.0";
|
|
233
|
-
};
|
|
234
|
-
|
|
235
232
|
//#endregion
|
|
236
233
|
//#region src/utils/bts-config.ts
|
|
237
234
|
const BTS_CONFIG_FILE = "bts.jsonc";
|
|
@@ -319,6 +316,7 @@ function normalizeGraphConfigForPersistence(projectConfig, stackParts) {
|
|
|
319
316
|
}
|
|
320
317
|
if (selectedEcosystems.has("go") && projectConfig.auth === "go-better-auth" && legacyConfig.auth === "none") normalized.auth = projectConfig.auth;
|
|
321
318
|
if (!selectedEcosystems.has("java")) {
|
|
319
|
+
normalized.javaLanguage = "java";
|
|
322
320
|
normalized.javaWebFramework = "none";
|
|
323
321
|
normalized.javaBuildTool = "none";
|
|
324
322
|
normalized.javaOrm = "none";
|
|
@@ -462,6 +460,7 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
462
460
|
testing: persistedConfig.testing,
|
|
463
461
|
packageManager: persistedConfig.packageManager,
|
|
464
462
|
versionChannel: persistedConfig.versionChannel,
|
|
463
|
+
workspaceShape: persistedConfig.workspaceShape === "single-app" ? "single-app" : void 0,
|
|
465
464
|
dbSetup: persistedConfig.dbSetup,
|
|
466
465
|
api: persistedConfig.api,
|
|
467
466
|
webDeploy: persistedConfig.webDeploy,
|
|
@@ -537,6 +536,7 @@ function buildBtsConfigForPersistence(projectConfig, metadata = {}) {
|
|
|
537
536
|
goCaching: persistedConfig.goCaching,
|
|
538
537
|
goConfig: persistedConfig.goConfig,
|
|
539
538
|
goObservability: persistedConfig.goObservability,
|
|
539
|
+
javaLanguage: persistedConfig.javaLanguage,
|
|
540
540
|
javaWebFramework: persistedConfig.javaWebFramework,
|
|
541
541
|
javaBuildTool: persistedConfig.javaBuildTool,
|
|
542
542
|
javaOrm: persistedConfig.javaOrm,
|
|
@@ -617,6 +617,7 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
617
617
|
testing: btsConfig.testing,
|
|
618
618
|
packageManager: btsConfig.packageManager,
|
|
619
619
|
versionChannel: btsConfig.versionChannel,
|
|
620
|
+
workspaceShape: btsConfig.workspaceShape,
|
|
620
621
|
dbSetup: btsConfig.dbSetup,
|
|
621
622
|
api: btsConfig.api,
|
|
622
623
|
webDeploy: btsConfig.webDeploy,
|
|
@@ -692,6 +693,7 @@ async function writeBtsConfig(projectConfig, metadata = {}) {
|
|
|
692
693
|
goCaching: btsConfig.goCaching,
|
|
693
694
|
goConfig: btsConfig.goConfig,
|
|
694
695
|
goObservability: btsConfig.goObservability,
|
|
696
|
+
javaLanguage: btsConfig.javaLanguage,
|
|
695
697
|
javaWebFramework: btsConfig.javaWebFramework,
|
|
696
698
|
javaBuildTool: btsConfig.javaBuildTool,
|
|
697
699
|
javaOrm: btsConfig.javaOrm,
|
|
@@ -814,83 +816,4 @@ async function updateBtsConfig(projectDir, updates) {
|
|
|
814
816
|
}
|
|
815
817
|
|
|
816
818
|
//#endregion
|
|
817
|
-
|
|
818
|
-
const cliStorage = new AsyncLocalStorage();
|
|
819
|
-
function defaultContext() {
|
|
820
|
-
return {
|
|
821
|
-
navigation: {
|
|
822
|
-
isFirstPrompt: false,
|
|
823
|
-
lastPromptShownUI: false
|
|
824
|
-
},
|
|
825
|
-
silent: false
|
|
826
|
-
};
|
|
827
|
-
}
|
|
828
|
-
function getContext() {
|
|
829
|
-
const ctx = cliStorage.getStore();
|
|
830
|
-
if (!ctx) return defaultContext();
|
|
831
|
-
return ctx;
|
|
832
|
-
}
|
|
833
|
-
function tryGetContext() {
|
|
834
|
-
return cliStorage.getStore();
|
|
835
|
-
}
|
|
836
|
-
function isSilent() {
|
|
837
|
-
return getContext().silent;
|
|
838
|
-
}
|
|
839
|
-
function isFirstPrompt() {
|
|
840
|
-
return getContext().navigation.isFirstPrompt;
|
|
841
|
-
}
|
|
842
|
-
function didLastPromptShowUI() {
|
|
843
|
-
return getContext().navigation.lastPromptShownUI;
|
|
844
|
-
}
|
|
845
|
-
function setIsFirstPrompt(value) {
|
|
846
|
-
const ctx = tryGetContext();
|
|
847
|
-
if (ctx) ctx.navigation.isFirstPrompt = value;
|
|
848
|
-
}
|
|
849
|
-
function setLastPromptShownUI(value) {
|
|
850
|
-
const ctx = tryGetContext();
|
|
851
|
-
if (ctx) ctx.navigation.lastPromptShownUI = value;
|
|
852
|
-
}
|
|
853
|
-
async function runWithContextAsync(options, fn) {
|
|
854
|
-
const ctx = {
|
|
855
|
-
navigation: {
|
|
856
|
-
isFirstPrompt: false,
|
|
857
|
-
lastPromptShownUI: false
|
|
858
|
-
},
|
|
859
|
-
silent: options.silent ?? false
|
|
860
|
-
};
|
|
861
|
-
return cliStorage.run(ctx, fn);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
//#endregion
|
|
865
|
-
//#region src/utils/errors.ts
|
|
866
|
-
var UserCancelledError = class extends Error {
|
|
867
|
-
constructor(message = "Operation cancelled") {
|
|
868
|
-
super(message);
|
|
869
|
-
this.name = "UserCancelledError";
|
|
870
|
-
}
|
|
871
|
-
};
|
|
872
|
-
var CLIError = class extends Error {
|
|
873
|
-
constructor(message) {
|
|
874
|
-
super(message);
|
|
875
|
-
this.name = "CLIError";
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
|
-
function exitWithError(message) {
|
|
879
|
-
if (isSilent()) throw new CLIError(message);
|
|
880
|
-
consola.error(pc.red(message));
|
|
881
|
-
process.exit(1);
|
|
882
|
-
}
|
|
883
|
-
function exitCancelled(message = "Operation cancelled") {
|
|
884
|
-
if (isSilent()) throw new UserCancelledError(message);
|
|
885
|
-
cancel(pc.red(message));
|
|
886
|
-
process.exit(1);
|
|
887
|
-
}
|
|
888
|
-
function handleError(error, fallbackMessage) {
|
|
889
|
-
const message = error instanceof Error ? error.message : fallbackMessage || String(error);
|
|
890
|
-
if (isSilent()) throw error instanceof Error ? error : new Error(message);
|
|
891
|
-
consola.error(pc.red(message));
|
|
892
|
-
process.exit(1);
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
//#endregion
|
|
896
|
-
export { types_exports as A, getEffectiveStack as C, getGraphSummary as D, getGraphPart as E, getPrimaryGraphPart as O, getUserPkgManager as S, getGraphBackendUrl as T, writeBtsConfig as _, handleError as a, DEFAULT_UI_LIBRARY_BY_FRONTEND as b, isSilent as c, setLastPromptShownUI as d, buildBtsConfigForPersistence as f, updateBtsConfig as g, readBtsConfigFromFile as h, exitWithError as i, hasGraphPart as k, runWithContextAsync as l, readBtsConfig as m, UserCancelledError as n, didLastPromptShowUI as o, previewBtsConfigUpdate as p, exitCancelled as r, isFirstPrompt as s, CLIError as t, setIsFirstPrompt as u, getLatestCLIVersion as v, getGraphBackendDeployInstructions as w, getDefaultConfig as x, DEFAULT_CONFIG as y };
|
|
819
|
+
export { DEFAULT_UI_LIBRARY_BY_FRONTEND as _, updateBtsConfig as a, types_exports as b, getGraphBackendDeployInstructions as c, getGraphSummary as d, getPrimaryGraphPart as f, DEFAULT_CONFIG as g, BUILDER_URL as h, readBtsConfigFromFile as i, getGraphBackendUrl as l, getLatestCLIVersion as m, previewBtsConfigUpdate as n, writeBtsConfig as o, hasGraphPart as p, readBtsConfig as r, getEffectiveStack as s, buildBtsConfigForPersistence as t, getGraphPart as u, getDefaultConfig as v, getUserPkgManager as y };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//#region src/cli.ts
|
|
3
|
-
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-
|
|
4
|
-
else import("./run-
|
|
3
|
+
if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-492OkjcS.mjs").then((m) => m.startMcpServer());
|
|
4
|
+
else import("./run-buK4aZS8.mjs").then((m) => m.createBtsCli().run());
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { };
|