@nexical/cli 0.11.9 → 0.11.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.
Files changed (36) hide show
  1. package/dist/{chunk-Q7YLW5HJ.js → chunk-GEESHGE4.js} +36 -3
  2. package/dist/chunk-GEESHGE4.js.map +1 -0
  3. package/dist/chunk-GUUPSHWC.js +70 -0
  4. package/dist/chunk-GUUPSHWC.js.map +1 -0
  5. package/dist/index.js +13 -12
  6. package/dist/index.js.map +1 -1
  7. package/dist/src/commands/deploy.d.ts +2 -0
  8. package/dist/src/commands/deploy.js +3 -3
  9. package/dist/src/commands/deploy.js.map +1 -1
  10. package/dist/src/commands/init.js +11 -4
  11. package/dist/src/commands/init.js.map +1 -1
  12. package/dist/src/commands/module/add.js +6 -5
  13. package/dist/src/commands/module/add.js.map +1 -1
  14. package/dist/src/commands/setup.js +4 -61
  15. package/dist/src/commands/setup.js.map +1 -1
  16. package/dist/src/utils/git.d.ts +2 -1
  17. package/dist/src/utils/git.js +3 -1
  18. package/package.json +13 -12
  19. package/src/commands/deploy.ts +3 -3
  20. package/src/commands/init.ts +7 -0
  21. package/src/commands/module/add.ts +2 -2
  22. package/src/commands/setup.ts +6 -13
  23. package/src/utils/git.ts +43 -2
  24. package/test/e2e/lifecycle.e2e.test.ts +5 -4
  25. package/test/integration/commands/init.integration.test.ts +3 -0
  26. package/test/unit/commands/deploy.test.ts +70 -0
  27. package/test/unit/commands/init.test.ts +19 -1
  28. package/test/unit/commands/module/add.test.ts +220 -20
  29. package/test/unit/commands/module/list.test.ts +205 -0
  30. package/test/unit/commands/module/remove.test.ts +30 -0
  31. package/test/unit/commands/run.test.ts +7 -0
  32. package/test/unit/commands/setup.test.ts +43 -1
  33. package/test/unit/deploy/registry.test.ts +41 -0
  34. package/test/unit/utils/git.test.ts +88 -0
  35. package/test/unit/utils/git_utils.test.ts +7 -0
  36. package/dist/chunk-Q7YLW5HJ.js.map +0 -1
@@ -11,8 +11,22 @@ import { promisify } from "util";
11
11
  var execAsync = promisify(exec);
12
12
  async function clone(url, destination, options = {}) {
13
13
  const { recursive = false, depth } = options;
14
- const cmd = `git clone ${recursive ? "--recursive " : ""}${depth ? `--depth ${depth} ` : ""}${url} .`;
15
- logger.debug(`Git clone: ${url} to ${destination}`);
14
+ const args = `${recursive ? "--recursive " : ""}${depth ? `--depth ${depth} ` : ""}${url} .`;
15
+ try {
16
+ const cmd2 = `git -c credential.helper= clone ${args}`;
17
+ logger.debug(`Git clone (anonymous): ${url} to ${destination}`);
18
+ const { stdout } = await execAsync(cmd2, { cwd: destination });
19
+ if (stdout) {
20
+ console.log(stdout);
21
+ }
22
+ return;
23
+ } catch (e) {
24
+ logger.debug(
25
+ `Anonymous clone failed (${e instanceof Error ? e.message : String(e)}), retrying with default credentials...`
26
+ );
27
+ }
28
+ const cmd = `git clone ${args}`;
29
+ logger.debug(`Git clone (authenticated): ${url} to ${destination}`);
16
30
  await runCommand(cmd, destination);
17
31
  }
18
32
  async function getRemoteUrl(cwd, remote = "origin") {
@@ -31,6 +45,24 @@ async function updateSubmodules(cwd) {
31
45
  cwd
32
46
  );
33
47
  }
48
+ async function addSubmodule(url, path, cwd) {
49
+ try {
50
+ const cmd2 = `git -c credential.helper= submodule add ${url} ${path}`;
51
+ logger.debug(`Git submodule add (anonymous): ${url} to ${path}`);
52
+ const { stdout } = await execAsync(cmd2, { cwd });
53
+ if (stdout) {
54
+ console.log(stdout);
55
+ }
56
+ return;
57
+ } catch (e) {
58
+ logger.debug(
59
+ `Anonymous submodule add failed (${e instanceof Error ? e.message : String(e)}), retrying with default credentials...`
60
+ );
61
+ }
62
+ const cmd = `git submodule add ${url} ${path}`;
63
+ logger.debug(`Git submodule add (authenticated): ${url} to ${path}`);
64
+ await runCommand(cmd, cwd);
65
+ }
34
66
  async function checkoutOrphan(branch, cwd) {
35
67
  await runCommand(`git checkout --orphan ${branch}`, cwd);
36
68
  }
