@makerkit/cli 2.0.7 → 2.0.9
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/index.mjs +114 -20
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.mjs +110 -18
- package/dist/mcp.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { execa, execaCommand } from "execa";
|
|
|
8
8
|
import fs from "fs-extra";
|
|
9
9
|
import invariant from "tiny-invariant";
|
|
10
10
|
import { homedir, tmpdir } from "os";
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
11
12
|
import { config } from "dotenv";
|
|
12
13
|
//#region src/version.ts
|
|
13
14
|
const CLI_VERSION = "2.0.3";
|
|
@@ -31,7 +32,10 @@ const VARIANT_REPO_MAP = {
|
|
|
31
32
|
"next-supabase": "makerkit/next-supabase-saas-kit-turbo",
|
|
32
33
|
"next-drizzle": "makerkit/next-drizzle-saas-kit-turbo",
|
|
33
34
|
"next-prisma": "makerkit/next-prisma-saas-kit-turbo",
|
|
34
|
-
"react-router-supabase": "makerkit/react-router-supabase-saas-kit-turbo"
|
|
35
|
+
"react-router-supabase": "makerkit/react-router-supabase-saas-kit-turbo",
|
|
36
|
+
"tanstack-supabase": "makerkit/tanstack-supabase-saas-kit-turbo",
|
|
37
|
+
"tanstack-drizzle": "makerkit/tanstack-drizzle-saas-kit-turbo",
|
|
38
|
+
"tanstack-prisma": "makerkit/tanstack-prisma-saas-kit-turbo"
|
|
35
39
|
};
|
|
36
40
|
function sshUrl(repo) {
|
|
37
41
|
return `git@github.com:${repo}`;
|
|
@@ -167,6 +171,51 @@ const VARIANT_CATALOG = [
|
|
|
167
171
|
database: "PostgreSQL (Supabase)",
|
|
168
172
|
auth: "Supabase Auth",
|
|
169
173
|
status: "stable"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: "tanstack-supabase",
|
|
177
|
+
name: "TanStack Start + Supabase",
|
|
178
|
+
description: "Full-stack SaaS kit with TanStack Start and Supabase",
|
|
179
|
+
repo: VARIANT_REPO_MAP["tanstack-supabase"],
|
|
180
|
+
tech: [
|
|
181
|
+
"TanStack Start",
|
|
182
|
+
"Supabase",
|
|
183
|
+
"Tailwind CSS",
|
|
184
|
+
"shadcn/ui"
|
|
185
|
+
],
|
|
186
|
+
database: "PostgreSQL (Supabase)",
|
|
187
|
+
auth: "Supabase Auth",
|
|
188
|
+
status: "stable"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "tanstack-drizzle",
|
|
192
|
+
name: "TanStack Start + Drizzle",
|
|
193
|
+
description: "Full-stack SaaS kit with TanStack Start and Drizzle ORM",
|
|
194
|
+
repo: VARIANT_REPO_MAP["tanstack-drizzle"],
|
|
195
|
+
tech: [
|
|
196
|
+
"TanStack Start",
|
|
197
|
+
"Drizzle",
|
|
198
|
+
"Tailwind CSS",
|
|
199
|
+
"shadcn/ui"
|
|
200
|
+
],
|
|
201
|
+
database: "PostgreSQL",
|
|
202
|
+
auth: "Better Auth",
|
|
203
|
+
status: "stable"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "tanstack-prisma",
|
|
207
|
+
name: "TanStack Start + Prisma",
|
|
208
|
+
description: "Full-stack SaaS kit with TanStack Start and Prisma ORM",
|
|
209
|
+
repo: VARIANT_REPO_MAP["tanstack-prisma"],
|
|
210
|
+
tech: [
|
|
211
|
+
"TanStack Start",
|
|
212
|
+
"Prisma",
|
|
213
|
+
"Tailwind CSS",
|
|
214
|
+
"shadcn/ui"
|
|
215
|
+
],
|
|
216
|
+
database: "PostgreSQL",
|
|
217
|
+
auth: "Better Auth",
|
|
218
|
+
status: "stable"
|
|
170
219
|
}
|
|
171
220
|
];
|
|
172
221
|
//#endregion
|
|
@@ -665,30 +714,65 @@ async function installRegistryFiles(variant, pluginId, username, majorVersion) {
|
|
|
665
714
|
//#endregion
|
|
666
715
|
//#region src/utils/run-codemod.ts
|
|
667
716
|
const CODEMOD_TIMEOUT_MS = 300 * 1e3;
|
|
717
|
+
const IDLE_KILL_MS = 3e3;
|
|
668
718
|
async function runCodemod(variant, pluginId, codemodVersion, options) {
|
|
669
719
|
try {
|
|
670
720
|
const localPath = process.env.MAKERKIT_CODEMODS_PATH;
|
|
671
721
|
const runner = process.env.MAKERKIT_PACKAGE_RUNNER ?? "npx --yes";
|
|
672
722
|
const versionTag = codemodVersion ? `@${codemodVersion}` : "";
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
723
|
+
const noInteractive = options?.noInteractive ?? true;
|
|
724
|
+
const flags = ["--allow-dirty", noInteractive && "--no-interactive"].filter(Boolean).join(" ");
|
|
725
|
+
const command = localPath ? `${runner} codemod@latest workflow run ${flags} -w ${localPath}/codemods/${variant}/${pluginId}` : `${runner} codemod@latest run @makerkit/${variant}-${pluginId}${versionTag} ${flags}`;
|
|
726
|
+
return await new Promise((resolve, reject) => {
|
|
727
|
+
const child = spawn(command, {
|
|
728
|
+
shell: true,
|
|
729
|
+
stdio: noInteractive ? [
|
|
730
|
+
"ignore",
|
|
731
|
+
"pipe",
|
|
732
|
+
"pipe"
|
|
733
|
+
] : "inherit"
|
|
734
|
+
});
|
|
735
|
+
let idleTimer = null;
|
|
736
|
+
const resetIdle = () => {
|
|
737
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
738
|
+
idleTimer = setTimeout(() => {
|
|
739
|
+
child.kill();
|
|
740
|
+
}, IDLE_KILL_MS);
|
|
741
|
+
};
|
|
742
|
+
if (child.stdout) {
|
|
743
|
+
child.stdout.pipe(process.stdout);
|
|
744
|
+
child.stdout.on("data", () => resetIdle());
|
|
745
|
+
}
|
|
746
|
+
if (child.stderr) {
|
|
747
|
+
child.stderr.pipe(process.stderr);
|
|
748
|
+
child.stderr.on("data", () => resetIdle());
|
|
749
|
+
}
|
|
750
|
+
resetIdle();
|
|
751
|
+
const globalTimer = setTimeout(() => {
|
|
752
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
753
|
+
child.kill();
|
|
754
|
+
resolve({
|
|
755
|
+
success: false,
|
|
756
|
+
output: `Codemod timed out after ${CODEMOD_TIMEOUT_MS / 1e3}s`
|
|
757
|
+
});
|
|
758
|
+
}, CODEMOD_TIMEOUT_MS);
|
|
759
|
+
child.on("exit", (code) => {
|
|
760
|
+
clearTimeout(globalTimer);
|
|
761
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
762
|
+
resolve({
|
|
763
|
+
success: code === 0 || code === null,
|
|
764
|
+
output: code === 0 || code === null ? "" : `Command failed with exit code ${code}`
|
|
765
|
+
});
|
|
766
|
+
});
|
|
767
|
+
child.on("error", (err) => {
|
|
768
|
+
clearTimeout(globalTimer);
|
|
769
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
770
|
+
reject(err);
|
|
771
|
+
});
|
|
680
772
|
});
|
|
681
|
-
return {
|
|
682
|
-
success: true,
|
|
683
|
-
output: stdout || stderr || ""
|
|
684
|
-
};
|
|
685
773
|
} catch (error) {
|
|
686
774
|
let message = "Unknown error during codemod";
|
|
687
|
-
if (error instanceof Error)
|
|
688
|
-
message = error.message;
|
|
689
|
-
if ("stderr" in error && error.stderr) message += `\n${error.stderr}`;
|
|
690
|
-
if ("timedOut" in error && error.timedOut) message = `Codemod timed out after ${CODEMOD_TIMEOUT_MS / 1e3}s (the workflow engine may have stalled after an error)`;
|
|
691
|
-
}
|
|
775
|
+
if (error instanceof Error) message = error.message;
|
|
692
776
|
return {
|
|
693
777
|
success: false,
|
|
694
778
|
output: message
|
|
@@ -757,8 +841,14 @@ async function detectVariant() {
|
|
|
757
841
|
const dbDeps = await readDeps(join(cwd, "packages", "database", "package.json"));
|
|
758
842
|
const hasSupabase = !!webDeps["@supabase/supabase-js"];
|
|
759
843
|
const hasReactRouter = !!webDeps["@react-router/node"];
|
|
844
|
+
const hasTanstack = !!webDeps["@tanstack/react-start"];
|
|
760
845
|
const hasDrizzle = !!webDeps["drizzle-orm"] || !!dbDeps["drizzle-orm"];
|
|
761
846
|
const hasPrisma = !!webDeps["@prisma/client"] || !!dbDeps["@prisma/client"];
|
|
847
|
+
if (hasTanstack) {
|
|
848
|
+
if (hasSupabase) return "tanstack-supabase";
|
|
849
|
+
if (hasDrizzle) return "tanstack-drizzle";
|
|
850
|
+
if (hasPrisma) return "tanstack-prisma";
|
|
851
|
+
}
|
|
762
852
|
if (hasReactRouter && hasSupabase) return "react-router-supabase";
|
|
763
853
|
if (hasSupabase) return "next-supabase";
|
|
764
854
|
if (hasDrizzle) return "next-drizzle";
|
|
@@ -798,7 +888,9 @@ async function addPlugin(options) {
|
|
|
798
888
|
};
|
|
799
889
|
const item = await installRegistryFiles(variant, options.pluginId, username, majorVersion);
|
|
800
890
|
await saveBaseVersions(options.pluginId, item.files);
|
|
801
|
-
|
|
891
|
+
options.onBeforeCodemod?.();
|
|
892
|
+
const codemodResult = await runCodemod(variant, options.pluginId, item.codemodVersion);
|
|
893
|
+
options.onAfterCodemod?.();
|
|
802
894
|
const envVars = getEnvVars(plugin, variant);
|
|
803
895
|
return {
|
|
804
896
|
success: true,
|
|
@@ -868,7 +960,8 @@ function createAddCommand(parentCommand) {
|
|
|
868
960
|
pluginId,
|
|
869
961
|
githubUsername: username,
|
|
870
962
|
skipGitCheck: true,
|
|
871
|
-
|
|
963
|
+
onBeforeCodemod: () => filesSpinner.stop(),
|
|
964
|
+
onAfterCodemod: () => filesSpinner.start("Installing plugin...")
|
|
872
965
|
});
|
|
873
966
|
} catch (error) {
|
|
874
967
|
filesSpinner.fail("Failed to install plugin.");
|
|
@@ -882,7 +975,8 @@ function createAddCommand(parentCommand) {
|
|
|
882
975
|
pluginId,
|
|
883
976
|
githubUsername: username,
|
|
884
977
|
skipGitCheck: true,
|
|
885
|
-
|
|
978
|
+
onBeforeCodemod: () => retrySpinner.stop(),
|
|
979
|
+
onAfterCodemod: () => retrySpinner.start("Installing plugin...")
|
|
886
980
|
});
|
|
887
981
|
} catch (retryError) {
|
|
888
982
|
retrySpinner.fail("Failed to install plugin.");
|