create-better-fullstack 2.1.3 → 2.1.5
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 +257 -0
- package/dist/{addons-setup-C_xrNtkL.mjs → addons-setup-CyrP1IV-.mjs} +1 -1
- package/dist/addons-setup-DyMm42a5.mjs +5 -0
- package/dist/cli.mjs +2 -2
- package/dist/{doctor-BFSSbS-U.mjs → doctor-DBoq7bZ9.mjs} +2 -2
- package/dist/{errors-D9yiiGVq.mjs → errors-Cyol8zbN.mjs} +18 -2
- package/dist/{config-validation-C4glouQh.mjs → file-formatter-B3dsev2l.mjs} +372 -456
- package/dist/{generated-checks-DUvVXWId.mjs → generated-checks-C8hn9w2i.mjs} +1 -1
- package/dist/index.d.mts +1012 -108
- package/dist/index.mjs +7 -8
- package/dist/{install-dependencies-DDGF-zDG.mjs → install-dependencies-CgNh-aOy.mjs} +2 -2
- package/dist/{mcp-BXLhb7wW.mjs → mcp-CsW3i66c.mjs} +2 -3
- package/dist/mcp-entry.mjs +195 -10
- package/dist/{run-DRzP53v3.mjs → run-BYse4yJy.mjs} +61 -61
- package/dist/run-_cf_sFwM.mjs +10 -0
- package/dist/templates-CnTOtKjm.mjs +497 -0
- package/package.json +3 -3
- package/dist/add-handler-9F-AsGM-.mjs +0 -151
- package/dist/addons-setup-C8eaCaH5.mjs +0 -5
- package/dist/compatibility-rules-D7zYNVjC.mjs +0 -372
- package/dist/run-BmRKR2wG.mjs +0 -11
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./errors-
|
|
3
|
-
import { a as
|
|
2
|
+
import "./errors-Cyol8zbN.mjs";
|
|
3
|
+
import { a as createBtsCli, c as history, d as telemetry, i as create, l as router, n as builder, o as docs, r as check, s as doctor, t as add, u as sponsors } from "./run-BYse4yJy.mjs";
|
|
4
4
|
import "./render-title-zvyKC1ej.mjs";
|
|
5
|
-
import "./addons-setup-
|
|
6
|
-
import "./
|
|
7
|
-
import "./
|
|
8
|
-
import "./
|
|
9
|
-
import "./generated-checks-DUvVXWId.mjs";
|
|
5
|
+
import "./addons-setup-CyrP1IV-.mjs";
|
|
6
|
+
import "./file-formatter-B3dsev2l.mjs";
|
|
7
|
+
import "./install-dependencies-CgNh-aOy.mjs";
|
|
8
|
+
import "./generated-checks-C8hn9w2i.mjs";
|
|
10
9
|
import { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, generateVirtualProject } from "@better-fullstack/template-generator";
|
|
11
10
|
|
|
12
11
|
//#region src/index.ts
|
|
@@ -199,4 +198,4 @@ async function createVirtual(options) {
|
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
//#endregion
|
|
202
|
-
export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors, telemetry };
|
|
201
|
+
export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, check, create, createBtsCli, createVirtual, docs, doctor, generateVirtualProject, history, router, sponsors, telemetry };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as types_exports, d as setLastPromptShownUI, r as exitCancelled, s as isFirstPrompt, u as setIsFirstPrompt$1, y as DEFAULT_CONFIG } from "./errors-
|
|
3
|
-
import {
|
|
2
|
+
import { A as types_exports, d as setLastPromptShownUI, r as exitCancelled, s as isFirstPrompt, u as setIsFirstPrompt$1, y as DEFAULT_CONFIG } from "./errors-Cyol8zbN.mjs";
|
|
3
|
+
import { g as validateAddonCompatibility, o as getCompatibleAddons } from "./file-formatter-B3dsev2l.mjs";
|
|
4
4
|
import { log, spinner } from "@clack/prompts";
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import fs from "fs-extra";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./errors-
|
|
3
|
-
import "./
|
|
4
|
-
import "./compatibility-rules-D7zYNVjC.mjs";
|
|
2
|
+
import "./errors-Cyol8zbN.mjs";
|
|
3
|
+
import "./file-formatter-B3dsev2l.mjs";
|
|
5
4
|
import { i as startMcpServer, n as MCP_STACK_UPDATE_SCHEMA, r as getMcpGraphPreview, t as MCP_PLAN_CREATE_SCHEMA } from "./mcp-entry.mjs";
|
|
6
5
|
|
|
7
6
|
export { startMcpServer };
|
package/dist/mcp-entry.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as types_exports, C as getEffectiveStack, D as getGraphSummary, _ as writeBtsConfig, f as buildBtsConfigForPersistence, m as readBtsConfig, p as previewBtsConfigUpdate, v as getLatestCLIVersion, x as getDefaultConfig } from "./errors-
|
|
3
|
-
import {
|
|
4
|
-
import "./
|
|
2
|
+
import { A as types_exports, C as getEffectiveStack, D as getGraphSummary, _ as writeBtsConfig, f as buildBtsConfigForPersistence, m as readBtsConfig, p as previewBtsConfigUpdate, v as getLatestCLIVersion, x as getDefaultConfig } from "./errors-Cyol8zbN.mjs";
|
|
3
|
+
import { r as validateConfigForProgrammaticUse, t as formatCode, v as CreateCommandOptionsSchema } from "./file-formatter-B3dsev2l.mjs";
|
|
4
|
+
import { n as getTemplateDescription, r as generateReproducibleCommand, t as getTemplateConfig } from "./templates-CnTOtKjm.mjs";
|
|
5
5
|
import z from "zod";
|
|
6
6
|
import fs from "fs-extra";
|
|
7
7
|
import path from "node:path";
|
|
@@ -153,6 +153,75 @@ function mergeStackPartSpecs(currentConfig, specs) {
|
|
|
153
153
|
stackParts
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
|
+
const GRAPH_CACHE_CONFIG_KEYS = new Set([
|
|
157
|
+
"stackParts",
|
|
158
|
+
"graphSummary",
|
|
159
|
+
"effectiveStack"
|
|
160
|
+
]);
|
|
161
|
+
function stableJson(value) {
|
|
162
|
+
return JSON.stringify(value);
|
|
163
|
+
}
|
|
164
|
+
function getChangedConfigKeys(currentConfig, proposedConfig) {
|
|
165
|
+
const keys = new Set([...Object.keys(currentConfig), ...Object.keys(proposedConfig)]);
|
|
166
|
+
const changed = /* @__PURE__ */ new Set();
|
|
167
|
+
for (const key of keys) {
|
|
168
|
+
if (GRAPH_CACHE_CONFIG_KEYS.has(key)) continue;
|
|
169
|
+
if (stableJson(currentConfig[key]) !== stableJson(proposedConfig[key])) changed.add(key);
|
|
170
|
+
}
|
|
171
|
+
return changed;
|
|
172
|
+
}
|
|
173
|
+
function getProjectedConfigKeys(part, parts) {
|
|
174
|
+
const owner = part.ownerPartId ? parts.find((candidate) => candidate.id === part.ownerPartId) : void 0;
|
|
175
|
+
const partProjection = (0, types_exports.stackPartsToLegacyProjectConfigPartial)(owner ? [owner, part] : [part]);
|
|
176
|
+
const keys = /* @__PURE__ */ new Set();
|
|
177
|
+
for (const key of Object.keys(partProjection)) {
|
|
178
|
+
if (GRAPH_CACHE_CONFIG_KEYS.has(key)) continue;
|
|
179
|
+
const value = partProjection[key];
|
|
180
|
+
if (value === part.toolId || Array.isArray(value) && value.includes(part.toolId)) keys.add(key);
|
|
181
|
+
}
|
|
182
|
+
return keys;
|
|
183
|
+
}
|
|
184
|
+
function getUpdatedSpecForChangedPart(part, parts, proposedConfig, changedKeys) {
|
|
185
|
+
const projectedKeys = getProjectedConfigKeys(part, parts);
|
|
186
|
+
for (const key of projectedKeys) {
|
|
187
|
+
if (!changedKeys.has(key)) continue;
|
|
188
|
+
const value = proposedConfig[key];
|
|
189
|
+
if (typeof value !== "string" || value === "none") continue;
|
|
190
|
+
return (0, types_exports.formatStackPartSpec)({
|
|
191
|
+
...part,
|
|
192
|
+
toolId: value
|
|
193
|
+
}, parts);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function mergeDerivedStackPartsWithExistingGraph(currentConfig, proposedConfig) {
|
|
197
|
+
const currentStackParts = currentConfig.stackParts?.length ? currentConfig.stackParts : (0, types_exports.legacyProjectConfigToStackParts)(currentConfig);
|
|
198
|
+
const derivedStackParts = (0, types_exports.legacyProjectConfigToStackParts)(proposedConfig);
|
|
199
|
+
if (currentStackParts.length === 0) return derivedStackParts;
|
|
200
|
+
const changedKeys = getChangedConfigKeys(currentConfig, proposedConfig);
|
|
201
|
+
const preservedParts = currentStackParts.filter((part) => {
|
|
202
|
+
if (part.source === "provided") return false;
|
|
203
|
+
if (part.toolId === "none") return false;
|
|
204
|
+
const projectedKeys = getProjectedConfigKeys(part, currentStackParts);
|
|
205
|
+
if (projectedKeys.size === 0) return true;
|
|
206
|
+
return [...projectedKeys].every((key) => !changedKeys.has(key));
|
|
207
|
+
});
|
|
208
|
+
const updatedSpecs = currentStackParts.filter((part) => part.source !== "provided" && part.toolId !== "none").flatMap((part) => {
|
|
209
|
+
const spec = getUpdatedSpecForChangedPart(part, currentStackParts, proposedConfig, changedKeys);
|
|
210
|
+
return spec ? [spec] : [];
|
|
211
|
+
});
|
|
212
|
+
const preservedSpecs = new Set(preservedParts.map((part) => (0, types_exports.formatStackPartSpec)(part, currentStackParts)));
|
|
213
|
+
const coveredParts = (0, types_exports.parseStackPartSpecs)([...new Set([...preservedSpecs, ...updatedSpecs])], "selected");
|
|
214
|
+
const preservedProjectedKeys = /* @__PURE__ */ new Set();
|
|
215
|
+
for (const part of coveredParts) for (const key of getProjectedConfigKeys(part, coveredParts)) preservedProjectedKeys.add(key);
|
|
216
|
+
const nextSpecs = [...new Set([...preservedSpecs, ...updatedSpecs])];
|
|
217
|
+
for (const part of derivedStackParts) {
|
|
218
|
+
if (part.source === "provided") continue;
|
|
219
|
+
const spec = (0, types_exports.formatStackPartSpec)(part, derivedStackParts);
|
|
220
|
+
if (nextSpecs.includes(spec)) continue;
|
|
221
|
+
if (![...getProjectedConfigKeys(part, derivedStackParts)].some((key) => preservedProjectedKeys.has(key))) nextSpecs.push(spec);
|
|
222
|
+
}
|
|
223
|
+
return (0, types_exports.parseStackPartSpecs)([...new Set(nextSpecs)], "selected");
|
|
224
|
+
}
|
|
156
225
|
function asString(value, fallback = "none") {
|
|
157
226
|
return typeof value === "string" ? value : fallback;
|
|
158
227
|
}
|
|
@@ -543,6 +612,30 @@ async function generateTree(config) {
|
|
|
543
612
|
if (!result.success || !result.tree) throw new Error(result.error ?? "Failed to generate virtual project");
|
|
544
613
|
return result.tree;
|
|
545
614
|
}
|
|
615
|
+
async function formatGeneratedTree(tree) {
|
|
616
|
+
const denoConfigDirs = /* @__PURE__ */ new Set();
|
|
617
|
+
function collectDenoConfigDirs(nodes) {
|
|
618
|
+
for (const node of nodes) if (node.type === "file") {
|
|
619
|
+
if (node.name === "deno.json") denoConfigDirs.add(path.posix.dirname(node.path));
|
|
620
|
+
} else collectDenoConfigDirs(node.children);
|
|
621
|
+
}
|
|
622
|
+
function isUnderDenoConfig(filePath) {
|
|
623
|
+
return [...denoConfigDirs].some((dir) => dir === "." || filePath === dir || filePath.startsWith(`${dir}/`));
|
|
624
|
+
}
|
|
625
|
+
async function formatNodes(nodes) {
|
|
626
|
+
await Promise.all(nodes.map(async (node) => {
|
|
627
|
+
if (node.type === "file") {
|
|
628
|
+
if (node.content === BINARY_FILE_MARKER || isUnderDenoConfig(node.path)) return;
|
|
629
|
+
const formatted = await formatCode(node.path, node.content);
|
|
630
|
+
if (formatted) node.content = formatted;
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
await formatNodes(node.children);
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
collectDenoConfigDirs(tree.root.children);
|
|
637
|
+
await formatNodes(tree.root.children);
|
|
638
|
+
}
|
|
546
639
|
function treeToFileMap(tree) {
|
|
547
640
|
const files = /* @__PURE__ */ new Map();
|
|
548
641
|
function walk(nodes) {
|
|
@@ -552,6 +645,27 @@ function treeToFileMap(tree) {
|
|
|
552
645
|
walk(tree.root.children);
|
|
553
646
|
return files;
|
|
554
647
|
}
|
|
648
|
+
function treeToFileSnapshotMap(tree) {
|
|
649
|
+
const files = /* @__PURE__ */ new Map();
|
|
650
|
+
function walk(nodes) {
|
|
651
|
+
for (const node of nodes) if (node.type === "file") files.set(node.path, {
|
|
652
|
+
content: node.content,
|
|
653
|
+
sourcePath: node.sourcePath
|
|
654
|
+
});
|
|
655
|
+
else walk(node.children);
|
|
656
|
+
}
|
|
657
|
+
walk(tree.root.children);
|
|
658
|
+
return files;
|
|
659
|
+
}
|
|
660
|
+
function uniqueContents(contents) {
|
|
661
|
+
return [...new Set(contents.filter((content) => content !== void 0))];
|
|
662
|
+
}
|
|
663
|
+
function contentMatchesAny(content, candidates) {
|
|
664
|
+
return candidates.some((candidate) => candidate === content);
|
|
665
|
+
}
|
|
666
|
+
function contentSetsIntersect(left, right) {
|
|
667
|
+
return left.some((candidate) => right.includes(candidate));
|
|
668
|
+
}
|
|
555
669
|
function parseJson(content) {
|
|
556
670
|
if (!content) return null;
|
|
557
671
|
try {
|
|
@@ -668,11 +782,61 @@ function collectEnvReferences(content) {
|
|
|
668
782
|
]) for (const match of content.matchAll(pattern)) if (match[1]) keys.add(match[1]);
|
|
669
783
|
return keys;
|
|
670
784
|
}
|
|
785
|
+
function collectImplicitEnvKeys(config) {
|
|
786
|
+
const keys = /* @__PURE__ */ new Set();
|
|
787
|
+
if (config.email === "resend") {
|
|
788
|
+
keys.add("RESEND_API_KEY");
|
|
789
|
+
keys.add("RESEND_FROM_EMAIL");
|
|
790
|
+
}
|
|
791
|
+
if (config.observability === "sentry") keys.add("SENTRY_DSN");
|
|
792
|
+
return [...keys].sort();
|
|
793
|
+
}
|
|
671
794
|
function recordEnvReferenceChanges(envChanges, filePath, previousContent, proposedContent) {
|
|
672
795
|
const previous = collectEnvReferences(previousContent);
|
|
673
796
|
const added = [...collectEnvReferences(proposedContent)].filter((key) => !previous.has(key)).sort();
|
|
674
797
|
if (added.length > 0) envChanges[filePath] = [...new Set([...envChanges[filePath] ?? [], ...added])].sort();
|
|
675
798
|
}
|
|
799
|
+
function appendMissingEnvKeys(content, keys) {
|
|
800
|
+
const existingKeys = parseEnvKeys(content);
|
|
801
|
+
const missing = keys.filter((key) => !existingKeys.has(key));
|
|
802
|
+
if (missing.length === 0) return { keys: [] };
|
|
803
|
+
return {
|
|
804
|
+
content: `${content}${content.trim().length === 0 ? "" : content.endsWith("\n") ? "\n" : "\n\n"}${missing.map((key) => `${key}=`).join("\n")}\n`,
|
|
805
|
+
keys: missing
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
async function addMissingEnvExampleOperation(options) {
|
|
809
|
+
const requiredKeys = [...new Set([...Object.entries(options.envChanges).filter(([filePath]) => !isEnvFilePath(filePath)).flatMap(([, keys]) => keys), ...collectImplicitEnvKeys(options.proposedConfig)])].sort();
|
|
810
|
+
if (requiredKeys.length === 0) return;
|
|
811
|
+
const candidatePaths = new Set([
|
|
812
|
+
"apps/server/.env.example",
|
|
813
|
+
".env.example",
|
|
814
|
+
...[...options.proposedGeneratedFiles.keys()].filter(isEnvFilePath)
|
|
815
|
+
]);
|
|
816
|
+
let targetPath;
|
|
817
|
+
for (const candidate of candidatePaths) if (options.proposedGeneratedFiles.has(candidate) || await fs.pathExists(path.join(options.projectDir, candidate))) {
|
|
818
|
+
targetPath = candidate;
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
if (!targetPath) return;
|
|
822
|
+
const existingOperation = options.operations.find((operation) => operation.path === targetPath && operation.writeMode === "content");
|
|
823
|
+
const targetFilePath = path.join(options.projectDir, targetPath);
|
|
824
|
+
const merged = appendMissingEnvKeys(existingOperation?.content ?? (await fs.pathExists(targetFilePath) ? await fs.readFile(targetFilePath, "utf-8") : ""), requiredKeys);
|
|
825
|
+
if (!merged.content) return;
|
|
826
|
+
if (existingOperation) {
|
|
827
|
+
existingOperation.content = merged.content;
|
|
828
|
+
existingOperation.summary = [...existingOperation.summary, `env refs: ${merged.keys.join(", ")}`];
|
|
829
|
+
} else options.operations.push({
|
|
830
|
+
kind: "merge",
|
|
831
|
+
path: targetPath,
|
|
832
|
+
writeMode: "content",
|
|
833
|
+
content: merged.content,
|
|
834
|
+
summary: [`env refs: ${merged.keys.join(", ")}`]
|
|
835
|
+
});
|
|
836
|
+
if (await fs.pathExists(targetFilePath)) options.filesToPatch.push(targetPath);
|
|
837
|
+
else options.filesToAdd.push(targetPath);
|
|
838
|
+
options.envChanges[targetPath] = [...new Set([...options.envChanges[targetPath] ?? [], ...merged.keys])].sort();
|
|
839
|
+
}
|
|
676
840
|
function getInstallCommand$1(config) {
|
|
677
841
|
switch (config.ecosystem) {
|
|
678
842
|
case "rust": return "cargo build";
|
|
@@ -687,7 +851,7 @@ function getGraphPreview(config) {
|
|
|
687
851
|
const stackParts = config.stackParts?.length ? config.stackParts : (0, types_exports.legacyProjectConfigToStackParts)(config);
|
|
688
852
|
const graphSummary = stackParts.length > 0 ? getGraphSummary({ stackParts }) : void 0;
|
|
689
853
|
const effectiveStack = stackParts.length > 0 ? getEffectiveStack({ stackParts }) : void 0;
|
|
690
|
-
const stackPartSpecs = stackParts.filter((part) => part.source !== "provided").map((part) => (0, types_exports.formatStackPartSpec)(part, stackParts));
|
|
854
|
+
const stackPartSpecs = stackParts.filter((part) => part.source !== "provided" && part.toolId !== "none").map((part) => (0, types_exports.formatStackPartSpec)(part, stackParts));
|
|
691
855
|
return {
|
|
692
856
|
...graphSummary ? {
|
|
693
857
|
graphSummary,
|
|
@@ -721,7 +885,7 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
721
885
|
};
|
|
722
886
|
const compatibilityAdjustments = [...dependencyExpansion.adjustments, ...compatibilityResult.changes.map((change) => `${change.category}: ${change.message}`)];
|
|
723
887
|
if (compatibilityResult.adjustedStack) proposedConfig = mergeProjectConfig(proposedConfig, compatibilityChangesToProjectConfig(compatibilityResult.adjustedStack, proposedConfig));
|
|
724
|
-
proposedConfig.stackParts = (
|
|
888
|
+
proposedConfig.stackParts = mergeDerivedStackPartsWithExistingGraph(currentConfig, proposedConfig);
|
|
725
889
|
Object.assign(proposedConfig, mergeStackPartSpecs(proposedConfig, stackPartSpecs));
|
|
726
890
|
try {
|
|
727
891
|
validateConfigForProgrammaticUse(proposedConfig);
|
|
@@ -748,6 +912,9 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
748
912
|
error: `Failed to generate stack update plan: ${error instanceof Error ? error.message : String(error)}`
|
|
749
913
|
};
|
|
750
914
|
}
|
|
915
|
+
const currentRawGeneratedFiles = treeToFileSnapshotMap(currentTree);
|
|
916
|
+
const proposedRawGeneratedFiles = treeToFileSnapshotMap(proposedTree);
|
|
917
|
+
await Promise.all([formatGeneratedTree(currentTree), formatGeneratedTree(proposedTree)]);
|
|
751
918
|
const currentGeneratedFiles = treeToFileMap(currentTree);
|
|
752
919
|
const proposedGeneratedFiles = treeToFileMap(proposedTree);
|
|
753
920
|
const operations = [];
|
|
@@ -770,8 +937,12 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
770
937
|
}));
|
|
771
938
|
for (const { filePath, proposedFile, exists, existingBuffer } of proposedFileEntries) {
|
|
772
939
|
const previousFile = currentGeneratedFiles.get(filePath);
|
|
940
|
+
const previousRawFile = currentRawGeneratedFiles.get(filePath);
|
|
941
|
+
const proposedRawFile = proposedRawGeneratedFiles.get(filePath);
|
|
773
942
|
const proposedContent = proposedFile.content;
|
|
774
943
|
const previousContent = previousFile?.content;
|
|
944
|
+
const currentBaselineContents = uniqueContents([previousRawFile?.content, previousContent]);
|
|
945
|
+
const proposedBaselineContents = uniqueContents([proposedRawFile?.content, proposedContent]);
|
|
775
946
|
const isBinaryFile = isGeneratedBinaryFile(proposedFile) || isGeneratedBinaryFile(previousFile);
|
|
776
947
|
const existingContent = exists && existingBuffer && !isBinaryFile ? existingBuffer.toString("utf-8") : void 0;
|
|
777
948
|
if (!exists) {
|
|
@@ -803,7 +974,7 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
803
974
|
manualReviewBlockers.push(`${filePath}: existing binary file differs from the generated baseline`);
|
|
804
975
|
continue;
|
|
805
976
|
}
|
|
806
|
-
if (existingContent === void 0 || existingContent
|
|
977
|
+
if (existingContent === void 0 || contentMatchesAny(existingContent, proposedBaselineContents)) {
|
|
807
978
|
filesUnchanged.push(filePath);
|
|
808
979
|
continue;
|
|
809
980
|
}
|
|
@@ -839,7 +1010,11 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
839
1010
|
}
|
|
840
1011
|
continue;
|
|
841
1012
|
}
|
|
842
|
-
if (
|
|
1013
|
+
if (existingContent !== void 0 && contentMatchesAny(existingContent, currentBaselineContents)) {
|
|
1014
|
+
if (contentSetsIntersect(currentBaselineContents, proposedBaselineContents)) {
|
|
1015
|
+
filesUnchanged.push(filePath);
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
843
1018
|
filesToPatch.push(filePath);
|
|
844
1019
|
operations.push({
|
|
845
1020
|
kind: "replace",
|
|
@@ -852,6 +1027,15 @@ async function planStackUpdate(projectDirInput, input) {
|
|
|
852
1027
|
if (isSkippableGeneratedDoc(filePath)) continue;
|
|
853
1028
|
manualReviewBlockers.push(`${filePath}: existing file differs from the generated baseline`);
|
|
854
1029
|
}
|
|
1030
|
+
await addMissingEnvExampleOperation({
|
|
1031
|
+
projectDir,
|
|
1032
|
+
proposedGeneratedFiles,
|
|
1033
|
+
operations,
|
|
1034
|
+
filesToAdd,
|
|
1035
|
+
filesToPatch,
|
|
1036
|
+
envChanges,
|
|
1037
|
+
proposedConfig: normalizedProposedConfig
|
|
1038
|
+
});
|
|
855
1039
|
const graphPreview = getGraphPreview(persistedProposedConfig);
|
|
856
1040
|
return {
|
|
857
1041
|
success: true,
|
|
@@ -882,6 +1066,7 @@ async function applyStackUpdate(projectDirInput, input) {
|
|
|
882
1066
|
const projectName = await inferProjectName(plan.projectDir);
|
|
883
1067
|
const proposedConfig = configFromBtsConfig(plan.proposedConfig, plan.projectDir, projectName);
|
|
884
1068
|
const proposedTree = await generateTree(proposedConfig);
|
|
1069
|
+
await formatGeneratedTree(proposedTree);
|
|
885
1070
|
const generatedPaths = new Set(plan.operations.filter((operation) => operation.writeMode === "generated").map((operation) => operation.path));
|
|
886
1071
|
if (generatedPaths.size > 0) await writeSelectedFiles(proposedTree, plan.projectDir, (filePath) => generatedPaths.has(filePath));
|
|
887
1072
|
await Promise.all(plan.operations.filter((operation) => operation.writeMode === "content").map(async (operation) => {
|
|
@@ -1336,7 +1521,7 @@ function getMcpGraphPreview(config) {
|
|
|
1336
1521
|
const stackParts = config.stackParts?.length ? config.stackParts : legacyProjectConfigToStackParts(config);
|
|
1337
1522
|
const graphSummary = stackParts.length > 0 ? getGraphSummary({ stackParts }) : void 0;
|
|
1338
1523
|
const effectiveStack = stackParts.length > 0 ? getEffectiveStack({ stackParts }) : void 0;
|
|
1339
|
-
const stackPartSpecs = stackParts.filter((part) => part.source !== "provided").map((part) => formatStackPartSpec(part, stackParts));
|
|
1524
|
+
const stackPartSpecs = stackParts.filter((part) => part.source !== "provided" && part.toolId !== "none").map((part) => formatStackPartSpec(part, stackParts));
|
|
1340
1525
|
return {
|
|
1341
1526
|
...graphSummary ? {
|
|
1342
1527
|
graphSummary,
|
|
@@ -2208,7 +2393,7 @@ async function startMcpServer() {
|
|
|
2208
2393
|
const graphPreview = getMcpGraphPreview(config);
|
|
2209
2394
|
let addonWarnings = [];
|
|
2210
2395
|
if (config.addons.length > 0 && config.addons[0] !== "none") {
|
|
2211
|
-
const { setupAddons } = await import("./addons-setup-
|
|
2396
|
+
const { setupAddons } = await import("./addons-setup-DyMm42a5.mjs");
|
|
2212
2397
|
addonWarnings = await setupAddons(config);
|
|
2213
2398
|
}
|
|
2214
2399
|
const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager, input.javaBuildTool, input.javaWebFramework);
|
|
@@ -2533,4 +2718,4 @@ async function startMcpServer() {
|
|
|
2533
2718
|
startMcpServer();
|
|
2534
2719
|
|
|
2535
2720
|
//#endregion
|
|
2536
|
-
export { startMcpServer as i, MCP_STACK_UPDATE_SCHEMA as n, getMcpGraphPreview as r, MCP_PLAN_CREATE_SCHEMA as t };
|
|
2721
|
+
export { applyStackUpdate as a, startMcpServer as i, MCP_STACK_UPDATE_SCHEMA as n, planStackUpdate as o, getMcpGraphPreview as r, MCP_PLAN_CREATE_SCHEMA as t };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as types_exports, D as getGraphSummary, E as getGraphPart, S as getUserPkgManager, T as getGraphBackendUrl, _ as writeBtsConfig, a as handleError, b as DEFAULT_UI_LIBRARY_BY_FRONTEND, c as isSilent, d as setLastPromptShownUI, f as buildBtsConfigForPersistence, h as readBtsConfigFromFile, i as exitWithError, k as hasGraphPart, l as runWithContextAsync, n as UserCancelledError, o as didLastPromptShowUI, r as exitCancelled, s as isFirstPrompt, t as CLIError, u as setIsFirstPrompt, v as getLatestCLIVersion, w as getGraphBackendDeployInstructions, x as getDefaultConfig, y as DEFAULT_CONFIG } from "./errors-
|
|
2
|
+
import { A as types_exports, D as getGraphSummary, E as getGraphPart, S as getUserPkgManager, T as getGraphBackendUrl, _ as writeBtsConfig, a as handleError, b as DEFAULT_UI_LIBRARY_BY_FRONTEND, c as isSilent, d as setLastPromptShownUI, f as buildBtsConfigForPersistence, h as readBtsConfigFromFile, i as exitWithError, k as hasGraphPart, l as runWithContextAsync, n as UserCancelledError, o as didLastPromptShowUI, r as exitCancelled, s as isFirstPrompt, t as CLIError, u as setIsFirstPrompt, v as getLatestCLIVersion, w as getGraphBackendDeployInstructions, x as getDefaultConfig, y as DEFAULT_CONFIG } from "./errors-Cyol8zbN.mjs";
|
|
3
3
|
import { t as renderTitle } from "./render-title-zvyKC1ej.mjs";
|
|
4
|
-
import { i as canPromptInteractively, n as getPackageExecutionArgs, r as addPackageDependency, t as setupAddons } from "./addons-setup-
|
|
5
|
-
import { a as
|
|
6
|
-
import { a as
|
|
7
|
-
import {
|
|
8
|
-
import { n as
|
|
4
|
+
import { i as canPromptInteractively, n as getPackageExecutionArgs, r as addPackageDependency, t as setupAddons } from "./addons-setup-CyrP1IV-.mjs";
|
|
5
|
+
import { _ as CreateCommandInputSchema, a as allowedApisForFrontends$1, c as getCompatibleUILibraries$1, d as isExampleChatSdkAllowed$1, f as isFrontendAllowedWithBackend$1, h as splitFrontends$1, i as validateFullConfig, l as hasWebStyling$1, m as requiresChatSdkVercelAI, n as formatProject, p as isWebFrontend$1, r as validateConfigForProgrammaticUse, s as getCompatibleCSSFrameworks$1, u as isExampleAIAllowed$1, v as CreateCommandOptionsSchema } from "./file-formatter-B3dsev2l.mjs";
|
|
6
|
+
import { _ as isGoBack, a as runMavenTests, c as applyDependencyVersionChannel, d as isCancel$1, f as navigableConfirm, g as GO_BACK_SYMBOL, h as setIsFirstPrompt$1, i as runGradleTests, l as getAddonsChoice, m as navigableSelect, n as runCargoBuild, o as runMixCompile, p as navigableMultiselect, r as runGoModTidy, s as runUvSync, t as installDependencies } from "./install-dependencies-CgNh-aOy.mjs";
|
|
7
|
+
import { n as commandExists, t as runGeneratedChecks } from "./generated-checks-C8hn9w2i.mjs";
|
|
8
|
+
import { n as getTemplateDescription, r as generateReproducibleCommand, t as getTemplateConfig } from "./templates-CnTOtKjm.mjs";
|
|
9
9
|
import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
|
|
10
10
|
import { createRouterClient, os } from "@orpc/server";
|
|
11
11
|
import pc from "picocolors";
|
|
@@ -19,7 +19,6 @@ import consola, { consola as consola$1 } from "consola";
|
|
|
19
19
|
import { $, execa } from "execa";
|
|
20
20
|
import { cliInputToProjectConfigPartial } from "@better-fullstack/types/stack-translation";
|
|
21
21
|
import os$1 from "node:os";
|
|
22
|
-
import { format } from "oxfmt";
|
|
23
22
|
|
|
24
23
|
//#region src/utils/project-history.ts
|
|
25
24
|
const paths$1 = envPaths("better-fullstack", { suffix: "" });
|
|
@@ -5500,7 +5499,7 @@ async function gatherMultiEcosystemConfig(flags, projectName, projectDir, relati
|
|
|
5500
5499
|
if (pythonOrm !== "none") stackPartSpecs.push(`backend.orm:python:${pythonOrm}`);
|
|
5501
5500
|
if (pythonAuth !== "none") stackPartSpecs.push(`backend.auth:python:${pythonAuth}`);
|
|
5502
5501
|
if (pythonTaskQueue !== "none") stackPartSpecs.push(`backend.jobQueue:python:${pythonTaskQueue}`);
|
|
5503
|
-
if (pythonGraphql !== "none") stackPartSpecs.push(`backend.
|
|
5502
|
+
if (pythonGraphql !== "none") stackPartSpecs.push(`backend.graphql:python:${pythonGraphql}`);
|
|
5504
5503
|
for (const testing of pythonTesting) if (testing !== "none") stackPartSpecs.push(`backend.testing:python:${testing}`);
|
|
5505
5504
|
if (pythonCaching !== "none") stackPartSpecs.push(`backend.caching:python:${pythonCaching}`);
|
|
5506
5505
|
if (pythonRealtime !== "none") stackPartSpecs.push(`backend.realtime:python:${pythonRealtime}`);
|
|
@@ -7278,7 +7277,10 @@ const COPYABLE_CREATE_INPUT_KEYS = Object.keys(types_exports.CreateInputSchema.s
|
|
|
7278
7277
|
* result can be safely overlaid by explicitly-passed CLI flags.
|
|
7279
7278
|
*/
|
|
7280
7279
|
function betterTStackConfigToCreateInput(config) {
|
|
7281
|
-
const source = config
|
|
7280
|
+
const source = buildBtsConfigForPersistence(config, {
|
|
7281
|
+
version: config.version,
|
|
7282
|
+
createdAt: config.createdAt
|
|
7283
|
+
});
|
|
7282
7284
|
const result = {};
|
|
7283
7285
|
for (const key of COPYABLE_CREATE_INPUT_KEYS) {
|
|
7284
7286
|
const value = source[key];
|
|
@@ -7341,7 +7343,7 @@ async function resolveCreateConfigBase(input) {
|
|
|
7341
7343
|
//#endregion
|
|
7342
7344
|
//#region src/utils/display-config.ts
|
|
7343
7345
|
function getSelectedGraphPart(config, role, ownerPartId) {
|
|
7344
|
-
return config.stackParts?.find((part) => part.role === role && part.ownerPartId === ownerPartId && part.source !== "provided");
|
|
7346
|
+
return config.stackParts?.find((part) => part.role === role && part.ownerPartId === ownerPartId && part.source !== "provided" && part.toolId !== "none");
|
|
7345
7347
|
}
|
|
7346
7348
|
function getGraphDisplayValue(config, role) {
|
|
7347
7349
|
const primaryBackend = getSelectedGraphPart(config, "backend");
|
|
@@ -7473,7 +7475,7 @@ function displayConfig(config) {
|
|
|
7473
7475
|
if (config.webDeploy !== void 0) configDisplay.push(`${pc.blue("Web Deployment:")} ${String(config.webDeploy)}`);
|
|
7474
7476
|
if (config.serverDeploy !== void 0) configDisplay.push(`${pc.blue("Server Deployment:")} ${String(config.serverDeploy)}`);
|
|
7475
7477
|
if (config.stackParts?.length) {
|
|
7476
|
-
const stackParts = config.stackParts.filter((part) => part.source !== "provided").map((part) => formatStackPartSpec(part, config.stackParts ?? []));
|
|
7478
|
+
const stackParts = config.stackParts.filter((part) => part.source !== "provided" && part.toolId !== "none").map((part) => formatStackPartSpec(part, config.stackParts ?? []));
|
|
7477
7479
|
if (stackParts.length > 0) configDisplay.push(`${pc.blue("Stack Parts:")} ${stackParts.join(", ")}`);
|
|
7478
7480
|
}
|
|
7479
7481
|
if (configDisplay.length === 0) return pc.yellow("No configuration selected.");
|
|
@@ -7692,39 +7694,6 @@ function validateConfigCompatibility(config, providedFlags, options) {
|
|
|
7692
7694
|
else validateConfigForProgrammaticUse(config);
|
|
7693
7695
|
}
|
|
7694
7696
|
|
|
7695
|
-
//#endregion
|
|
7696
|
-
//#region src/utils/file-formatter.ts
|
|
7697
|
-
const formatOptions = {
|
|
7698
|
-
experimentalSortPackageJson: true,
|
|
7699
|
-
experimentalSortImports: { order: "asc" }
|
|
7700
|
-
};
|
|
7701
|
-
async function formatCode(filePath, content) {
|
|
7702
|
-
try {
|
|
7703
|
-
const result = await format(path.basename(filePath), content, formatOptions);
|
|
7704
|
-
if (result.errors && result.errors.length > 0) return null;
|
|
7705
|
-
return result.code;
|
|
7706
|
-
} catch {
|
|
7707
|
-
return null;
|
|
7708
|
-
}
|
|
7709
|
-
}
|
|
7710
|
-
async function formatProject(projectDir) {
|
|
7711
|
-
async function formatDirectory(dir) {
|
|
7712
|
-
const denoConfigPath = path.join(dir, "deno.json");
|
|
7713
|
-
if (await fs.pathExists(denoConfigPath)) return;
|
|
7714
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
7715
|
-
await Promise.all(entries.map(async (entry) => {
|
|
7716
|
-
const fullPath = path.join(dir, entry.name);
|
|
7717
|
-
if (entry.isDirectory()) await formatDirectory(fullPath);
|
|
7718
|
-
else if (entry.isFile()) try {
|
|
7719
|
-
const content = await fs.readFile(fullPath, "utf-8");
|
|
7720
|
-
const formatted = await formatCode(fullPath, content);
|
|
7721
|
-
if (formatted && formatted !== content) await fs.writeFile(fullPath, formatted, "utf-8");
|
|
7722
|
-
} catch {}
|
|
7723
|
-
}));
|
|
7724
|
-
}
|
|
7725
|
-
await formatDirectory(projectDir);
|
|
7726
|
-
}
|
|
7727
|
-
|
|
7728
7697
|
//#endregion
|
|
7729
7698
|
//#region src/utils/env-utils.ts
|
|
7730
7699
|
async function addEnvVariablesToFile(envPath, variables) {
|
|
@@ -9169,7 +9138,10 @@ function getAuthSetupInstructions(auth, backend, frontend) {
|
|
|
9169
9138
|
const envPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
|
|
9170
9139
|
if (auth === "nextauth") return `${pc.bold("NextAuth.js Setup:")}\n${pc.cyan("•")} Generate a secret: ${pc.white("npx auth secret")}\n${pc.cyan("•")} Set ${pc.white("AUTH_SECRET")} in ${pc.white(envPath)}\n${pc.cyan("•")} Configure your OAuth providers (e.g. ${pc.white("AUTH_GITHUB_ID")}, ${pc.white("AUTH_GITHUB_SECRET")})\n${pc.cyan("•")} Docs: ${pc.underline("https://authjs.dev/getting-started")}`;
|
|
9171
9140
|
if (auth === "stack-auth") return `${pc.bold("Stack Auth Setup:")}\n${pc.cyan("•")} Create a project at ${pc.underline("https://app.stack-auth.com")}\n${pc.cyan("•")} Set ${pc.white("NEXT_PUBLIC_STACK_PROJECT_ID")}, ${pc.white("NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY")},\n and ${pc.white("STACK_SECRET_SERVER_KEY")} in ${pc.white(envPath)}`;
|
|
9172
|
-
if (auth === "supabase-auth")
|
|
9141
|
+
if (auth === "supabase-auth") {
|
|
9142
|
+
const supabasePublicPrefix = frontend.includes("tanstack-start") ? "VITE_" : "NEXT_PUBLIC_";
|
|
9143
|
+
return `${pc.bold("Supabase Auth Setup:")}\n${pc.cyan("•")} Create a project at ${pc.underline("https://supabase.com/dashboard")}\n${pc.cyan("•")} Set ${pc.white(`${supabasePublicPrefix}SUPABASE_URL`)}, ${pc.white(`${supabasePublicPrefix}SUPABASE_ANON_KEY`)},\n and ${pc.white("SUPABASE_SERVICE_ROLE_KEY")} in ${pc.white(envPath)}`;
|
|
9144
|
+
}
|
|
9173
9145
|
if (auth === "auth0") return `${pc.bold("Auth0 Setup:")}\n${pc.cyan("•")} Create an application at ${pc.underline("https://manage.auth0.com")}\n${pc.cyan("•")} Set ${pc.white("AUTH0_SECRET")}, ${pc.white("AUTH0_CLIENT_ID")}, ${pc.white("AUTH0_CLIENT_SECRET")},\n and ${pc.white("AUTH0_ISSUER_BASE_URL")} in ${pc.white(envPath)}\n${pc.cyan("•")} Docs: ${pc.underline("https://auth0.com/docs/quickstart")}`;
|
|
9174
9146
|
return "";
|
|
9175
9147
|
}
|
|
@@ -10220,6 +10192,24 @@ function displaySponsorsBox(sponsors$1) {
|
|
|
10220
10192
|
//#endregion
|
|
10221
10193
|
//#region src/run.ts
|
|
10222
10194
|
const OPTION_ENTRY_COUNT = Object.values(types_exports.OPTION_CATEGORY_METADATA).reduce((sum, metadata) => sum + metadata.options.length, 0);
|
|
10195
|
+
const AddCommandInputSchema = CreateCommandOptionsSchema.omit({
|
|
10196
|
+
template: true,
|
|
10197
|
+
fromHistory: true,
|
|
10198
|
+
config: true,
|
|
10199
|
+
yes: true,
|
|
10200
|
+
yolo: true,
|
|
10201
|
+
verbose: true,
|
|
10202
|
+
verify: true,
|
|
10203
|
+
git: true,
|
|
10204
|
+
directoryConflict: true,
|
|
10205
|
+
renderTitle: true,
|
|
10206
|
+
disableAnalytics: true,
|
|
10207
|
+
manualDb: true
|
|
10208
|
+
}).extend({ projectDir: z.string().optional().describe("Project directory (defaults to current)") });
|
|
10209
|
+
const ProjectCheckInputSchema = z.tuple([z.string().optional().describe("Project directory to diagnose (defaults to current directory)"), z.object({
|
|
10210
|
+
skipChecks: z.boolean().optional().default(false).describe("Skip the ecosystem build/type checks (config + deps + env only)"),
|
|
10211
|
+
json: z.boolean().optional().default(false).describe("Output the diagnosis as JSON")
|
|
10212
|
+
})]);
|
|
10223
10213
|
const router = os.router({
|
|
10224
10214
|
create: os.meta({
|
|
10225
10215
|
description: `Scaffold a new Better Fullstack project from ${OPTION_ENTRY_COUNT} compatible stack options`,
|
|
@@ -10260,15 +10250,8 @@ const router = os.router({
|
|
|
10260
10250
|
log.message(`Please visit ${BUILDER_URL}`);
|
|
10261
10251
|
}
|
|
10262
10252
|
}),
|
|
10263
|
-
add: os.meta({ description: "Add addons or
|
|
10264
|
-
|
|
10265
|
-
webDeploy: types_exports.WebDeploySchema.optional().describe("Web deployment option to set"),
|
|
10266
|
-
serverDeploy: types_exports.ServerDeploySchema.optional().describe("Server deployment option to set"),
|
|
10267
|
-
install: z.boolean().optional().default(false).describe("Install dependencies after adding"),
|
|
10268
|
-
packageManager: types_exports.PackageManagerSchema.optional().describe("Package manager to use"),
|
|
10269
|
-
projectDir: z.string().optional().describe("Project directory (defaults to current)")
|
|
10270
|
-
})).handler(async ({ input }) => {
|
|
10271
|
-
const { addHandler } = await import("./add-handler-9F-AsGM-.mjs");
|
|
10253
|
+
add: os.meta({ description: "Add addons, deploy targets, or stack capabilities to an existing Better Fullstack project using its bts.jsonc config" }).input(AddCommandInputSchema).handler(async ({ input }) => {
|
|
10254
|
+
const { addHandler } = await import("./add-handler-BNSL6HdM.mjs");
|
|
10272
10255
|
await addHandler(input);
|
|
10273
10256
|
}),
|
|
10274
10257
|
history: os.meta({ description: "Show history of scaffolded projects with reproducible commands" }).input(z.object({
|
|
@@ -10312,12 +10295,17 @@ const router = os.router({
|
|
|
10312
10295
|
log.message("MCP server is started via the 'mcp' subcommand intercepted in cli.ts.");
|
|
10313
10296
|
log.message("Run: create-better-fullstack mcp");
|
|
10314
10297
|
}),
|
|
10315
|
-
doctor: os.meta({ description: "Diagnose a scaffolded Better Fullstack project: verify its bts.jsonc, installed dependencies, required env vars, and run ecosystem build/type checks" }).input(
|
|
10316
|
-
skipChecks: z.boolean().optional().default(false).describe("Skip the ecosystem build/type checks (config + deps + env only)"),
|
|
10317
|
-
json: z.boolean().optional().default(false).describe("Output the diagnosis as JSON")
|
|
10318
|
-
})])).handler(async ({ input }) => {
|
|
10298
|
+
doctor: os.meta({ description: "Diagnose a scaffolded Better Fullstack project: verify its bts.jsonc, installed dependencies, required env vars, and run ecosystem build/type checks" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
|
|
10319
10299
|
const [projectDir, options] = input;
|
|
10320
|
-
const { doctorCommand } = await import("./doctor-
|
|
10300
|
+
const { doctorCommand } = await import("./doctor-DBoq7bZ9.mjs");
|
|
10301
|
+
await doctorCommand({
|
|
10302
|
+
projectDir,
|
|
10303
|
+
...options
|
|
10304
|
+
});
|
|
10305
|
+
}),
|
|
10306
|
+
check: os.meta({ description: "Check a scaffolded Better Fullstack project for config, dependency, env, and generated build/type drift" }).input(ProjectCheckInputSchema).handler(async ({ input }) => {
|
|
10307
|
+
const [projectDir, options] = input;
|
|
10308
|
+
const { doctorCommand } = await import("./doctor-DBoq7bZ9.mjs");
|
|
10321
10309
|
await doctorCommand({
|
|
10322
10310
|
projectDir,
|
|
10323
10311
|
...options
|
|
@@ -10387,7 +10375,7 @@ async function builder() {
|
|
|
10387
10375
|
return caller.builder();
|
|
10388
10376
|
}
|
|
10389
10377
|
async function add(input) {
|
|
10390
|
-
const { addHandler } = await import("./add-handler-
|
|
10378
|
+
const { addHandler } = await import("./add-handler-BNSL6HdM.mjs");
|
|
10391
10379
|
return addHandler(input, { silent: true });
|
|
10392
10380
|
}
|
|
10393
10381
|
async function history(options) {
|
|
@@ -10400,6 +10388,18 @@ async function history(options) {
|
|
|
10400
10388
|
async function telemetry(action = "status", options) {
|
|
10401
10389
|
return caller.telemetry([action, { json: options?.json ?? false }]);
|
|
10402
10390
|
}
|
|
10391
|
+
async function doctor(projectDir, options) {
|
|
10392
|
+
return caller.doctor([projectDir, {
|
|
10393
|
+
skipChecks: options?.skipChecks ?? false,
|
|
10394
|
+
json: options?.json ?? false
|
|
10395
|
+
}]);
|
|
10396
|
+
}
|
|
10397
|
+
async function check(projectDir, options) {
|
|
10398
|
+
return caller.check([projectDir, {
|
|
10399
|
+
skipChecks: options?.skipChecks ?? false,
|
|
10400
|
+
json: options?.json ?? false
|
|
10401
|
+
}]);
|
|
10402
|
+
}
|
|
10403
10403
|
|
|
10404
10404
|
//#endregion
|
|
10405
|
-
export {
|
|
10405
|
+
export { createBtsCli as a, history as c, telemetry as d, create as i, router as l, builder as n, docs as o, check as r, doctor as s, add as t, sponsors as u };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./errors-Cyol8zbN.mjs";
|
|
3
|
+
import { a as createBtsCli, c as history, d as telemetry, i as create, l as router, n as builder, o as docs, r as check, s as doctor, t as add, u as sponsors } from "./run-BYse4yJy.mjs";
|
|
4
|
+
import "./render-title-zvyKC1ej.mjs";
|
|
5
|
+
import "./addons-setup-CyrP1IV-.mjs";
|
|
6
|
+
import "./file-formatter-B3dsev2l.mjs";
|
|
7
|
+
import "./install-dependencies-CgNh-aOy.mjs";
|
|
8
|
+
import "./generated-checks-C8hn9w2i.mjs";
|
|
9
|
+
|
|
10
|
+
export { createBtsCli };
|