@fractary/codex-cli 0.10.11 → 0.10.14
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/README.md +41 -315
- package/dist/cli.cjs +109 -128
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +107 -126
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,8 @@ import * as path5 from 'path';
|
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import * as fs from 'fs/promises';
|
|
6
|
-
import * as
|
|
7
|
-
import { ValidationError, PermissionDeniedError, ConfigurationError, CodexError } from '@fractary/codex';
|
|
6
|
+
import * as yaml2 from 'js-yaml';
|
|
7
|
+
import { readCodexConfig, CONFIG_SCHEMA_VERSION, expandEnvVarsInConfig, expandEnvVars, parseSize, parseDuration, ValidationError, PermissionDeniedError, ConfigurationError, CodexError } from '@fractary/codex';
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import { spawn } from 'child_process';
|
|
10
10
|
import { Command } from 'commander';
|
|
@@ -38,7 +38,7 @@ __export(migrate_config_exports, {
|
|
|
38
38
|
getDefaultYamlConfig: () => getDefaultYamlConfig,
|
|
39
39
|
isLegacyConfig: () => isLegacyConfig,
|
|
40
40
|
migrateConfig: () => migrateConfig,
|
|
41
|
-
readYamlConfig: () =>
|
|
41
|
+
readYamlConfig: () => readCodexConfig,
|
|
42
42
|
writeYamlConfig: () => writeYamlConfig
|
|
43
43
|
});
|
|
44
44
|
async function isLegacyConfig(configPath) {
|
|
@@ -163,7 +163,7 @@ async function migrateConfig(legacyConfigPath, options) {
|
|
|
163
163
|
async function writeYamlConfig(config, outputPath) {
|
|
164
164
|
const dir = path5.dirname(outputPath);
|
|
165
165
|
await fs.mkdir(dir, { recursive: true });
|
|
166
|
-
const yamlContent =
|
|
166
|
+
const yamlContent = yaml2.dump(config, {
|
|
167
167
|
indent: 2,
|
|
168
168
|
lineWidth: 80,
|
|
169
169
|
noRefs: true,
|
|
@@ -228,20 +228,6 @@ function getDefaultYamlConfig(organization) {
|
|
|
228
228
|
}
|
|
229
229
|
};
|
|
230
230
|
}
|
|
231
|
-
async function readYamlConfig(configPath) {
|
|
232
|
-
const content = await fs.readFile(configPath, "utf-8");
|
|
233
|
-
const rawConfig = yaml.load(content);
|
|
234
|
-
let config;
|
|
235
|
-
if (rawConfig.codex && typeof rawConfig.codex === "object") {
|
|
236
|
-
config = rawConfig.codex;
|
|
237
|
-
} else {
|
|
238
|
-
config = rawConfig;
|
|
239
|
-
}
|
|
240
|
-
if (!config.organization) {
|
|
241
|
-
throw new Error("Invalid config: organization is required");
|
|
242
|
-
}
|
|
243
|
-
return config;
|
|
244
|
-
}
|
|
245
231
|
var init_migrate_config = __esm({
|
|
246
232
|
"src/config/migrate-config.ts"() {
|
|
247
233
|
init_esm_shims();
|
|
@@ -253,89 +239,9 @@ var config_types_exports = {};
|
|
|
253
239
|
__export(config_types_exports, {
|
|
254
240
|
parseDuration: () => parseDuration,
|
|
255
241
|
parseSize: () => parseSize,
|
|
256
|
-
resolveEnvVars: () =>
|
|
257
|
-
resolveEnvVarsInConfig: () =>
|
|
242
|
+
resolveEnvVars: () => expandEnvVars,
|
|
243
|
+
resolveEnvVarsInConfig: () => expandEnvVarsInConfig
|
|
258
244
|
});
|
|
259
|
-
function parseDuration(duration) {
|
|
260
|
-
if (typeof duration === "number") {
|
|
261
|
-
return duration;
|
|
262
|
-
}
|
|
263
|
-
const match = duration.match(/^(\d+)([smhdwMy])$/);
|
|
264
|
-
if (!match) {
|
|
265
|
-
throw new Error(`Invalid duration format: ${duration}`);
|
|
266
|
-
}
|
|
267
|
-
const [, valueStr, unit] = match;
|
|
268
|
-
const value = parseInt(valueStr, 10);
|
|
269
|
-
switch (unit) {
|
|
270
|
-
case "s":
|
|
271
|
-
return value;
|
|
272
|
-
case "m":
|
|
273
|
-
return value * 60;
|
|
274
|
-
case "h":
|
|
275
|
-
return value * 3600;
|
|
276
|
-
case "d":
|
|
277
|
-
return value * 86400;
|
|
278
|
-
case "w":
|
|
279
|
-
return value * 604800;
|
|
280
|
-
case "M":
|
|
281
|
-
return value * 2592e3;
|
|
282
|
-
// 30 days
|
|
283
|
-
case "y":
|
|
284
|
-
return value * 31536e3;
|
|
285
|
-
// 365 days
|
|
286
|
-
default:
|
|
287
|
-
throw new Error(`Unknown duration unit: ${unit}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
function parseSize(size) {
|
|
291
|
-
if (typeof size === "number") {
|
|
292
|
-
return size;
|
|
293
|
-
}
|
|
294
|
-
const match = size.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB)$/i);
|
|
295
|
-
if (!match) {
|
|
296
|
-
throw new Error(`Invalid size format: ${size}`);
|
|
297
|
-
}
|
|
298
|
-
const [, valueStr, unit] = match;
|
|
299
|
-
const value = parseFloat(valueStr);
|
|
300
|
-
switch (unit.toUpperCase()) {
|
|
301
|
-
case "B":
|
|
302
|
-
return value;
|
|
303
|
-
case "KB":
|
|
304
|
-
return value * 1024;
|
|
305
|
-
case "MB":
|
|
306
|
-
return value * 1024 * 1024;
|
|
307
|
-
case "GB":
|
|
308
|
-
return value * 1024 * 1024 * 1024;
|
|
309
|
-
default:
|
|
310
|
-
throw new Error(`Unknown size unit: ${unit}`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
function resolveEnvVars(value) {
|
|
314
|
-
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
315
|
-
const envValue = process.env[varName];
|
|
316
|
-
if (envValue === void 0) {
|
|
317
|
-
console.warn(`Warning: Environment variable ${varName} is not set`);
|
|
318
|
-
return `\${${varName}}`;
|
|
319
|
-
}
|
|
320
|
-
return envValue;
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
function resolveEnvVarsInConfig(config) {
|
|
324
|
-
if (typeof config === "string") {
|
|
325
|
-
return resolveEnvVars(config);
|
|
326
|
-
}
|
|
327
|
-
if (Array.isArray(config)) {
|
|
328
|
-
return config.map((item) => resolveEnvVarsInConfig(item));
|
|
329
|
-
}
|
|
330
|
-
if (config !== null && typeof config === "object") {
|
|
331
|
-
const result = {};
|
|
332
|
-
for (const [key, value] of Object.entries(config)) {
|
|
333
|
-
result[key] = resolveEnvVarsInConfig(value);
|
|
334
|
-
}
|
|
335
|
-
return result;
|
|
336
|
-
}
|
|
337
|
-
return config;
|
|
338
|
-
}
|
|
339
245
|
var init_config_types = __esm({
|
|
340
246
|
"src/config/config-types.ts"() {
|
|
341
247
|
init_esm_shims();
|
|
@@ -388,14 +294,14 @@ var init_codex_client = __esm({
|
|
|
388
294
|
CodexError: CodexError2,
|
|
389
295
|
ConfigurationError: ConfigurationError2
|
|
390
296
|
} = await import('@fractary/codex');
|
|
391
|
-
const { readYamlConfig
|
|
392
|
-
const { resolveEnvVarsInConfig
|
|
297
|
+
const { readYamlConfig } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
|
|
298
|
+
const { resolveEnvVarsInConfig } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
|
|
393
299
|
try {
|
|
394
300
|
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
395
301
|
let config;
|
|
396
302
|
try {
|
|
397
|
-
config = await
|
|
398
|
-
config =
|
|
303
|
+
config = await readYamlConfig(configPath);
|
|
304
|
+
config = resolveEnvVarsInConfig(config);
|
|
399
305
|
} catch (error) {
|
|
400
306
|
throw new ConfigurationError2(
|
|
401
307
|
`Failed to load configuration from ${configPath}. Run "fractary codex init" to create a configuration.`
|
|
@@ -884,7 +790,7 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
|
|
|
884
790
|
const sanitizedProject = sanitizeForS3BucketName(project);
|
|
885
791
|
return {
|
|
886
792
|
file: {
|
|
887
|
-
schema_version:
|
|
793
|
+
schema_version: CONFIG_SCHEMA_VERSION,
|
|
888
794
|
sources: {
|
|
889
795
|
specs: {
|
|
890
796
|
type: "s3",
|
|
@@ -921,18 +827,23 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
|
|
|
921
827
|
}
|
|
922
828
|
},
|
|
923
829
|
codex: {
|
|
924
|
-
schema_version:
|
|
830
|
+
schema_version: CONFIG_SCHEMA_VERSION,
|
|
925
831
|
organization,
|
|
926
832
|
project,
|
|
927
833
|
codex_repo: codexRepo,
|
|
928
|
-
|
|
834
|
+
remotes: {
|
|
835
|
+
// The codex repository - uses same token as git operations
|
|
836
|
+
[`${organization}/${codexRepo}`]: {
|
|
837
|
+
token: "${GITHUB_TOKEN}"
|
|
838
|
+
}
|
|
839
|
+
}
|
|
929
840
|
}
|
|
930
841
|
};
|
|
931
842
|
}
|
|
932
843
|
async function readUnifiedConfig(configPath) {
|
|
933
844
|
try {
|
|
934
845
|
const content = await fs.readFile(configPath, "utf-8");
|
|
935
|
-
const config =
|
|
846
|
+
const config = yaml2.load(content);
|
|
936
847
|
return config;
|
|
937
848
|
} catch (error) {
|
|
938
849
|
if (error.code === "ENOENT") {
|
|
@@ -944,7 +855,7 @@ async function readUnifiedConfig(configPath) {
|
|
|
944
855
|
async function writeUnifiedConfig(config, outputPath) {
|
|
945
856
|
const dir = path5.dirname(outputPath);
|
|
946
857
|
await fs.mkdir(dir, { recursive: true });
|
|
947
|
-
const yamlContent =
|
|
858
|
+
const yamlContent = yaml2.dump(config, {
|
|
948
859
|
indent: 2,
|
|
949
860
|
lineWidth: 120,
|
|
950
861
|
noRefs: true,
|
|
@@ -956,7 +867,7 @@ function mergeUnifiedConfigs(existing, updates) {
|
|
|
956
867
|
const merged = {};
|
|
957
868
|
if (updates.file || existing.file) {
|
|
958
869
|
merged.file = {
|
|
959
|
-
schema_version: updates.file?.schema_version || existing.file?.schema_version ||
|
|
870
|
+
schema_version: updates.file?.schema_version || existing.file?.schema_version || CONFIG_SCHEMA_VERSION,
|
|
960
871
|
sources: {
|
|
961
872
|
...existing.file?.sources || {},
|
|
962
873
|
...updates.file?.sources || {}
|
|
@@ -965,13 +876,13 @@ function mergeUnifiedConfigs(existing, updates) {
|
|
|
965
876
|
}
|
|
966
877
|
if (updates.codex || existing.codex) {
|
|
967
878
|
merged.codex = {
|
|
968
|
-
schema_version: updates.codex?.schema_version || existing.codex?.schema_version ||
|
|
879
|
+
schema_version: updates.codex?.schema_version || existing.codex?.schema_version || CONFIG_SCHEMA_VERSION,
|
|
969
880
|
organization: updates.codex?.organization || existing.codex?.organization || "default",
|
|
970
881
|
project: updates.codex?.project || existing.codex?.project || "default",
|
|
971
882
|
codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
|
|
972
|
-
|
|
973
|
-
...existing.codex?.
|
|
974
|
-
...updates.codex?.
|
|
883
|
+
remotes: {
|
|
884
|
+
...existing.codex?.remotes || {},
|
|
885
|
+
...updates.codex?.remotes || {}
|
|
975
886
|
}
|
|
976
887
|
};
|
|
977
888
|
}
|
|
@@ -1185,9 +1096,64 @@ async function fileExists(filePath) {
|
|
|
1185
1096
|
return false;
|
|
1186
1097
|
}
|
|
1187
1098
|
}
|
|
1099
|
+
async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml", options = {}) {
|
|
1100
|
+
const mcpJsonPath = path5.join(projectRoot, ".mcp.json");
|
|
1101
|
+
const { backup = true } = options;
|
|
1102
|
+
let existingConfig = { mcpServers: {} };
|
|
1103
|
+
let backupPath;
|
|
1104
|
+
let migrated = false;
|
|
1105
|
+
if (await fileExists(mcpJsonPath)) {
|
|
1106
|
+
try {
|
|
1107
|
+
const content = await fs.readFile(mcpJsonPath, "utf-8");
|
|
1108
|
+
existingConfig = JSON.parse(content);
|
|
1109
|
+
if (backup) {
|
|
1110
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 18);
|
|
1111
|
+
const suffix = Math.random().toString(36).substring(2, 6);
|
|
1112
|
+
backupPath = `${mcpJsonPath}.backup.${timestamp}-${suffix}`;
|
|
1113
|
+
await fs.writeFile(backupPath, content);
|
|
1114
|
+
}
|
|
1115
|
+
} catch {
|
|
1116
|
+
console.log(chalk7.yellow("\u26A0 Warning: .mcp.json contains invalid JSON, starting fresh"));
|
|
1117
|
+
existingConfig = { mcpServers: {} };
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
if (!existingConfig.mcpServers) {
|
|
1121
|
+
existingConfig.mcpServers = {};
|
|
1122
|
+
}
|
|
1123
|
+
const existing = existingConfig.mcpServers["fractary-codex"];
|
|
1124
|
+
if (existing) {
|
|
1125
|
+
const existingCommand = existing.command;
|
|
1126
|
+
const existingArgs = existing.args || [];
|
|
1127
|
+
if (existingCommand === "npx" && existingArgs.includes("@fractary/codex-mcp")) {
|
|
1128
|
+
return {
|
|
1129
|
+
installed: false,
|
|
1130
|
+
migrated: false,
|
|
1131
|
+
alreadyInstalled: true,
|
|
1132
|
+
backupPath
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
if (existingCommand === "node" || existingArgs.includes("@fractary/codex")) {
|
|
1136
|
+
migrated = true;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
existingConfig.mcpServers["fractary-codex"] = {
|
|
1140
|
+
command: "npx",
|
|
1141
|
+
args: ["-y", "@fractary/codex-mcp", "--config", configPath]
|
|
1142
|
+
};
|
|
1143
|
+
await fs.writeFile(
|
|
1144
|
+
mcpJsonPath,
|
|
1145
|
+
JSON.stringify(existingConfig, null, 2) + "\n"
|
|
1146
|
+
);
|
|
1147
|
+
return {
|
|
1148
|
+
installed: true,
|
|
1149
|
+
migrated,
|
|
1150
|
+
alreadyInstalled: false,
|
|
1151
|
+
backupPath
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1188
1154
|
function initCommand() {
|
|
1189
1155
|
const cmd = new Command("init");
|
|
1190
|
-
cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
1156
|
+
cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--force", "Overwrite existing configuration").option("--no-mcp", "Skip MCP server installation").action(async (options) => {
|
|
1191
1157
|
try {
|
|
1192
1158
|
console.log(chalk7.blue("Initializing unified Fractary configuration...\n"));
|
|
1193
1159
|
let org = options.org;
|
|
@@ -1299,6 +1265,20 @@ function initCommand() {
|
|
|
1299
1265
|
} else if (result.merged) {
|
|
1300
1266
|
console.log(chalk7.green("\u2713"), chalk7.dim(".fractary/config.yaml (merged with existing)"));
|
|
1301
1267
|
}
|
|
1268
|
+
if (options.mcp !== false) {
|
|
1269
|
+
console.log("\nConfiguring MCP server...");
|
|
1270
|
+
const mcpResult = await installMcpServer(process.cwd(), ".fractary/config.yaml");
|
|
1271
|
+
if (mcpResult.alreadyInstalled) {
|
|
1272
|
+
console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (already configured)"));
|
|
1273
|
+
} else if (mcpResult.migrated) {
|
|
1274
|
+
console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (migrated from old format)"));
|
|
1275
|
+
if (mcpResult.backupPath) {
|
|
1276
|
+
console.log(chalk7.dim(` Backup: ${path5.basename(mcpResult.backupPath)}`));
|
|
1277
|
+
}
|
|
1278
|
+
} else if (mcpResult.installed) {
|
|
1279
|
+
console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (created)"));
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1302
1282
|
console.log(chalk7.green("\n\u2713 Unified configuration initialized successfully!\n"));
|
|
1303
1283
|
console.log(chalk7.bold("Configuration:"));
|
|
1304
1284
|
console.log(chalk7.dim(` Organization: ${org}`));
|
|
@@ -1310,18 +1290,19 @@ function initCommand() {
|
|
|
1310
1290
|
console.log(chalk7.dim(" - logs: .fractary/logs/ \u2192 S3"));
|
|
1311
1291
|
console.log(chalk7.bold("\nCodex plugin:"));
|
|
1312
1292
|
console.log(chalk7.dim(" - Cache: .fractary/codex/cache/"));
|
|
1313
|
-
console.log(chalk7.dim(" -
|
|
1293
|
+
console.log(chalk7.dim(" - MCP Server: @fractary/codex-mcp (via npx)"));
|
|
1294
|
+
console.log(chalk7.dim(" - Remotes: codex repo configured"));
|
|
1314
1295
|
console.log(chalk7.bold("\nGit Authentication:"));
|
|
1315
1296
|
console.log(chalk7.dim(" Codex sync uses your existing git credentials."));
|
|
1316
1297
|
console.log(chalk7.dim(" Ensure you have access to the codex repository:"));
|
|
1317
1298
|
console.log(chalk7.dim(` gh repo view ${org}/${codexRepo}`));
|
|
1318
1299
|
console.log(chalk7.dim(" Or set GITHUB_TOKEN environment variable."));
|
|
1319
1300
|
console.log(chalk7.bold("\nNext steps:"));
|
|
1320
|
-
console.log(chalk7.dim(" 1.
|
|
1321
|
-
console.log(chalk7.dim(" 2.
|
|
1322
|
-
console.log(chalk7.dim(" 3.
|
|
1323
|
-
console.log(chalk7.dim(" 4.
|
|
1324
|
-
console.log(chalk7.dim(" 5.
|
|
1301
|
+
console.log(chalk7.dim(" 1. Restart Claude Code to load the MCP server"));
|
|
1302
|
+
console.log(chalk7.dim(" 2. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
|
|
1303
|
+
console.log(chalk7.dim(" 3. Configure AWS credentials for S3 access (if using file plugin)"));
|
|
1304
|
+
console.log(chalk7.dim(" 4. Edit .fractary/config.yaml to add external project remotes"));
|
|
1305
|
+
console.log(chalk7.dim(" 5. Reference docs via codex:// URIs (auto-fetched by MCP)"));
|
|
1325
1306
|
} catch (error) {
|
|
1326
1307
|
console.error(chalk7.red("Error:"), error.message);
|
|
1327
1308
|
process.exit(1);
|
|
@@ -1539,7 +1520,7 @@ async function checkConfiguration() {
|
|
|
1539
1520
|
details: 'Run "fractary codex init" to create configuration'
|
|
1540
1521
|
};
|
|
1541
1522
|
}
|
|
1542
|
-
const config = await
|
|
1523
|
+
const config = await readCodexConfig(configPath);
|
|
1543
1524
|
if (!config.organization) {
|
|
1544
1525
|
return {
|
|
1545
1526
|
name: "Configuration",
|
|
@@ -1630,7 +1611,7 @@ async function checkCache() {
|
|
|
1630
1611
|
async function checkStorage() {
|
|
1631
1612
|
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
1632
1613
|
try {
|
|
1633
|
-
const config = await
|
|
1614
|
+
const config = await readCodexConfig(configPath);
|
|
1634
1615
|
const providers = config.storage || [];
|
|
1635
1616
|
if (providers.length === 0) {
|
|
1636
1617
|
return {
|
|
@@ -1789,7 +1770,7 @@ function syncCommand() {
|
|
|
1789
1770
|
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
1790
1771
|
let config;
|
|
1791
1772
|
try {
|
|
1792
|
-
config = await
|
|
1773
|
+
config = await readCodexConfig(configPath);
|
|
1793
1774
|
} catch (error) {
|
|
1794
1775
|
console.error(chalk7.red("Error:"), "Codex not initialized.");
|
|
1795
1776
|
console.log(chalk7.dim('Run "fractary codex init" first.'));
|
|
@@ -2357,7 +2338,7 @@ function typesAddCommand() {
|
|
|
2357
2338
|
process.exit(1);
|
|
2358
2339
|
}
|
|
2359
2340
|
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
2360
|
-
const config = await
|
|
2341
|
+
const config = await readCodexConfig(configPath);
|
|
2361
2342
|
if (!config.types) {
|
|
2362
2343
|
config.types = { custom: {} };
|
|
2363
2344
|
}
|
|
@@ -2426,7 +2407,7 @@ function typesRemoveCommand() {
|
|
|
2426
2407
|
}
|
|
2427
2408
|
const typeInfo = registry.get(name);
|
|
2428
2409
|
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
2429
|
-
const config = await
|
|
2410
|
+
const config = await readCodexConfig(configPath);
|
|
2430
2411
|
if (!config.types?.custom?.[name]) {
|
|
2431
2412
|
console.error(chalk7.red("Error:"), `Custom type "${name}" not found in configuration.`);
|
|
2432
2413
|
process.exit(1);
|