@kuckit/cli 2.0.1 → 2.0.2
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/bin.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as isLegacyConfig, c as loadTryLoadKuckitConfig, i as isGcpConfig, l as addModule, o as migrateLegacyConfig, s as discoverModules, u as generateModule } from "./provider-
|
|
2
|
+
import { a as isLegacyConfig, c as loadTryLoadKuckitConfig, i as isGcpConfig, l as addModule, o as migrateLegacyConfig, s as discoverModules, u as generateModule } from "./provider-Cx1wuAN4.js";
|
|
3
3
|
import { program } from "commander";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
5
6
|
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { spawn } from "child_process";
|
|
7
|
+
import { spawn as spawn$1 } from "child_process";
|
|
7
8
|
import { access, constants as constants$1, mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
8
9
|
import { dirname as dirname$1, join as join$1 } from "path";
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
|
-
import { confirm, input, select } from "@inquirer/prompts";
|
|
11
11
|
import { accessSync as accessSync$1, constants as constants$2 } from "fs";
|
|
12
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
12
13
|
|
|
13
14
|
//#region src/commands/doctor.ts
|
|
14
|
-
const CONFIG_FILES = [
|
|
15
|
+
const CONFIG_FILES$1 = [
|
|
15
16
|
"kuckit.config.ts",
|
|
16
17
|
"kuckit.config.js",
|
|
17
18
|
"kuckit.config.mjs"
|
|
@@ -25,10 +26,10 @@ const FRAMEWORK_PACKAGES = [
|
|
|
25
26
|
"@kuckit/domain",
|
|
26
27
|
"@kuckit/contracts"
|
|
27
28
|
];
|
|
28
|
-
function findConfigFile(cwd) {
|
|
29
|
+
function findConfigFile$1(cwd) {
|
|
29
30
|
let dir = cwd;
|
|
30
31
|
while (dir !== dirname(dir)) {
|
|
31
|
-
for (const file of CONFIG_FILES) {
|
|
32
|
+
for (const file of CONFIG_FILES$1) {
|
|
32
33
|
const configPath = join(dir, file);
|
|
33
34
|
if (existsSync(configPath)) return configPath;
|
|
34
35
|
}
|
|
@@ -42,7 +43,7 @@ function readPackageJson(packageName, cwd) {
|
|
|
42
43
|
join(cwd, "apps", "server", "node_modules", packageName, "package.json"),
|
|
43
44
|
join(cwd, "apps", "web", "node_modules", packageName, "package.json")
|
|
44
45
|
];
|
|
45
|
-
const packageDir = packageName.startsWith("@") ? packageName.split("/")[1] : packageName;
|
|
46
|
+
const packageDir = packageName.startsWith("@") ? packageName.split("/")[1] ?? packageName : packageName;
|
|
46
47
|
locations.push(join(cwd, "packages", packageDir, "package.json"));
|
|
47
48
|
for (const location of locations) try {
|
|
48
49
|
const content = readFileSync(location, "utf-8");
|
|
@@ -57,7 +58,7 @@ function findPackagePath(packageName, cwd) {
|
|
|
57
58
|
join(cwd, "apps", "server", "node_modules", packageName),
|
|
58
59
|
join(cwd, "apps", "web", "node_modules", packageName)
|
|
59
60
|
];
|
|
60
|
-
const packageDir = packageName.startsWith("@") ? packageName.split("/")[1] : packageName;
|
|
61
|
+
const packageDir = packageName.startsWith("@") ? packageName.split("/")[1] ?? packageName : packageName;
|
|
61
62
|
locations.push(join(cwd, "packages", packageDir));
|
|
62
63
|
for (const location of locations) if (existsSync(location)) {
|
|
63
64
|
const pkgJsonPath = join(location, "package.json");
|
|
@@ -127,7 +128,7 @@ async function doctor(options) {
|
|
|
127
128
|
const cwd = process.cwd();
|
|
128
129
|
const checks = [];
|
|
129
130
|
if (!options.json) console.log("\nKuckit Doctor - Checking your setup...\n");
|
|
130
|
-
const configPath = findConfigFile(cwd);
|
|
131
|
+
const configPath = findConfigFile$1(cwd);
|
|
131
132
|
if (configPath) checks.push({
|
|
132
133
|
name: "config-exists",
|
|
133
134
|
status: "pass",
|
|
@@ -315,11 +316,17 @@ async function doctor(options) {
|
|
|
315
316
|
let match;
|
|
316
317
|
while ((match = serverModulePattern.exec(serverContent)) !== null) {
|
|
317
318
|
const lineStart = serverContent.lastIndexOf("\n", match.index) + 1;
|
|
318
|
-
if (!serverContent.slice(lineStart, match.index).includes("//"))
|
|
319
|
+
if (!serverContent.slice(lineStart, match.index).includes("//")) {
|
|
320
|
+
const matchedModule = match[1];
|
|
321
|
+
if (matchedModule) serverModules.add(matchedModule);
|
|
322
|
+
}
|
|
319
323
|
}
|
|
320
324
|
while ((match = clientModulePattern.exec(clientContent)) !== null) {
|
|
321
325
|
const lineStart = clientContent.lastIndexOf("\n", match.index) + 1;
|
|
322
|
-
if (!clientContent.slice(lineStart, match.index).includes("//"))
|
|
326
|
+
if (!clientContent.slice(lineStart, match.index).includes("//")) {
|
|
327
|
+
const matchedModule = match[1];
|
|
328
|
+
if (matchedModule) clientModules.add(matchedModule);
|
|
329
|
+
}
|
|
323
330
|
}
|
|
324
331
|
const clientOnly = [...clientModules].filter((m) => !serverModules.has(m));
|
|
325
332
|
const serverOnly = [...serverModules].filter((m) => !clientModules.has(m));
|
|
@@ -448,7 +455,7 @@ async function search(keyword, options) {
|
|
|
448
455
|
}
|
|
449
456
|
console.log(`\n${results.length} package${results.length === 1 ? "" : "s"} found`);
|
|
450
457
|
if (results.some((r) => !r.isKuckitModule)) console.log("\n[?] = May not be a Kuckit module (verify before installing)");
|
|
451
|
-
if (results.length > 0) console.log(`\nInstall: kuckit add ${results[0].name}`);
|
|
458
|
+
if (results.length > 0 && results[0]) console.log(`\nInstall: kuckit add ${results[0].name}`);
|
|
452
459
|
} catch (error) {
|
|
453
460
|
if (options.json) console.log(JSON.stringify({
|
|
454
461
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
@@ -491,7 +498,7 @@ async function getDatabaseUrl(cwd, options) {
|
|
|
491
498
|
];
|
|
492
499
|
for (const envPath of envPaths) if (await fileExists$11(envPath)) try {
|
|
493
500
|
const match = (await readFile(envPath, "utf-8")).match(/^DATABASE_URL=(.+)$/m);
|
|
494
|
-
if (match) return match[1].replace(/^["']|["']$/g, "");
|
|
501
|
+
if (match?.[1]) return match[1].replace(/^["']|["']$/g, "");
|
|
495
502
|
} catch {}
|
|
496
503
|
return null;
|
|
497
504
|
}
|
|
@@ -557,8 +564,8 @@ export default defineConfig({
|
|
|
557
564
|
return configPath;
|
|
558
565
|
}
|
|
559
566
|
function runDrizzleKit(command, configPath, cwd) {
|
|
560
|
-
return new Promise((resolve) => {
|
|
561
|
-
const proc = spawn("npx", ["drizzle-kit", ...[
|
|
567
|
+
return new Promise((resolve$1) => {
|
|
568
|
+
const proc = spawn$1("npx", ["drizzle-kit", ...[
|
|
562
569
|
command,
|
|
563
570
|
"--config",
|
|
564
571
|
configPath
|
|
@@ -582,7 +589,7 @@ function runDrizzleKit(command, configPath, cwd) {
|
|
|
582
589
|
process.stderr.write(data);
|
|
583
590
|
});
|
|
584
591
|
proc.on("close", (code) => {
|
|
585
|
-
resolve({
|
|
592
|
+
resolve$1({
|
|
586
593
|
code: code ?? 1,
|
|
587
594
|
stdout,
|
|
588
595
|
stderr
|
|
@@ -680,7 +687,7 @@ async function openBrowser(url) {
|
|
|
680
687
|
}
|
|
681
688
|
}
|
|
682
689
|
function sleep(ms) {
|
|
683
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
690
|
+
return new Promise((resolve$1) => setTimeout(resolve$1, ms));
|
|
684
691
|
}
|
|
685
692
|
function formatExpiryDate(expiresAt) {
|
|
686
693
|
return new Date(expiresAt).toLocaleDateString("en-US", {
|
|
@@ -861,6 +868,32 @@ function requireAuth() {
|
|
|
861
868
|
}
|
|
862
869
|
}
|
|
863
870
|
|
|
871
|
+
//#endregion
|
|
872
|
+
//#region src/commands/server-utils.ts
|
|
873
|
+
const CONFIG_FILES = [
|
|
874
|
+
"kuckit.config.ts",
|
|
875
|
+
"kuckit.config.js",
|
|
876
|
+
"kuckit.config.mjs"
|
|
877
|
+
];
|
|
878
|
+
/**
|
|
879
|
+
* Find the config file path by searching from cwd upward
|
|
880
|
+
*/
|
|
881
|
+
function findConfigFile(cwd = process.cwd()) {
|
|
882
|
+
let dir = cwd;
|
|
883
|
+
while (dir !== dirname(dir)) {
|
|
884
|
+
for (const file of CONFIG_FILES) {
|
|
885
|
+
const configPath = resolve(dir, file);
|
|
886
|
+
if (existsSync(configPath)) return configPath;
|
|
887
|
+
}
|
|
888
|
+
dir = dirname(dir);
|
|
889
|
+
}
|
|
890
|
+
for (const file of CONFIG_FILES) {
|
|
891
|
+
const configPath = resolve(dir, file);
|
|
892
|
+
if (existsSync(configPath)) return configPath;
|
|
893
|
+
}
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
|
|
864
897
|
//#endregion
|
|
865
898
|
//#region src/lib/package-manager.ts
|
|
866
899
|
/**
|
|
@@ -901,11 +934,238 @@ function getInstallCommand(pm, packageName, options = {}) {
|
|
|
901
934
|
}
|
|
902
935
|
}
|
|
903
936
|
|
|
937
|
+
//#endregion
|
|
938
|
+
//#region src/commands/dev.ts
|
|
939
|
+
/**
|
|
940
|
+
* Start the development server
|
|
941
|
+
*/
|
|
942
|
+
async function dev(options) {
|
|
943
|
+
const cwd = process.cwd();
|
|
944
|
+
const configPath = options.config ? resolve(cwd, options.config) : findConfigFile(cwd);
|
|
945
|
+
if (!configPath) {
|
|
946
|
+
console.error("Error: No kuckit.config.ts found.");
|
|
947
|
+
console.error("Create one at your project root or specify with --config");
|
|
948
|
+
process.exit(1);
|
|
949
|
+
}
|
|
950
|
+
const projectRoot = dirname(configPath);
|
|
951
|
+
const pm = detectPackageManager(projectRoot);
|
|
952
|
+
console.log(`[kuckit] Using config: ${configPath}`);
|
|
953
|
+
console.log(`[kuckit] Starting development server...`);
|
|
954
|
+
const env = {
|
|
955
|
+
...process.env,
|
|
956
|
+
KUCKIT_CONFIG_PATH: configPath,
|
|
957
|
+
NODE_ENV: "development"
|
|
958
|
+
};
|
|
959
|
+
if (options.port) env.PORT = options.port;
|
|
960
|
+
const serverEntry = await findServerEntry(projectRoot);
|
|
961
|
+
if (serverEntry) {
|
|
962
|
+
const args = getRunArgs(pm, serverEntry);
|
|
963
|
+
const command = args[0];
|
|
964
|
+
if (!command) {
|
|
965
|
+
console.error("Error: Could not determine run command.");
|
|
966
|
+
process.exit(1);
|
|
967
|
+
}
|
|
968
|
+
const child = spawn(command, args.slice(1), {
|
|
969
|
+
cwd: projectRoot,
|
|
970
|
+
env,
|
|
971
|
+
stdio: "inherit"
|
|
972
|
+
});
|
|
973
|
+
child.on("error", (error) => {
|
|
974
|
+
console.error("Failed to start dev server:", error);
|
|
975
|
+
process.exit(1);
|
|
976
|
+
});
|
|
977
|
+
child.on("exit", (code) => {
|
|
978
|
+
process.exit(code ?? 0);
|
|
979
|
+
});
|
|
980
|
+
} else {
|
|
981
|
+
console.error("Error: Could not find server entry point.");
|
|
982
|
+
console.error("Expected: apps/server/src/server.ts or src/server.ts");
|
|
983
|
+
process.exit(1);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Find the server entry point
|
|
988
|
+
*/
|
|
989
|
+
async function findServerEntry(projectRoot) {
|
|
990
|
+
const { existsSync: existsSync$1 } = await import("node:fs");
|
|
991
|
+
for (const candidate of [
|
|
992
|
+
"apps/server/src/server.ts",
|
|
993
|
+
"server/src/server.ts",
|
|
994
|
+
"src/server.ts",
|
|
995
|
+
"server.ts"
|
|
996
|
+
]) if (existsSync$1(resolve(projectRoot, candidate))) return candidate;
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Get run command arguments based on package manager
|
|
1001
|
+
*/
|
|
1002
|
+
function getRunArgs(pm, entry) {
|
|
1003
|
+
switch (pm) {
|
|
1004
|
+
case "bun": return [
|
|
1005
|
+
"bun",
|
|
1006
|
+
"--watch",
|
|
1007
|
+
entry
|
|
1008
|
+
];
|
|
1009
|
+
default: return [
|
|
1010
|
+
"npx",
|
|
1011
|
+
"tsx",
|
|
1012
|
+
"watch",
|
|
1013
|
+
entry
|
|
1014
|
+
];
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
//#endregion
|
|
1019
|
+
//#region src/commands/build.ts
|
|
1020
|
+
/**
|
|
1021
|
+
* Build the production bundle
|
|
1022
|
+
*/
|
|
1023
|
+
async function build(options) {
|
|
1024
|
+
const cwd = process.cwd();
|
|
1025
|
+
const configPath = options.config ? resolve(cwd, options.config) : findConfigFile(cwd);
|
|
1026
|
+
if (!configPath) {
|
|
1027
|
+
console.error("Error: No kuckit.config.ts found.");
|
|
1028
|
+
console.error("Create one at your project root or specify with --config");
|
|
1029
|
+
process.exit(1);
|
|
1030
|
+
}
|
|
1031
|
+
const projectRoot = dirname(configPath);
|
|
1032
|
+
const pm = detectPackageManager(projectRoot);
|
|
1033
|
+
const outDir = options.outDir || "dist";
|
|
1034
|
+
console.log(`[kuckit] Using config: ${configPath}`);
|
|
1035
|
+
console.log(`[kuckit] Building for production...`);
|
|
1036
|
+
const args = getBuildArgs(pm);
|
|
1037
|
+
const command = args[0];
|
|
1038
|
+
if (!command) {
|
|
1039
|
+
console.error("Error: Could not determine build command.");
|
|
1040
|
+
process.exit(1);
|
|
1041
|
+
}
|
|
1042
|
+
const child = spawn(command, args.slice(1), {
|
|
1043
|
+
cwd: projectRoot,
|
|
1044
|
+
env: {
|
|
1045
|
+
...process.env,
|
|
1046
|
+
KUCKIT_CONFIG_PATH: configPath,
|
|
1047
|
+
NODE_ENV: "production",
|
|
1048
|
+
BUILD_OUT_DIR: outDir
|
|
1049
|
+
},
|
|
1050
|
+
stdio: "inherit"
|
|
1051
|
+
});
|
|
1052
|
+
child.on("error", (error) => {
|
|
1053
|
+
console.error("Failed to run build:", error);
|
|
1054
|
+
process.exit(1);
|
|
1055
|
+
});
|
|
1056
|
+
child.on("exit", (code) => {
|
|
1057
|
+
if (code === 0) console.log(`[kuckit] Build complete. Output: ${outDir}/`);
|
|
1058
|
+
process.exit(code ?? 0);
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Get build command arguments based on package manager
|
|
1063
|
+
*/
|
|
1064
|
+
function getBuildArgs(pm) {
|
|
1065
|
+
switch (pm) {
|
|
1066
|
+
case "bun": return [
|
|
1067
|
+
"bun",
|
|
1068
|
+
"run",
|
|
1069
|
+
"build"
|
|
1070
|
+
];
|
|
1071
|
+
case "pnpm": return [
|
|
1072
|
+
"pnpm",
|
|
1073
|
+
"run",
|
|
1074
|
+
"build"
|
|
1075
|
+
];
|
|
1076
|
+
case "yarn": return ["yarn", "build"];
|
|
1077
|
+
default: return [
|
|
1078
|
+
"npm",
|
|
1079
|
+
"run",
|
|
1080
|
+
"build"
|
|
1081
|
+
];
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
//#endregion
|
|
1086
|
+
//#region src/commands/start.ts
|
|
1087
|
+
/**
|
|
1088
|
+
* Start the production server
|
|
1089
|
+
*/
|
|
1090
|
+
async function start(options) {
|
|
1091
|
+
const cwd = process.cwd();
|
|
1092
|
+
const configPath = options.config ? resolve(cwd, options.config) : findConfigFile(cwd);
|
|
1093
|
+
if (!configPath) {
|
|
1094
|
+
console.error("Error: No kuckit.config.ts found.");
|
|
1095
|
+
console.error("Create one at your project root or specify with --config");
|
|
1096
|
+
process.exit(1);
|
|
1097
|
+
}
|
|
1098
|
+
const projectRoot = dirname(configPath);
|
|
1099
|
+
const pm = detectPackageManager(projectRoot);
|
|
1100
|
+
console.log(`[kuckit] Using config: ${configPath}`);
|
|
1101
|
+
console.log(`[kuckit] Starting production server...`);
|
|
1102
|
+
const env = {
|
|
1103
|
+
...process.env,
|
|
1104
|
+
KUCKIT_CONFIG_PATH: configPath,
|
|
1105
|
+
NODE_ENV: "production"
|
|
1106
|
+
};
|
|
1107
|
+
if (options.port) env.PORT = options.port;
|
|
1108
|
+
const serverEntry = await findBuiltServerEntry(projectRoot);
|
|
1109
|
+
if (serverEntry) {
|
|
1110
|
+
const args = getStartArgs(pm, serverEntry);
|
|
1111
|
+
const command = args[0];
|
|
1112
|
+
if (!command) {
|
|
1113
|
+
console.error("Error: Could not determine start command.");
|
|
1114
|
+
process.exit(1);
|
|
1115
|
+
}
|
|
1116
|
+
const child = spawn(command, args.slice(1), {
|
|
1117
|
+
cwd: projectRoot,
|
|
1118
|
+
env,
|
|
1119
|
+
stdio: "inherit"
|
|
1120
|
+
});
|
|
1121
|
+
child.on("error", (error) => {
|
|
1122
|
+
console.error("Failed to start production server:", error);
|
|
1123
|
+
process.exit(1);
|
|
1124
|
+
});
|
|
1125
|
+
child.on("exit", (code) => {
|
|
1126
|
+
process.exit(code ?? 0);
|
|
1127
|
+
});
|
|
1128
|
+
} else {
|
|
1129
|
+
console.error("Error: Could not find built server entry point.");
|
|
1130
|
+
console.error("Run `kuckit build` first, then `kuckit start`");
|
|
1131
|
+
console.error("Expected: dist/server.js or apps/server/dist/server.js");
|
|
1132
|
+
process.exit(1);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Find the built server entry point
|
|
1137
|
+
*/
|
|
1138
|
+
async function findBuiltServerEntry(projectRoot) {
|
|
1139
|
+
for (const candidate of [
|
|
1140
|
+
"dist/server.js",
|
|
1141
|
+
"apps/server/dist/server.js",
|
|
1142
|
+
"server/dist/server.js",
|
|
1143
|
+
"build/server.js"
|
|
1144
|
+
]) if (existsSync(resolve(projectRoot, candidate))) return candidate;
|
|
1145
|
+
return null;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Get start command arguments based on package manager
|
|
1149
|
+
*/
|
|
1150
|
+
function getStartArgs(pm, entry) {
|
|
1151
|
+
switch (pm) {
|
|
1152
|
+
case "bun": return ["bun", entry];
|
|
1153
|
+
default: return ["node", entry];
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
904
1157
|
//#endregion
|
|
905
1158
|
//#region src/commands/infra/provider-loader.ts
|
|
906
1159
|
const KUCKIT_DIR$7 = ".kuckit";
|
|
907
1160
|
const CONFIG_FILE$7 = "infra.json";
|
|
908
1161
|
/**
|
|
1162
|
+
* Get the config file name for a specific environment
|
|
1163
|
+
* Returns 'infra.{env}.json' for per-env configs
|
|
1164
|
+
*/
|
|
1165
|
+
function getEnvConfigFile(env) {
|
|
1166
|
+
return `infra.${env}.json`;
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
909
1169
|
* Default provider packages by provider ID
|
|
910
1170
|
*/
|
|
911
1171
|
const DEFAULT_PROVIDER_PACKAGES = {
|
|
@@ -914,10 +1174,28 @@ const DEFAULT_PROVIDER_PACKAGES = {
|
|
|
914
1174
|
azure: "@kuckit/infra-azure"
|
|
915
1175
|
};
|
|
916
1176
|
/**
|
|
917
|
-
* Load the stored infrastructure config
|
|
1177
|
+
* Load the stored infrastructure config
|
|
1178
|
+
*
|
|
1179
|
+
* Priority:
|
|
1180
|
+
* 1. If env is specified, try .kuckit/infra.{env}.json first
|
|
1181
|
+
* 2. Fall back to .kuckit/infra.json (legacy single-file format)
|
|
1182
|
+
*
|
|
1183
|
+
* @param projectRoot - Project root directory
|
|
1184
|
+
* @param env - Optional environment to load config for
|
|
918
1185
|
*/
|
|
919
|
-
async function loadStoredConfig(projectRoot) {
|
|
920
|
-
const
|
|
1186
|
+
async function loadStoredConfig(projectRoot, env) {
|
|
1187
|
+
const kuckitDir = join$1(projectRoot, KUCKIT_DIR$7);
|
|
1188
|
+
if (env) {
|
|
1189
|
+
const envConfigPath = join$1(kuckitDir, getEnvConfigFile(env));
|
|
1190
|
+
try {
|
|
1191
|
+
await access(envConfigPath, constants$1.F_OK);
|
|
1192
|
+
const content = await readFile(envConfigPath, "utf-8");
|
|
1193
|
+
const parsed = JSON.parse(content);
|
|
1194
|
+
if (isLegacyConfig(parsed)) return migrateLegacyConfig(parsed);
|
|
1195
|
+
return parsed;
|
|
1196
|
+
} catch {}
|
|
1197
|
+
}
|
|
1198
|
+
const configPath = join$1(kuckitDir, CONFIG_FILE$7);
|
|
921
1199
|
try {
|
|
922
1200
|
await access(configPath, constants$1.F_OK);
|
|
923
1201
|
const content = await readFile(configPath, "utf-8");
|
|
@@ -929,13 +1207,16 @@ async function loadStoredConfig(projectRoot) {
|
|
|
929
1207
|
}
|
|
930
1208
|
}
|
|
931
1209
|
/**
|
|
932
|
-
* Save infrastructure config to
|
|
1210
|
+
* Save infrastructure config to per-environment file
|
|
1211
|
+
*
|
|
1212
|
+
* Saves to .kuckit/infra.{env}.json based on the config's env field
|
|
1213
|
+
* Falls back to .kuckit/infra.json if no env is set
|
|
933
1214
|
*/
|
|
934
1215
|
async function saveStoredConfig(projectRoot, config) {
|
|
935
1216
|
const { mkdir: mkdir$1, writeFile: writeFile$1 } = await import("fs/promises");
|
|
936
1217
|
const kuckitDir = join$1(projectRoot, KUCKIT_DIR$7);
|
|
937
1218
|
await mkdir$1(kuckitDir, { recursive: true });
|
|
938
|
-
const configPath = join$1(kuckitDir, CONFIG_FILE$7);
|
|
1219
|
+
const configPath = join$1(kuckitDir, config.env ? getEnvConfigFile(config.env) : CONFIG_FILE$7);
|
|
939
1220
|
config.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
940
1221
|
await writeFile$1(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
941
1222
|
}
|
|
@@ -989,6 +1270,18 @@ function getProviderPackage(providerId) {
|
|
|
989
1270
|
return DEFAULT_PROVIDER_PACKAGES[providerId] ?? `@kuckit/infra-${providerId}`;
|
|
990
1271
|
}
|
|
991
1272
|
/**
|
|
1273
|
+
* Compute the Pulumi stack name for a given config and environment.
|
|
1274
|
+
* Stack names follow the pattern: {gcpProject}-{env}
|
|
1275
|
+
*
|
|
1276
|
+
* @param config - The stored infrastructure config
|
|
1277
|
+
* @param env - The target environment (dev, staging, prod)
|
|
1278
|
+
* @returns The computed stack name
|
|
1279
|
+
*/
|
|
1280
|
+
function computeStackName(config, env) {
|
|
1281
|
+
if (config.provider === "gcp" && "gcpProject" in config.providerConfig) return `${config.providerConfig.gcpProject}-${env}`;
|
|
1282
|
+
return config.stackName;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
992
1285
|
* Check if a provider package is available
|
|
993
1286
|
*/
|
|
994
1287
|
async function isProviderAvailable(providerId) {
|
|
@@ -1052,7 +1345,7 @@ async function infraInit(options) {
|
|
|
1052
1345
|
console.log("See docs/MIGRATION.md for details.");
|
|
1053
1346
|
console.log("");
|
|
1054
1347
|
}
|
|
1055
|
-
const existingConfig = await loadStoredConfig(projectRoot);
|
|
1348
|
+
const existingConfig = await loadStoredConfig(projectRoot, options.env);
|
|
1056
1349
|
let providerId = options.provider ?? existingConfig?.provider ?? "gcp";
|
|
1057
1350
|
if (!options.provider && !existingConfig) {
|
|
1058
1351
|
const installedProviders = (await listAvailableProviders()).filter((p) => p.available);
|
|
@@ -1265,7 +1558,7 @@ async function infraDeploy(options) {
|
|
|
1265
1558
|
console.error("Error: Could not find project root (no package.json found)");
|
|
1266
1559
|
process.exit(1);
|
|
1267
1560
|
}
|
|
1268
|
-
const config = await loadStoredConfig(projectRoot);
|
|
1561
|
+
const config = await loadStoredConfig(projectRoot, options.env);
|
|
1269
1562
|
if (!config) {
|
|
1270
1563
|
console.error("Error: No infrastructure configuration found.");
|
|
1271
1564
|
console.error("Run: kuckit infra init");
|
|
@@ -1426,7 +1719,7 @@ async function infraUp(options) {
|
|
|
1426
1719
|
console.error("Error: Could not find project root (no package.json found)");
|
|
1427
1720
|
process.exit(1);
|
|
1428
1721
|
}
|
|
1429
|
-
const existingConfig = await loadStoredConfig(projectRoot);
|
|
1722
|
+
const existingConfig = await loadStoredConfig(projectRoot, options.env);
|
|
1430
1723
|
if (!existingConfig) {
|
|
1431
1724
|
const providerPackage = getProviderPackage(options.provider ?? "gcp");
|
|
1432
1725
|
let providerLabel = "cloud";
|
|
@@ -1460,7 +1753,7 @@ async function infraUp(options) {
|
|
|
1460
1753
|
env: options.env,
|
|
1461
1754
|
yes: options.yes
|
|
1462
1755
|
});
|
|
1463
|
-
if (!await loadStoredConfig(projectRoot)) {
|
|
1756
|
+
if (!await loadStoredConfig(projectRoot, options.env)) {
|
|
1464
1757
|
console.error("Error: Initialization completed but no configuration found.");
|
|
1465
1758
|
process.exit(1);
|
|
1466
1759
|
}
|
|
@@ -1607,8 +1900,8 @@ async function infraEject(options) {
|
|
|
1607
1900
|
* Run a Pulumi CLI command
|
|
1608
1901
|
*/
|
|
1609
1902
|
function runPulumi(args, options) {
|
|
1610
|
-
return new Promise((resolve) => {
|
|
1611
|
-
const proc = spawn("pulumi", args, {
|
|
1903
|
+
return new Promise((resolve$1) => {
|
|
1904
|
+
const proc = spawn$1("pulumi", args, {
|
|
1612
1905
|
cwd: options.cwd,
|
|
1613
1906
|
stdio: options.stream ? [
|
|
1614
1907
|
"inherit",
|
|
@@ -1639,7 +1932,7 @@ function runPulumi(args, options) {
|
|
|
1639
1932
|
if (options.stream) process.stderr.write(data);
|
|
1640
1933
|
});
|
|
1641
1934
|
proc.on("close", (code) => {
|
|
1642
|
-
resolve({
|
|
1935
|
+
resolve$1({
|
|
1643
1936
|
code: code ?? 1,
|
|
1644
1937
|
stdout,
|
|
1645
1938
|
stderr
|
|
@@ -1786,8 +2079,8 @@ async function pulumiStackExport(filePath, options) {
|
|
|
1786
2079
|
* Run a gcloud CLI command
|
|
1787
2080
|
*/
|
|
1788
2081
|
function runGcloud(args, options = {}) {
|
|
1789
|
-
return new Promise((resolve) => {
|
|
1790
|
-
const proc = spawn("gcloud", args, {
|
|
2082
|
+
return new Promise((resolve$1) => {
|
|
2083
|
+
const proc = spawn$1("gcloud", args, {
|
|
1791
2084
|
cwd: options.cwd ?? process.cwd(),
|
|
1792
2085
|
stdio: options.stream ? [
|
|
1793
2086
|
"inherit",
|
|
@@ -1813,7 +2106,7 @@ function runGcloud(args, options = {}) {
|
|
|
1813
2106
|
if (options.stream) process.stderr.write(data);
|
|
1814
2107
|
});
|
|
1815
2108
|
proc.on("close", (code) => {
|
|
1816
|
-
resolve({
|
|
2109
|
+
resolve$1({
|
|
1817
2110
|
code: code ?? 1,
|
|
1818
2111
|
stdout,
|
|
1819
2112
|
stderr
|
|
@@ -1922,7 +2215,7 @@ function extractServiceNameFromUrl(url) {
|
|
|
1922
2215
|
try {
|
|
1923
2216
|
const hostname = new URL(url).hostname;
|
|
1924
2217
|
const match = hostname.match(/^([^-]+(?:-[^-]+)*?)-[a-z0-9]+-[a-z]+\.a\.run\.app$/);
|
|
1925
|
-
if (match) return match[1];
|
|
2218
|
+
if (match) return match[1] ?? null;
|
|
1926
2219
|
const parts = hostname.split("-");
|
|
1927
2220
|
if (parts.length >= 3) return parts.slice(0, -2).join("-");
|
|
1928
2221
|
return null;
|
|
@@ -2124,16 +2417,18 @@ async function infraDestroy(options) {
|
|
|
2124
2417
|
console.error(`Error: Invalid environment '${env}'. Must be 'dev' or 'prod'.`);
|
|
2125
2418
|
process.exit(1);
|
|
2126
2419
|
}
|
|
2420
|
+
const stackName = computeStackName(config, env);
|
|
2127
2421
|
const infraDir = getInfraDir$1(projectRoot);
|
|
2128
2422
|
if (!await fileExists$6(infraDir)) {
|
|
2129
2423
|
console.error("Error: packages/infra not found.");
|
|
2130
2424
|
process.exit(1);
|
|
2131
2425
|
}
|
|
2426
|
+
const projectDisplay = isGcpConfig(config) ? config.providerConfig.gcpProject : config.projectName;
|
|
2132
2427
|
console.log("Configuration:");
|
|
2133
|
-
console.log(` Project: ${
|
|
2428
|
+
console.log(` Project: ${projectDisplay}`);
|
|
2134
2429
|
console.log(` Region: ${config.region}`);
|
|
2135
2430
|
console.log(` Environment: ${env}`);
|
|
2136
|
-
console.log(` Stack: ${
|
|
2431
|
+
console.log(` Stack: ${stackName}`);
|
|
2137
2432
|
console.log("");
|
|
2138
2433
|
if (isAppOnly) {
|
|
2139
2434
|
console.log("WARNING: This will destroy the Cloud Run service.");
|
|
@@ -2171,7 +2466,6 @@ async function infraDestroy(options) {
|
|
|
2171
2466
|
}
|
|
2172
2467
|
}
|
|
2173
2468
|
}
|
|
2174
|
-
const stackName = config.stackName;
|
|
2175
2469
|
console.log(`\nSelecting Pulumi stack: ${stackName}`);
|
|
2176
2470
|
if (!await selectOrCreateStack(stackName, { cwd: infraDir })) {
|
|
2177
2471
|
console.error("Error: Failed to select Pulumi stack");
|
|
@@ -2277,6 +2571,7 @@ async function infraRepair(options) {
|
|
|
2277
2571
|
console.error(`Error: Invalid environment '${env}'. Must be 'dev' or 'prod'.`);
|
|
2278
2572
|
process.exit(1);
|
|
2279
2573
|
}
|
|
2574
|
+
const stackName = computeStackName(config, env);
|
|
2280
2575
|
const infraDir = getInfraDir$1(projectRoot);
|
|
2281
2576
|
if (!await fileExists$5(infraDir)) {
|
|
2282
2577
|
console.error("Error: packages/infra not found.");
|
|
@@ -2284,7 +2579,7 @@ async function infraRepair(options) {
|
|
|
2284
2579
|
}
|
|
2285
2580
|
const runCancel = options.cancel || !options.cancel && !options.refresh;
|
|
2286
2581
|
const runRefresh = options.refresh || !options.cancel && !options.refresh;
|
|
2287
|
-
console.log(`Repairing stack: ${
|
|
2582
|
+
console.log(`Repairing stack: ${stackName}`);
|
|
2288
2583
|
console.log(` Environment: ${env}`);
|
|
2289
2584
|
console.log(` Operations: ${[runCancel && "cancel", runRefresh && "refresh"].filter(Boolean).join(", ")}`);
|
|
2290
2585
|
console.log("");
|
|
@@ -2297,8 +2592,8 @@ async function infraRepair(options) {
|
|
|
2297
2592
|
process.exit(0);
|
|
2298
2593
|
}
|
|
2299
2594
|
}
|
|
2300
|
-
console.log(`Selecting Pulumi stack: ${
|
|
2301
|
-
if (!await selectOrCreateStack(
|
|
2595
|
+
console.log(`Selecting Pulumi stack: ${stackName}`);
|
|
2596
|
+
if (!await selectOrCreateStack(stackName, { cwd: infraDir })) {
|
|
2302
2597
|
console.error("Error: Failed to select Pulumi stack");
|
|
2303
2598
|
process.exit(1);
|
|
2304
2599
|
}
|
|
@@ -2616,12 +2911,17 @@ async function infraRollback(options) {
|
|
|
2616
2911
|
console.error("Error: Could not determine service name from URL:", serviceUrl);
|
|
2617
2912
|
process.exit(1);
|
|
2618
2913
|
}
|
|
2914
|
+
if (!isGcpConfig(config)) {
|
|
2915
|
+
console.error("Error: Rollback command is only supported for GCP deployments.");
|
|
2916
|
+
process.exit(1);
|
|
2917
|
+
}
|
|
2918
|
+
const gcpProject = config.providerConfig.gcpProject;
|
|
2619
2919
|
console.log(`Service: ${serviceName}`);
|
|
2620
|
-
console.log(`Project: ${
|
|
2920
|
+
console.log(`Project: ${gcpProject}`);
|
|
2621
2921
|
console.log(`Region: ${config.region}`);
|
|
2622
2922
|
console.log("");
|
|
2623
2923
|
console.log("Fetching revisions...");
|
|
2624
|
-
const revisions = await listCloudRunRevisions(serviceName,
|
|
2924
|
+
const revisions = await listCloudRunRevisions(serviceName, gcpProject, config.region);
|
|
2625
2925
|
if (revisions.length === 0) {
|
|
2626
2926
|
console.error("Error: No revisions found for service:", serviceName);
|
|
2627
2927
|
process.exit(1);
|
|
@@ -2668,7 +2968,7 @@ async function infraRollback(options) {
|
|
|
2668
2968
|
process.exit(0);
|
|
2669
2969
|
}
|
|
2670
2970
|
console.log(`Rolling back to ${targetRevision}...`);
|
|
2671
|
-
const result = await updateCloudRunTraffic(serviceName, targetRevision,
|
|
2971
|
+
const result = await updateCloudRunTraffic(serviceName, targetRevision, gcpProject, config.region);
|
|
2672
2972
|
if (result.code !== 0) {
|
|
2673
2973
|
console.error("\nError: Failed to update traffic routing");
|
|
2674
2974
|
console.error(result.stderr);
|
|
@@ -2708,12 +3008,12 @@ async function loadConfig$2(projectRoot) {
|
|
|
2708
3008
|
}
|
|
2709
3009
|
}
|
|
2710
3010
|
function runGcloudStreaming(args) {
|
|
2711
|
-
return new Promise((resolve) => {
|
|
2712
|
-
spawn("gcloud", args, {
|
|
3011
|
+
return new Promise((resolve$1) => {
|
|
3012
|
+
spawn$1("gcloud", args, {
|
|
2713
3013
|
stdio: "inherit",
|
|
2714
3014
|
shell: true
|
|
2715
3015
|
}).on("close", (code) => {
|
|
2716
|
-
resolve(code ?? 1);
|
|
3016
|
+
resolve$1(code ?? 1);
|
|
2717
3017
|
});
|
|
2718
3018
|
});
|
|
2719
3019
|
}
|
|
@@ -2752,8 +3052,13 @@ async function infraLogs(options) {
|
|
|
2752
3052
|
process.exit(1);
|
|
2753
3053
|
}
|
|
2754
3054
|
const since = options.since ?? "1h";
|
|
3055
|
+
if (!isGcpConfig(config)) {
|
|
3056
|
+
console.error("Error: Logs command is only supported for GCP deployments.");
|
|
3057
|
+
process.exit(1);
|
|
3058
|
+
}
|
|
3059
|
+
const gcpProject = config.providerConfig.gcpProject;
|
|
2755
3060
|
console.log(`Fetching logs for service: ${serviceName}`);
|
|
2756
|
-
console.log(` Project: ${
|
|
3061
|
+
console.log(` Project: ${gcpProject}`);
|
|
2757
3062
|
console.log(` Region: ${config.region}`);
|
|
2758
3063
|
if (options.follow) console.log(" Mode: Following (Ctrl+C to stop)");
|
|
2759
3064
|
else console.log(` Since: ${since}`);
|
|
@@ -2767,7 +3072,7 @@ async function infraLogs(options) {
|
|
|
2767
3072
|
if (options.follow) args.push("tail");
|
|
2768
3073
|
else args.push("read");
|
|
2769
3074
|
args.push(serviceName);
|
|
2770
|
-
args.push("--project",
|
|
3075
|
+
args.push("--project", gcpProject);
|
|
2771
3076
|
args.push("--region", config.region);
|
|
2772
3077
|
if (!options.follow) {
|
|
2773
3078
|
args.push("--limit", "100");
|
|
@@ -2844,7 +3149,7 @@ async function infraStatus(options) {
|
|
|
2844
3149
|
console.error("Run: kuckit infra init");
|
|
2845
3150
|
process.exit(1);
|
|
2846
3151
|
}
|
|
2847
|
-
const stackName = config.
|
|
3152
|
+
const stackName = computeStackName(config, options.env ?? config.env);
|
|
2848
3153
|
const infraDir = getInfraDir$1(projectRoot);
|
|
2849
3154
|
if (!await fileExists$1(infraDir)) {
|
|
2850
3155
|
console.error("Error: packages/infra not found.");
|
|
@@ -2955,7 +3260,7 @@ async function infraOutputs(options) {
|
|
|
2955
3260
|
process.exit(1);
|
|
2956
3261
|
}
|
|
2957
3262
|
const env = options.env ?? config.env ?? "dev";
|
|
2958
|
-
const stackName = config
|
|
3263
|
+
const stackName = computeStackName(config, env);
|
|
2959
3264
|
const infraDir = getInfraDir$1(projectRoot);
|
|
2960
3265
|
if (!await fileExists(infraDir)) {
|
|
2961
3266
|
console.error("Error: packages/infra not found.");
|
|
@@ -3024,8 +3329,8 @@ const KNOWN_CONFIG_KEYS = {
|
|
|
3024
3329
|
function getProjectRoot() {
|
|
3025
3330
|
return process.cwd();
|
|
3026
3331
|
}
|
|
3027
|
-
async function ensureConfigExists(projectRoot) {
|
|
3028
|
-
const config = await loadStoredConfig(projectRoot);
|
|
3332
|
+
async function ensureConfigExists(projectRoot, env) {
|
|
3333
|
+
const config = await loadStoredConfig(projectRoot, env);
|
|
3029
3334
|
if (!config) throw new Error("No infrastructure configuration found. Run `kuckit infra init` first.");
|
|
3030
3335
|
return config;
|
|
3031
3336
|
}
|
|
@@ -3099,8 +3404,9 @@ async function unsetPulumiConfig(projectRoot, config, env, key) {
|
|
|
3099
3404
|
*/
|
|
3100
3405
|
async function infraConfigSet(key, value, options = {}) {
|
|
3101
3406
|
const projectRoot = getProjectRoot();
|
|
3102
|
-
const
|
|
3103
|
-
const
|
|
3407
|
+
const env = options.env;
|
|
3408
|
+
const config = await ensureConfigExists(projectRoot, env);
|
|
3409
|
+
const resolvedEnv = env ?? config.env ?? "dev";
|
|
3104
3410
|
if (["region", "projectName"].includes(key)) {
|
|
3105
3411
|
if (key === "region") config.region = value;
|
|
3106
3412
|
else if (key === "projectName") config.projectName = value;
|
|
@@ -3117,17 +3423,18 @@ async function infraConfigSet(key, value, options = {}) {
|
|
|
3117
3423
|
return;
|
|
3118
3424
|
}
|
|
3119
3425
|
}
|
|
3120
|
-
await syncToPulumi(projectRoot, config,
|
|
3121
|
-
console.log(`✓ Set ${key}=${value} for env '${
|
|
3122
|
-
if (key === "appUrl") console.log(`\nNote: Run 'kuckit infra deploy --env ${
|
|
3426
|
+
await syncToPulumi(projectRoot, config, resolvedEnv, key, value);
|
|
3427
|
+
console.log(`✓ Set ${key}=${value} for env '${resolvedEnv}'`);
|
|
3428
|
+
if (key === "appUrl") console.log(`\nNote: Run 'kuckit infra deploy --env ${resolvedEnv}' to apply this change.`);
|
|
3123
3429
|
}
|
|
3124
3430
|
/**
|
|
3125
3431
|
* Get a configuration value
|
|
3126
3432
|
*/
|
|
3127
3433
|
async function infraConfigGet(key, options = {}) {
|
|
3128
3434
|
const projectRoot = getProjectRoot();
|
|
3129
|
-
const
|
|
3130
|
-
const
|
|
3435
|
+
const env = options.env;
|
|
3436
|
+
const config = await ensureConfigExists(projectRoot, env);
|
|
3437
|
+
const resolvedEnv = env ?? config.env ?? "dev";
|
|
3131
3438
|
const localKeys = {
|
|
3132
3439
|
region: (c) => c.region,
|
|
3133
3440
|
projectName: (c) => c.projectName,
|
|
@@ -3144,10 +3451,10 @@ async function infraConfigGet(key, options = {}) {
|
|
|
3144
3451
|
}
|
|
3145
3452
|
}
|
|
3146
3453
|
}
|
|
3147
|
-
const value = await getPulumiConfigValue(projectRoot, config,
|
|
3454
|
+
const value = await getPulumiConfigValue(projectRoot, config, resolvedEnv, key);
|
|
3148
3455
|
if (value !== null) console.log(value);
|
|
3149
3456
|
else {
|
|
3150
|
-
console.error(`Config key '${key}' is not set for env '${
|
|
3457
|
+
console.error(`Config key '${key}' is not set for env '${resolvedEnv}'.`);
|
|
3151
3458
|
process.exit(1);
|
|
3152
3459
|
}
|
|
3153
3460
|
}
|
|
@@ -3156,36 +3463,37 @@ async function infraConfigGet(key, options = {}) {
|
|
|
3156
3463
|
*/
|
|
3157
3464
|
async function infraConfigList(options = {}) {
|
|
3158
3465
|
const projectRoot = getProjectRoot();
|
|
3159
|
-
const
|
|
3160
|
-
const
|
|
3466
|
+
const env = options.env;
|
|
3467
|
+
const config = await ensureConfigExists(projectRoot, env);
|
|
3468
|
+
const resolvedEnv = env ?? config.env ?? "dev";
|
|
3161
3469
|
const localConfig = {
|
|
3162
3470
|
provider: config.provider,
|
|
3163
3471
|
region: config.region,
|
|
3164
3472
|
projectName: config.projectName
|
|
3165
3473
|
};
|
|
3166
3474
|
if (isGcpConfig(config)) localConfig["provider.gcpProject"] = config.providerConfig.gcpProject;
|
|
3167
|
-
const pulumiConfig = await getAllPulumiConfig(projectRoot, config,
|
|
3475
|
+
const pulumiConfig = await getAllPulumiConfig(projectRoot, config, resolvedEnv);
|
|
3168
3476
|
const allConfig = {
|
|
3169
3477
|
...localConfig,
|
|
3170
3478
|
...pulumiConfig
|
|
3171
3479
|
};
|
|
3172
3480
|
if (options.json) {
|
|
3173
3481
|
console.log(JSON.stringify({
|
|
3174
|
-
env,
|
|
3482
|
+
env: resolvedEnv,
|
|
3175
3483
|
config: allConfig
|
|
3176
3484
|
}, null, 2));
|
|
3177
3485
|
return;
|
|
3178
3486
|
}
|
|
3179
|
-
console.log(`\nInfrastructure Configuration (env: ${
|
|
3487
|
+
console.log(`\nInfrastructure Configuration (env: ${resolvedEnv})\n`);
|
|
3180
3488
|
console.log("Shared (.kuckit/infra.json):");
|
|
3181
3489
|
for (const [key, value] of Object.entries(localConfig)) console.log(` ${key}: ${value}`);
|
|
3182
3490
|
if (Object.keys(pulumiConfig).length > 0) {
|
|
3183
|
-
console.log(`\nEnvironment '${
|
|
3491
|
+
console.log(`\nEnvironment '${resolvedEnv}' Config:`);
|
|
3184
3492
|
for (const [key, value] of Object.entries(pulumiConfig)) if (!(key in localConfig)) {
|
|
3185
3493
|
const desc = KNOWN_CONFIG_KEYS[key]?.description;
|
|
3186
3494
|
console.log(` ${key}: ${value}${desc ? ` (${desc})` : ""}`);
|
|
3187
3495
|
}
|
|
3188
|
-
} else console.log(`\nEnvironment '${
|
|
3496
|
+
} else console.log(`\nEnvironment '${resolvedEnv}' Config: (none set)`);
|
|
3189
3497
|
console.log("\nAvailable keys:");
|
|
3190
3498
|
for (const [key, info] of Object.entries(KNOWN_CONFIG_KEYS)) if (!(key in allConfig)) console.log(` ${key}: ${info.description} (e.g., ${info.example})`);
|
|
3191
3499
|
console.log(`\nTip: Use --env to configure other environments (dev, staging, prod)`);
|
|
@@ -3195,20 +3503,30 @@ async function infraConfigList(options = {}) {
|
|
|
3195
3503
|
*/
|
|
3196
3504
|
async function infraConfigUnset(key, options = {}) {
|
|
3197
3505
|
const projectRoot = getProjectRoot();
|
|
3198
|
-
const
|
|
3199
|
-
const
|
|
3506
|
+
const env = options.env;
|
|
3507
|
+
const config = await ensureConfigExists(projectRoot, env);
|
|
3508
|
+
const resolvedEnv = env ?? config.env ?? "dev";
|
|
3200
3509
|
if ([
|
|
3201
3510
|
"provider",
|
|
3202
3511
|
"region",
|
|
3203
3512
|
"projectName"
|
|
3204
3513
|
].includes(key)) throw new Error(`Cannot unset required key '${key}'.`);
|
|
3205
|
-
await unsetPulumiConfig(projectRoot, config,
|
|
3206
|
-
console.log(`✓ Unset ${key} for env '${
|
|
3514
|
+
await unsetPulumiConfig(projectRoot, config, resolvedEnv, key);
|
|
3515
|
+
console.log(`✓ Unset ${key} for env '${resolvedEnv}'`);
|
|
3207
3516
|
}
|
|
3208
3517
|
|
|
3209
3518
|
//#endregion
|
|
3210
3519
|
//#region src/bin.ts
|
|
3211
3520
|
program.name("kuckit").description("CLI tools for Kuckit SDK module development").version("0.1.0");
|
|
3521
|
+
program.command("dev").description("Start the development server with hot reload").option("-c, --config <path>", "Path to kuckit.config.ts").option("-p, --port <port>", "Port to run the server on").action(async (options) => {
|
|
3522
|
+
await dev(options);
|
|
3523
|
+
});
|
|
3524
|
+
program.command("build").description("Build the application for production").option("-c, --config <path>", "Path to kuckit.config.ts").option("-o, --out-dir <dir>", "Output directory", "dist").action(async (options) => {
|
|
3525
|
+
await build(options);
|
|
3526
|
+
});
|
|
3527
|
+
program.command("start").description("Start the production server").option("-c, --config <path>", "Path to kuckit.config.ts").option("-p, --port <port>", "Port to run the server on").action(async (options) => {
|
|
3528
|
+
await start(options);
|
|
3529
|
+
});
|
|
3212
3530
|
program.command("generate").description("Generate Kuckit resources").command("module <name>").description("Generate a new Kuckit module").option("-o, --org <org>", "Organization scope for package name", "").option("-d, --dir <directory>", "Target directory", "packages").action(async (name, options) => {
|
|
3213
3531
|
requireAuth();
|
|
3214
3532
|
await generateModule(name, options);
|