@@ -65,6 +97,7 @@ export {
65
97
  clone,
66
98
  getRemoteUrl,
67
99
  updateSubmodules,
100
+ addSubmodule,
68
101
  checkoutOrphan,
69
102
  addAll,
70
103
  commit,
@@ -74,4 +107,4 @@ export {
74
107
  renameRemote,
75
108
  branchExists
76
109
  };
77
- //# sourceMappingURL=chunk-Q7YLW5HJ.js.map
110
+ //# sourceMappingURL=chunk-GEESHGE4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/git.ts"],"sourcesContent":["import { logger, runCommand } from '@nexical/cli-core';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nexport async function clone(\n url: string,\n destination: string,\n options: { recursive?: boolean; depth?: number } = {},\n): Promise<void> {\n const { recursive = false, depth } = options;\n const args = `${recursive ? '--recursive ' : ''}${depth ? `--depth ${depth} ` : ''}${url} .`;\n\n // Attempt 1: Anonymous (no credentials)\n // We use execAsync directly here to handle the error silently if it fails due to auth\n try {\n const cmd = `git -c credential.helper= clone ${args}`;\n logger.debug(`Git clone (anonymous): ${url} to ${destination}`);\n const { stdout } = await execAsync(cmd, { cwd: destination });\n if (stdout) {\n console.log(stdout);\n }\n return;\n } catch (e) {\n logger.debug(\n `Anonymous clone failed (${e instanceof Error ? e.message : String(e)}), retrying with default credentials...`,\n );\n }\n\n // Attempt 2: Default (Authenticated or whatever is configured)\n const cmd = `git clone ${args}`;\n logger.debug(`Git clone (authenticated): ${url} to ${destination}`);\n await runCommand(cmd, destination);\n}\n\nexport async function getRemoteUrl(cwd: string, remote = 'origin'): Promise<string> {\n try {\n const { stdout } = await execAsync(`git remote get-url ${remote}`, { cwd });\n return stdout.trim();\n } catch (e) {\n console.error('getRemoteUrl failed:', e);\n return '';\n }\n}\n\nexport async function updateSubmodules(cwd: string): Promise<void> {\n logger.debug(`Updating submodules in ${cwd}`);\n await runCommand(\n 'git submodule foreach --recursive \"git checkout main && git pull origin main\"',\n cwd,\n );\n}\n\nexport async function addSubmodule(url: string, path: string, cwd: string): Promise<void> {\n // Attempt 1: Anonymous\n try {\n const cmd = `git -c credential.helper= submodule add ${url} ${path}`;\n logger.debug(`Git submodule add (anonymous): ${url} to ${path}`);\n const { stdout } = await execAsync(cmd, { cwd });\n if (stdout) {\n console.log(stdout);\n }\n return;\n } catch (e) {\n logger.debug(\n `Anonymous submodule add failed (${e instanceof Error ? e.message : String(e)}), retrying with default credentials...`,\n );\n }\n\n // Attempt 2: Default\n const cmd = `git submodule add ${url} ${path}`;\n logger.debug(`Git submodule add (authenticated): ${url} to ${path}`);\n await runCommand(cmd, cwd);\n}\n\nexport async function checkoutOrphan(branch: string, cwd: string): Promise<void> {\n await runCommand(`git checkout --orphan ${branch}`, cwd);\n}\n\nexport async function addAll(cwd: string): Promise<void> {\n await runCommand('git add -A', cwd);\n}\n\nexport async function commit(message: string, cwd: string): Promise<void> {\n // Escape quotes in message if needed, for now assuming simple messages\n await runCommand(`git commit -m \"${message}\"`, cwd);\n}\n\nexport async function deleteBranch(branch: string, cwd: string): Promise<void> {\n await runCommand(`git branch -D ${branch}`, cwd);\n}\n\nexport async function renameBranch(branch: string, cwd: string): Promise<void> {\n await runCommand(`git branch -m ${branch}`, cwd);\n}\n\nexport async function removeRemote(remote: string, cwd: string): Promise<void> {\n await runCommand(`git remote remove ${remote}`, cwd);\n}\n\nexport async function renameRemote(oldName: string, newName: string, cwd: string): Promise<void> {\n await runCommand(`git remote rename ${oldName} ${newName}`, cwd);\n}\n\nexport async function branchExists(branch: string, cwd: string): Promise<boolean> {\n try {\n await execAsync(`git show-ref --verify --quiet refs/heads/${branch}`, { cwd });\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["cmd"]}
@@ -0,0 +1,70 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ require_lib
4
+ } from "./chunk-OUGA4CB4.js";
5
+ import {
6
+ __toESM,
7
+ init_esm_shims
8
+ } from "./chunk-OYFWMYPG.js";
9
+
10
+ // src/commands/setup.ts
11
+ init_esm_shims();
12
+ var import_fs_extra = __toESM(require_lib(), 1);
13
+ import { BaseCommand, logger } from "@nexical/cli-core";
14
+ import path from "path";
15
+ var SetupCommand = class extends BaseCommand {
16
+ static description = "Setup the application environment by symlinking core assets.";
17
+ async run() {
18
+ const rootDir = this.projectRoot || process.cwd();
19
+ if (!import_fs_extra.default.existsSync(path.join(rootDir, "core"))) {
20
+ this.error('Could not find "core" directory. Are you in the project root?');
21
+ process.exit(1);
22
+ }
23
+ const apps = ["frontend", "backend"];
24
+ const sharedAssets = ["prisma", "src", "public", "locales", "scripts"];
25
+ for (const app of apps) {
26
+ const appDir = path.join(rootDir, "apps", app);
27
+ if (!import_fs_extra.default.existsSync(appDir)) {
28
+ this.warn(`App directory ${app} not found. Skipping.`);
29
+ continue;
30
+ }
31
+ this.info(`Setting up ${app}...`);
32
+ for (const asset of sharedAssets) {
33
+ const source = path.join(rootDir, "core", asset);
34
+ const dest = path.join(appDir, asset);
35
+ if (!import_fs_extra.default.existsSync(source)) {
36
+ this.warn(`Source asset ${asset} not found in core.`);
37
+ continue;
38
+ }
39
+ try {
40
+ const destDir = path.dirname(dest);
41
+ await import_fs_extra.default.ensureDir(destDir);
42
+ try {
43
+ import_fs_extra.default.lstatSync(dest);
44
+ import_fs_extra.default.removeSync(dest);
45
+ } catch (e) {
46
+ const isEnoent = e && typeof e === "object" && "code" in e && e.code === "ENOENT";
47
+ if (!isEnoent) {
48
+ throw e;
49
+ }
50
+ }
51
+ const relSource = path.relative(destDir, source);
52
+ await import_fs_extra.default.symlink(relSource, dest);
53
+ logger.debug(`Symlinked ${asset} to ${app}`);
54
+ } catch (e) {
55
+ if (e instanceof Error) {
56
+ this.error(`Failed to symlink ${asset} to ${app}: ${e.message}`);
57
+ } else {
58
+ this.error(`Failed to symlink ${asset} to ${app}: ${String(e)}`);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ this.success("Application setup complete.");
64
+ }
65
+ };
66
+
67
+ export {
68
+ SetupCommand
69
+ };
70
+ //# sourceMappingURL=chunk-GUUPSHWC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/setup.ts"],"sourcesContent":["import { BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport default class SetupCommand extends BaseCommand {\n static description = 'Setup the application environment by symlinking core assets.';\n\n async run() {\n // Use projectRoot from BaseCommand if available, fallback to cwd\n const rootDir = this.projectRoot || process.cwd();\n\n // Verify we are in the right place\n if (!fs.existsSync(path.join(rootDir, 'core'))) {\n this.error('Could not find \"core\" directory. Are you in the project root?');\n process.exit(1);\n }\n\n const apps = ['frontend', 'backend'];\n const sharedAssets = ['prisma', 'src', 'public', 'locales', 'scripts']; // tsconfig might be needed if extended\n\n for (const app of apps) {\n const appDir = path.join(rootDir, 'apps', app);\n if (!fs.existsSync(appDir)) {\n this.warn(`App directory ${app} not found. Skipping.`);\n continue;\n }\n\n this.info(`Setting up ${app}...`);\n\n for (const asset of sharedAssets) {\n const source = path.join(rootDir, 'core', asset);\n const dest = path.join(appDir, asset);\n\n if (!fs.existsSync(source)) {\n this.warn(`Source asset ${asset} not found in core.`);\n continue;\n }\n\n try {\n // Remove existing destination if it exists (to ensure clean symlink)\n // Be careful not to delete real files if they aren't symlinks?\n // For now, we assume setup controls these.\n\n const destDir = path.dirname(dest);\n await fs.ensureDir(destDir);\n\n try {\n fs.lstatSync(dest);\n fs.removeSync(dest);\n } catch (e: unknown) {\n const isEnoent =\n e &&\n typeof e === 'object' &&\n 'code' in e &&\n (e as { code: string }).code === 'ENOENT';\n if (!isEnoent) {\n throw e;\n }\n }\n\n const relSource = path.relative(destDir, source);\n await fs.symlink(relSource, dest);\n\n logger.debug(`Symlinked ${asset} to ${app}`);\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to symlink ${asset} to ${app}: ${e.message}`);\n } else {\n this.error(`Failed to symlink ${asset} to ${app}: ${String(e)}`);\n }\n }\n }\n }\n\n this.success('Application setup complete.');\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,sBAAe;AADf,SAAS,aAAa,cAAc;AAEpC,OAAO,UAAU;AAEjB,IAAqB,eAArB,cAA0C,YAAY;AAAA,EACpD,OAAO,cAAc;AAAA,EAErB,MAAM,MAAM;AAEV,UAAM,UAAU,KAAK,eAAe,QAAQ,IAAI;AAGhD,QAAI,CAAC,gBAAAA,QAAG,WAAW,KAAK,KAAK,SAAS,MAAM,CAAC,GAAG;AAC9C,WAAK,MAAM,+DAA+D;AAC1E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,OAAO,CAAC,YAAY,SAAS;AACnC,UAAM,eAAe,CAAC,UAAU,OAAO,UAAU,WAAW,SAAS;AAErE,eAAW,OAAO,MAAM;AACtB,YAAM,SAAS,KAAK,KAAK,SAAS,QAAQ,GAAG;AAC7C,UAAI,CAAC,gBAAAA,QAAG,WAAW,MAAM,GAAG;AAC1B,aAAK,KAAK,iBAAiB,GAAG,uBAAuB;AACrD;AAAA,MACF;AAEA,WAAK,KAAK,cAAc,GAAG,KAAK;AAEhC,iBAAW,SAAS,cAAc;AAChC,cAAM,SAAS,KAAK,KAAK,SAAS,QAAQ,KAAK;AAC/C,cAAM,OAAO,KAAK,KAAK,QAAQ,KAAK;AAEpC,YAAI,CAAC,gBAAAA,QAAG,WAAW,MAAM,GAAG;AAC1B,eAAK,KAAK,gBAAgB,KAAK,qBAAqB;AACpD;AAAA,QACF;AAEA,YAAI;AAKF,gBAAM,UAAU,KAAK,QAAQ,IAAI;AACjC,gBAAM,gBAAAA,QAAG,UAAU,OAAO;AAE1B,cAAI;AACF,4BAAAA,QAAG,UAAU,IAAI;AACjB,4BAAAA,QAAG,WAAW,IAAI;AAAA,UACpB,SAAS,GAAY;AACnB,kBAAM,WACJ,KACA,OAAO,MAAM,YACb,UAAU,KACT,EAAuB,SAAS;AACnC,gBAAI,CAAC,UAAU;AACb,oBAAM;AAAA,YACR;AAAA,UACF;AAEA,gBAAM,YAAY,KAAK,SAAS,SAAS,MAAM;AAC/C,gBAAM,gBAAAA,QAAG,QAAQ,WAAW,IAAI;AAEhC,iBAAO,MAAM,aAAa,KAAK,OAAO,GAAG,EAAE;AAAA,QAC7C,SAAS,GAAY;AACnB,cAAI,aAAa,OAAO;AACtB,iBAAK,MAAM,qBAAqB,KAAK,OAAO,GAAG,KAAK,EAAE,OAAO,EAAE;AAAA,UACjE,OAAO;AACL,iBAAK,MAAM,qBAAqB,KAAK,OAAO,GAAG,KAAK,OAAO,CAAC,CAAC,EAAE;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,6BAA6B;AAAA,EAC5C;AACF;","names":["fs"]}
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { fileURLToPath } from "url";
15
15
  // package.json
16
16
  var package_default = {
17
17
  name: "@nexical/cli",
18
- version: "0.11.9",
18
+ version: "0.11.14",
19
19
  type: "module",
20
20
  bin: {
21
21
  nexical: "./dist/index.js"
@@ -43,34 +43,35 @@ var package_default = {
43
43
  ]
44
44
  },
45
45
  dependencies: {
46
- "@nexical/cli-core": "^0.1.12",
46
+ "@nexical/cli-core": "^0.1.15",
47
47
  dotenv: "^17.3.1",
48
48
  "fast-glob": "^3.3.3",
49
+ glob: "^13.0.5",
49
50
  jiti: "^2.6.1",
50
- yaml: "^2.3.4"
51
+ yaml: "^2.8.2"
51
52
  },
52
53
  devDependencies: {
53
54
  "@eslint/js": "^9.39.2",
54
55
  "@types/fs-extra": "^11.0.4",
55
- "@types/node": "^20.10.0",
56
- "@vitest/coverage-v8": "^4.0.15",
56
+ "@types/node": "^25.3.0",
57
+ "@vitest/coverage-v8": "^4.0.18",
57
58
  eslint: "^9.39.2",
58
59
  "eslint-config-prettier": "^10.1.8",
59
- "eslint-plugin-astro": "^1.5.0",
60
+ "eslint-plugin-astro": "^1.6.0",
60
61
  "eslint-plugin-jsx-a11y": "^6.10.2",
61
62
  "eslint-plugin-react": "^7.37.5",
62
63
  "eslint-plugin-react-hooks": "^7.0.1",
63
64
  execa: "^9.6.1",
64
- "fs-extra": "^11.3.2",
65
- globals: "^17.2.0",
65
+ "fs-extra": "^11.3.3",
66
+ globals: "^17.3.0",
66
67
  husky: "^9.1.7",
67
68
  "lint-staged": "^16.2.7",
68
69
  prettier: "^3.8.1",
69
- tsup: "^8.0.1",
70
+ tsup: "^8.5.1",
70
71
  tsx: "^4.21.0",
71
- typescript: "^5.3.3",
72
- "typescript-eslint": "^8.54.0",
73
- vitest: "^4.0.15"
72
+ typescript: "^5.9.3",
73
+ "typescript-eslint": "^8.56.0",
74
+ vitest: "^4.0.18"
74
75
  }
75
76
  };
76
77
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\nimport { CLI, findProjectRoot } from '@nexical/cli-core';\nimport { fileURLToPath } from 'node:url';\nimport { discoverCommandDirectories } from './src/utils/discovery.js';\nimport pkg from './package.json';\nimport path from 'node:path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst commandName = 'nexical';\nconst projectRoot = (await findProjectRoot(commandName, process.cwd())) || process.cwd();\nconst coreCommandsDir = path.resolve(__dirname, './src/commands');\nconst additionalCommands = discoverCommandDirectories(projectRoot);\n\n// Filter out duplicate core commands and source versions\nconst filteredAdditional = additionalCommands.filter((dir) => {\n const resolvedDir = path.resolve(dir);\n const resolvedCore = path.resolve(coreCommandsDir);\n\n if (resolvedDir === resolvedCore) return false;\n\n // Check if this is another instance of the core CLI commands (by checking path suffix)\n const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');\n const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');\n const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');\n\n if (\n resolvedDir.endsWith(coreSuffix) ||\n resolvedDir.endsWith(coreSuffixSrc) ||\n resolvedDir.endsWith(coreSuffixRawSrc)\n ) {\n return false;\n }\n\n // Handle mismatch between dist/src and src/\n if (resolvedCore.includes(path.join(path.sep, 'dist', 'src', 'commands'))) {\n const srcVersion = resolvedCore.replace(\n path.join(path.sep, 'dist', 'src', 'commands'),\n path.join(path.sep, 'src', 'commands'),\n );\n if (resolvedDir === srcVersion) return false;\n }\n\n return true;\n});\n\nconst app = new CLI({\n version: pkg.version,\n commandName: commandName,\n searchDirectories: [...new Set([coreCommandsDir, ...filteredAdditional])],\n});\napp.start();\n","{\n \"name\": \"@nexical/cli\",\n \"version\": \"0.11.9\",\n \"type\": \"module\",\n \"bin\": {\n \"nexical\": \"./dist/index.js\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"start\": \"node dist/index.js\",\n \"test\": \"npm run test:unit && npm run test:integration && npm run test:e2e\",\n \"test:unit\": \"vitest run --config vitest.config.ts --coverage\",\n \"test:integration\": \"vitest run --config vitest.integration.config.ts\",\n \"test:e2e\": \"npm run build && vitest run --config vitest.e2e.config.ts\",\n \"test:watch\": \"vitest\",\n \"format\": \"prettier --write .\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"prepare\": \"husky\"\n },\n \"lint-staged\": {\n \"**/*\": [\n \"prettier --write --ignore-unknown\"\n ],\n \"**/*.{js,jsx,ts,tsx,astro}\": [\n \"eslint --fix\"\n ]\n },\n \"dependencies\": {\n \"@nexical/cli-core\": \"^0.1.12\",\n \"dotenv\": \"^17.3.1\",\n \"fast-glob\": \"^3.3.3\",\n \"jiti\": \"^2.6.1\",\n \"yaml\": \"^2.3.4\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.2\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/node\": \"^20.10.0\",\n \"@vitest/coverage-v8\": \"^4.0.15\",\n \"eslint\": \"^9.39.2\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-astro\": \"^1.5.0\",\n \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.0.1\",\n \"execa\": \"^9.6.1\",\n \"fs-extra\": \"^11.3.2\",\n \"globals\": \"^17.2.0\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^16.2.7\",\n \"prettier\": \"^3.8.1\",\n \"tsup\": \"^8.0.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.3.3\",\n \"typescript-eslint\": \"^8.54.0\",\n \"vitest\": \"^4.0.15\"\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,SAAS,KAAK,uBAAuB;AACrC,SAAS,qBAAqB;;;ACF9B;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,KAAO;AAAA,IACL,SAAW;AAAA,EACb;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,QAAU;AAAA,IACV,MAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,IACA,8BAA8B;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,uBAAuB;AAAA,IACvB,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,6BAA6B;AAAA,IAC7B,OAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAW;AAAA,IACX,OAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,EACZ;AACF;;;ADtDA,OAAO,UAAU;AAEjB,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,IAAM,cAAc;AACpB,IAAM,cAAe,MAAM,gBAAgB,aAAa,QAAQ,IAAI,CAAC,KAAM,QAAQ,IAAI;AACvF,IAAM,kBAAkB,KAAK,QAAQ,WAAW,gBAAgB;AAChE,IAAM,qBAAqB,2BAA2B,WAAW;AAGjE,IAAM,qBAAqB,mBAAmB,OAAO,CAAC,QAAQ;AAC5D,QAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,MAAI,gBAAgB,aAAc,QAAO;AAGzC,QAAM,aAAa,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AACzE,QAAM,gBAAgB,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AAC5E,QAAM,mBAAmB,KAAK,KAAK,YAAY,OAAO,OAAO,UAAU;AAEvE,MACE,YAAY,SAAS,UAAU,KAC/B,YAAY,SAAS,aAAa,KAClC,YAAY,SAAS,gBAAgB,GACrC;AACA,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,SAAS,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU,CAAC,GAAG;AACzE,UAAM,aAAa,aAAa;AAAA,MAC9B,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU;AAAA,MAC7C,KAAK,KAAK,KAAK,KAAK,OAAO,UAAU;AAAA,IACvC;AACA,QAAI,gBAAgB,WAAY,QAAO;AAAA,EACzC;AAEA,SAAO;AACT,CAAC;AAED,IAAM,MAAM,IAAI,IAAI;AAAA,EAClB,SAAS,gBAAI;AAAA,EACb;AAAA,EACA,mBAAmB,CAAC,GAAG,oBAAI,IAAI,CAAC,iBAAiB,GAAG,kBAAkB,CAAC,CAAC;AAC1E,CAAC;AACD,IAAI,MAAM;","names":[]}
1
+ {"version":3,"sources":["../index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\nimport { CLI, findProjectRoot } from '@nexical/cli-core';\nimport { fileURLToPath } from 'node:url';\nimport { discoverCommandDirectories } from './src/utils/discovery.js';\nimport pkg from './package.json';\nimport path from 'node:path';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nconst commandName = 'nexical';\nconst projectRoot = (await findProjectRoot(commandName, process.cwd())) || process.cwd();\nconst coreCommandsDir = path.resolve(__dirname, './src/commands');\nconst additionalCommands = discoverCommandDirectories(projectRoot);\n\n// Filter out duplicate core commands and source versions\nconst filteredAdditional = additionalCommands.filter((dir) => {\n const resolvedDir = path.resolve(dir);\n const resolvedCore = path.resolve(coreCommandsDir);\n\n if (resolvedDir === resolvedCore) return false;\n\n // Check if this is another instance of the core CLI commands (by checking path suffix)\n const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');\n const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');\n const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');\n\n if (\n resolvedDir.endsWith(coreSuffix) ||\n resolvedDir.endsWith(coreSuffixSrc) ||\n resolvedDir.endsWith(coreSuffixRawSrc)\n ) {\n return false;\n }\n\n // Handle mismatch between dist/src and src/\n if (resolvedCore.includes(path.join(path.sep, 'dist', 'src', 'commands'))) {\n const srcVersion = resolvedCore.replace(\n path.join(path.sep, 'dist', 'src', 'commands'),\n path.join(path.sep, 'src', 'commands'),\n );\n if (resolvedDir === srcVersion) return false;\n }\n\n return true;\n});\n\nconst app = new CLI({\n version: pkg.version,\n commandName: commandName,\n searchDirectories: [...new Set([coreCommandsDir, ...filteredAdditional])],\n});\napp.start();\n","{\n \"name\": \"@nexical/cli\",\n \"version\": \"0.11.14\",\n \"type\": \"module\",\n \"bin\": {\n \"nexical\": \"./dist/index.js\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"start\": \"node dist/index.js\",\n \"test\": \"npm run test:unit && npm run test:integration && npm run test:e2e\",\n \"test:unit\": \"vitest run --config vitest.config.ts --coverage\",\n \"test:integration\": \"vitest run --config vitest.integration.config.ts\",\n \"test:e2e\": \"npm run build && vitest run --config vitest.e2e.config.ts\",\n \"test:watch\": \"vitest\",\n \"format\": \"prettier --write .\",\n \"lint\": \"eslint .\",\n \"lint:fix\": \"eslint . --fix\",\n \"prepare\": \"husky\"\n },\n \"lint-staged\": {\n \"**/*\": [\n \"prettier --write --ignore-unknown\"\n ],\n \"**/*.{js,jsx,ts,tsx,astro}\": [\n \"eslint --fix\"\n ]\n },\n \"dependencies\": {\n \"@nexical/cli-core\": \"^0.1.15\",\n \"dotenv\": \"^17.3.1\",\n \"fast-glob\": \"^3.3.3\",\n \"glob\": \"^13.0.5\",\n \"jiti\": \"^2.6.1\",\n \"yaml\": \"^2.8.2\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.2\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/node\": \"^25.3.0\",\n \"@vitest/coverage-v8\": \"^4.0.18\",\n \"eslint\": \"^9.39.2\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-astro\": \"^1.6.0\",\n \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.0.1\",\n \"execa\": \"^9.6.1\",\n \"fs-extra\": \"^11.3.3\",\n \"globals\": \"^17.3.0\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^16.2.7\",\n \"prettier\": \"^3.8.1\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.56.0\",\n \"vitest\": \"^4.0.18\"\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,SAAS,KAAK,uBAAuB;AACrC,SAAS,qBAAqB;;;ACF9B;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,KAAO;AAAA,IACL,SAAW;AAAA,EACb;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,QAAU;AAAA,IACV,MAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,IACA,8BAA8B;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,MAAQ;AAAA,IACR,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,uBAAuB;AAAA,IACvB,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,6BAA6B;AAAA,IAC7B,OAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAW;AAAA,IACX,OAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,QAAU;AAAA,EACZ;AACF;;;ADvDA,OAAO,UAAU;AAEjB,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,IAAM,cAAc;AACpB,IAAM,cAAe,MAAM,gBAAgB,aAAa,QAAQ,IAAI,CAAC,KAAM,QAAQ,IAAI;AACvF,IAAM,kBAAkB,KAAK,QAAQ,WAAW,gBAAgB;AAChE,IAAM,qBAAqB,2BAA2B,WAAW;AAGjE,IAAM,qBAAqB,mBAAmB,OAAO,CAAC,QAAQ;AAC5D,QAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,MAAI,gBAAgB,aAAc,QAAO;AAGzC,QAAM,aAAa,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AACzE,QAAM,gBAAgB,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AAC5E,QAAM,mBAAmB,KAAK,KAAK,YAAY,OAAO,OAAO,UAAU;AAEvE,MACE,YAAY,SAAS,UAAU,KAC/B,YAAY,SAAS,aAAa,KAClC,YAAY,SAAS,gBAAgB,GACrC;AACA,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,SAAS,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU,CAAC,GAAG;AACzE,UAAM,aAAa,aAAa;AAAA,MAC9B,KAAK,KAAK,KAAK,KAAK,QAAQ,OAAO,UAAU;AAAA,MAC7C,KAAK,KAAK,KAAK,KAAK,OAAO,UAAU;AAAA,IACvC;AACA,QAAI,gBAAgB,WAAY,QAAO;AAAA,EACzC;AAEA,SAAO;AACT,CAAC;AAED,IAAM,MAAM,IAAI,IAAI;AAAA,EAClB,SAAS,gBAAI;AAAA,EACb;AAAA,EACA,mBAAmB,CAAC,GAAG,oBAAI,IAAI,CAAC,iBAAiB,GAAG,kBAAkB,CAAC,CAAC;AAC1E,CAAC;AACD,IAAI,MAAM;","names":[]}
@@ -1,7 +1,9 @@
1
1
  import { BaseCommand } from '@nexical/cli-core';
2
2
 
3
3
  declare class DeployCommand extends BaseCommand {
4
+ static usage: string;
4
5
  static description: string;
6
+ static help: string;
5
7
  static args: {
6
8
  options: ({
7
9
  name: string;
@@ -15,9 +15,9 @@ import path from "path";
15
15
  import dotenv from "dotenv";
16
16
  import { BaseCommand } from "@nexical/cli-core";
17
17
  var DeployCommand = class extends BaseCommand {
18
- static description = `Deploy the application based on nexical.yaml configuration.
19
-
20
- This command orchestrates the deployment of your frontend and backend applications
18
+ static usage = "deploy";
19
+ static description = "Deploy the application based on nexical.yaml configuration.";
20
+ static help = `This command orchestrates the deployment of your frontend and backend applications
21
21
  by interacting with the providers specified in your configuration file.
22
22
 
23
23
  CONFIGURATION:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/deploy.ts"],"sourcesContent":["import path from 'node:path';\nimport dotenv from 'dotenv';\nimport { BaseCommand } from '@nexical/cli-core';\nimport { ConfigManager } from '../deploy/config-manager';\nimport { ProviderRegistry } from '../deploy/registry';\nimport { DeploymentContext } from '../deploy/types';\n\nexport default class DeployCommand extends BaseCommand {\n static description = `Deploy the application based on nexical.yaml configuration.\n\nThis command orchestrates the deployment of your frontend and backend applications \nby interacting with the providers specified in your configuration file.\n\nCONFIGURATION:\n- Requires a 'nexical.yaml' file in the project root.\n- If the file or specific sections are missing, the CLI will prompt you to run an interactive setup \n and save the configuration for future uses.\n- Supports loading environment variables from a .env file in the project root.\n\nPROVIDERS:\n- Backend: Railway, etc.\n- Frontend: Cloudflare Pages, etc.\n- Repository: GitHub, GitLab, etc.\n\nPROCESS:\n1. Loads environment variables from '.env'.\n2. Loads configuration from 'nexical.yaml'.\n3. Provisions resources via the selected providers.\n4. Configures the repository (secrets/variables) for CI/CD.\n5. Generates CI/CD workflow files.`;\n\n static args = {\n options: [\n {\n name: '--backend <provider>',\n description: 'Override backend provider',\n },\n {\n name: '--frontend <provider>',\n description: 'Override frontend provider',\n },\n {\n name: '--repo <provider>',\n description: 'Override repositroy provider',\n },\n {\n name: '--env <environment>',\n description: 'Deployment environment (e.g. production, staging)',\n default: 'production',\n },\n {\n name: '--dry-run',\n description: 'Simulate the deployment process',\n default: false,\n },\n ],\n };\n\n async run(options: Record<string, unknown>) {\n this.info('Starting Nexical Deployment...');\n\n // Load environment variables from .env\n dotenv.config({ path: path.join(process.cwd(), '.env') });\n\n const configManager = new ConfigManager(process.cwd());\n const config = await configManager.load();\n const registry = new ProviderRegistry();\n\n // Register core and local providers\n await registry.loadCoreProviders();\n await registry.loadLocalProviders(process.cwd());\n\n // Resolve providers (CLI flags > Config > Error)\n const backendProviderName =\n (options.backend as string | undefined) || config.deploy?.backend?.provider;\n if (!backendProviderName) {\n this.error(\n \"Backend provider not specified. Use --backend flag or configure 'deploy.backend.provider' in nexical.yaml.\",\n );\n }\n\n const frontendProviderName =\n (options.frontend as string | undefined) || config.deploy?.frontend?.provider;\n if (!frontendProviderName) {\n this.error(\n \"Frontend provider not specified. Use --frontend flag or configure 'deploy.frontend.provider' in nexical.yaml.\",\n );\n }\n\n const repoProviderName =\n (options.repo as string | undefined) || config.deploy?.repository?.provider;\n if (!repoProviderName) {\n this.error(\n \"Repository provider not specified. Use --repo flag or configure 'deploy.repository.provider' in nexical.yaml.\",\n );\n }\n\n const backendProvider = registry.getDeploymentProvider(backendProviderName!);\n const frontendProvider = registry.getDeploymentProvider(frontendProviderName!);\n const repoProvider = registry.getRepositoryProvider(repoProviderName!);\n\n if (!backendProvider) throw new Error(`Backend provider '${backendProviderName}' not found.`);\n if (!frontendProvider)\n throw new Error(`Frontend provider '${frontendProviderName}' not found.`);\n if (!repoProvider) throw new Error(`Repository provider '${repoProviderName}' not found.`);\n\n const context: DeploymentContext = {\n cwd: process.cwd(),\n config,\n options,\n };\n\n // Provision\n this.info(`Provisioning Backend with ${backendProvider.name}...`);\n await backendProvider.provision(context);\n\n this.info(`Provisioning Frontend with ${frontendProvider.name}...`);\n await frontendProvider.provision(context);\n\n // Configure Repo\n this.info(`Configuring Repository with ${repoProvider.name}...`);\n\n const secrets: Record<string, string> = {};\n\n // Collect secrets from Backend Provider\n this.info(`Resolving secrets from ${backendProvider.name}...`);\n try {\n const backendSecrets = await backendProvider.getSecrets(context);\n Object.assign(secrets, backendSecrets);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve secrets for ${backendProvider.name}: ${message}`);\n }\n\n // Collect secrets from Frontend Provider\n this.info(`Resolving secrets from ${frontendProvider.name}...`);\n try {\n const frontendSecrets = await frontendProvider.getSecrets(context);\n Object.assign(secrets, frontendSecrets);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve secrets for ${frontendProvider.name}: ${message}`);\n }\n\n await repoProvider.configureSecrets(context, secrets);\n\n const variables: Record<string, string> = {};\n\n // Collect variables from Backend Provider\n try {\n const backendVars = await backendProvider.getVariables(context);\n Object.assign(variables, backendVars);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve variables for ${backendProvider.name}: ${message}`);\n }\n\n // Collect variables from Frontend Provider\n try {\n const frontendVars = await frontendProvider.getVariables(context);\n Object.assign(variables, frontendVars);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve variables for ${frontendProvider.name}: ${message}`);\n }\n\n await repoProvider.configureVariables(context, variables);\n\n // Generate Workflows\n this.info('Generating CI/CD Workflows...');\n await repoProvider.generateWorkflow(context, [backendProvider, frontendProvider]);\n\n this.success('Deployment configuration complete!');\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/commands/deploy.ts"],"sourcesContent":["import path from 'node:path';\nimport dotenv from 'dotenv';\nimport { BaseCommand } from '@nexical/cli-core';\nimport { ConfigManager } from '../deploy/config-manager';\nimport { ProviderRegistry } from '../deploy/registry';\nimport { DeploymentContext } from '../deploy/types';\n\nexport default class DeployCommand extends BaseCommand {\n static usage = 'deploy';\n static description = 'Deploy the application based on nexical.yaml configuration.';\n static help = `This command orchestrates the deployment of your frontend and backend applications \nby interacting with the providers specified in your configuration file.\n\nCONFIGURATION:\n- Requires a 'nexical.yaml' file in the project root.\n- If the file or specific sections are missing, the CLI will prompt you to run an interactive setup \n and save the configuration for future uses.\n- Supports loading environment variables from a .env file in the project root.\n\nPROVIDERS:\n- Backend: Railway, etc.\n- Frontend: Cloudflare Pages, etc.\n- Repository: GitHub, GitLab, etc.\n\nPROCESS:\n1. Loads environment variables from '.env'.\n2. Loads configuration from 'nexical.yaml'.\n3. Provisions resources via the selected providers.\n4. Configures the repository (secrets/variables) for CI/CD.\n5. Generates CI/CD workflow files.`;\n\n static args = {\n options: [\n {\n name: '--backend <provider>',\n description: 'Override backend provider',\n },\n {\n name: '--frontend <provider>',\n description: 'Override frontend provider',\n },\n {\n name: '--repo <provider>',\n description: 'Override repositroy provider',\n },\n {\n name: '--env <environment>',\n description: 'Deployment environment (e.g. production, staging)',\n default: 'production',\n },\n {\n name: '--dry-run',\n description: 'Simulate the deployment process',\n default: false,\n },\n ],\n };\n\n async run(options: Record<string, unknown>) {\n this.info('Starting Nexical Deployment...');\n\n // Load environment variables from .env\n dotenv.config({ path: path.join(process.cwd(), '.env') });\n\n const configManager = new ConfigManager(process.cwd());\n const config = await configManager.load();\n const registry = new ProviderRegistry();\n\n // Register core and local providers\n await registry.loadCoreProviders();\n await registry.loadLocalProviders(process.cwd());\n\n // Resolve providers (CLI flags > Config > Error)\n const backendProviderName =\n (options.backend as string | undefined) || config.deploy?.backend?.provider;\n if (!backendProviderName) {\n this.error(\n \"Backend provider not specified. Use --backend flag or configure 'deploy.backend.provider' in nexical.yaml.\",\n );\n }\n\n const frontendProviderName =\n (options.frontend as string | undefined) || config.deploy?.frontend?.provider;\n if (!frontendProviderName) {\n this.error(\n \"Frontend provider not specified. Use --frontend flag or configure 'deploy.frontend.provider' in nexical.yaml.\",\n );\n }\n\n const repoProviderName =\n (options.repo as string | undefined) || config.deploy?.repository?.provider;\n if (!repoProviderName) {\n this.error(\n \"Repository provider not specified. Use --repo flag or configure 'deploy.repository.provider' in nexical.yaml.\",\n );\n }\n\n const backendProvider = registry.getDeploymentProvider(backendProviderName!);\n const frontendProvider = registry.getDeploymentProvider(frontendProviderName!);\n const repoProvider = registry.getRepositoryProvider(repoProviderName!);\n\n if (!backendProvider) throw new Error(`Backend provider '${backendProviderName}' not found.`);\n if (!frontendProvider)\n throw new Error(`Frontend provider '${frontendProviderName}' not found.`);\n if (!repoProvider) throw new Error(`Repository provider '${repoProviderName}' not found.`);\n\n const context: DeploymentContext = {\n cwd: process.cwd(),\n config,\n options,\n };\n\n // Provision\n this.info(`Provisioning Backend with ${backendProvider.name}...`);\n await backendProvider.provision(context);\n\n this.info(`Provisioning Frontend with ${frontendProvider.name}...`);\n await frontendProvider.provision(context);\n\n // Configure Repo\n this.info(`Configuring Repository with ${repoProvider.name}...`);\n\n const secrets: Record<string, string> = {};\n\n // Collect secrets from Backend Provider\n this.info(`Resolving secrets from ${backendProvider.name}...`);\n try {\n const backendSecrets = await backendProvider.getSecrets(context);\n Object.assign(secrets, backendSecrets);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve secrets for ${backendProvider.name}: ${message}`);\n }\n\n // Collect secrets from Frontend Provider\n this.info(`Resolving secrets from ${frontendProvider.name}...`);\n try {\n const frontendSecrets = await frontendProvider.getSecrets(context);\n Object.assign(secrets, frontendSecrets);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve secrets for ${frontendProvider.name}: ${message}`);\n }\n\n await repoProvider.configureSecrets(context, secrets);\n\n const variables: Record<string, string> = {};\n\n // Collect variables from Backend Provider\n try {\n const backendVars = await backendProvider.getVariables(context);\n Object.assign(variables, backendVars);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve variables for ${backendProvider.name}: ${message}`);\n }\n\n // Collect variables from Frontend Provider\n try {\n const frontendVars = await frontendProvider.getVariables(context);\n Object.assign(variables, frontendVars);\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n this.error(`Failed to resolve variables for ${frontendProvider.name}: ${message}`);\n }\n\n await repoProvider.configureVariables(context, variables);\n\n // Generate Workflows\n this.info('Generating CI/CD Workflows...');\n await repoProvider.generateWorkflow(context, [backendProvider, frontendProvider]);\n\n this.success('Deployment configuration complete!');\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,17 +1,20 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ SetupCommand
4
+ } from "../../chunk-GUUPSHWC.js";
5
+ import {
6
+ require_lib
7
+ } from "../../chunk-OUGA4CB4.js";
2
8
  import {
3
9
  addAll,
4
10
  clone,
5
11
  commit,
6
12
  renameRemote,
7
13
  updateSubmodules
8
- } from "../../chunk-Q7YLW5HJ.js";
14
+ } from "../../chunk-GEESHGE4.js";
9
15
  import {
10
16
  resolveGitUrl
11
17
  } from "../../chunk-PJIOCW2A.js";
12
- import {
13
- require_lib
14
- } from "../../chunk-OUGA4CB4.js";
15
18
  import {
16
19
  __toESM,
17
20
  init_esm_shims
@@ -62,6 +65,10 @@ var InitCommand = class extends BaseCommand {
62
65
  await runCommand("npm install", targetPath);
63
66
  this.info("Setting up upstream remote...");
64
67
  await renameRemote("origin", "upstream", targetPath);
68
+ this.info("Initializing project assets...");
69
+ const setup = new SetupCommand(this.cli, { ...this.globalOptions, rootDir: targetPath });
70
+ await setup.init();
71
+ await setup.run();
65
72
  this.info("Running project setup...");
66
73
  await runCommand("npm run setup", targetPath);
67
74
  const configPath = path.join(targetPath, "nexical.yaml");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/init.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport * as git from '../utils/git.js';\nimport { resolveGitUrl } from '../utils/url-resolver.js';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport default class InitCommand extends BaseCommand {\n static usage = 'init';\n static description = 'Initialize a new Nexical project.';\n static requiresProject = false;\n\n static args: CommandDefinition = {\n args: [\n { name: 'directory', required: true, description: 'Directory to initialize the project in' },\n ],\n options: [\n {\n name: '--repo <url>',\n description: 'Starter repository URL (supports gh@owner/repo syntax)',\n default: 'gh@nexical/app-starter',\n },\n ],\n };\n\n async run(options: { directory: string; repo: string }) {\n const directory = options.directory;\n const targetPath = path.resolve(process.cwd(), directory);\n const repoUrl = resolveGitUrl(options.repo);\n\n logger.debug('Init options:', { directory, targetPath, repoUrl });\n\n this.info(`Initializing project in: ${targetPath}`);\n this.info(`Using starter repository: ${repoUrl}`);\n\n if (await fs.pathExists(targetPath)) {\n if ((await fs.readdir(targetPath)).length > 0) {\n this.error(`Directory ${directory} is not empty.`);\n process.exit(1);\n }\n } else {\n await fs.mkdir(targetPath, { recursive: true });\n }\n\n try {\n this.info('Cloning starter repository...');\n await git.clone(repoUrl, targetPath, { recursive: true });\n\n this.info('Updating submodules...');\n await git.updateSubmodules(targetPath);\n\n this.info('Installing dependencies...');\n await runCommand('npm install', targetPath);\n\n this.info('Setting up upstream remote...');\n await git.renameRemote('origin', 'upstream', targetPath);\n\n // Run setup script\n this.info('Running project setup...');\n await runCommand('npm run setup', targetPath);\n\n // Check for nexical.yaml, if not present create a default one\n const configPath = path.join(targetPath, 'nexical.yaml');\n if (!(await fs.pathExists(configPath))) {\n this.info('Creating default nexical.yaml...');\n await fs.writeFile(configPath, 'name: ' + path.basename(targetPath) + '\\nmodules: []\\n');\n }\n\n // Create VERSION file\n const versionPath = path.join(targetPath, 'VERSION');\n // Check if version file exists, if not create it\n if (!(await fs.pathExists(versionPath))) {\n this.info('Creating VERSION file with 0.1.0...');\n await fs.writeFile(versionPath, '0.1.0');\n }\n\n await git.addAll(targetPath);\n await git.commit('Initial site commit', targetPath);\n\n this.success(`Project initialized successfully in ${directory}!`);\n } catch (error: unknown) {\n if (error instanceof Error) {\n this.error(`Failed to initialize project: ${error.message}`);\n } else {\n this.error(`Failed to initialize project: ${String(error)}`);\n }\n process.exit(1);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAiC,aAAa,QAAQ,kBAAkB;AAGxE,sBAAe;AACf,OAAO,UAAU;AAEjB,IAAqB,cAArB,cAAyC,YAAY;AAAA,EACnD,OAAO,QAAQ;AAAA,EACf,OAAO,cAAc;AAAA,EACrB,OAAO,kBAAkB;AAAA,EAEzB,OAAO,OAA0B;AAAA,IAC/B,MAAM;AAAA,MACJ,EAAE,MAAM,aAAa,UAAU,MAAM,aAAa,yCAAyC;AAAA,IAC7F;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAA8C;AACtD,UAAM,YAAY,QAAQ;AAC1B,UAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;AACxD,UAAM,UAAU,cAAc,QAAQ,IAAI;AAE1C,WAAO,MAAM,iBAAiB,EAAE,WAAW,YAAY,QAAQ,CAAC;AAEhE,SAAK,KAAK,4BAA4B,UAAU,EAAE;AAClD,SAAK,KAAK,6BAA6B,OAAO,EAAE;AAEhD,QAAI,MAAM,gBAAAA,QAAG,WAAW,UAAU,GAAG;AACnC,WAAK,MAAM,gBAAAA,QAAG,QAAQ,UAAU,GAAG,SAAS,GAAG;AAC7C,aAAK,MAAM,aAAa,SAAS,gBAAgB;AACjD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF,OAAO;AACL,YAAM,gBAAAA,QAAG,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD;AAEA,QAAI;AACF,WAAK,KAAK,+BAA+B;AACzC,YAAU,MAAM,SAAS,YAAY,EAAE,WAAW,KAAK,CAAC;AAExD,WAAK,KAAK,wBAAwB;AAClC,YAAU,iBAAiB,UAAU;AAErC,WAAK,KAAK,4BAA4B;AACtC,YAAM,WAAW,eAAe,UAAU;AAE1C,WAAK,KAAK,+BAA+B;AACzC,YAAU,aAAa,UAAU,YAAY,UAAU;AAGvD,WAAK,KAAK,0BAA0B;AACpC,YAAM,WAAW,iBAAiB,UAAU;AAG5C,YAAM,aAAa,KAAK,KAAK,YAAY,cAAc;AACvD,UAAI,CAAE,MAAM,gBAAAA,QAAG,WAAW,UAAU,GAAI;AACtC,aAAK,KAAK,kCAAkC;AAC5C,cAAM,gBAAAA,QAAG,UAAU,YAAY,WAAW,KAAK,SAAS,UAAU,IAAI,iBAAiB;AAAA,MACzF;AAGA,YAAM,cAAc,KAAK,KAAK,YAAY,SAAS;AAEnD,UAAI,CAAE,MAAM,gBAAAA,QAAG,WAAW,WAAW,GAAI;AACvC,aAAK,KAAK,qCAAqC;AAC/C,cAAM,gBAAAA,QAAG,UAAU,aAAa,OAAO;AAAA,MACzC;AAEA,YAAU,OAAO,UAAU;AAC3B,YAAU,OAAO,uBAAuB,UAAU;AAElD,WAAK,QAAQ,uCAAuC,SAAS,GAAG;AAAA,IAClE,SAAS,OAAgB;AACvB,UAAI,iBAAiB,OAAO;AAC1B,aAAK,MAAM,iCAAiC,MAAM,OAAO,EAAE;AAAA,MAC7D,OAAO;AACL,aAAK,MAAM,iCAAiC,OAAO,KAAK,CAAC,EAAE;AAAA,MAC7D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF;","names":["fs"]}
1
+ {"version":3,"sources":["../../../src/commands/init.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport * as git from '../utils/git.js';\nimport { resolveGitUrl } from '../utils/url-resolver.js';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport SetupCommand from './setup.js';\n\nexport default class InitCommand extends BaseCommand {\n static usage = 'init';\n static description = 'Initialize a new Nexical project.';\n static requiresProject = false;\n\n static args: CommandDefinition = {\n args: [\n { name: 'directory', required: true, description: 'Directory to initialize the project in' },\n ],\n options: [\n {\n name: '--repo <url>',\n description: 'Starter repository URL (supports gh@owner/repo syntax)',\n default: 'gh@nexical/app-starter',\n },\n ],\n };\n\n async run(options: { directory: string; repo: string }) {\n const directory = options.directory;\n const targetPath = path.resolve(process.cwd(), directory);\n const repoUrl = resolveGitUrl(options.repo);\n\n logger.debug('Init options:', { directory, targetPath, repoUrl });\n\n this.info(`Initializing project in: ${targetPath}`);\n this.info(`Using starter repository: ${repoUrl}`);\n\n if (await fs.pathExists(targetPath)) {\n if ((await fs.readdir(targetPath)).length > 0) {\n this.error(`Directory ${directory} is not empty.`);\n process.exit(1);\n }\n } else {\n await fs.mkdir(targetPath, { recursive: true });\n }\n\n try {\n this.info('Cloning starter repository...');\n await git.clone(repoUrl, targetPath, { recursive: true });\n\n this.info('Updating submodules...');\n await git.updateSubmodules(targetPath);\n\n this.info('Installing dependencies...');\n await runCommand('npm install', targetPath);\n\n this.info('Setting up upstream remote...');\n await git.renameRemote('origin', 'upstream', targetPath);\n\n // Run Nexical CLI setup command\n this.info('Initializing project assets...');\n const setup = new SetupCommand(this.cli, { ...this.globalOptions, rootDir: targetPath });\n await setup.init();\n await setup.run();\n\n // Run setup script\n this.info('Running project setup...');\n await runCommand('npm run setup', targetPath);\n\n // Check for nexical.yaml, if not present create a default one\n const configPath = path.join(targetPath, 'nexical.yaml');\n if (!(await fs.pathExists(configPath))) {\n this.info('Creating default nexical.yaml...');\n await fs.writeFile(configPath, 'name: ' + path.basename(targetPath) + '\\nmodules: []\\n');\n }\n\n // Create VERSION file\n const versionPath = path.join(targetPath, 'VERSION');\n // Check if version file exists, if not create it\n if (!(await fs.pathExists(versionPath))) {\n this.info('Creating VERSION file with 0.1.0...');\n await fs.writeFile(versionPath, '0.1.0');\n }\n\n await git.addAll(targetPath);\n await git.commit('Initial site commit', targetPath);\n\n this.success(`Project initialized successfully in ${directory}!`);\n } catch (error: unknown) {\n if (error instanceof Error) {\n this.error(`Failed to initialize project: ${error.message}`);\n } else {\n this.error(`Failed to initialize project: ${String(error)}`);\n }\n process.exit(1);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAiC,aAAa,QAAQ,kBAAkB;AAGxE,sBAAe;AACf,OAAO,UAAU;AAGjB,IAAqB,cAArB,cAAyC,YAAY;AAAA,EACnD,OAAO,QAAQ;AAAA,EACf,OAAO,cAAc;AAAA,EACrB,OAAO,kBAAkB;AAAA,EAEzB,OAAO,OAA0B;AAAA,IAC/B,MAAM;AAAA,MACJ,EAAE,MAAM,aAAa,UAAU,MAAM,aAAa,yCAAyC;AAAA,IAC7F;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAA8C;AACtD,UAAM,YAAY,QAAQ;AAC1B,UAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS;AACxD,UAAM,UAAU,cAAc,QAAQ,IAAI;AAE1C,WAAO,MAAM,iBAAiB,EAAE,WAAW,YAAY,QAAQ,CAAC;AAEhE,SAAK,KAAK,4BAA4B,UAAU,EAAE;AAClD,SAAK,KAAK,6BAA6B,OAAO,EAAE;AAEhD,QAAI,MAAM,gBAAAA,QAAG,WAAW,UAAU,GAAG;AACnC,WAAK,MAAM,gBAAAA,QAAG,QAAQ,UAAU,GAAG,SAAS,GAAG;AAC7C,aAAK,MAAM,aAAa,SAAS,gBAAgB;AACjD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF,OAAO;AACL,YAAM,gBAAAA,QAAG,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD;AAEA,QAAI;AACF,WAAK,KAAK,+BAA+B;AACzC,YAAU,MAAM,SAAS,YAAY,EAAE,WAAW,KAAK,CAAC;AAExD,WAAK,KAAK,wBAAwB;AAClC,YAAU,iBAAiB,UAAU;AAErC,WAAK,KAAK,4BAA4B;AACtC,YAAM,WAAW,eAAe,UAAU;AAE1C,WAAK,KAAK,+BAA+B;AACzC,YAAU,aAAa,UAAU,YAAY,UAAU;AAGvD,WAAK,KAAK,gCAAgC;AAC1C,YAAM,QAAQ,IAAI,aAAa,KAAK,KAAK,EAAE,GAAG,KAAK,eAAe,SAAS,WAAW,CAAC;AACvF,YAAM,MAAM,KAAK;AACjB,YAAM,MAAM,IAAI;AAGhB,WAAK,KAAK,0BAA0B;AACpC,YAAM,WAAW,iBAAiB,UAAU;AAG5C,YAAM,aAAa,KAAK,KAAK,YAAY,cAAc;AACvD,UAAI,CAAE,MAAM,gBAAAA,QAAG,WAAW,UAAU,GAAI;AACtC,aAAK,KAAK,kCAAkC;AAC5C,cAAM,gBAAAA,QAAG,UAAU,YAAY,WAAW,KAAK,SAAS,UAAU,IAAI,iBAAiB;AAAA,MACzF;AAGA,YAAM,cAAc,KAAK,KAAK,YAAY,SAAS;AAEnD,UAAI,CAAE,MAAM,gBAAAA,QAAG,WAAW,WAAW,GAAI;AACvC,aAAK,KAAK,qCAAqC;AAC/C,cAAM,gBAAAA,QAAG,UAAU,aAAa,OAAO;AAAA,MACzC;AAEA,YAAU,OAAO,UAAU;AAC3B,YAAU,OAAO,uBAAuB,UAAU;AAElD,WAAK,QAAQ,uCAAuC,SAAS,GAAG;AAAA,IAClE,SAAS,OAAgB;AACvB,UAAI,iBAAiB,OAAO;AAC1B,aAAK,MAAM,iCAAiC,MAAM,OAAO,EAAE;AAAA,MAC7D,OAAO;AACL,aAAK,MAAM,iCAAiC,OAAO,KAAK,CAAC,EAAE;AAAA,MAC7D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF;","names":["fs"]}
@@ -1,14 +1,15 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
2
  import {
3
+ require_lib
4
+ } from "../../../chunk-OUGA4CB4.js";
5
+ import {
6
+ addSubmodule,
3
7
  clone,
4
8
  getRemoteUrl
5
- } from "../../../chunk-Q7YLW5HJ.js";
9
+ } from "../../../chunk-GEESHGE4.js";
6
10
  import {
7
11
  resolveGitUrl
8
12
  } from "../../../chunk-PJIOCW2A.js";
9
- import {
10
- require_lib
11
- } from "../../../chunk-OUGA4CB4.js";
12
13
  import {
13
14
  __toESM,
14
15
  init_esm_shims
@@ -132,7 +133,7 @@ var ModuleAddCommand = class extends BaseCommand {
132
133
  } else {
133
134
  this.info(`Installing ${moduleName} (${moduleType}) to ${relativeTargetDir}...`);
134
135
  await import_fs_extra.default.ensureDir(path.dirname(targetDir));
135
- await runCommand(`git submodule add ${cleanUrl} ${relativeTargetDir}`, projectRoot);
136
+ await addSubmodule(cleanUrl, relativeTargetDir, projectRoot);
136
137
  }
137
138
  await this.addToConfig(moduleName, moduleType);
138
139
  if (dependencies.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/commands/module/add.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { clone, getRemoteUrl } from '../../utils/git.js';\nimport { resolveGitUrl } from '../../utils/url-resolver.js';\nimport YAML from 'yaml';\n\nexport default class ModuleAddCommand extends BaseCommand {\n static usage = 'module add <url>';\n static description = 'Add a module and its dependencies as git submodules.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'url', required: true, description: 'Git repository URL or gh@org/repo' }],\n };\n\n private visited = new Set<string>();\n\n async run(options: { url: string }) {\n const projectRoot = this.projectRoot as string;\n const { url } = options;\n\n if (!url) {\n this.error('Please specify a repository URL.');\n return;\n }\n\n try {\n await this.installModule(url);\n\n this.info('Syncing workspace dependencies...');\n await runCommand('npm install', projectRoot);\n\n this.success('All modules installed successfully.');\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to add module: ${e.message}`);\n } else {\n this.error(`Failed to add module: ${String(e)}`);\n }\n }\n }\n\n private async installModule(url: string) {\n const projectRoot = this.projectRoot as string;\n\n // Resolve URL using utility\n url = resolveGitUrl(url);\n\n const [repoUrl, subPath] = url.split('.git//');\n const cleanUrl = subPath ? repoUrl + '.git' : url;\n\n if (this.visited.has(cleanUrl)) {\n logger.debug(`Already visited ${cleanUrl}, skipping.`);\n return;\n }\n this.visited.add(cleanUrl);\n\n this.info(`Inspecting ${cleanUrl}...`);\n\n // Stage 1: Inspect (Temp Clone)\n const stagingDir = path.resolve(\n projectRoot!,\n '.nexical',\n 'cache',\n `staging-${Date.now()}-${Math.random().toString(36).substring(7)}`,\n );\n let moduleName = '';\n let moduleType: 'backend' | 'frontend' = 'backend'; // Default to backend if uncertain, but we should detect.\n let dependencies: string[] = [];\n\n try {\n await fs.ensureDir(stagingDir);\n\n // Shallow clone to inspect\n await clone(cleanUrl, stagingDir, { depth: 1 });\n\n // Search path handling\n const searchPath = subPath ? path.join(stagingDir, subPath) : stagingDir;\n\n // 1. Detect Module Name & Dependencies\n const moduleYamlPath = path.join(searchPath, 'module.yaml');\n const moduleYmlPath = path.join(searchPath, 'module.yml');\n const pkgJsonPath = path.join(searchPath, 'package.json');\n\n let configPath = '';\n if (await fs.pathExists(moduleYamlPath)) configPath = moduleYamlPath;\n else if (await fs.pathExists(moduleYmlPath)) configPath = moduleYmlPath;\n\n // Try to get name from module.yaml/yml\n if (configPath) {\n const configContent = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(configContent);\n if (config.name) moduleName = config.name;\n dependencies = config.dependencies || [];\n }\n\n // If no name yet, try package.json\n if (!moduleName && (await fs.pathExists(pkgJsonPath))) {\n try {\n const pkg = await fs.readJson(pkgJsonPath);\n if (pkg.name) {\n // Handle scoped packages @modules/name -> name\n moduleName = pkg.name.startsWith('@modules/') ? pkg.name.split('/')[1] : pkg.name;\n }\n } catch {\n /* ignore */\n }\n }\n\n // Fallback to git repo name if still no name\n if (!moduleName) {\n moduleName = path.basename(cleanUrl, '.git');\n }\n\n // 2. Detect Module Type\n // 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).\n // Backend indicators: models.yaml, api.yaml, access.yaml.\n\n const hasUiYaml = await fs.pathExists(path.join(searchPath, 'ui.yaml'));\n const hasModelsYaml = await fs.pathExists(path.join(searchPath, 'models.yaml'));\n const hasApiYaml = await fs.pathExists(path.join(searchPath, 'api.yaml'));\n\n if (hasUiYaml) {\n moduleType = 'frontend';\n } else if (hasModelsYaml || hasApiYaml) {\n moduleType = 'backend';\n } else {\n // Fallback: Check checking package.json for \"auth-astro\" which is common in both, but maybe \"react\" or \"vue\" for frontend?\n // Let's assume Backend default if ambiguous for now, or check for specific folder structure?\n // Let's look for `src/components` vs `src/services`.\n if (await fs.pathExists(path.join(searchPath, 'src', 'components'))) {\n moduleType = 'frontend';\n } else {\n moduleType = 'backend';\n }\n }\n\n // Normalize dependencies\n if (dependencies && !Array.isArray(dependencies)) {\n dependencies = Object.keys(dependencies);\n }\n } finally {\n // Cleanup staging always\n await fs.remove(stagingDir);\n }\n\n // Stage 2: Conflict Detection & Path Resolution\n const modulesBaseDir =\n moduleType === 'frontend' ? 'apps/frontend/modules' : 'apps/backend/modules';\n const relativeTargetDir = path.join(modulesBaseDir, moduleName);\n const targetDir = path.join(projectRoot!, relativeTargetDir);\n\n if (await fs.pathExists(targetDir)) {\n // Check origin\n const existingRemote = await getRemoteUrl(targetDir);\n const normExisting = existingRemote.replace(/\\.git$/, '');\n const normNew = cleanUrl.replace(/\\.git$/, '');\n\n if (normExisting !== normNew && existingRemote !== '') {\n throw new Error(\n `Dependency Conflict! Module '${moduleName}' exists in ${moduleType} but remote '${existingRemote}' does not match '${cleanUrl}'.`,\n );\n }\n\n this.info(`Module ${moduleName} already installed in ${moduleType}.`);\n } else {\n // Stage 3: Submodule Add\n this.info(`Installing ${moduleName} (${moduleType}) to ${relativeTargetDir}...`);\n await fs.ensureDir(path.dirname(targetDir)); // Ensure apps/backend/modules exists\n await runCommand(`git submodule add ${cleanUrl} ${relativeTargetDir}`, projectRoot!);\n }\n\n // Update nexical.yaml\n await this.addToConfig(moduleName, moduleType);\n\n // Stage 4: Recurse\n if (dependencies.length > 0) {\n this.info(`Resolving ${dependencies.length} dependencies for ${moduleName}...`);\n for (const depUrl of dependencies) {\n await this.installModule(depUrl);\n }\n }\n }\n\n private async addToConfig(moduleName: string, type: 'backend' | 'frontend') {\n const projectRoot = this.projectRoot as string;\n const configPath = path.join(projectRoot, 'nexical.yaml');\n\n if (!(await fs.pathExists(configPath))) {\n logger.warn('nexical.yaml not found, skipping module list update.');\n return;\n }\n\n try {\n const content = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(content) || {};\n\n if (!config.modules) config.modules = {};\n\n // Migration: If modules is array, convert to object\n if (Array.isArray(config.modules)) {\n const oldModules = config.modules;\n config.modules = { backend: oldModules, frontend: [] }; // Assume old were backend? Or just move them to backend for safety.\n }\n\n if (!config.modules[type]) config.modules[type] = [];\n\n if (!config.modules[type].includes(moduleName)) {\n config.modules[type].push(moduleName);\n await fs.writeFile(configPath, YAML.stringify(config));\n logger.debug(`Added ${moduleName} to nexical.yaml modules.${type} 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
+ {"version":3,"sources":["../../../../src/commands/module/add.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger, runCommand } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { clone, getRemoteUrl, addSubmodule } from '../../utils/git.js';\nimport { resolveGitUrl } from '../../utils/url-resolver.js';\nimport YAML from 'yaml';\n\nexport default class ModuleAddCommand extends BaseCommand {\n static usage = 'module add <url>';\n static description = 'Add a module and its dependencies as git submodules.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [{ name: 'url', required: true, description: 'Git repository URL or gh@org/repo' }],\n };\n\n private visited = new Set<string>();\n\n async run(options: { url: string }) {\n const projectRoot = this.projectRoot as string;\n const { url } = options;\n\n if (!url) {\n this.error('Please specify a repository URL.');\n return;\n }\n\n try {\n await this.installModule(url);\n\n this.info('Syncing workspace dependencies...');\n await runCommand('npm install', projectRoot);\n\n this.success('All modules installed successfully.');\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to add module: ${e.message}`);\n } else {\n this.error(`Failed to add module: ${String(e)}`);\n }\n }\n }\n\n private async installModule(url: string) {\n const projectRoot = this.projectRoot as string;\n\n // Resolve URL using utility\n url = resolveGitUrl(url);\n\n const [repoUrl, subPath] = url.split('.git//');\n const cleanUrl = subPath ? repoUrl + '.git' : url;\n\n if (this.visited.has(cleanUrl)) {\n logger.debug(`Already visited ${cleanUrl}, skipping.`);\n return;\n }\n this.visited.add(cleanUrl);\n\n this.info(`Inspecting ${cleanUrl}...`);\n\n // Stage 1: Inspect (Temp Clone)\n const stagingDir = path.resolve(\n projectRoot!,\n '.nexical',\n 'cache',\n `staging-${Date.now()}-${Math.random().toString(36).substring(7)}`,\n );\n let moduleName = '';\n let moduleType: 'backend' | 'frontend' = 'backend'; // Default to backend if uncertain, but we should detect.\n let dependencies: string[] = [];\n\n try {\n await fs.ensureDir(stagingDir);\n\n // Shallow clone to inspect\n await clone(cleanUrl, stagingDir, { depth: 1 });\n\n // Search path handling\n const searchPath = subPath ? path.join(stagingDir, subPath) : stagingDir;\n\n // 1. Detect Module Name & Dependencies\n const moduleYamlPath = path.join(searchPath, 'module.yaml');\n const moduleYmlPath = path.join(searchPath, 'module.yml');\n const pkgJsonPath = path.join(searchPath, 'package.json');\n\n let configPath = '';\n if (await fs.pathExists(moduleYamlPath)) configPath = moduleYamlPath;\n else if (await fs.pathExists(moduleYmlPath)) configPath = moduleYmlPath;\n\n // Try to get name from module.yaml/yml\n if (configPath) {\n const configContent = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(configContent);\n if (config.name) moduleName = config.name;\n dependencies = config.dependencies || [];\n }\n\n // If no name yet, try package.json\n if (!moduleName && (await fs.pathExists(pkgJsonPath))) {\n try {\n const pkg = await fs.readJson(pkgJsonPath);\n if (pkg.name) {\n // Handle scoped packages @modules/name -> name\n moduleName = pkg.name.startsWith('@modules/') ? pkg.name.split('/')[1] : pkg.name;\n }\n } catch {\n /* ignore */\n }\n }\n\n // Fallback to git repo name if still no name\n if (!moduleName) {\n moduleName = path.basename(cleanUrl, '.git');\n }\n\n // 2. Detect Module Type\n // 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).\n // Backend indicators: models.yaml, api.yaml, access.yaml.\n\n const hasUiYaml = await fs.pathExists(path.join(searchPath, 'ui.yaml'));\n const hasModelsYaml = await fs.pathExists(path.join(searchPath, 'models.yaml'));\n const hasApiYaml = await fs.pathExists(path.join(searchPath, 'api.yaml'));\n\n if (hasUiYaml) {\n moduleType = 'frontend';\n } else if (hasModelsYaml || hasApiYaml) {\n moduleType = 'backend';\n } else {\n // Fallback: Check checking package.json for \"auth-astro\" which is common in both, but maybe \"react\" or \"vue\" for frontend?\n // Let's assume Backend default if ambiguous for now, or check for specific folder structure?\n // Let's look for `src/components` vs `src/services`.\n if (await fs.pathExists(path.join(searchPath, 'src', 'components'))) {\n moduleType = 'frontend';\n } else {\n moduleType = 'backend';\n }\n }\n\n // Normalize dependencies\n if (dependencies && !Array.isArray(dependencies)) {\n dependencies = Object.keys(dependencies);\n }\n } finally {\n // Cleanup staging always\n await fs.remove(stagingDir);\n }\n\n // Stage 2: Conflict Detection & Path Resolution\n const modulesBaseDir =\n moduleType === 'frontend' ? 'apps/frontend/modules' : 'apps/backend/modules';\n const relativeTargetDir = path.join(modulesBaseDir, moduleName);\n const targetDir = path.join(projectRoot!, relativeTargetDir);\n\n if (await fs.pathExists(targetDir)) {\n // Check origin\n const existingRemote = await getRemoteUrl(targetDir);\n const normExisting = existingRemote.replace(/\\.git$/, '');\n const normNew = cleanUrl.replace(/\\.git$/, '');\n\n if (normExisting !== normNew && existingRemote !== '') {\n throw new Error(\n `Dependency Conflict! Module '${moduleName}' exists in ${moduleType} but remote '${existingRemote}' does not match '${cleanUrl}'.`,\n );\n }\n\n this.info(`Module ${moduleName} already installed in ${moduleType}.`);\n } else {\n // Stage 3: Submodule Add\n this.info(`Installing ${moduleName} (${moduleType}) to ${relativeTargetDir}...`);\n await fs.ensureDir(path.dirname(targetDir)); // Ensure apps/backend/modules exists\n await addSubmodule(cleanUrl, relativeTargetDir, projectRoot!);\n }\n\n // Update nexical.yaml\n await this.addToConfig(moduleName, moduleType);\n\n // Stage 4: Recurse\n if (dependencies.length > 0) {\n this.info(`Resolving ${dependencies.length} dependencies for ${moduleName}...`);\n for (const depUrl of dependencies) {\n await this.installModule(depUrl);\n }\n }\n }\n\n private async addToConfig(moduleName: string, type: 'backend' | 'frontend') {\n const projectRoot = this.projectRoot as string;\n const configPath = path.join(projectRoot, 'nexical.yaml');\n\n if (!(await fs.pathExists(configPath))) {\n logger.warn('nexical.yaml not found, skipping module list update.');\n return;\n }\n\n try {\n const content = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(content) || {};\n\n if (!config.modules) config.modules = {};\n\n // Migration: If modules is array, convert to object\n if (Array.isArray(config.modules)) {\n const oldModules = config.modules;\n config.modules = { backend: oldModules, frontend: [] }; // Assume old were backend? Or just move them to backend for safety.\n }\n\n if (!config.modules[type]) config.modules[type] = [];\n\n if (!config.modules[type].includes(moduleName)) {\n config.modules[type].push(moduleName);\n await fs.writeFile(configPath, YAML.stringify(config));\n logger.debug(`Added ${moduleName} to nexical.yaml modules.${type} 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,66 +1,9 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
2
  import {
3
- require_lib
4
- } from "../../chunk-OUGA4CB4.js";
5
- import {
6
- __toESM,
7
- init_esm_shims
8
- } from "../../chunk-OYFWMYPG.js";
9
-
10
- // src/commands/setup.ts
11
- init_esm_shims();
12
- var import_fs_extra = __toESM(require_lib(), 1);
13
- import { BaseCommand, logger } from "@nexical/cli-core";
14
- import path from "path";
15
- var SetupCommand = class extends BaseCommand {
16
- static description = "Setup the application environment by symlinking core assets.";
17
- async run() {
18
- const rootDir = process.cwd();
19
- if (!import_fs_extra.default.existsSync(path.join(rootDir, "core"))) {
20
- this.error('Could not find "core" directory. Are you in the project root?');
21
- process.exit(1);
22
- }
23
- const apps = ["frontend", "backend"];
24
- const sharedAssets = ["prisma", "src", "public", "locales", "scripts"];
25
- for (const app of apps) {
26
- const appDir = path.join(rootDir, "apps", app);
27
- if (!import_fs_extra.default.existsSync(appDir)) {
28
- this.warn(`App directory ${app} not found. Skipping.`);
29
- continue;
30
- }
31
- this.info(`Setting up ${app}...`);
32
- for (const asset of sharedAssets) {
33
- const source = path.join(rootDir, "core", asset);
34
- const dest = path.join(appDir, asset);
35
- if (!import_fs_extra.default.existsSync(source)) {
36
- this.warn(`Source asset ${asset} not found in core.`);
37
- continue;
38
- }
39
- try {
40
- const destDir = path.dirname(dest);
41
- await import_fs_extra.default.ensureDir(destDir);
42
- try {
43
- import_fs_extra.default.lstatSync(dest);
44
- import_fs_extra.default.removeSync(dest);
45
- } catch (e) {
46
- if (e && typeof e === "object" && "code" in e && e.code !== "ENOENT")
47
- throw e;
48
- }
49
- const relSource = path.relative(destDir, source);
50
- await import_fs_extra.default.symlink(relSource, dest);
51
- logger.debug(`Symlinked ${asset} to ${app}`);
52
- } catch (e) {
53
- if (e instanceof Error) {
54
- this.error(`Failed to symlink ${asset} to ${app}: ${e.message}`);
55
- } else {
56
- this.error(`Failed to symlink ${asset} to ${app}: ${String(e)}`);
57
- }
58
- }
59
- }
60
- }
61
- this.success("Application setup complete.");
62
- }
63
- };
3
+ SetupCommand
4
+ } from "../../chunk-GUUPSHWC.js";
5
+ import "../../chunk-OUGA4CB4.js";
6
+ import "../../chunk-OYFWMYPG.js";
64
7
  export {
65
8
  SetupCommand as default
66
9
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/setup.ts"],"sourcesContent":["import { BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport default class SetupCommand extends BaseCommand {\n static description = 'Setup the application environment by symlinking core assets.';\n\n async run() {\n // We assume we are in the project root\n // But the CLI might be run from anywhere?\n // findProjectRoot in index.ts handles finding the root.\n // BaseCommand has this.projectRoot?\n\n // BaseCommand doesn't expose projectRoot directly in current implementation seen in memory, checking source if possible?\n // InitCommand used process.cwd().\n\n // Let's assume process.cwd() is project root if run via `npm run setup` from root.\n const rootDir = process.cwd();\n\n // Verify we are in the right place\n if (!fs.existsSync(path.join(rootDir, 'core'))) {\n this.error('Could not find \"core\" directory. Are you in the project root?');\n process.exit(1);\n }\n\n const apps = ['frontend', 'backend'];\n const sharedAssets = ['prisma', 'src', 'public', 'locales', 'scripts']; // tsconfig might be needed if extended\n\n for (const app of apps) {\n const appDir = path.join(rootDir, 'apps', app);\n if (!fs.existsSync(appDir)) {\n this.warn(`App directory ${app} not found. Skipping.`);\n continue;\n }\n\n this.info(`Setting up ${app}...`);\n\n for (const asset of sharedAssets) {\n const source = path.join(rootDir, 'core', asset);\n const dest = path.join(appDir, asset);\n\n if (!fs.existsSync(source)) {\n this.warn(`Source asset ${asset} not found in core.`);\n continue;\n }\n\n try {\n // Remove existing destination if it exists (to ensure clean symlink)\n // Be careful not to delete real files if they aren't symlinks?\n // For now, we assume setup controls these.\n\n const destDir = path.dirname(dest);\n await fs.ensureDir(destDir);\n\n try {\n fs.lstatSync(dest);\n fs.removeSync(dest);\n } catch (e: unknown) {\n if (\n e &&\n typeof e === 'object' &&\n 'code' in e &&\n (e as { code: string }).code !== 'ENOENT'\n )\n throw e;\n }\n\n const relSource = path.relative(destDir, source);\n await fs.symlink(relSource, dest);\n\n logger.debug(`Symlinked ${asset} to ${app}`);\n } catch (e: unknown) {\n if (e instanceof Error) {\n this.error(`Failed to symlink ${asset} to ${app}: ${e.message}`);\n } else {\n this.error(`Failed to symlink ${asset} to ${app}: ${String(e)}`);\n }\n }\n }\n }\n\n this.success('Application setup complete.');\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,sBAAe;AADf,SAAS,aAAa,cAAc;AAEpC,OAAO,UAAU;AAEjB,IAAqB,eAArB,cAA0C,YAAY;AAAA,EACpD,OAAO,cAAc;AAAA,EAErB,MAAM,MAAM;AAUV,UAAM,UAAU,QAAQ,IAAI;AAG5B,QAAI,CAAC,gBAAAA,QAAG,WAAW,KAAK,KAAK,SAAS,MAAM,CAAC,GAAG;AAC9C,WAAK,MAAM,+DAA+D;AAC1E,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,OAAO,CAAC,YAAY,SAAS;AACnC,UAAM,eAAe,CAAC,UAAU,OAAO,UAAU,WAAW,SAAS;AAErE,eAAW,OAAO,MAAM;AACtB,YAAM,SAAS,KAAK,KAAK,SAAS,QAAQ,GAAG;AAC7C,UAAI,CAAC,gBAAAA,QAAG,WAAW,MAAM,GAAG;AAC1B,aAAK,KAAK,iBAAiB,GAAG,uBAAuB;AACrD;AAAA,MACF;AAEA,WAAK,KAAK,cAAc,GAAG,KAAK;AAEhC,iBAAW,SAAS,cAAc;AAChC,cAAM,SAAS,KAAK,KAAK,SAAS,QAAQ,KAAK;AAC/C,cAAM,OAAO,KAAK,KAAK,QAAQ,KAAK;AAEpC,YAAI,CAAC,gBAAAA,QAAG,WAAW,MAAM,GAAG;AAC1B,eAAK,KAAK,gBAAgB,KAAK,qBAAqB;AACpD;AAAA,QACF;AAEA,YAAI;AAKF,gBAAM,UAAU,KAAK,QAAQ,IAAI;AACjC,gBAAM,gBAAAA,QAAG,UAAU,OAAO;AAE1B,cAAI;AACF,4BAAAA,QAAG,UAAU,IAAI;AACjB,4BAAAA,QAAG,WAAW,IAAI;AAAA,UACpB,SAAS,GAAY;AACnB,gBACE,KACA,OAAO,MAAM,YACb,UAAU,KACT,EAAuB,SAAS;AAEjC,oBAAM;AAAA,UACV;AAEA,gBAAM,YAAY,KAAK,SAAS,SAAS,MAAM;AAC/C,gBAAM,gBAAAA,QAAG,QAAQ,WAAW,IAAI;AAEhC,iBAAO,MAAM,aAAa,KAAK,OAAO,GAAG,EAAE;AAAA,QAC7C,SAAS,GAAY;AACnB,cAAI,aAAa,OAAO;AACtB,iBAAK,MAAM,qBAAqB,KAAK,OAAO,GAAG,KAAK,EAAE,OAAO,EAAE;AAAA,UACjE,OAAO;AACL,iBAAK,MAAM,qBAAqB,KAAK,OAAO,GAAG,KAAK,OAAO,CAAC,CAAC,EAAE;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,6BAA6B;AAAA,EAC5C;AACF;","names":["fs"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -4,6 +4,7 @@ declare function clone(url: string, destination: string, options?: {
4
4
  }): Promise<void>;
5
5
  declare function getRemoteUrl(cwd: string, remote?: string): Promise<string>;
6
6
  declare function updateSubmodules(cwd: string): Promise<void>;
7
+ declare function addSubmodule(url: string, path: string, cwd: string): Promise<void>;
7
8
  declare function checkoutOrphan(branch: string, cwd: string): Promise<void>;
8
9
  declare function addAll(cwd: string): Promise<void>;
9
10
  declare function commit(message: string, cwd: string): Promise<void>;
@@ -13,4 +14,4 @@ declare function removeRemote(remote: string, cwd: string): Promise<void>;
13
14
  declare function renameRemote(oldName: string, newName: string, cwd: string): Promise<void>;
14
15
  declare function branchExists(branch: string, cwd: string): Promise<boolean>;
15
16
 
16
- export { addAll, branchExists, checkoutOrphan, clone, commit, deleteBranch, getRemoteUrl, removeRemote, renameBranch, renameRemote, updateSubmodules };
17
+ export { addAll, addSubmodule, branchExists, checkoutOrphan, clone, commit, deleteBranch, getRemoteUrl, removeRemote, renameBranch, renameRemote, updateSubmodules };
@@ -1,6 +1,7 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  addAll,
4
+ addSubmodule,
4
5
  branchExists,
5
6
  checkoutOrphan,
6
7
  clone,
@@ -11,10 +12,11 @@ import {
11
12
  renameBranch,
12
13
  renameRemote,
13
14
  updateSubmodules
14
- } from "../../chunk-Q7YLW5HJ.js";
15
+ } from "../../chunk-GEESHGE4.js";
15
16
  import "../../chunk-OYFWMYPG.js";
16
17
  export {
17
18
  addAll,
19
+ addSubmodule,
18
20
  branchExists,
19
21
  checkoutOrphan,
20
22
  clone,