@nexical/cli 0.11.18 → 0.11.19

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.
@@ -0,0 +1,38 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-OYFWMYPG.js";
5
+
6
+ // src/utils/filter.ts
7
+ init_esm_shims();
8
+ import path from "path";
9
+ function filterCommandDirectories(additionalCommands, coreCommandsDir) {
10
+ return additionalCommands.filter((dir) => {
11
+ const resolvedDir = path.resolve(dir);
12
+ const resolvedCore = path.resolve(coreCommandsDir);
13
+ if (resolvedDir === resolvedCore) return false;
14
+ const coreSuffix = path.join("@nexical", "cli", "dist", "src", "commands");
15
+ const coreSuffixSrc = path.join("packages", "cli", "dist", "src", "commands");
16
+ const coreSuffixRawSrc = path.join("packages", "cli", "src", "commands");
17
+ if (resolvedDir.endsWith(coreSuffix) || resolvedDir.endsWith(coreSuffixSrc) || resolvedDir.endsWith(coreSuffixRawSrc)) {
18
+ return false;
19
+ }
20
+ const distSuffix = path.join("dist", "src", "commands");
21
+ const srcSuffix = path.join("src", "commands");
22
+ if (resolvedCore.endsWith(distSuffix)) {
23
+ const baseDir = resolvedCore.substring(0, resolvedCore.length - distSuffix.length);
24
+ const srcVersion = path.join(baseDir, srcSuffix);
25
+ const normalizedDir = path.normalize(resolvedDir);
26
+ const normalizedSrc = path.normalize(srcVersion);
27
+ if (normalizedDir === normalizedSrc) {
28
+ return false;
29
+ }
30
+ }
31
+ return true;
32
+ });
33
+ }
34
+
35
+ export {
36
+ filterCommandDirectories
37
+ };
38
+ //# sourceMappingURL=chunk-54HY52LH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/filter.ts"],"sourcesContent":["import path from 'node:path';\n\n/**\n * Filters out duplicate core commands and source versions from additional command directories.\n * @param additionalCommands List of discovered command directories.\n * @param coreCommandsDir The primary core commands directory.\n * @returns Filtered list of additional command directories.\n */\nexport function filterCommandDirectories(\n additionalCommands: string[],\n coreCommandsDir: string,\n): string[] {\n return 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 const distSuffix = path.join('dist', 'src', 'commands');\n const srcSuffix = path.join('src', 'commands');\n if (resolvedCore.endsWith(distSuffix)) {\n const baseDir = resolvedCore.substring(0, resolvedCore.length - distSuffix.length);\n const srcVersion = path.join(baseDir, srcSuffix);\n const normalizedDir = path.normalize(resolvedDir);\n const normalizedSrc = path.normalize(srcVersion);\n if (normalizedDir === normalizedSrc) {\n return false;\n }\n }\n\n return true;\n });\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,UAAU;AAQV,SAAS,yBACd,oBACA,iBACU;AACV,SAAO,mBAAmB,OAAO,CAAC,QAAQ;AACxC,UAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,UAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,QAAI,gBAAgB,aAAc,QAAO;AAGzC,UAAM,aAAa,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AACzE,UAAM,gBAAgB,KAAK,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU;AAC5E,UAAM,mBAAmB,KAAK,KAAK,YAAY,OAAO,OAAO,UAAU;AAEvE,QACE,YAAY,SAAS,UAAU,KAC/B,YAAY,SAAS,aAAa,KAClC,YAAY,SAAS,gBAAgB,GACrC;AACA,aAAO;AAAA,IACT;AAGA,UAAM,aAAa,KAAK,KAAK,QAAQ,OAAO,UAAU;AACtD,UAAM,YAAY,KAAK,KAAK,OAAO,UAAU;AAC7C,QAAI,aAAa,SAAS,UAAU,GAAG;AACrC,YAAM,UAAU,aAAa,UAAU,GAAG,aAAa,SAAS,WAAW,MAAM;AACjF,YAAM,aAAa,KAAK,KAAK,SAAS,SAAS;AAC/C,YAAM,gBAAgB,KAAK,UAAU,WAAW;AAChD,YAAM,gBAAgB,KAAK,UAAU,UAAU;AAC/C,UAAI,kBAAkB,eAAe;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AACH;","names":[]}
package/dist/index.js CHANGED
@@ -3,6 +3,9 @@ import { createRequire } from "module"; const require = createRequire(import.met
3
3
  import {
4
4
  discoverCommandDirectories
5
5
  } from "./chunk-AC4B3HPJ.js";
6
+ import {
7
+ filterCommandDirectories
8
+ } from "./chunk-54HY52LH.js";
6
9
  import {
7
10
  init_esm_shims
8
11
  } from "./chunk-OYFWMYPG.js";
@@ -15,7 +18,7 @@ import { fileURLToPath } from "url";
15
18
  // package.json
16
19
  var package_default = {
17
20
  name: "@nexical/cli",
18
- version: "0.11.18",
21
+ version: "0.11.19",
19
22
  license: "Apache-2.0",
20
23
  type: "module",
21
24
  bin: {
@@ -87,25 +90,7 @@ var commandName = "nexical";
87
90
  var projectRoot = await findProjectRoot(commandName, process.cwd()) || process.cwd();
88
91
  var coreCommandsDir = path.resolve(__dirname, "./src/commands");
89
92
  var additionalCommands = discoverCommandDirectories(projectRoot);
90
- var filteredAdditional = additionalCommands.filter((dir) => {
91
- const resolvedDir = path.resolve(dir);
92
- const resolvedCore = path.resolve(coreCommandsDir);
93
- if (resolvedDir === resolvedCore) return false;
94
- const coreSuffix = path.join("@nexical", "cli", "dist", "src", "commands");
95
- const coreSuffixSrc = path.join("packages", "cli", "dist", "src", "commands");
96
- const coreSuffixRawSrc = path.join("packages", "cli", "src", "commands");
97
- if (resolvedDir.endsWith(coreSuffix) || resolvedDir.endsWith(coreSuffixSrc) || resolvedDir.endsWith(coreSuffixRawSrc)) {
98
- return false;
99
- }
100
- if (resolvedCore.includes(path.join(path.sep, "dist", "src", "commands"))) {
101
- const srcVersion = resolvedCore.replace(
102
- path.join(path.sep, "dist", "src", "commands"),
103
- path.join(path.sep, "src", "commands")
104
- );
105
- if (resolvedDir === srcVersion) return false;
106
- }
107
- return true;
108
- });
93
+ var filteredAdditional = filterCommandDirectories(additionalCommands, coreCommandsDir);
109
94
  var app = new CLI({
110
95
  version: package_default.version,
111
96
  commandName,
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.18\",\n \"license\": \"Apache-2.0\",\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/ai\": \"^0.1.5\",\n \"@nexical/cli-core\": \"^0.1.16\",\n \"dotenv\": \"^17.3.1\",\n \"fast-glob\": \"^3.3.3\",\n \"glob\": \"^13.0.5\",\n \"jiti\": \"^2.6.1\",\n \"minimist\": \"^1.2.8\",\n \"yaml\": \"^2.8.2\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.2\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/minimist\": \"^1.2.5\",\n \"@types/node\": \"^25.3.0\",\n \"@types/nunjucks\": \"^3.2.6\",\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":"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","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';\nimport { filterCommandDirectories } from './src/utils/filter.js';\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\nconst filteredAdditional = filterCommandDirectories(additionalCommands, coreCommandsDir);\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.19\",\n \"license\": \"Apache-2.0\",\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/ai\": \"^0.1.5\",\n \"@nexical/cli-core\": \"^0.1.16\",\n \"dotenv\": \"^17.3.1\",\n \"fast-glob\": \"^3.3.3\",\n \"glob\": \"^13.0.5\",\n \"jiti\": \"^2.6.1\",\n \"minimist\": \"^1.2.8\",\n \"yaml\": \"^2.8.2\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.39.2\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/minimist\": \"^1.2.5\",\n \"@types/node\": \"^25.3.0\",\n \"@types/nunjucks\": \"^3.2.6\",\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,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,eAAe;AAAA,IACf,qBAAqB;AAAA,IACrB,QAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,MAAQ;AAAA,IACR,UAAY;AAAA,IACZ,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,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;;;AD5DA,OAAO,UAAU;AAGjB,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;AAEjE,IAAM,qBAAqB,yBAAyB,oBAAoB,eAAe;AAEvF,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,4 +1,11 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ addAll,
4
+ clone,
5
+ commit,
6
+ renameRemote,
7
+ updateSubmodules
8
+ } from "../../chunk-GEESHGE4.js";
2
9
  import {
3
10
  resolveGitUrl
4
11
  } from "../../chunk-PJIOCW2A.js";
@@ -8,13 +15,6 @@ import {
8
15
  import {
9
16
  require_lib
10
17
  } from "../../chunk-OUGA4CB4.js";
11
- import {
12
- addAll,
13
- clone,
14
- commit,
15
- renameRemote,
16
- updateSubmodules
17
- } from "../../chunk-GEESHGE4.js";
18
18
  import {
19
19
  __toESM,
20
20
  init_esm_shims
@@ -1,15 +1,15 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ addSubmodule,
4
+ clone,
5
+ getRemoteUrl
6
+ } from "../../../chunk-GEESHGE4.js";
2
7
  import {
3
8
  resolveGitUrl
4
9
  } from "../../../chunk-PJIOCW2A.js";
5
10
  import {
6
11
  require_lib
7
12
  } from "../../../chunk-OUGA4CB4.js";
8
- import {
9
- addSubmodule,
10
- clone,
11
- getRemoteUrl
12
- } from "../../../chunk-GEESHGE4.js";
13
13
  import {
14
14
  __toESM,
15
15
  init_esm_shims
@@ -49,7 +49,7 @@ var PromptCommand = class extends BaseCommand {
49
49
  const projectRoot = this.projectRoot;
50
50
  const promptName = options.promptName;
51
51
  const argv = minimist(options.args || []);
52
- const isInteractive = options.interactive || options.i || argv.interactive || argv.i;
52
+ const isInteractive = !!(options.interactive || options.i || argv.interactive || argv.i);
53
53
  const moduleName = options.module || options.m || argv.module || argv.m;
54
54
  const modelsArg = options.models || argv.models || "gemini-3-flash-preview,gemini-3-pro-preview";
55
55
  const models = modelsArg.split(",").map((m) => m.trim()).filter(Boolean);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/prompt.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport minimist from 'minimist';\nimport YAML from 'yaml';\nimport { PromptRunner } from '@nexical/ai';\n\nexport default class PromptCommand extends BaseCommand {\n static usage = 'prompt <prompt-name> [args...]';\n static description = 'Run an AI prompt using templates from the prompts directory.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [\n {\n name: 'promptName',\n required: true,\n description: 'The name of the markdown file in the prompts directory.',\n },\n {\n name: 'args...',\n required: false,\n description: 'Additional arguments for the template and command',\n },\n ],\n options: [\n {\n name: '--module, -m <module>',\n description:\n 'Target a specific module (searches apps/frontend/modules and apps/backend/modules)',\n },\n { name: '--interactive, -i', description: 'Run in interactive chat mode' },\n {\n name: '--models <models>',\n description: 'Comma-separated list of models to try',\n default: 'gemini-3-flash-preview,gemini-3-pro-preview',\n },\n ],\n };\n\n async run(options: {\n promptName: string;\n args?: string[];\n module?: string;\n m?: string;\n interactive?: boolean;\n i?: boolean;\n models?: string;\n }) {\n const projectRoot = this.projectRoot as string;\n const promptName = options.promptName;\n\n // Parse additional template flags\n const argv = minimist(options.args || []);\n const isInteractive = options.interactive || options.i || argv.interactive || argv.i;\n const moduleName = options.module || options.m || argv.module || argv.m;\n const modelsArg =\n options.models || argv.models || 'gemini-3-flash-preview,gemini-3-pro-preview';\n const models = modelsArg\n .split(',')\n .map((m: string) => m.trim())\n .filter(Boolean);\n\n const PROMPTS_DIRS = [path.join(projectRoot, 'prompts')];\n const generatorAgentsPrompts = path.join(projectRoot, 'packages/generator/prompts/agents');\n\n if (await fs.pathExists(generatorAgentsPrompts)) {\n PROMPTS_DIRS.push(generatorAgentsPrompts);\n }\n\n // Module Resolution Logic\n const contextVars = { ...argv };\n if (moduleName) {\n const frontendPath = path.join(projectRoot, 'apps/frontend/modules', moduleName);\n const backendPath = path.join(projectRoot, 'apps/backend/modules', moduleName);\n\n let moduleRoot: string | undefined;\n let moduleType: 'frontend' | 'backend' | undefined;\n\n if (await fs.pathExists(frontendPath)) {\n moduleRoot = frontendPath;\n moduleType = 'frontend';\n } else if (await fs.pathExists(backendPath)) {\n moduleRoot = backendPath;\n moduleType = 'backend';\n }\n\n if (!moduleRoot) {\n this.error(\n `Module '${moduleName}' not found in apps/frontend/modules or apps/backend/modules.`,\n );\n return;\n }\n\n logger.debug(`[Context] Targeting ${moduleType} module: ${moduleName}`);\n contextVars.module_root = moduleRoot;\n contextVars.module_name = moduleName;\n contextVars.module_type = moduleType;\n contextVars.root_path = moduleRoot + '/';\n } else {\n if (!contextVars.root_path) {\n contextVars.root_path = process.cwd() + '/';\n }\n }\n\n // Extract AI configuration from nexical.yaml\n const configPath = path.join(projectRoot, 'nexical.yaml');\n let aiConfig: Record<string, unknown> = {};\n if (await fs.pathExists(configPath)) {\n try {\n const content = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(content) || {};\n aiConfig = (config.ai as Record<string, unknown>) || {};\n } catch {\n logger.warn('Failed to parse nexical.yaml AI config, using defaults.');\n }\n }\n\n const finalCode = await PromptRunner.run({\n promptName,\n promptDirs: PROMPTS_DIRS,\n args: contextVars,\n aiConfig,\n models,\n interactive: isInteractive as boolean,\n });\n\n if (finalCode !== 0) {\n process.exit(finalCode);\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAAA;AACA,sBAAe;AADf,SAAiC,aAAa,cAAc;AAE5D,OAAO,UAAU;AACjB,OAAO,cAAc;AACrB,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAE7B,IAAqB,gBAArB,cAA2C,YAAY;AAAA,EACrD,OAAO,QAAQ;AAAA,EACf,OAAO,cAAc;AAAA,EACrB,OAAO,kBAAkB;AAAA,EAEzB,OAAO,OAA0B;AAAA,IAC/B,MAAM;AAAA,MACJ;AAAA,QACE,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,MACJ;AAAA,MACA,EAAE,MAAM,qBAAqB,aAAa,+BAA+B;AAAA,MACzE;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAQP;AACD,UAAM,cAAc,KAAK;AACzB,UAAM,aAAa,QAAQ;AAG3B,UAAM,OAAO,SAAS,QAAQ,QAAQ,CAAC,CAAC;AACxC,UAAM,gBAAgB,QAAQ,eAAe,QAAQ,KAAK,KAAK,eAAe,KAAK;AACnF,UAAM,aAAa,QAAQ,UAAU,QAAQ,KAAK,KAAK,UAAU,KAAK;AACtE,UAAM,YACJ,QAAQ,UAAU,KAAK,UAAU;AACnC,UAAM,SAAS,UACZ,MAAM,GAAG,EACT,IAAI,CAAC,MAAc,EAAE,KAAK,CAAC,EAC3B,OAAO,OAAO;AAEjB,UAAM,eAAe,CAAC,KAAK,KAAK,aAAa,SAAS,CAAC;AACvD,UAAM,yBAAyB,KAAK,KAAK,aAAa,mCAAmC;AAEzF,QAAI,MAAM,gBAAAA,QAAG,WAAW,sBAAsB,GAAG;AAC/C,mBAAa,KAAK,sBAAsB;AAAA,IAC1C;AAGA,UAAM,cAAc,EAAE,GAAG,KAAK;AAC9B,QAAI,YAAY;AACd,YAAM,eAAe,KAAK,KAAK,aAAa,yBAAyB,UAAU;AAC/E,YAAM,cAAc,KAAK,KAAK,aAAa,wBAAwB,UAAU;AAE7E,UAAI;AACJ,UAAI;AAEJ,UAAI,MAAM,gBAAAA,QAAG,WAAW,YAAY,GAAG;AACrC,qBAAa;AACb,qBAAa;AAAA,MACf,WAAW,MAAM,gBAAAA,QAAG,WAAW,WAAW,GAAG;AAC3C,qBAAa;AACb,qBAAa;AAAA,MACf;AAEA,UAAI,CAAC,YAAY;AACf,aAAK;AAAA,UACH,WAAW,UAAU;AAAA,QACvB;AACA;AAAA,MACF;AAEA,aAAO,MAAM,uBAAuB,UAAU,YAAY,UAAU,EAAE;AACtE,kBAAY,cAAc;AAC1B,kBAAY,cAAc;AAC1B,kBAAY,cAAc;AAC1B,kBAAY,YAAY,aAAa;AAAA,IACvC,OAAO;AACL,UAAI,CAAC,YAAY,WAAW;AAC1B,oBAAY,YAAY,QAAQ,IAAI,IAAI;AAAA,MAC1C;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,KAAK,aAAa,cAAc;AACxD,QAAI,WAAoC,CAAC;AACzC,QAAI,MAAM,gBAAAA,QAAG,WAAW,UAAU,GAAG;AACnC,UAAI;AACF,cAAM,UAAU,MAAM,gBAAAA,QAAG,SAAS,YAAY,MAAM;AACpD,cAAM,SAAS,KAAK,MAAM,OAAO,KAAK,CAAC;AACvC,mBAAY,OAAO,MAAkC,CAAC;AAAA,MACxD,QAAQ;AACN,eAAO,KAAK,yDAAyD;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,aAAa,IAAI;AAAA,MACvC;AAAA,MACA,YAAY;AAAA,MACZ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,aAAa;AAAA,IACf,CAAC;AAED,QAAI,cAAc,GAAG;AACnB,cAAQ,KAAK,SAAS;AAAA,IACxB;AAAA,EACF;AACF;","names":["fs"]}
1
+ {"version":3,"sources":["../../../src/commands/prompt.ts"],"sourcesContent":["import { type CommandDefinition, BaseCommand, logger } from '@nexical/cli-core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport minimist from 'minimist';\nimport YAML from 'yaml';\nimport { PromptRunner } from '@nexical/ai';\n\nexport default class PromptCommand extends BaseCommand {\n static usage = 'prompt <prompt-name> [args...]';\n static description = 'Run an AI prompt using templates from the prompts directory.';\n static requiresProject = true;\n\n static args: CommandDefinition = {\n args: [\n {\n name: 'promptName',\n required: true,\n description: 'The name of the markdown file in the prompts directory.',\n },\n {\n name: 'args...',\n required: false,\n description: 'Additional arguments for the template and command',\n },\n ],\n options: [\n {\n name: '--module, -m <module>',\n description:\n 'Target a specific module (searches apps/frontend/modules and apps/backend/modules)',\n },\n { name: '--interactive, -i', description: 'Run in interactive chat mode' },\n {\n name: '--models <models>',\n description: 'Comma-separated list of models to try',\n default: 'gemini-3-flash-preview,gemini-3-pro-preview',\n },\n ],\n };\n\n async run(options: {\n promptName: string;\n args?: string[];\n module?: string;\n m?: string;\n interactive?: boolean;\n i?: boolean;\n models?: string;\n }) {\n const projectRoot = this.projectRoot as string;\n const promptName = options.promptName;\n\n // Parse additional template flags\n const argv = minimist(options.args || []);\n const isInteractive = !!(options.interactive || options.i || argv.interactive || argv.i);\n const moduleName = options.module || options.m || argv.module || argv.m;\n const modelsArg =\n options.models || argv.models || 'gemini-3-flash-preview,gemini-3-pro-preview';\n const models = modelsArg\n .split(',')\n .map((m: string) => m.trim())\n .filter(Boolean);\n\n const PROMPTS_DIRS = [path.join(projectRoot, 'prompts')];\n const generatorAgentsPrompts = path.join(projectRoot, 'packages/generator/prompts/agents');\n\n if (await fs.pathExists(generatorAgentsPrompts)) {\n PROMPTS_DIRS.push(generatorAgentsPrompts);\n }\n\n // Module Resolution Logic\n const contextVars = { ...argv };\n if (moduleName) {\n const frontendPath = path.join(projectRoot, 'apps/frontend/modules', moduleName);\n const backendPath = path.join(projectRoot, 'apps/backend/modules', moduleName);\n\n let moduleRoot: string | undefined;\n let moduleType: 'frontend' | 'backend' | undefined;\n\n if (await fs.pathExists(frontendPath)) {\n moduleRoot = frontendPath;\n moduleType = 'frontend';\n } else if (await fs.pathExists(backendPath)) {\n moduleRoot = backendPath;\n moduleType = 'backend';\n }\n\n if (!moduleRoot) {\n this.error(\n `Module '${moduleName}' not found in apps/frontend/modules or apps/backend/modules.`,\n );\n return;\n }\n\n logger.debug(`[Context] Targeting ${moduleType} module: ${moduleName}`);\n contextVars.module_root = moduleRoot;\n contextVars.module_name = moduleName;\n contextVars.module_type = moduleType;\n contextVars.root_path = moduleRoot + '/';\n } else {\n if (!contextVars.root_path) {\n contextVars.root_path = process.cwd() + '/';\n }\n }\n\n // Extract AI configuration from nexical.yaml\n const configPath = path.join(projectRoot, 'nexical.yaml');\n let aiConfig: Record<string, unknown> = {};\n if (await fs.pathExists(configPath)) {\n try {\n const content = await fs.readFile(configPath, 'utf8');\n const config = YAML.parse(content) || {};\n aiConfig = (config.ai as Record<string, unknown>) || {};\n } catch {\n logger.warn('Failed to parse nexical.yaml AI config, using defaults.');\n }\n }\n\n const finalCode = await PromptRunner.run({\n promptName,\n promptDirs: PROMPTS_DIRS,\n args: contextVars,\n aiConfig,\n models,\n interactive: isInteractive as boolean,\n });\n\n if (finalCode !== 0) {\n process.exit(finalCode);\n }\n }\n}\n"],"mappings":"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","names":["fs"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Filters out duplicate core commands and source versions from additional command directories.
3
+ * @param additionalCommands List of discovered command directories.
4
+ * @param coreCommandsDir The primary core commands directory.
5
+ * @returns Filtered list of additional command directories.
6
+ */
7
+ declare function filterCommandDirectories(additionalCommands: string[], coreCommandsDir: string): string[];
8
+
9
+ export { filterCommandDirectories };
@@ -0,0 +1,9 @@
1
+ import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
+ import {
3
+ filterCommandDirectories
4
+ } from "../../chunk-54HY52LH.js";
5
+ import "../../chunk-OYFWMYPG.js";
6
+ export {
7
+ filterCommandDirectories
8
+ };
9
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/index.ts CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import { discoverCommandDirectories } from './src/utils/discovery.js';
5
5
  import pkg from './package.json';
6
6
  import path from 'node:path';
7
+ import { filterCommandDirectories } from './src/utils/filter.js';
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
 
@@ -12,37 +13,7 @@ const projectRoot = (await findProjectRoot(commandName, process.cwd())) || proce
12
13
  const coreCommandsDir = path.resolve(__dirname, './src/commands');
13
14
  const additionalCommands = discoverCommandDirectories(projectRoot);
14
15
 
15
- // Filter out duplicate core commands and source versions
16
- const filteredAdditional = additionalCommands.filter((dir) => {
17
- const resolvedDir = path.resolve(dir);
18
- const resolvedCore = path.resolve(coreCommandsDir);
19
-
20
- if (resolvedDir === resolvedCore) return false;
21
-
22
- // Check if this is another instance of the core CLI commands (by checking path suffix)
23
- const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');
24
- const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');
25
- const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');
26
-
27
- if (
28
- resolvedDir.endsWith(coreSuffix) ||
29
- resolvedDir.endsWith(coreSuffixSrc) ||
30
- resolvedDir.endsWith(coreSuffixRawSrc)
31
- ) {
32
- return false;
33
- }
34
-
35
- // Handle mismatch between dist/src and src/
36
- if (resolvedCore.includes(path.join(path.sep, 'dist', 'src', 'commands'))) {
37
- const srcVersion = resolvedCore.replace(
38
- path.join(path.sep, 'dist', 'src', 'commands'),
39
- path.join(path.sep, 'src', 'commands'),
40
- );
41
- if (resolvedDir === srcVersion) return false;
42
- }
43
-
44
- return true;
45
- });
16
+ const filteredAdditional = filterCommandDirectories(additionalCommands, coreCommandsDir);
46
17
 
47
18
  const app = new CLI({
48
19
  version: pkg.version,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexical/cli",
3
- "version": "0.11.18",
3
+ "version": "0.11.19",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,7 +52,7 @@ export default class PromptCommand extends BaseCommand {
52
52
 
53
53
  // Parse additional template flags
54
54
  const argv = minimist(options.args || []);
55
- const isInteractive = options.interactive || options.i || argv.interactive || argv.i;
55
+ const isInteractive = !!(options.interactive || options.i || argv.interactive || argv.i);
56
56
  const moduleName = options.module || options.m || argv.module || argv.m;
57
57
  const modelsArg =
58
58
  options.models || argv.models || 'gemini-3-flash-preview,gemini-3-pro-preview';
@@ -0,0 +1,47 @@
1
+ import path from 'node:path';
2
+
3
+ /**
4
+ * Filters out duplicate core commands and source versions from additional command directories.
5
+ * @param additionalCommands List of discovered command directories.
6
+ * @param coreCommandsDir The primary core commands directory.
7
+ * @returns Filtered list of additional command directories.
8
+ */
9
+ export function filterCommandDirectories(
10
+ additionalCommands: string[],
11
+ coreCommandsDir: string,
12
+ ): string[] {
13
+ return additionalCommands.filter((dir) => {
14
+ const resolvedDir = path.resolve(dir);
15
+ const resolvedCore = path.resolve(coreCommandsDir);
16
+
17
+ if (resolvedDir === resolvedCore) return false;
18
+
19
+ // Check if this is another instance of the core CLI commands (by checking path suffix)
20
+ const coreSuffix = path.join('@nexical', 'cli', 'dist', 'src', 'commands');
21
+ const coreSuffixSrc = path.join('packages', 'cli', 'dist', 'src', 'commands');
22
+ const coreSuffixRawSrc = path.join('packages', 'cli', 'src', 'commands');
23
+
24
+ if (
25
+ resolvedDir.endsWith(coreSuffix) ||
26
+ resolvedDir.endsWith(coreSuffixSrc) ||
27
+ resolvedDir.endsWith(coreSuffixRawSrc)
28
+ ) {
29
+ return false;
30
+ }
31
+
32
+ // Handle mismatch between dist/src and src/
33
+ const distSuffix = path.join('dist', 'src', 'commands');
34
+ const srcSuffix = path.join('src', 'commands');
35
+ if (resolvedCore.endsWith(distSuffix)) {
36
+ const baseDir = resolvedCore.substring(0, resolvedCore.length - distSuffix.length);
37
+ const srcVersion = path.join(baseDir, srcSuffix);
38
+ const normalizedDir = path.normalize(resolvedDir);
39
+ const normalizedSrc = path.normalize(srcVersion);
40
+ if (normalizedDir === normalizedSrc) {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ return true;
46
+ });
47
+ }
@@ -0,0 +1,110 @@
1
+ import { describe, it, expect, vi, beforeEach, afterAll } from 'vitest';
2
+ import PromptCommand from '../../../src/commands/prompt.js';
3
+ import { createTempDir, createMockRepo, cleanupTestRoot } from '../../utils/integration-helpers.js';
4
+ import path from 'node:path';
5
+ import fs from 'fs-extra';
6
+ import { CLI } from '@nexical/cli-core';
7
+ import { PromptRunner } from '@nexical/ai';
8
+
9
+ vi.mock('@nexical/ai', () => ({
10
+ PromptRunner: {
11
+ run: vi.fn().mockResolvedValue(0),
12
+ },
13
+ }));
14
+
15
+ describe('Prompt Command Integration', () => {
16
+ let projectDir: string;
17
+
18
+ beforeEach(async () => {
19
+ const temp = await createTempDir('prompt-integration-');
20
+ projectDir = await createMockRepo(temp, {
21
+ 'package.json': '{"name": "prompt-project", "version": "1.0.0"}',
22
+ 'nexical.yaml': 'ai:\n provider: vertex',
23
+ 'prompts/test-prompt.md': 'Testing {{ name }}',
24
+ });
25
+ });
26
+
27
+ afterAll(async () => {
28
+ await cleanupTestRoot();
29
+ });
30
+
31
+ it('should resolve project config and call PromptRunner', async () => {
32
+ const originalCwd = process.cwd();
33
+ try {
34
+ process.chdir(projectDir);
35
+ const cli = new CLI({ commandName: 'nexical' });
36
+ const command = new PromptCommand(cli);
37
+
38
+ // We need to set projectRoot manually because BaseCommand detection
39
+ // might fail if not properly initialized in test env
40
+ (command as unknown as { projectRoot: string }).projectRoot = projectDir;
41
+
42
+ await command.run({ promptName: 'test-prompt' });
43
+
44
+ expect(PromptRunner.run).toHaveBeenCalledWith(
45
+ expect.objectContaining({
46
+ promptName: 'test-prompt',
47
+ promptDirs: [path.join(projectDir, 'prompts')],
48
+ aiConfig: { provider: 'vertex' },
49
+ }),
50
+ );
51
+ } finally {
52
+ process.chdir(originalCwd);
53
+ }
54
+ });
55
+
56
+ it('should resolve module context in integration', async () => {
57
+ const originalCwd = process.cwd();
58
+ try {
59
+ process.chdir(projectDir);
60
+
61
+ const moduleDir = path.join(projectDir, 'apps/frontend/modules/my-mod');
62
+ await fs.ensureDir(moduleDir);
63
+
64
+ const cli = new CLI({ commandName: 'nexical' });
65
+ const command = new PromptCommand(cli);
66
+ (command as unknown as { projectRoot: string }).projectRoot = projectDir;
67
+
68
+ await command.run({ promptName: 'test-prompt', module: 'my-mod' });
69
+
70
+ expect(PromptRunner.run).toHaveBeenCalledWith(
71
+ expect.objectContaining({
72
+ args: expect.objectContaining({
73
+ module_name: 'my-mod',
74
+ module_type: 'frontend',
75
+ module_root: moduleDir,
76
+ }),
77
+ }),
78
+ );
79
+ } finally {
80
+ process.chdir(originalCwd);
81
+ }
82
+ });
83
+
84
+ it('should include generator agents prompts if they exist in integration', async () => {
85
+ const originalCwd = process.cwd();
86
+ try {
87
+ process.chdir(projectDir);
88
+
89
+ const generatorPromptsDir = path.join(projectDir, 'packages/generator/prompts/agents');
90
+ await fs.ensureDir(generatorPromptsDir);
91
+
92
+ const cli = new CLI({ commandName: 'nexical' });
93
+ const command = new PromptCommand(cli);
94
+ (command as unknown as { projectRoot: string }).projectRoot = projectDir;
95
+
96
+ await command.run({ promptName: 'test-prompt' });
97
+
98
+ expect(PromptRunner.run).toHaveBeenCalledWith(
99
+ expect.objectContaining({
100
+ promptDirs: expect.arrayContaining([
101
+ path.join(projectDir, 'prompts'),
102
+ generatorPromptsDir,
103
+ ]),
104
+ }),
105
+ );
106
+ } finally {
107
+ process.chdir(originalCwd);
108
+ }
109
+ });
110
+ });
@@ -0,0 +1,257 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import PromptCommand from '../../../src/commands/prompt.js';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ import YAML from 'yaml';
6
+ import { PromptRunner } from '@nexical/ai';
7
+ import { logger } from '@nexical/cli-core';
8
+
9
+ vi.mock('@nexical/cli-core', async (importOriginal) => {
10
+ const mod = await importOriginal<typeof import('@nexical/cli-core')>();
11
+ return {
12
+ ...mod,
13
+ logger: {
14
+ code: vi.fn(),
15
+ debug: vi.fn(),
16
+ error: vi.fn(),
17
+ success: vi.fn(),
18
+ info: vi.fn(),
19
+ warn: vi.fn(),
20
+ },
21
+ };
22
+ });
23
+
24
+ vi.mock('fs-extra');
25
+ vi.mock('yaml');
26
+ vi.mock('@nexical/ai');
27
+
28
+ describe('PromptCommand', () => {
29
+ let command: PromptCommand;
30
+ const projectRoot = '/test/project';
31
+
32
+ beforeEach(() => {
33
+ vi.clearAllMocks();
34
+ command = new PromptCommand({});
35
+ (command as unknown as { projectRoot: string }).projectRoot = projectRoot;
36
+
37
+ vi.spyOn(command, 'error').mockImplementation(() => {});
38
+
39
+ // Default fs mocks
40
+ vi.spyOn(fs, 'pathExists').mockResolvedValue(false);
41
+ vi.spyOn(fs, 'readFile').mockResolvedValue('');
42
+
43
+ // Default PromptRunner mock
44
+ vi.mocked(PromptRunner.run).mockResolvedValue(0);
45
+
46
+ // Mock process.exit
47
+ vi.spyOn(process, 'exit').mockImplementation((code) => {
48
+ throw new Error(`Process.exit(${code})`);
49
+ });
50
+ });
51
+
52
+ afterEach(() => {
53
+ vi.resetAllMocks();
54
+ });
55
+
56
+ it('should have correct metadata', () => {
57
+ expect(PromptCommand.usage).toBeDefined();
58
+ expect(PromptCommand.description).toBeDefined();
59
+ expect(PromptCommand.requiresProject).toBe(true);
60
+ expect(PromptCommand.args).toBeDefined();
61
+ });
62
+
63
+ it('should run prompt with default options', async () => {
64
+ await command.run({ promptName: 'test-prompt' });
65
+
66
+ expect(PromptRunner.run).toHaveBeenCalledWith(
67
+ expect.objectContaining({
68
+ promptName: 'test-prompt',
69
+ models: ['gemini-3-flash-preview', 'gemini-3-pro-preview'],
70
+ interactive: false,
71
+ }),
72
+ );
73
+ });
74
+
75
+ it('should handle interactive flag', async () => {
76
+ await command.run({ promptName: 'test-prompt', interactive: true });
77
+ expect(PromptRunner.run).toHaveBeenCalledWith(
78
+ expect.objectContaining({
79
+ interactive: true,
80
+ }),
81
+ );
82
+
83
+ vi.clearAllMocks();
84
+ await command.run({ promptName: 'test-prompt', i: true });
85
+ expect(PromptRunner.run).toHaveBeenCalledWith(
86
+ expect.objectContaining({
87
+ interactive: true,
88
+ }),
89
+ );
90
+
91
+ vi.clearAllMocks();
92
+ await command.run({ promptName: 'test-prompt', args: ['--interactive'] });
93
+ expect(PromptRunner.run).toHaveBeenCalledWith(
94
+ expect.objectContaining({
95
+ interactive: true,
96
+ }),
97
+ );
98
+ });
99
+
100
+ it('should handle custom models', async () => {
101
+ await command.run({ promptName: 'test-prompt', models: 'model1, model2 ' });
102
+ expect(PromptRunner.run).toHaveBeenCalledWith(
103
+ expect.objectContaining({
104
+ models: ['model1', 'model2'],
105
+ }),
106
+ );
107
+ });
108
+
109
+ it('should include generator agents prompts if they exist', async () => {
110
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) => {
111
+ return (p as string).includes('packages/generator/prompts/agents');
112
+ });
113
+
114
+ await command.run({ promptName: 'test-prompt' });
115
+
116
+ const call = vi.mocked(PromptRunner.run).mock.calls[0][0];
117
+ expect(call?.promptDirs).toHaveLength(2);
118
+ expect(call?.promptDirs).toContain(path.join(projectRoot, 'prompts'));
119
+ expect(call?.promptDirs).toContain(path.join(projectRoot, 'packages/generator/prompts/agents'));
120
+ });
121
+
122
+ it('should resolve frontend module context', async () => {
123
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) => {
124
+ return (p as string).includes('apps/frontend/modules/test-module');
125
+ });
126
+
127
+ await command.run({ promptName: 'test-prompt', module: 'test-module' });
128
+
129
+ expect(PromptRunner.run).toHaveBeenCalledWith(
130
+ expect.objectContaining({
131
+ args: expect.objectContaining({
132
+ module_name: 'test-module',
133
+ module_type: 'frontend',
134
+ module_root: path.join(projectRoot, 'apps/frontend/modules/test-module'),
135
+ }),
136
+ }),
137
+ );
138
+ });
139
+
140
+ it('should resolve backend module context', async () => {
141
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) => {
142
+ return (p as string).includes('apps/backend/modules/test-module');
143
+ });
144
+
145
+ await command.run({ promptName: 'test-prompt', m: 'test-module' });
146
+
147
+ expect(PromptRunner.run).toHaveBeenCalledWith(
148
+ expect.objectContaining({
149
+ args: expect.objectContaining({
150
+ module_name: 'test-module',
151
+ module_type: 'backend',
152
+ module_root: path.join(projectRoot, 'apps/backend/modules/test-module'),
153
+ }),
154
+ }),
155
+ );
156
+ });
157
+
158
+ it('should fail if module not found', async () => {
159
+ vi.mocked(fs.pathExists).mockResolvedValue(false);
160
+
161
+ await command.run({ promptName: 'test-prompt', module: 'missing-module' });
162
+
163
+ expect(command.error).toHaveBeenCalledWith(
164
+ expect.stringContaining("Module 'missing-module' not found"),
165
+ );
166
+ expect(PromptRunner.run).not.toHaveBeenCalled();
167
+ });
168
+
169
+ it('should load AI config from nexical.yaml', async () => {
170
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) =>
171
+ (p as string).includes('nexical.yaml'),
172
+ );
173
+ vi.spyOn(fs, 'readFile').mockResolvedValue('ai:\n provider: vertex');
174
+ vi.mocked(YAML.parse).mockReturnValue({ ai: { provider: 'vertex' } });
175
+
176
+ await command.run({ promptName: 'test-prompt' });
177
+
178
+ expect(PromptRunner.run).toHaveBeenCalledWith(
179
+ expect.objectContaining({
180
+ aiConfig: { provider: 'vertex' },
181
+ }),
182
+ );
183
+ });
184
+
185
+ it('should handle missing AI config in nexical.yaml', async () => {
186
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) =>
187
+ (p as string).includes('nexical.yaml'),
188
+ );
189
+ vi.spyOn(fs, 'readFile').mockResolvedValue('name: my-project');
190
+ vi.mocked(YAML.parse).mockReturnValue({ name: 'my-project' });
191
+
192
+ await command.run({ promptName: 'test-prompt' });
193
+
194
+ expect(PromptRunner.run).toHaveBeenCalledWith(
195
+ expect.objectContaining({
196
+ aiConfig: {},
197
+ }),
198
+ );
199
+ });
200
+
201
+ it('should handle falsy YAML parse result', async () => {
202
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) =>
203
+ (p as string).includes('nexical.yaml'),
204
+ );
205
+ vi.spyOn(fs, 'readFile').mockResolvedValue('');
206
+ vi.mocked(YAML.parse).mockReturnValue(null);
207
+
208
+ await command.run({ promptName: 'test-prompt' });
209
+
210
+ expect(PromptRunner.run).toHaveBeenCalledWith(
211
+ expect.objectContaining({
212
+ aiConfig: {},
213
+ }),
214
+ );
215
+ });
216
+
217
+ it('should handle nexical.yaml parse errors', async () => {
218
+ vi.spyOn(fs, 'pathExists').mockImplementation(async (p: string | Buffer | URL) =>
219
+ (p as string).includes('nexical.yaml'),
220
+ );
221
+ vi.spyOn(fs, 'readFile').mockResolvedValue('invalid: yaml: :');
222
+ vi.mocked(YAML.parse).mockImplementation(() => {
223
+ throw new Error('parse error');
224
+ });
225
+
226
+ await command.run({ promptName: 'test-prompt' });
227
+
228
+ expect(logger.warn).toHaveBeenCalledWith(
229
+ expect.stringContaining('Failed to parse nexical.yaml'),
230
+ );
231
+ expect(PromptRunner.run).toHaveBeenCalledWith(
232
+ expect.objectContaining({
233
+ aiConfig: {},
234
+ }),
235
+ );
236
+ });
237
+
238
+ it('should exit with error code if PromptRunner fails', async () => {
239
+ vi.mocked(PromptRunner.run).mockResolvedValue(1);
240
+
241
+ await expect(command.run({ promptName: 'test-prompt' })).rejects.toThrow('Process.exit(1)');
242
+ });
243
+
244
+ it('should set default root_path if not provided', async () => {
245
+ await command.run({ promptName: 'test-prompt' });
246
+
247
+ const call = vi.mocked(PromptRunner.run).mock.calls[0][0];
248
+ expect(call?.args?.root_path).toBe(process.cwd() + '/');
249
+ });
250
+
251
+ it('should use provided root_path from args', async () => {
252
+ await command.run({ promptName: 'test-prompt', args: ['--root_path', '/custom/path/'] });
253
+
254
+ const call = vi.mocked(PromptRunner.run).mock.calls[0][0];
255
+ expect(call?.args?.root_path).toBe('/custom/path/');
256
+ });
257
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { filterCommandDirectories } from '../../../src/utils/filter.js';
3
+ import path from 'node:path';
4
+
5
+ describe('filterCommandDirectories', () => {
6
+ const coreDir = path.resolve('/test/packages/cli/src/commands');
7
+
8
+ it('should filter out the core commands directory itself', () => {
9
+ const dirs = [coreDir, path.resolve('/test/other')];
10
+ const filtered = filterCommandDirectories(dirs, coreDir);
11
+ expect(filtered).toEqual([path.resolve('/test/other')]);
12
+ });
13
+
14
+ it('should filter out default core suffixes', () => {
15
+ const dirs = [
16
+ path.join('/some/path', '@nexical', 'cli', 'dist', 'src', 'commands'),
17
+ path.join('/another/path', 'packages', 'cli', 'dist', 'src', 'commands'),
18
+ path.join('/yet/another', 'packages', 'cli', 'src', 'commands'),
19
+ path.resolve('/test/valid'),
20
+ ];
21
+ const filtered = filterCommandDirectories(dirs, coreDir);
22
+ expect(filtered).toEqual([path.resolve('/test/valid')]);
23
+ });
24
+
25
+ it('should handle dist/src mismatch and filter src version', () => {
26
+ const base = '/another/project';
27
+ const distCore = path.join(base, 'dist', 'src', 'commands');
28
+ const srcCore = path.join(base, 'src', 'commands');
29
+
30
+ const dirs = [srcCore, path.resolve('/test/other')];
31
+ const filtered = filterCommandDirectories(dirs, distCore);
32
+ expect(filtered).toEqual([path.resolve('/test/other')]);
33
+ });
34
+
35
+ it('should not filter out non-matching directories', () => {
36
+ const dirs = [path.resolve('/test/modules/mod1/src/commands')];
37
+ const filtered = filterCommandDirectories(dirs, coreDir);
38
+ expect(filtered).toEqual(dirs);
39
+ });
40
+ });
package/vitest.config.ts CHANGED
@@ -9,7 +9,7 @@ export default defineConfig({
9
9
  provider: 'v8',
10
10
  reporter: ['text', 'json', 'html'],
11
11
  include: ['src/**/*.ts'],
12
- exclude: ['index.ts', '**/*.d.ts'],
12
+ exclude: ['index.ts', 'src/**/types.ts', '**/*.d.ts'],
13
13
  },
14
14
  },
15
15
  });