@nexical/cli 0.11.16 → 0.11.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/src/commands/init.js +7 -7
- package/dist/src/commands/module/add.js +5 -5
- package/dist/src/commands/prompt.d.ts +19 -0
- package/dist/src/commands/prompt.js +117 -0
- package/dist/src/commands/prompt.js.map +1 -0
- package/package.json +5 -1
- package/src/commands/prompt.ts +132 -0
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.
|
|
18
|
+
version: "0.11.18",
|
|
19
19
|
license: "Apache-2.0",
|
|
20
20
|
type: "module",
|
|
21
21
|
bin: {
|
|
@@ -44,17 +44,21 @@ var package_default = {
|
|
|
44
44
|
]
|
|
45
45
|
},
|
|
46
46
|
dependencies: {
|
|
47
|
+
"@nexical/ai": "^0.1.5",
|
|
47
48
|
"@nexical/cli-core": "^0.1.16",
|
|
48
49
|
dotenv: "^17.3.1",
|
|
49
50
|
"fast-glob": "^3.3.3",
|
|
50
51
|
glob: "^13.0.5",
|
|
51
52
|
jiti: "^2.6.1",
|
|
53
|
+
minimist: "^1.2.8",
|
|
52
54
|
yaml: "^2.8.2"
|
|
53
55
|
},
|
|
54
56
|
devDependencies: {
|
|
55
57
|
"@eslint/js": "^9.39.2",
|
|
56
58
|
"@types/fs-extra": "^11.0.4",
|
|
59
|
+
"@types/minimist": "^1.2.5",
|
|
57
60
|
"@types/node": "^25.3.0",
|
|
61
|
+
"@types/nunjucks": "^3.2.6",
|
|
58
62
|
"@vitest/coverage-v8": "^4.0.18",
|
|
59
63
|
eslint: "^9.39.2",
|
|
60
64
|
"eslint-config-prettier": "^10.1.8",
|
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.
|
|
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,11 +1,4 @@
|
|
|
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";
|
|
9
2
|
import {
|
|
10
3
|
resolveGitUrl
|
|
11
4
|
} from "../../chunk-PJIOCW2A.js";
|
|
@@ -15,6 +8,13 @@ import {
|
|
|
15
8
|
import {
|
|
16
9
|
require_lib
|
|
17
10
|
} 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";
|
|
7
2
|
import {
|
|
8
3
|
resolveGitUrl
|
|
9
4
|
} from "../../../chunk-PJIOCW2A.js";
|
|
10
5
|
import {
|
|
11
6
|
require_lib
|
|
12
7
|
} 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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand, CommandDefinition } from '@nexical/cli-core';
|
|
2
|
+
|
|
3
|
+
declare class PromptCommand extends BaseCommand {
|
|
4
|
+
static usage: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static requiresProject: boolean;
|
|
7
|
+
static args: CommandDefinition;
|
|
8
|
+
run(options: {
|
|
9
|
+
promptName: string;
|
|
10
|
+
args?: string[];
|
|
11
|
+
module?: string;
|
|
12
|
+
m?: string;
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
i?: boolean;
|
|
15
|
+
models?: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { PromptCommand as default };
|
|
@@ -0,0 +1,117 @@
|
|
|
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/prompt.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
|
+
import minimist from "minimist";
|
|
16
|
+
import YAML from "yaml";
|
|
17
|
+
import { PromptRunner } from "@nexical/ai";
|
|
18
|
+
var PromptCommand = class extends BaseCommand {
|
|
19
|
+
static usage = "prompt <prompt-name> [args...]";
|
|
20
|
+
static description = "Run an AI prompt using templates from the prompts directory.";
|
|
21
|
+
static requiresProject = true;
|
|
22
|
+
static args = {
|
|
23
|
+
args: [
|
|
24
|
+
{
|
|
25
|
+
name: "promptName",
|
|
26
|
+
required: true,
|
|
27
|
+
description: "The name of the markdown file in the prompts directory."
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "args...",
|
|
31
|
+
required: false,
|
|
32
|
+
description: "Additional arguments for the template and command"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
options: [
|
|
36
|
+
{
|
|
37
|
+
name: "--module, -m <module>",
|
|
38
|
+
description: "Target a specific module (searches apps/frontend/modules and apps/backend/modules)"
|
|
39
|
+
},
|
|
40
|
+
{ name: "--interactive, -i", description: "Run in interactive chat mode" },
|
|
41
|
+
{
|
|
42
|
+
name: "--models <models>",
|
|
43
|
+
description: "Comma-separated list of models to try",
|
|
44
|
+
default: "gemini-3-flash-preview,gemini-3-pro-preview"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
async run(options) {
|
|
49
|
+
const projectRoot = this.projectRoot;
|
|
50
|
+
const promptName = options.promptName;
|
|
51
|
+
const argv = minimist(options.args || []);
|
|
52
|
+
const isInteractive = options.interactive || options.i || argv.interactive || argv.i;
|
|
53
|
+
const moduleName = options.module || options.m || argv.module || argv.m;
|
|
54
|
+
const modelsArg = options.models || argv.models || "gemini-3-flash-preview,gemini-3-pro-preview";
|
|
55
|
+
const models = modelsArg.split(",").map((m) => m.trim()).filter(Boolean);
|
|
56
|
+
const PROMPTS_DIRS = [path.join(projectRoot, "prompts")];
|
|
57
|
+
const generatorAgentsPrompts = path.join(projectRoot, "packages/generator/prompts/agents");
|
|
58
|
+
if (await import_fs_extra.default.pathExists(generatorAgentsPrompts)) {
|
|
59
|
+
PROMPTS_DIRS.push(generatorAgentsPrompts);
|
|
60
|
+
}
|
|
61
|
+
const contextVars = { ...argv };
|
|
62
|
+
if (moduleName) {
|
|
63
|
+
const frontendPath = path.join(projectRoot, "apps/frontend/modules", moduleName);
|
|
64
|
+
const backendPath = path.join(projectRoot, "apps/backend/modules", moduleName);
|
|
65
|
+
let moduleRoot;
|
|
66
|
+
let moduleType;
|
|
67
|
+
if (await import_fs_extra.default.pathExists(frontendPath)) {
|
|
68
|
+
moduleRoot = frontendPath;
|
|
69
|
+
moduleType = "frontend";
|
|
70
|
+
} else if (await import_fs_extra.default.pathExists(backendPath)) {
|
|
71
|
+
moduleRoot = backendPath;
|
|
72
|
+
moduleType = "backend";
|
|
73
|
+
}
|
|
74
|
+
if (!moduleRoot) {
|
|
75
|
+
this.error(
|
|
76
|
+
`Module '${moduleName}' not found in apps/frontend/modules or apps/backend/modules.`
|
|
77
|
+
);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
logger.debug(`[Context] Targeting ${moduleType} module: ${moduleName}`);
|
|
81
|
+
contextVars.module_root = moduleRoot;
|
|
82
|
+
contextVars.module_name = moduleName;
|
|
83
|
+
contextVars.module_type = moduleType;
|
|
84
|
+
contextVars.root_path = moduleRoot + "/";
|
|
85
|
+
} else {
|
|
86
|
+
if (!contextVars.root_path) {
|
|
87
|
+
contextVars.root_path = process.cwd() + "/";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const configPath = path.join(projectRoot, "nexical.yaml");
|
|
91
|
+
let aiConfig = {};
|
|
92
|
+
if (await import_fs_extra.default.pathExists(configPath)) {
|
|
93
|
+
try {
|
|
94
|
+
const content = await import_fs_extra.default.readFile(configPath, "utf8");
|
|
95
|
+
const config = YAML.parse(content) || {};
|
|
96
|
+
aiConfig = config.ai || {};
|
|
97
|
+
} catch {
|
|
98
|
+
logger.warn("Failed to parse nexical.yaml AI config, using defaults.");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const finalCode = await PromptRunner.run({
|
|
102
|
+
promptName,
|
|
103
|
+
promptDirs: PROMPTS_DIRS,
|
|
104
|
+
args: contextVars,
|
|
105
|
+
aiConfig,
|
|
106
|
+
models,
|
|
107
|
+
interactive: isInteractive
|
|
108
|
+
});
|
|
109
|
+
if (finalCode !== 0) {
|
|
110
|
+
process.exit(finalCode);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
export {
|
|
115
|
+
PromptCommand as default
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +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":"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","names":["fs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexical/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.18",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,17 +29,21 @@
|
|
|
29
29
|
]
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@nexical/ai": "^0.1.5",
|
|
32
33
|
"@nexical/cli-core": "^0.1.16",
|
|
33
34
|
"dotenv": "^17.3.1",
|
|
34
35
|
"fast-glob": "^3.3.3",
|
|
35
36
|
"glob": "^13.0.5",
|
|
36
37
|
"jiti": "^2.6.1",
|
|
38
|
+
"minimist": "^1.2.8",
|
|
37
39
|
"yaml": "^2.8.2"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@eslint/js": "^9.39.2",
|
|
41
43
|
"@types/fs-extra": "^11.0.4",
|
|
44
|
+
"@types/minimist": "^1.2.5",
|
|
42
45
|
"@types/node": "^25.3.0",
|
|
46
|
+
"@types/nunjucks": "^3.2.6",
|
|
43
47
|
"@vitest/coverage-v8": "^4.0.18",
|
|
44
48
|
"eslint": "^9.39.2",
|
|
45
49
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type CommandDefinition, BaseCommand, logger } from '@nexical/cli-core';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import minimist from 'minimist';
|
|
5
|
+
import YAML from 'yaml';
|
|
6
|
+
import { PromptRunner } from '@nexical/ai';
|
|
7
|
+
|
|
8
|
+
export default class PromptCommand extends BaseCommand {
|
|
9
|
+
static usage = 'prompt <prompt-name> [args...]';
|
|
10
|
+
static description = 'Run an AI prompt using templates from the prompts directory.';
|
|
11
|
+
static requiresProject = true;
|
|
12
|
+
|
|
13
|
+
static args: CommandDefinition = {
|
|
14
|
+
args: [
|
|
15
|
+
{
|
|
16
|
+
name: 'promptName',
|
|
17
|
+
required: true,
|
|
18
|
+
description: 'The name of the markdown file in the prompts directory.',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'args...',
|
|
22
|
+
required: false,
|
|
23
|
+
description: 'Additional arguments for the template and command',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
options: [
|
|
27
|
+
{
|
|
28
|
+
name: '--module, -m <module>',
|
|
29
|
+
description:
|
|
30
|
+
'Target a specific module (searches apps/frontend/modules and apps/backend/modules)',
|
|
31
|
+
},
|
|
32
|
+
{ name: '--interactive, -i', description: 'Run in interactive chat mode' },
|
|
33
|
+
{
|
|
34
|
+
name: '--models <models>',
|
|
35
|
+
description: 'Comma-separated list of models to try',
|
|
36
|
+
default: 'gemini-3-flash-preview,gemini-3-pro-preview',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
async run(options: {
|
|
42
|
+
promptName: string;
|
|
43
|
+
args?: string[];
|
|
44
|
+
module?: string;
|
|
45
|
+
m?: string;
|
|
46
|
+
interactive?: boolean;
|
|
47
|
+
i?: boolean;
|
|
48
|
+
models?: string;
|
|
49
|
+
}) {
|
|
50
|
+
const projectRoot = this.projectRoot as string;
|
|
51
|
+
const promptName = options.promptName;
|
|
52
|
+
|
|
53
|
+
// Parse additional template flags
|
|
54
|
+
const argv = minimist(options.args || []);
|
|
55
|
+
const isInteractive = options.interactive || options.i || argv.interactive || argv.i;
|
|
56
|
+
const moduleName = options.module || options.m || argv.module || argv.m;
|
|
57
|
+
const modelsArg =
|
|
58
|
+
options.models || argv.models || 'gemini-3-flash-preview,gemini-3-pro-preview';
|
|
59
|
+
const models = modelsArg
|
|
60
|
+
.split(',')
|
|
61
|
+
.map((m: string) => m.trim())
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
|
|
64
|
+
const PROMPTS_DIRS = [path.join(projectRoot, 'prompts')];
|
|
65
|
+
const generatorAgentsPrompts = path.join(projectRoot, 'packages/generator/prompts/agents');
|
|
66
|
+
|
|
67
|
+
if (await fs.pathExists(generatorAgentsPrompts)) {
|
|
68
|
+
PROMPTS_DIRS.push(generatorAgentsPrompts);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Module Resolution Logic
|
|
72
|
+
const contextVars = { ...argv };
|
|
73
|
+
if (moduleName) {
|
|
74
|
+
const frontendPath = path.join(projectRoot, 'apps/frontend/modules', moduleName);
|
|
75
|
+
const backendPath = path.join(projectRoot, 'apps/backend/modules', moduleName);
|
|
76
|
+
|
|
77
|
+
let moduleRoot: string | undefined;
|
|
78
|
+
let moduleType: 'frontend' | 'backend' | undefined;
|
|
79
|
+
|
|
80
|
+
if (await fs.pathExists(frontendPath)) {
|
|
81
|
+
moduleRoot = frontendPath;
|
|
82
|
+
moduleType = 'frontend';
|
|
83
|
+
} else if (await fs.pathExists(backendPath)) {
|
|
84
|
+
moduleRoot = backendPath;
|
|
85
|
+
moduleType = 'backend';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!moduleRoot) {
|
|
89
|
+
this.error(
|
|
90
|
+
`Module '${moduleName}' not found in apps/frontend/modules or apps/backend/modules.`,
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
logger.debug(`[Context] Targeting ${moduleType} module: ${moduleName}`);
|
|
96
|
+
contextVars.module_root = moduleRoot;
|
|
97
|
+
contextVars.module_name = moduleName;
|
|
98
|
+
contextVars.module_type = moduleType;
|
|
99
|
+
contextVars.root_path = moduleRoot + '/';
|
|
100
|
+
} else {
|
|
101
|
+
if (!contextVars.root_path) {
|
|
102
|
+
contextVars.root_path = process.cwd() + '/';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Extract AI configuration from nexical.yaml
|
|
107
|
+
const configPath = path.join(projectRoot, 'nexical.yaml');
|
|
108
|
+
let aiConfig: Record<string, unknown> = {};
|
|
109
|
+
if (await fs.pathExists(configPath)) {
|
|
110
|
+
try {
|
|
111
|
+
const content = await fs.readFile(configPath, 'utf8');
|
|
112
|
+
const config = YAML.parse(content) || {};
|
|
113
|
+
aiConfig = (config.ai as Record<string, unknown>) || {};
|
|
114
|
+
} catch {
|
|
115
|
+
logger.warn('Failed to parse nexical.yaml AI config, using defaults.');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const finalCode = await PromptRunner.run({
|
|
120
|
+
promptName,
|
|
121
|
+
promptDirs: PROMPTS_DIRS,
|
|
122
|
+
args: contextVars,
|
|
123
|
+
aiConfig,
|
|
124
|
+
models,
|
|
125
|
+
interactive: isInteractive as boolean,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (finalCode !== 0) {
|
|
129
|
+
process.exit(finalCode);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|