@nexical/cli 0.11.7 → 0.11.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/{chunk-LZ3YQWAR.js → chunk-OUGA4CB4.js} +15 -11
- package/dist/chunk-OUGA4CB4.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/module/add.js +51 -20
- package/dist/src/commands/module/add.js.map +1 -1
- package/dist/src/commands/module/list.d.ts +1 -0
- package/dist/src/commands/module/list.js +55 -46
- package/dist/src/commands/module/list.js.map +1 -1
- package/dist/src/commands/module/remove.js +38 -13
- package/dist/src/commands/module/remove.js.map +1 -1
- package/dist/src/commands/module/update.js +16 -4
- package/dist/src/commands/module/update.js.map +1 -1
- package/dist/src/commands/run.js +19 -2
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/setup.js +1 -1
- package/package.json +1 -1
- package/src/commands/module/add.ts +74 -31
- package/src/commands/module/list.ts +80 -57
- package/src/commands/module/remove.ts +50 -14
- package/src/commands/module/update.ts +19 -5
- package/src/commands/run.ts +21 -1
- package/test/e2e/lifecycle.e2e.test.ts +3 -2
- package/test/integration/commands/deploy.integration.test.ts +102 -0
- package/test/integration/commands/init.integration.test.ts +16 -1
- package/test/integration/commands/module.integration.test.ts +81 -55
- package/test/integration/commands/run.integration.test.ts +69 -74
- package/test/integration/commands/setup.integration.test.ts +53 -0
- package/test/unit/commands/deploy.test.ts +285 -0
- package/test/unit/commands/init.test.ts +15 -0
- package/test/unit/commands/module/add.test.ts +363 -254
- package/test/unit/commands/module/list.test.ts +100 -99
- package/test/unit/commands/module/remove.test.ts +143 -58
- package/test/unit/commands/module/update.test.ts +45 -62
- package/test/unit/commands/run.test.ts +16 -1
- package/test/unit/commands/setup.test.ts +25 -66
- package/test/unit/deploy/config-manager.test.ts +65 -0
- package/test/unit/deploy/providers/cloudflare.test.ts +210 -0
- package/test/unit/deploy/providers/github.test.ts +139 -0
- package/test/unit/deploy/providers/railway.test.ts +328 -0
- package/test/unit/deploy/registry.test.ts +227 -0
- package/test/unit/deploy/utils.test.ts +30 -0
- package/test/unit/utils/command-discovery.test.ts +145 -142
- package/test/unit/utils/git_utils.test.ts +49 -0
- package/dist/chunk-LZ3YQWAR.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
require_lib
|
|
4
|
-
} from "../../../chunk-
|
|
4
|
+
} from "../../../chunk-OUGA4CB4.js";
|
|
5
5
|
import {
|
|
6
6
|
__toESM,
|
|
7
7
|
init_esm_shims
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
// src/commands/module/list.ts
|
|
11
11
|
init_esm_shims();
|
|
12
12
|
var import_fs_extra = __toESM(require_lib(), 1);
|
|
13
|
-
import { BaseCommand
|
|
13
|
+
import { BaseCommand } from "@nexical/cli-core";
|
|
14
14
|
import path from "path";
|
|
15
15
|
import YAML from "yaml";
|
|
16
16
|
var ModuleListCommand = class extends BaseCommand {
|
|
@@ -19,56 +19,65 @@ var ModuleListCommand = class extends BaseCommand {
|
|
|
19
19
|
static requiresProject = true;
|
|
20
20
|
async run() {
|
|
21
21
|
const projectRoot = this.projectRoot;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (await import_fs_extra.default.pathExists(pkgJsonPath)) {
|
|
42
|
-
try {
|
|
43
|
-
pkg = await import_fs_extra.default.readJson(pkgJsonPath);
|
|
44
|
-
} catch {
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (await import_fs_extra.default.pathExists(moduleYamlPath) || await import_fs_extra.default.pathExists(moduleYmlPath)) {
|
|
48
|
-
try {
|
|
49
|
-
const configPath = await import_fs_extra.default.pathExists(moduleYamlPath) ? moduleYamlPath : moduleYmlPath;
|
|
50
|
-
const content = await import_fs_extra.default.readFile(configPath, "utf8");
|
|
51
|
-
modConfig = YAML.parse(content) || {};
|
|
52
|
-
} catch {
|
|
53
|
-
}
|
|
22
|
+
const builtInLocations = [
|
|
23
|
+
{ type: "backend", path: path.join(projectRoot, "apps/backend/modules") },
|
|
24
|
+
{ type: "frontend", path: path.join(projectRoot, "apps/frontend/modules") },
|
|
25
|
+
// Check legacy `modules` folder just in case?
|
|
26
|
+
{ type: "legacy", path: path.join(projectRoot, "modules") }
|
|
27
|
+
];
|
|
28
|
+
const allModules = [];
|
|
29
|
+
for (const loc of builtInLocations) {
|
|
30
|
+
if (await import_fs_extra.default.pathExists(loc.path)) {
|
|
31
|
+
const modules = await import_fs_extra.default.readdir(loc.path);
|
|
32
|
+
for (const moduleName of modules) {
|
|
33
|
+
const modulePath = path.join(loc.path, moduleName);
|
|
34
|
+
if ((await import_fs_extra.default.stat(modulePath)).isDirectory()) {
|
|
35
|
+
const info = await this.getModuleInfo(
|
|
36
|
+
modulePath,
|
|
37
|
+
moduleName,
|
|
38
|
+
loc.type
|
|
39
|
+
);
|
|
40
|
+
allModules.push(info);
|
|
54
41
|
}
|
|
55
|
-
version = pkg.version || modConfig.version || "unknown";
|
|
56
|
-
description = pkg.description || modConfig.description || "";
|
|
57
|
-
validModules.push({ name: moduleName, version, description });
|
|
58
42
|
}
|
|
59
43
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
}
|
|
45
|
+
if (allModules.length === 0) {
|
|
46
|
+
this.info("No modules installed.");
|
|
47
|
+
} else {
|
|
48
|
+
allModules.sort((a, b) => {
|
|
49
|
+
if (a.type !== b.type) return a.type.localeCompare(b.type);
|
|
50
|
+
return a.name.localeCompare(b.name);
|
|
51
|
+
});
|
|
52
|
+
console.table(allModules);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async getModuleInfo(modulePath, dirName, type) {
|
|
56
|
+
let version = "unknown";
|
|
57
|
+
let description = "";
|
|
58
|
+
const pkgJsonPath = path.join(modulePath, "package.json");
|
|
59
|
+
const moduleYamlPath = path.join(modulePath, "module.yaml");
|
|
60
|
+
const moduleYmlPath = path.join(modulePath, "module.yml");
|
|
61
|
+
let pkg = {};
|
|
62
|
+
let modConfig = {};
|
|
63
|
+
if (await import_fs_extra.default.pathExists(pkgJsonPath)) {
|
|
64
|
+
try {
|
|
65
|
+
pkg = await import_fs_extra.default.readJson(pkgJsonPath) || {};
|
|
66
|
+
} catch {
|
|
64
67
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
}
|
|
69
|
+
if (await import_fs_extra.default.pathExists(moduleYamlPath) || await import_fs_extra.default.pathExists(moduleYmlPath)) {
|
|
70
|
+
try {
|
|
71
|
+
const configPath = await import_fs_extra.default.pathExists(moduleYamlPath) ? moduleYamlPath : moduleYmlPath;
|
|
72
|
+
const content = await import_fs_extra.default.readFile(configPath, "utf8");
|
|
73
|
+
modConfig = YAML.parse(content) || {};
|
|
74
|
+
} catch {
|
|
70
75
|
}
|
|
71
76
|
}
|
|
77
|
+
version = pkg.version || modConfig.version || "unknown";
|
|
78
|
+
description = pkg.description || modConfig.description || "";
|
|
79
|
+
const name = modConfig.name || dirName;
|
|
80
|
+
return { name, version, description, type };
|
|
72
81
|
}
|
|
73
82
|
};
|
|
74
83
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/commands/module/list.ts"],"sourcesContent":["import { BaseCommand
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/module/list.ts"],"sourcesContent":["import { BaseCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport YAML from 'yaml';\n\ninterface ModuleInfo {\n name: string;\n version: string;\n description: string;\n type: 'backend' | 'frontend' | 'legacy';\n}\n\nexport default class ModuleListCommand extends BaseCommand {\n static usage = 'module list';\n static description = 'List installed modules.';\n static requiresProject = true;\n\n async run() {\n const projectRoot = this.projectRoot as string;\n\n // Define locations to scan\n const builtInLocations = [\n { type: 'backend', path: path.join(projectRoot, 'apps/backend/modules') },\n { type: 'frontend', path: path.join(projectRoot, 'apps/frontend/modules') },\n // Check legacy `modules` folder just in case?\n { type: 'legacy', path: path.join(projectRoot, 'modules') },\n ];\n\n const allModules: ModuleInfo[] = [];\n\n for (const loc of builtInLocations) {\n if (await fs.pathExists(loc.path)) {\n const modules = await fs.readdir(loc.path);\n\n for (const moduleName of modules) {\n const modulePath = path.join(loc.path, moduleName);\n if ((await fs.stat(modulePath)).isDirectory()) {\n const info = await this.getModuleInfo(\n modulePath,\n moduleName,\n loc.type as 'backend' | 'frontend' | 'legacy',\n );\n allModules.push(info);\n }\n }\n }\n }\n\n if (allModules.length === 0) {\n this.info('No modules installed.');\n } else {\n // Sort by type then name\n allModules.sort((a, b) => {\n if (a.type !== b.type) return a.type.localeCompare(b.type);\n return a.name.localeCompare(b.name);\n });\n // eslint-disable-next-line no-console\n console.table(allModules);\n }\n }\n\n private async getModuleInfo(\n modulePath: string,\n dirName: string,\n type: 'backend' | 'frontend' | 'legacy',\n ): Promise<ModuleInfo> {\n let version = 'unknown';\n let description = '';\n\n const pkgJsonPath = path.join(modulePath, 'package.json');\n const moduleYamlPath = path.join(modulePath, 'module.yaml');\n const moduleYmlPath = path.join(modulePath, 'module.yml');\n\n let pkg: Record<string, unknown> = {};\n let modConfig: Record<string, unknown> = {};\n\n if (await fs.pathExists(pkgJsonPath)) {\n try {\n pkg = (await fs.readJson(pkgJsonPath)) || {};\n } catch {\n /* ignore */\n }\n }\n\n if ((await fs.pathExists(moduleYamlPath)) || (await fs.pathExists(moduleYmlPath))) {\n try {\n const configPath = (await fs.pathExists(moduleYamlPath)) ? moduleYamlPath : moduleYmlPath;\n const content = await fs.readFile(configPath, 'utf8');\n modConfig = YAML.parse(content) || {};\n } catch {\n /* ignore */\n }\n }\n\n version = (pkg.version as string) || (modConfig.version as string) || 'unknown';\n description = (pkg.description as string) || (modConfig.description as string) || '';\n\n // Use config name if available, else dirName\n const name = (modConfig.name as string) || dirName;\n\n return { name, version, description, type };\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,sBAAe;AADf,SAAS,mBAAmB;AAE5B,OAAO,UAAU;AACjB,OAAO,UAAU;AASjB,IAAqB,oBAArB,cAA+C,YAAY;AAAA,EACzD,OAAO,QAAQ;AAAA,EACf,OAAO,cAAc;AAAA,EACrB,OAAO,kBAAkB;AAAA,EAEzB,MAAM,MAAM;AACV,UAAM,cAAc,KAAK;AAGzB,UAAM,mBAAmB;AAAA,MACvB,EAAE,MAAM,WAAW,MAAM,KAAK,KAAK,aAAa,sBAAsB,EAAE;AAAA,MACxE,EAAE,MAAM,YAAY,MAAM,KAAK,KAAK,aAAa,uBAAuB,EAAE;AAAA;AAAA,MAE1E,EAAE,MAAM,UAAU,MAAM,KAAK,KAAK,aAAa,SAAS,EAAE;AAAA,IAC5D;AAEA,UAAM,aAA2B,CAAC;AAElC,eAAW,OAAO,kBAAkB;AAClC,UAAI,MAAM,gBAAAA,QAAG,WAAW,IAAI,IAAI,GAAG;AACjC,cAAM,UAAU,MAAM,gBAAAA,QAAG,QAAQ,IAAI,IAAI;AAEzC,mBAAW,cAAc,SAAS;AAChC,gBAAM,aAAa,KAAK,KAAK,IAAI,MAAM,UAAU;AACjD,eAAK,MAAM,gBAAAA,QAAG,KAAK,UAAU,GAAG,YAAY,GAAG;AAC7C,kBAAM,OAAO,MAAM,KAAK;AAAA,cACtB;AAAA,cACA;AAAA,cACA,IAAI;AAAA,YACN;AACA,uBAAW,KAAK,IAAI;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,WAAW,GAAG;AAC3B,WAAK,KAAK,uBAAuB;AAAA,IACnC,OAAO;AAEL,iBAAW,KAAK,CAAC,GAAG,MAAM;AACxB,YAAI,EAAE,SAAS,EAAE,KAAM,QAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AACzD,eAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,MACpC,CAAC;AAED,cAAQ,MAAM,UAAU;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,YACA,SACA,MACqB;AACrB,QAAI,UAAU;AACd,QAAI,cAAc;AAElB,UAAM,cAAc,KAAK,KAAK,YAAY,cAAc;AACxD,UAAM,iBAAiB,KAAK,KAAK,YAAY,aAAa;AAC1D,UAAM,gBAAgB,KAAK,KAAK,YAAY,YAAY;AAExD,QAAI,MAA+B,CAAC;AACpC,QAAI,YAAqC,CAAC;AAE1C,QAAI,MAAM,gBAAAA,QAAG,WAAW,WAAW,GAAG;AACpC,UAAI;AACF,cAAO,MAAM,gBAAAA,QAAG,SAAS,WAAW,KAAM,CAAC;AAAA,MAC7C,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAK,MAAM,gBAAAA,QAAG,WAAW,cAAc,KAAO,MAAM,gBAAAA,QAAG,WAAW,aAAa,GAAI;AACjF,UAAI;AACF,cAAM,aAAc,MAAM,gBAAAA,QAAG,WAAW,cAAc,IAAK,iBAAiB;AAC5E,cAAM,UAAU,MAAM,gBAAAA,QAAG,SAAS,YAAY,MAAM;AACpD,oBAAY,KAAK,MAAM,OAAO,KAAK,CAAC;AAAA,MACtC,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,cAAW,IAAI,WAAuB,UAAU,WAAsB;AACtE,kBAAe,IAAI,eAA2B,UAAU,eAA0B;AAGlF,UAAM,OAAQ,UAAU,QAAmB;AAE3C,WAAO,EAAE,MAAM,SAAS,aAAa,KAAK;AAAA,EAC5C;AACF;","names":["fs"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
require_lib
|
|
4
|
-
} from "../../../chunk-
|
|
4
|
+
} from "../../../chunk-OUGA4CB4.js";
|
|
5
5
|
import {
|
|
6
6
|
__toESM,
|
|
7
7
|
init_esm_shims
|
|
@@ -23,21 +23,31 @@ var ModuleRemoveCommand = class extends BaseCommand {
|
|
|
23
23
|
async run(options) {
|
|
24
24
|
const projectRoot = this.projectRoot;
|
|
25
25
|
const { name } = options;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
const locations = [
|
|
27
|
+
{ type: "backend", path: `apps/backend/modules/${name}` },
|
|
28
|
+
{ type: "frontend", path: `apps/frontend/modules/${name}` },
|
|
29
|
+
{ type: "legacy", path: `modules/${name}` }
|
|
30
|
+
];
|
|
31
|
+
let targetLoc = null;
|
|
32
|
+
let fullPath = "";
|
|
33
|
+
for (const loc of locations) {
|
|
34
|
+
const absPath = path.resolve(projectRoot, loc.path);
|
|
35
|
+
if (await import_fs_extra.default.pathExists(absPath)) {
|
|
36
|
+
targetLoc = loc;
|
|
37
|
+
fullPath = absPath;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!targetLoc) {
|
|
42
|
+
this.error(`Module ${name} not found in any standard location.`);
|
|
31
43
|
return;
|
|
32
44
|
}
|
|
33
|
-
|
|
45
|
+
const relativePath = targetLoc.path;
|
|
46
|
+
logger.debug("Removing module at:", fullPath);
|
|
47
|
+
this.info(`Removing module ${name} (${targetLoc.type})...`);
|
|
34
48
|
try {
|
|
35
49
|
await runCommand(`git submodule deinit -f ${relativePath}`, projectRoot);
|
|
36
50
|
await runCommand(`git rm -f ${relativePath}`, projectRoot);
|
|
37
|
-
const gitModulesDir = path.resolve(projectRoot, ".git", "modules", "modules", name);
|
|
38
|
-
if (await import_fs_extra.default.pathExists(gitModulesDir)) {
|
|
39
|
-
await import_fs_extra.default.remove(gitModulesDir);
|
|
40
|
-
}
|
|
41
51
|
this.info("Syncing workspace dependencies...");
|
|
42
52
|
await runCommand("npm install", projectRoot);
|
|
43
53
|
await this.removeFromConfig(name);
|
|
@@ -57,8 +67,23 @@ var ModuleRemoveCommand = class extends BaseCommand {
|
|
|
57
67
|
try {
|
|
58
68
|
const content = await import_fs_extra.default.readFile(configPath, "utf8");
|
|
59
69
|
const config = YAML.parse(content) || {};
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
let changed = false;
|
|
71
|
+
if (config.modules) {
|
|
72
|
+
if (!Array.isArray(config.modules)) {
|
|
73
|
+
for (const key of Object.keys(config.modules)) {
|
|
74
|
+
if (Array.isArray(config.modules[key]) && config.modules[key].includes(moduleName)) {
|
|
75
|
+
config.modules[key] = config.modules[key].filter((m) => m !== moduleName);
|
|
76
|
+
changed = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
if (config.modules.includes(moduleName)) {
|
|
81
|
+
config.modules = config.modules.filter((m) => m !== moduleName);
|
|
82
|
+
changed = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (changed) {
|
|
62
87
|
await import_fs_extra.default.writeFile(configPath, YAML.stringify(config));
|
|
63
88
|
logger.debug(`Removed ${moduleName} from nexical.yaml modules list.`);
|
|
64
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/commands/module/remove.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport YAML from 'yaml';\n\nexport default class ModuleRemoveCommand extends BaseCommand {\n static usage = 'module remove <name>';\n static description = 'Remove an installed module.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'name', required: true, description: 'Name of the module to remove' }],\n };\n\n async run(options: { name: string }) {\n const projectRoot = this.projectRoot as string;\n const { name } = options;\n\n const
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/module/remove.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport YAML from 'yaml';\n\nexport default class ModuleRemoveCommand extends BaseCommand {\n static usage = 'module remove <name>';\n static description = 'Remove an installed module.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'name', required: true, description: 'Name of the module to remove' }],\n };\n\n async run(options: { name: string }) {\n const projectRoot = this.projectRoot as string;\n const { name } = options;\n\n // Check locations\n const locations = [\n { type: 'backend', path: `apps/backend/modules/${name}` },\n { type: 'frontend', path: `apps/frontend/modules/${name}` },\n { type: 'legacy', path: `modules/${name}` },\n ];\n\n let targetLoc: { type: string; path: string } | null = null;\n let fullPath = '';\n\n for (const loc of locations) {\n const absPath = path.resolve(projectRoot, loc.path);\n if (await fs.pathExists(absPath)) {\n targetLoc = loc;\n fullPath = absPath;\n break;\n }\n }\n\n if (!targetLoc) {\n this.error(`Module ${name} not found in any standard location.`);\n return;\n }\n\n const relativePath = targetLoc.path;\n\n logger.debug('Removing module at:', fullPath);\n this.info(`Removing module ${name} (${targetLoc.type})...`);\n\n try {\n await runCommand(`git submodule deinit -f ${relativePath}`, projectRoot);\n await runCommand(`git rm -f ${relativePath}`, projectRoot);\n\n // Clean up .git/modules if needed (git rm often handles this but sometimes leaves stale dirs in .git/modules)\n // The path in .git/modules depends on how it was added.\n // Usually .git/modules/apps/backend/modules/name\n // We'll leave strict git cleanup to git, manually removing can be risky if path structure varies.\n // But we can check for the directory itself just in case.\n\n this.info('Syncing workspace dependencies...');\n await runCommand('npm install', projectRoot);\n\n await this.removeFromConfig(name);\n\n this.success(`Module ${name} removed successfully.`);\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to remove module: ${e.message}`);\n } else {\n this.error(`Failed to remove module: ${String(e)}`);\n }\n }\n }\n\n private async removeFromConfig(moduleName: string) {\n const projectRoot = this.projectRoot as string;\n const configPath = path.join(projectRoot, 'nexical.yaml');\n\n if (!(await fs.pathExists(configPath))) return;\n\n try {\n const content = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(content) || {};\n\n let changed = false;\n\n if (config.modules) {\n // Check if object\n if (!Array.isArray(config.modules)) {\n for (const key of Object.keys(config.modules)) {\n if (Array.isArray(config.modules[key]) && config.modules[key].includes(moduleName)) {\n config.modules[key] = config.modules[key].filter((m: string) => m !== moduleName);\n changed = true;\n }\n }\n } else {\n // Legacy array\n if (config.modules.includes(moduleName)) {\n config.modules = config.modules.filter((m: string) => m !== moduleName);\n changed = true;\n }\n }\n }\n\n if (changed) {\n await fs.writeFile(configPath, YAML.stringify(config));\n logger.debug(`Removed ${moduleName} from nexical.yaml modules list.`);\n }\n } catch (e: unknown) {\n if (e instanceof Error) {\n logger.warn(`Failed to update nexical.yaml: ${e.message}`);\n } else {\n logger.warn(`Failed to update nexical.yaml: ${String(e)}`);\n }\n }\n }\n}\n"],"mappings":"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","names":["fs"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
require_lib
|
|
4
|
-
} from "../../../chunk-
|
|
4
|
+
} from "../../../chunk-OUGA4CB4.js";
|
|
5
5
|
import {
|
|
6
6
|
__toESM,
|
|
7
7
|
init_esm_shims
|
|
@@ -26,12 +26,24 @@ var ModuleUpdateCommand = class extends BaseCommand {
|
|
|
26
26
|
logger.debug("Update context:", { name, projectRoot });
|
|
27
27
|
try {
|
|
28
28
|
if (name) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const locations = [
|
|
30
|
+
{ type: "backend", path: `apps/backend/modules/${name}` },
|
|
31
|
+
{ type: "frontend", path: `apps/frontend/modules/${name}` },
|
|
32
|
+
{ type: "legacy", path: `modules/${name}` }
|
|
33
|
+
];
|
|
34
|
+
let targetLoc = null;
|
|
35
|
+
for (const loc of locations) {
|
|
36
|
+
const absPath = path.resolve(projectRoot, loc.path);
|
|
37
|
+
if (await import_fs_extra.default.pathExists(absPath)) {
|
|
38
|
+
targetLoc = loc;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!targetLoc) {
|
|
32
43
|
this.error(`Module ${name} not found.`);
|
|
33
44
|
return;
|
|
34
45
|
}
|
|
46
|
+
const relativePath = targetLoc.path;
|
|
35
47
|
await runCommand(`git submodule update --remote --merge ${relativePath}`, projectRoot);
|
|
36
48
|
} else {
|
|
37
49
|
await runCommand("git submodule update --remote --merge", projectRoot);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/commands/module/update.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport default class ModuleUpdateCommand extends BaseCommand {\n static usage = 'module update [name]';\n static description = 'Update a specific module or all modules.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'name', required: false, description: 'Name of the module to update' }],\n };\n\n async run(options: { name?: string }) {\n const projectRoot = this.projectRoot as string;\n const { name } = options;\n\n this.info(name ? `Updating module ${name}...` : 'Updating all modules...');\n logger.debug('Update context:', { name, projectRoot: projectRoot });\n\n try {\n if (name) {\n const
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/module/update.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport default class ModuleUpdateCommand extends BaseCommand {\n static usage = 'module update [name]';\n static description = 'Update a specific module or all modules.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'name', required: false, description: 'Name of the module to update' }],\n };\n\n async run(options: { name?: string }) {\n const projectRoot = this.projectRoot as string;\n const { name } = options;\n\n this.info(name ? `Updating module ${name}...` : 'Updating all modules...');\n logger.debug('Update context:', { name, projectRoot: projectRoot });\n\n try {\n if (name) {\n // Check locations\n const locations = [\n { type: 'backend', path: `apps/backend/modules/${name}` },\n { type: 'frontend', path: `apps/frontend/modules/${name}` },\n { type: 'legacy', path: `modules/${name}` },\n ];\n\n let targetLoc: { type: string; path: string } | null = null;\n\n for (const loc of locations) {\n const absPath = path.resolve(projectRoot, loc.path);\n if (await fs.pathExists(absPath)) {\n targetLoc = loc;\n break;\n }\n }\n\n if (!targetLoc) {\n this.error(`Module ${name} not found.`);\n return;\n }\n\n const relativePath = targetLoc.path;\n\n // Update specific module\n await runCommand(`git submodule update --remote --merge ${relativePath}`, projectRoot);\n } else {\n // Update all\n await runCommand('git submodule update --remote --merge', projectRoot);\n }\n\n this.info('Syncing workspace dependencies...');\n await runCommand('npm install', projectRoot);\n\n this.success('Modules updated successfully.');\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to update modules: ${e.message}`);\n } else {\n this.error(`Failed to update modules: ${String(e)}`);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,sBAAe;AADf,SAAiC,aAAa,QAAQ,kBAAkB;AAExE,OAAO,UAAU;AAEjB,IAAqB,sBAArB,cAAiD,YAAY;AAAA,EAC3D,OAAO,QAAQ;AAAA,EACf,OAAO,cAAc;AAAA,EACrB,OAAO,kBAAkB;AAAA,EAEzB,OAAO,OAA0B;AAAA,IAC/B,MAAM,CAAC,EAAE,MAAM,QAAQ,UAAU,OAAO,aAAa,+BAA+B,CAAC;AAAA,EACvF;AAAA,EAEA,MAAM,IAAI,SAA4B;AACpC,UAAM,cAAc,KAAK;AACzB,UAAM,EAAE,KAAK,IAAI;AAEjB,SAAK,KAAK,OAAO,mBAAmB,IAAI,QAAQ,yBAAyB;AACzE,WAAO,MAAM,mBAAmB,EAAE,MAAM,YAAyB,CAAC;AAElE,QAAI;AACF,UAAI,MAAM;AAER,cAAM,YAAY;AAAA,UAChB,EAAE,MAAM,WAAW,MAAM,wBAAwB,IAAI,GAAG;AAAA,UACxD,EAAE,MAAM,YAAY,MAAM,yBAAyB,IAAI,GAAG;AAAA,UAC1D,EAAE,MAAM,UAAU,MAAM,WAAW,IAAI,GAAG;AAAA,QAC5C;AAEA,YAAI,YAAmD;AAEvD,mBAAW,OAAO,WAAW;AAC3B,gBAAM,UAAU,KAAK,QAAQ,aAAa,IAAI,IAAI;AAClD,cAAI,MAAM,gBAAAA,QAAG,WAAW,OAAO,GAAG;AAChC,wBAAY;AACZ;AAAA,UACF;AAAA,QACF;AAEA,YAAI,CAAC,WAAW;AACd,eAAK,MAAM,UAAU,IAAI,aAAa;AACtC;AAAA,QACF;AAEA,cAAM,eAAe,UAAU;AAG/B,cAAM,WAAW,yCAAyC,YAAY,IAAI,WAAW;AAAA,MACvF,OAAO;AAEL,cAAM,WAAW,yCAAyC,WAAW;AAAA,MACvE;AAEA,WAAK,KAAK,mCAAmC;AAC7C,YAAM,WAAW,eAAe,WAAW;AAE3C,WAAK,QAAQ,+BAA+B;AAAA,IAC9C,SAAS,GAAY;AACnB,UAAI,aAAa,OAAO;AACtB,aAAK,MAAM,6BAA6B,EAAE,OAAO,EAAE;AAAA,MACrD,OAAO;AACL,aAAK,MAAM,6BAA6B,OAAO,CAAC,CAAC,EAAE;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF;","names":["fs"]}
|
package/dist/src/commands/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "module"; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
require_lib
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-OUGA4CB4.js";
|
|
5
5
|
import {
|
|
6
6
|
__toESM,
|
|
7
7
|
init_esm_shims
|
|
@@ -41,8 +41,25 @@ var RunCommand = class extends BaseCommand {
|
|
|
41
41
|
let scriptName = script;
|
|
42
42
|
if (script.includes(":")) {
|
|
43
43
|
const [moduleName, name] = script.split(":");
|
|
44
|
-
execPath = path.resolve(projectRoot, "modules", moduleName);
|
|
45
44
|
scriptName = name;
|
|
45
|
+
const locations = [
|
|
46
|
+
{ type: "backend", path: `apps/backend/modules/${moduleName}` },
|
|
47
|
+
{ type: "frontend", path: `apps/frontend/modules/${moduleName}` },
|
|
48
|
+
{ type: "legacy", path: `modules/${moduleName}` }
|
|
49
|
+
];
|
|
50
|
+
let found = false;
|
|
51
|
+
for (const loc of locations) {
|
|
52
|
+
const absPath = path.resolve(projectRoot, loc.path);
|
|
53
|
+
if (await import_fs_extra.default.pathExists(absPath)) {
|
|
54
|
+
execPath = absPath;
|
|
55
|
+
found = true;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!found) {
|
|
60
|
+
this.error(`Module ${moduleName} not found.`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
46
63
|
logger.debug(`Resolving module script: ${moduleName}:${scriptName} at ${execPath}`);
|
|
47
64
|
} else {
|
|
48
65
|
logger.debug(`Resolving core script: ${scriptName} at ${execPath}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/run.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { spawn } from 'child_process';\nimport process from 'node:process';\n\nexport default class RunCommand extends BaseCommand {\n static usage = 'run <script> [args...]';\n static description = 'Run a script inside the Nexical environment.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [\n {\n name: 'script',\n required: true,\n description: 'The script to run (script-name OR module:script-name)',\n },\n { name: 'args...', required: false, description: 'Arguments for the script' },\n ],\n };\n\n async run(options: { script: string; args?: string[] }) {\n const projectRoot = this.projectRoot as string;\n const script = options.script;\n const scriptArgs = options.args || [];\n\n if (!script) {\n this.error('Please specify a script to run.');\n return;\n }\n\n logger.debug('Run command context:', { script, args: scriptArgs, projectRoot });\n\n let execPath = projectRoot;\n let scriptName = script;\n\n // Handle module:script syntax\n if (script.includes(':')) {\n const [moduleName, name] = script.split(':');\n
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/run.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { spawn } from 'child_process';\nimport process from 'node:process';\n\nexport default class RunCommand extends BaseCommand {\n static usage = 'run <script> [args...]';\n static description = 'Run a script inside the Nexical environment.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [\n {\n name: 'script',\n required: true,\n description: 'The script to run (script-name OR module:script-name)',\n },\n { name: 'args...', required: false, description: 'Arguments for the script' },\n ],\n };\n\n async run(options: { script: string; args?: string[] }) {\n const projectRoot = this.projectRoot as string;\n const script = options.script;\n const scriptArgs = options.args || [];\n\n if (!script) {\n this.error('Please specify a script to run.');\n return;\n }\n\n logger.debug('Run command context:', { script, args: scriptArgs, projectRoot });\n\n let execPath = projectRoot;\n let scriptName = script;\n\n // Handle module:script syntax\n if (script.includes(':')) {\n const [moduleName, name] = script.split(':');\n scriptName = name;\n\n const locations = [\n { type: 'backend', path: `apps/backend/modules/${moduleName}` },\n { type: 'frontend', path: `apps/frontend/modules/${moduleName}` },\n { type: 'legacy', path: `modules/${moduleName}` },\n ];\n\n let found = false;\n for (const loc of locations) {\n const absPath = path.resolve(projectRoot, loc.path);\n if (await fs.pathExists(absPath)) {\n execPath = absPath;\n found = true;\n break;\n }\n }\n\n if (!found) {\n this.error(`Module ${moduleName} not found.`);\n return;\n }\n\n logger.debug(`Resolving module script: ${moduleName}:${scriptName} at ${execPath}`);\n } else {\n logger.debug(`Resolving core script: ${scriptName} at ${execPath}`);\n }\n\n // Validate script existence\n const pkgJsonPath = path.join(execPath, 'package.json');\n if (!(await fs.pathExists(pkgJsonPath))) {\n this.error(`Failed to find package.json at ${execPath}`);\n return;\n }\n\n try {\n const pkg = await fs.readJson(pkgJsonPath);\n if (!pkg.scripts || !pkg.scripts[scriptName]) {\n const type = script.includes(':') ? `module ${script.split(':')[0]}` : 'Nexical core';\n this.error(`Script \"${scriptName}\" does not exist in ${type}`);\n return;\n }\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to read package.json at ${execPath}: ${e.message}`);\n } else {\n this.error(`Failed to read package.json at ${execPath}: ${String(e)}`);\n }\n return;\n }\n\n const finalArgs = ['run', scriptName, '--', ...scriptArgs];\n logger.debug(`Executing: npm ${finalArgs.join(' ')} in ${execPath}`);\n\n const child = spawn('npm', finalArgs, {\n cwd: execPath,\n stdio: 'inherit',\n env: {\n ...process.env,\n FORCE_COLOR: '1',\n },\n });\n\n // Handle process termination to kill child\n const cleanup = () => {\n child.kill();\n process.exit();\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n await new Promise<void>((resolve) => {\n child.on('close', (code) => {\n // Remove listeners to prevent memory leaks if this command is run multiple times in-process (e.g. tests)\n process.off('SIGINT', cleanup);\n process.off('SIGTERM', cleanup);\n\n if (code !== 0) {\n process.exit(code || 1);\n }\n resolve();\n });\n });\n }\n}\n"],"mappings":"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","names":["fs"]}
|
package/package.json
CHANGED
|
@@ -66,6 +66,7 @@ export default class ModuleAddCommand extends BaseCommand {
|
|
|
66
66
|
`staging-${Date.now()}-${Math.random().toString(36).substring(7)}`,
|
|
67
67
|
);
|
|
68
68
|
let moduleName = '';
|
|
69
|
+
let moduleType: 'backend' | 'frontend' = 'backend'; // Default to backend if uncertain, but we should detect.
|
|
69
70
|
let dependencies: string[] = [];
|
|
70
71
|
|
|
71
72
|
try {
|
|
@@ -74,28 +75,68 @@ export default class ModuleAddCommand extends BaseCommand {
|
|
|
74
75
|
// Shallow clone to inspect
|
|
75
76
|
await clone(cleanUrl, stagingDir, { depth: 1 });
|
|
76
77
|
|
|
77
|
-
//
|
|
78
|
+
// Search path handling
|
|
78
79
|
const searchPath = subPath ? path.join(stagingDir, subPath) : stagingDir;
|
|
80
|
+
|
|
81
|
+
// 1. Detect Module Name & Dependencies
|
|
79
82
|
const moduleYamlPath = path.join(searchPath, 'module.yaml');
|
|
80
83
|
const moduleYmlPath = path.join(searchPath, 'module.yml');
|
|
84
|
+
const pkgJsonPath = path.join(searchPath, 'package.json');
|
|
81
85
|
|
|
82
86
|
let configPath = '';
|
|
83
87
|
if (await fs.pathExists(moduleYamlPath)) configPath = moduleYamlPath;
|
|
84
88
|
else if (await fs.pathExists(moduleYmlPath)) configPath = moduleYmlPath;
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
|
|
90
|
+
// Try to get name from module.yaml/yml
|
|
91
|
+
if (configPath) {
|
|
92
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
93
|
+
const config = YAML.parse(configContent);
|
|
94
|
+
if (config.name) moduleName = config.name;
|
|
95
|
+
dependencies = config.dependencies || [];
|
|
87
96
|
}
|
|
88
97
|
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
// If no name yet, try package.json
|
|
99
|
+
if (!moduleName && (await fs.pathExists(pkgJsonPath))) {
|
|
100
|
+
try {
|
|
101
|
+
const pkg = await fs.readJson(pkgJsonPath);
|
|
102
|
+
if (pkg.name) {
|
|
103
|
+
// Handle scoped packages @modules/name -> name
|
|
104
|
+
moduleName = pkg.name.startsWith('@modules/') ? pkg.name.split('/')[1] : pkg.name;
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
/* ignore */
|
|
108
|
+
}
|
|
109
|
+
}
|
|
91
110
|
|
|
92
|
-
if
|
|
93
|
-
|
|
111
|
+
// Fallback to git repo name if still no name
|
|
112
|
+
if (!moduleName) {
|
|
113
|
+
moduleName = path.basename(cleanUrl, '.git');
|
|
94
114
|
}
|
|
95
|
-
moduleName = config.name;
|
|
96
|
-
dependencies = config.dependencies || [];
|
|
97
115
|
|
|
98
|
-
//
|
|
116
|
+
// 2. Detect Module Type
|
|
117
|
+
// Frontend indicators: ui.yaml, or specifically typed in module.config.mjs (harder to parse statically), or package.json dependencies like 'react'/'astro' (maybe too broad).
|
|
118
|
+
// Backend indicators: models.yaml, api.yaml, access.yaml.
|
|
119
|
+
|
|
120
|
+
const hasUiYaml = await fs.pathExists(path.join(searchPath, 'ui.yaml'));
|
|
121
|
+
const hasModelsYaml = await fs.pathExists(path.join(searchPath, 'models.yaml'));
|
|
122
|
+
const hasApiYaml = await fs.pathExists(path.join(searchPath, 'api.yaml'));
|
|
123
|
+
|
|
124
|
+
if (hasUiYaml) {
|
|
125
|
+
moduleType = 'frontend';
|
|
126
|
+
} else if (hasModelsYaml || hasApiYaml) {
|
|
127
|
+
moduleType = 'backend';
|
|
128
|
+
} else {
|
|
129
|
+
// Fallback: Check checking package.json for "auth-astro" which is common in both, but maybe "react" or "vue" for frontend?
|
|
130
|
+
// Let's assume Backend default if ambiguous for now, or check for specific folder structure?
|
|
131
|
+
// Let's look for `src/components` vs `src/services`.
|
|
132
|
+
if (await fs.pathExists(path.join(searchPath, 'src', 'components'))) {
|
|
133
|
+
moduleType = 'frontend';
|
|
134
|
+
} else {
|
|
135
|
+
moduleType = 'backend';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Normalize dependencies
|
|
99
140
|
if (dependencies && !Array.isArray(dependencies)) {
|
|
100
141
|
dependencies = Object.keys(dependencies);
|
|
101
142
|
}
|
|
@@ -104,39 +145,34 @@ export default class ModuleAddCommand extends BaseCommand {
|
|
|
104
145
|
await fs.remove(stagingDir);
|
|
105
146
|
}
|
|
106
147
|
|
|
107
|
-
// Stage 2: Conflict Detection
|
|
108
|
-
const
|
|
109
|
-
|
|
148
|
+
// Stage 2: Conflict Detection & Path Resolution
|
|
149
|
+
const modulesBaseDir =
|
|
150
|
+
moduleType === 'frontend' ? 'apps/frontend/modules' : 'apps/backend/modules';
|
|
151
|
+
const relativeTargetDir = path.join(modulesBaseDir, moduleName);
|
|
152
|
+
const targetDir = path.join(projectRoot!, relativeTargetDir);
|
|
110
153
|
|
|
111
154
|
if (await fs.pathExists(targetDir)) {
|
|
112
155
|
// Check origin
|
|
113
156
|
const existingRemote = await getRemoteUrl(targetDir);
|
|
114
|
-
// We compare cleanUrl (the repo root).
|
|
115
|
-
// normalize both
|
|
116
157
|
const normExisting = existingRemote.replace(/\.git$/, '');
|
|
117
158
|
const normNew = cleanUrl.replace(/\.git$/, '');
|
|
118
159
|
|
|
119
160
|
if (normExisting !== normNew && existingRemote !== '') {
|
|
120
161
|
throw new Error(
|
|
121
|
-
`Dependency Conflict! Module '${moduleName}' exists but remote '${existingRemote}' does not match '${cleanUrl}'.`,
|
|
162
|
+
`Dependency Conflict! Module '${moduleName}' exists in ${moduleType} but remote '${existingRemote}' does not match '${cleanUrl}'.`,
|
|
122
163
|
);
|
|
123
164
|
}
|
|
124
165
|
|
|
125
|
-
this.info(`Module ${moduleName} already installed.`);
|
|
126
|
-
// Proceed to recurse, but skip add
|
|
166
|
+
this.info(`Module ${moduleName} already installed in ${moduleType}.`);
|
|
127
167
|
} else {
|
|
128
168
|
// Stage 3: Submodule Add
|
|
129
|
-
this.info(`Installing ${moduleName} to ${relativeTargetDir}...`);
|
|
130
|
-
|
|
131
|
-
// IMPORTANT: If subPath exists, "Identity is Internal" means we name the folder `moduleName`.
|
|
132
|
-
// But the CONTENT will be the whole repo.
|
|
133
|
-
// If the user meant to only have the subdir, we can't do that with submodule add easily without manual git plumbing.
|
|
134
|
-
// Given instructions, I will proceed with submodule add of root repo to target dir.
|
|
169
|
+
this.info(`Installing ${moduleName} (${moduleType}) to ${relativeTargetDir}...`);
|
|
170
|
+
await fs.ensureDir(path.dirname(targetDir)); // Ensure apps/backend/modules exists
|
|
135
171
|
await runCommand(`git submodule add ${cleanUrl} ${relativeTargetDir}`, projectRoot!);
|
|
136
172
|
}
|
|
137
173
|
|
|
138
174
|
// Update nexical.yaml
|
|
139
|
-
await this.addToConfig(moduleName);
|
|
175
|
+
await this.addToConfig(moduleName, moduleType);
|
|
140
176
|
|
|
141
177
|
// Stage 4: Recurse
|
|
142
178
|
if (dependencies.length > 0) {
|
|
@@ -147,12 +183,11 @@ export default class ModuleAddCommand extends BaseCommand {
|
|
|
147
183
|
}
|
|
148
184
|
}
|
|
149
185
|
|
|
150
|
-
private async addToConfig(moduleName: string) {
|
|
186
|
+
private async addToConfig(moduleName: string, type: 'backend' | 'frontend') {
|
|
151
187
|
const projectRoot = this.projectRoot as string;
|
|
152
188
|
const configPath = path.join(projectRoot, 'nexical.yaml');
|
|
153
189
|
|
|
154
190
|
if (!(await fs.pathExists(configPath))) {
|
|
155
|
-
// Not strictly required to exist for all operations, but good to have if we are tracking modules.
|
|
156
191
|
logger.warn('nexical.yaml not found, skipping module list update.');
|
|
157
192
|
return;
|
|
158
193
|
}
|
|
@@ -161,12 +196,20 @@ export default class ModuleAddCommand extends BaseCommand {
|
|
|
161
196
|
const content = await fs.readFile(configPath, 'utf8');
|
|
162
197
|
const config = YAML.parse(content) || {};
|
|
163
198
|
|
|
164
|
-
if (!config.modules) config.modules =
|
|
199
|
+
if (!config.modules) config.modules = {};
|
|
200
|
+
|
|
201
|
+
// Migration: If modules is array, convert to object
|
|
202
|
+
if (Array.isArray(config.modules)) {
|
|
203
|
+
const oldModules = config.modules;
|
|
204
|
+
config.modules = { backend: oldModules, frontend: [] }; // Assume old were backend? Or just move them to backend for safety.
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!config.modules[type]) config.modules[type] = [];
|
|
165
208
|
|
|
166
|
-
if (!config.modules.includes(moduleName)) {
|
|
167
|
-
config.modules.push(moduleName);
|
|
209
|
+
if (!config.modules[type].includes(moduleName)) {
|
|
210
|
+
config.modules[type].push(moduleName);
|
|
168
211
|
await fs.writeFile(configPath, YAML.stringify(config));
|
|
169
|
-
logger.debug(`Added ${moduleName} to nexical.yaml modules list.`);
|
|
212
|
+
logger.debug(`Added ${moduleName} to nexical.yaml modules.${type} list.`);
|
|
170
213
|
}
|
|
171
214
|
} catch (e: unknown) {
|
|
172
215
|
if (e instanceof Error) {
|