nex-framework-cli 1.0.19 → 1.0.21
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/cli/nex-cli.js +22 -8
- package/package.json +1 -1
- package/scripts/postinstall.js +19 -9
- package/src/services/nex-marketplace/NEXMarketplace.js +150 -76
package/cli/nex-cli.js
CHANGED
|
@@ -28,7 +28,7 @@ program.configureHelp({
|
|
|
28
28
|
program
|
|
29
29
|
.name('nex')
|
|
30
30
|
.description('NEX Framework - Framework completo de agentes AI')
|
|
31
|
-
.version('1.0.
|
|
31
|
+
.version('1.0.20', '-v, --version', 'Mostra a versão')
|
|
32
32
|
.addHelpText('before', chalk.bold.cyan(`
|
|
33
33
|
╔════════════════════════════════════════════════════════════════╗
|
|
34
34
|
║ NEX Framework - CLI v1.0.9 ║
|
|
@@ -64,12 +64,26 @@ Exemplos:
|
|
|
64
64
|
console.log(chalk.blue('🚀 Inicializando projeto NEX...'))
|
|
65
65
|
console.log()
|
|
66
66
|
|
|
67
|
+
// Detectar nome do projeto atual (da pasta ou package.json)
|
|
68
|
+
let currentProjectName = path.basename(process.cwd())
|
|
69
|
+
try {
|
|
70
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json')
|
|
71
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
72
|
+
const packageJson = await fs.readJSON(packageJsonPath)
|
|
73
|
+
if (packageJson.name) {
|
|
74
|
+
currentProjectName = packageJson.name
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// Ignore errors
|
|
79
|
+
}
|
|
80
|
+
|
|
67
81
|
const answers = await inquirer.prompt([
|
|
68
82
|
{
|
|
69
83
|
type: 'input',
|
|
70
84
|
name: 'projectName',
|
|
71
85
|
message: 'Nome do projeto:',
|
|
72
|
-
default: options.name ||
|
|
86
|
+
default: options.name || currentProjectName,
|
|
73
87
|
when: !options.name
|
|
74
88
|
},
|
|
75
89
|
{
|
|
@@ -85,10 +99,10 @@ Exemplos:
|
|
|
85
99
|
const projectName = options.name || answers.projectName
|
|
86
100
|
const template = options.template || answers.template
|
|
87
101
|
|
|
88
|
-
// Criar estrutura do projeto (
|
|
89
|
-
await createProjectStructure(projectName, template)
|
|
102
|
+
// Criar estrutura do projeto no diretório atual (não criar nova pasta)
|
|
103
|
+
await createProjectStructure(projectName, template, true)
|
|
90
104
|
|
|
91
|
-
console.log(chalk.green(`\n✅ Projeto ${projectName}
|
|
105
|
+
console.log(chalk.green(`\n✅ Projeto ${projectName} inicializado com sucesso!`))
|
|
92
106
|
console.log()
|
|
93
107
|
})
|
|
94
108
|
|
|
@@ -351,7 +365,7 @@ configCmd
|
|
|
351
365
|
.description('Reconfigura o NEX CLI (nome, idiomas, integração Cursor)')
|
|
352
366
|
.action(async () => {
|
|
353
367
|
const { runSetup } = await import('../scripts/postinstall.js')
|
|
354
|
-
await runSetup()
|
|
368
|
+
await runSetup(true) // Force reconfiguration
|
|
355
369
|
})
|
|
356
370
|
|
|
357
371
|
configCmd
|
|
@@ -376,8 +390,8 @@ configCmd
|
|
|
376
390
|
})
|
|
377
391
|
|
|
378
392
|
// Funções auxiliares
|
|
379
|
-
async function createProjectStructure(projectName, template) {
|
|
380
|
-
const projectDir = path.join(process.cwd(), projectName)
|
|
393
|
+
async function createProjectStructure(projectName, template, useCurrentDir = false) {
|
|
394
|
+
const projectDir = useCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)
|
|
381
395
|
await fs.ensureDir(projectDir)
|
|
382
396
|
|
|
383
397
|
// Criar estrutura básica
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -27,20 +27,30 @@ export function getGlobalConfigPath() {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export async function runSetup() {
|
|
30
|
+
export async function runSetup(force = false) {
|
|
31
31
|
// Check if config already exists
|
|
32
32
|
const configPath = getGlobalConfigPath()
|
|
33
33
|
const configDir = path.dirname(configPath)
|
|
34
34
|
|
|
35
|
-
if (await fs.pathExists(configPath)) {
|
|
35
|
+
if (!force && await fs.pathExists(configPath)) {
|
|
36
36
|
try {
|
|
37
37
|
const existingConfig = await fs.readJSON(configPath)
|
|
38
|
-
// If config exists and is valid,
|
|
38
|
+
// If config exists and is valid, ask if user wants to reconfigure
|
|
39
39
|
if (existingConfig.user && existingConfig.user.name) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
const { overwrite } = await inquirer.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: 'confirm',
|
|
43
|
+
name: 'overwrite',
|
|
44
|
+
message: 'NEX CLI já está configurado. Deseja reconfigurar?',
|
|
45
|
+
default: false
|
|
46
|
+
}
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
if (!overwrite) {
|
|
50
|
+
console.log(chalk.green('\n✅ Configuração mantida.'))
|
|
51
|
+
console.log(chalk.gray(` Config: ${configPath}\n`))
|
|
52
|
+
return
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
} catch (error) {
|
|
46
56
|
// Config file exists but is invalid, continue with setup
|
|
@@ -106,7 +116,7 @@ export async function runSetup() {
|
|
|
106
116
|
enabled: answers.cursorIntegration
|
|
107
117
|
},
|
|
108
118
|
installedAt: new Date().toISOString(),
|
|
109
|
-
version: '1.0.
|
|
119
|
+
version: '1.0.20'
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
// Save config
|
|
@@ -152,7 +162,7 @@ if (!isCI && !skipSetup && isInteractive) {
|
|
|
152
162
|
enabled: false
|
|
153
163
|
},
|
|
154
164
|
installedAt: new Date().toISOString(),
|
|
155
|
-
version: '1.0.
|
|
165
|
+
version: '1.0.20'
|
|
156
166
|
}
|
|
157
167
|
|
|
158
168
|
fs.ensureDir(configDir)
|
|
@@ -1021,99 +1021,103 @@ export default class NEXMarketplace {
|
|
|
1021
1021
|
}
|
|
1022
1022
|
|
|
1023
1023
|
/**
|
|
1024
|
-
* Integrate BMAD agent with Cursor
|
|
1024
|
+
* Integrate BMAD agent with Cursor (following BMAD pattern)
|
|
1025
|
+
* Creates .mdc files in .cursor/rules/nex/ similar to BMAD
|
|
1025
1026
|
*/
|
|
1026
1027
|
async integrateWithCursor(agentId, manifest, sourcePath) {
|
|
1027
1028
|
try {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1029
|
+
// Get global config for user info
|
|
1030
|
+
const globalConfig = this.getGlobalConfig()
|
|
1031
|
+
const userConfig = globalConfig.user || {}
|
|
1032
|
+
|
|
1033
|
+
// Create NEX core config directory (similar to BMAD)
|
|
1034
|
+
const nexCoreDir = path.join(this.projectRoot, 'nex', 'core')
|
|
1035
|
+
await fs.ensureDir(nexCoreDir)
|
|
1036
|
+
|
|
1037
|
+
// Create config.yaml (similar to BMAD)
|
|
1038
|
+
const configYaml = {
|
|
1039
|
+
user_name: userConfig.name || 'Developer',
|
|
1040
|
+
communication_language: userConfig.conversationLanguage || 'pt-br',
|
|
1041
|
+
document_output_language: userConfig.documentLanguage || 'pt-br',
|
|
1042
|
+
output_folder: '{project-root}/docs'
|
|
1031
1043
|
}
|
|
1032
1044
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1045
|
+
const configPath = path.join(nexCoreDir, 'config.yaml')
|
|
1046
|
+
if (!await fs.pathExists(configPath)) {
|
|
1047
|
+
const configYamlContent = yaml.stringify(configYaml)
|
|
1048
|
+
await fs.writeFile(configPath, configYamlContent, 'utf8')
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// Create .cursor/rules/nex directory structure (following BMAD pattern)
|
|
1052
|
+
const cursorRulesDir = path.join(this.projectRoot, '.cursor', 'rules', 'nex')
|
|
1053
|
+
const agentCategory = manifest.category || 'bmad'
|
|
1054
|
+
const agentRulesDir = path.join(cursorRulesDir, agentCategory, 'agents')
|
|
1055
|
+
await fs.ensureDir(agentRulesDir)
|
|
1056
|
+
|
|
1057
|
+
// Check if agent has a README.md or similar file to convert to .mdc
|
|
1058
|
+
let agentContent = ''
|
|
1059
|
+
const possibleAgentFiles = [
|
|
1060
|
+
path.join(sourcePath, 'README.md'),
|
|
1061
|
+
path.join(sourcePath, `${agentId}.md`),
|
|
1062
|
+
path.join(sourcePath, 'agent.md')
|
|
1063
|
+
]
|
|
1064
|
+
|
|
1065
|
+
let agentFile = null
|
|
1066
|
+
for (const filePath of possibleAgentFiles) {
|
|
1067
|
+
if (await fs.pathExists(filePath)) {
|
|
1068
|
+
agentFile = filePath
|
|
1069
|
+
agentContent = await fs.readFile(filePath, 'utf8')
|
|
1070
|
+
break
|
|
1051
1071
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// If no agent file found, create one from manifest
|
|
1075
|
+
if (!agentFile) {
|
|
1076
|
+
const trigger = manifest.bmad?.activation_trigger || `@${agentId}`
|
|
1077
|
+
agentContent = `# ${manifest.name}
|
|
1078
|
+
|
|
1079
|
+
${manifest.tagline || manifest.description || ''}
|
|
1080
|
+
|
|
1081
|
+
## Activation
|
|
1082
|
+
|
|
1083
|
+
Use \`${trigger}\` in Cursor to activate this agent.
|
|
1084
|
+
|
|
1085
|
+
## Description
|
|
1086
|
+
|
|
1087
|
+
${manifest.long_description || manifest.description || 'NEX Agent'}
|
|
1058
1088
|
|
|
1059
|
-
|
|
1089
|
+
## Usage
|
|
1060
1090
|
|
|
1061
|
-
|
|
1091
|
+
\`\`\`
|
|
1092
|
+
${trigger} <command>
|
|
1093
|
+
\`\`\`
|
|
1062
1094
|
|
|
1063
|
-
|
|
1064
|
-
# ${trigger} <command>
|
|
1095
|
+
## Examples
|
|
1065
1096
|
|
|
1066
|
-
|
|
1067
|
-
# ${trigger} analyze-page https://example.com
|
|
1097
|
+
${trigger} analyze-page https://example.com
|
|
1068
1098
|
`
|
|
1069
|
-
|
|
1070
|
-
// Write basic rules file to agent directory
|
|
1071
|
-
await fs.writeFile(agentRulesPath, basicRules, 'utf8')
|
|
1072
|
-
console.log(chalk.cyan(`\n📝 Created basic Cursor rules file: ${rulesFile}`))
|
|
1073
|
-
} else {
|
|
1074
|
-
agentRulesPath = foundPath
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
// Create .cursorrules directory in project (for storing individual agent rules)
|
|
1079
|
-
const cursorRulesDir = path.join(this.projectRoot, '.cursorrules')
|
|
1080
|
-
await fs.ensureDir(cursorRulesDir)
|
|
1081
|
-
|
|
1082
|
-
// Copy rules file to .cursorrules directory
|
|
1083
|
-
const targetRulesPath = path.join(cursorRulesDir, rulesFile)
|
|
1084
|
-
await fs.copy(agentRulesPath, targetRulesPath)
|
|
1085
|
-
|
|
1086
|
-
// Update main .cursorrules file (in project root)
|
|
1087
|
-
const mainCursorRulesPath = path.join(this.projectRoot, '.cursorrules')
|
|
1088
|
-
const importLine = `import .cursorrules/${rulesFile}`
|
|
1089
|
-
const commentLine = `# ${manifest.name} - ${manifest.tagline || manifest.description?.substring(0, 50)}`
|
|
1090
|
-
const trigger = manifest.bmad?.activation_trigger || `@${agentId}`
|
|
1091
|
-
const agentComment = `# Use: ${trigger} <command>`
|
|
1092
|
-
|
|
1093
|
-
let cursorRulesContent = ''
|
|
1094
|
-
if (await fs.pathExists(mainCursorRulesPath)) {
|
|
1095
|
-
cursorRulesContent = await fs.readFile(mainCursorRulesPath, 'utf8')
|
|
1096
1099
|
}
|
|
1097
1100
|
|
|
1098
|
-
//
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1101
|
+
// Convert to .mdc format (similar to BMAD)
|
|
1102
|
+
const mdcContent = `---
|
|
1103
|
+
description: ${manifest.name} - ${manifest.tagline || manifest.description?.substring(0, 100) || 'NEX Agent'}
|
|
1104
|
+
globs:
|
|
1105
|
+
alwaysApply: false
|
|
1106
|
+
---
|
|
1107
|
+
|
|
1108
|
+
${agentContent}`
|
|
1103
1109
|
|
|
1104
|
-
//
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
commentLine + '\n' +
|
|
1108
|
-
agentComment + '\n' +
|
|
1109
|
-
importLine + '\n'
|
|
1110
|
+
// Write .mdc file
|
|
1111
|
+
const mdcPath = path.join(agentRulesDir, `${agentId}.mdc`)
|
|
1112
|
+
await fs.writeFile(mdcPath, mdcContent, 'utf8')
|
|
1110
1113
|
|
|
1111
|
-
|
|
1114
|
+
// Update index.mdc (similar to BMAD index)
|
|
1115
|
+
await this.updateNexIndex(agentId, manifest, agentCategory)
|
|
1112
1116
|
|
|
1117
|
+
const agentTrigger = manifest.bmad?.activation_trigger || `@${agentId}`
|
|
1113
1118
|
console.log(chalk.green(`\n✅ Cursor integration complete!`))
|
|
1114
|
-
console.log(chalk.gray(`
|
|
1115
|
-
|
|
1116
|
-
console.log(chalk.gray(` Use: ${trigger} <command> in Cursor\n`))
|
|
1119
|
+
console.log(chalk.gray(` Agent installed in: .cursor/rules/nex/${agentCategory}/agents/${agentId}.mdc`))
|
|
1120
|
+
console.log(chalk.gray(` Use: ${agentTrigger} or @nex/${agentCategory}/agents/${agentId} in Cursor\n`))
|
|
1117
1121
|
|
|
1118
1122
|
} catch (error) {
|
|
1119
1123
|
console.log(chalk.yellow(`\n⚠️ Cursor integration failed: ${error.message}`))
|
|
@@ -1121,6 +1125,76 @@ export default class NEXMarketplace {
|
|
|
1121
1125
|
}
|
|
1122
1126
|
}
|
|
1123
1127
|
|
|
1128
|
+
/**
|
|
1129
|
+
* Update NEX index.mdc file (similar to BMAD index)
|
|
1130
|
+
*/
|
|
1131
|
+
async updateNexIndex(agentId, manifest, category) {
|
|
1132
|
+
const indexPath = path.join(this.projectRoot, '.cursor', 'rules', 'nex', 'index.mdc')
|
|
1133
|
+
const indexDir = path.dirname(indexPath)
|
|
1134
|
+
await fs.ensureDir(indexDir)
|
|
1135
|
+
|
|
1136
|
+
let indexContent = ''
|
|
1137
|
+
if (await fs.pathExists(indexPath)) {
|
|
1138
|
+
indexContent = await fs.readFile(indexPath, 'utf8')
|
|
1139
|
+
} else {
|
|
1140
|
+
// Create initial index
|
|
1141
|
+
indexContent = `---
|
|
1142
|
+
description: NEX Framework - Master Index
|
|
1143
|
+
globs:
|
|
1144
|
+
alwaysApply: true
|
|
1145
|
+
---
|
|
1146
|
+
|
|
1147
|
+
# NEX Framework - Cursor Rules Index
|
|
1148
|
+
|
|
1149
|
+
This is the master index for all NEX agents available in your project.
|
|
1150
|
+
|
|
1151
|
+
## Installation Complete!
|
|
1152
|
+
|
|
1153
|
+
NEX rules have been installed to: \`.cursor/rules/nex/\`
|
|
1154
|
+
|
|
1155
|
+
**Note:** NEX does not modify your \`.cursorrules\` file. You manage that separately.
|
|
1156
|
+
|
|
1157
|
+
## How to Use
|
|
1158
|
+
|
|
1159
|
+
- Reference specific agents: @nex/{category}/agents/{agent-name}
|
|
1160
|
+
- Reference this index: @nex/index
|
|
1161
|
+
|
|
1162
|
+
## Available Agents
|
|
1163
|
+
|
|
1164
|
+
`
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// Check if agent is already listed
|
|
1168
|
+
const agentRef = `@nex/${category}/agents/${agentId}`
|
|
1169
|
+
if (indexContent.includes(agentRef)) {
|
|
1170
|
+
return // Already listed
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// Add agent to index
|
|
1174
|
+
const categorySection = `### ${category.toUpperCase()}\n\n**Agents:**\n`
|
|
1175
|
+
if (!indexContent.includes(categorySection)) {
|
|
1176
|
+
indexContent += categorySection
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
const agentEntry = `- ${agentRef} - ${manifest.name}\n`
|
|
1180
|
+
if (!indexContent.includes(agentEntry)) {
|
|
1181
|
+
// Find the category section and add agent
|
|
1182
|
+
const categoryIndex = indexContent.indexOf(`### ${category.toUpperCase()}`)
|
|
1183
|
+
if (categoryIndex !== -1) {
|
|
1184
|
+
const agentsIndex = indexContent.indexOf('**Agents:**', categoryIndex)
|
|
1185
|
+
if (agentsIndex !== -1) {
|
|
1186
|
+
const insertIndex = indexContent.indexOf('\n', agentsIndex) + 1
|
|
1187
|
+
indexContent = indexContent.slice(0, insertIndex) + agentEntry + indexContent.slice(insertIndex)
|
|
1188
|
+
}
|
|
1189
|
+
} else {
|
|
1190
|
+
// Category doesn't exist, add it
|
|
1191
|
+
indexContent += `### ${category.toUpperCase()}\n\n**Agents:**\n${agentEntry}\n\n`
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
await fs.writeFile(indexPath, indexContent, 'utf8')
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1124
1198
|
/**
|
|
1125
1199
|
* Get latest version of agent
|
|
1126
1200
|
*/
|