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 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.18', '-v, --version', 'Mostra a versão')
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 || 'nex-project',
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 (sem config, usa global)
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} criado com sucesso!`))
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nex-framework-cli",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "NEX CLI - Command-line interface for NEX Framework and Agent Marketplace",
5
5
  "type": "module",
6
6
  "main": "cli/nex-cli.js",
@@ -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, skip setup
38
+ // If config exists and is valid, ask if user wants to reconfigure
39
39
  if (existingConfig.user && existingConfig.user.name) {
40
- console.log(chalk.green('\n✅ NEX CLI está configurado!'))
41
- console.log(chalk.gray(` Config: ${configPath}`))
42
- console.log(chalk.gray(` Para reconfigurar, delete o arquivo ou execute: nex config reset\n`))
43
- return
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.18'
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.18'
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
- const rulesFile = manifest.bmad?.rules_file
1029
- if (!rulesFile) {
1030
- return // No rules file specified
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
- // Path to .cursorrules file in agent directory
1034
- let agentRulesPath = path.join(sourcePath, rulesFile)
1035
-
1036
- // Check if rules file exists
1037
- if (!await fs.pathExists(agentRulesPath)) {
1038
- // Try alternative locations
1039
- const alternativePaths = [
1040
- path.join(sourcePath, '..', rulesFile), // Parent directory
1041
- path.join(this.registryPath, manifest.category || 'bmad', agentId, rulesFile), // Registry root
1042
- path.join(this.registryPath, 'bmad', agentId, rulesFile) // BMAD category
1043
- ]
1044
-
1045
- let foundPath = null
1046
- for (const altPath of alternativePaths) {
1047
- if (await fs.pathExists(altPath)) {
1048
- foundPath = altPath
1049
- break
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
- if (!foundPath) {
1054
- // Create a basic .cursorrules file from manifest
1055
- const trigger = manifest.bmad?.activation_trigger || `@${agentId}`
1056
- const basicRules = `# ${manifest.name}
1057
- # ${manifest.tagline || manifest.description?.substring(0, 100)}
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
- # Activation: ${trigger}
1089
+ ## Usage
1060
1090
 
1061
- # ${manifest.name} - ${manifest.description || 'BMAD Expert Agent'}
1091
+ \`\`\`
1092
+ ${trigger} <command>
1093
+ \`\`\`
1062
1094
 
1063
- # Usage in Cursor:
1064
- # ${trigger} <command>
1095
+ ## Examples
1065
1096
 
1066
- # Example:
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
- // Check if already imported
1099
- if (cursorRulesContent.includes(importLine) || cursorRulesContent.includes(rulesFile)) {
1100
- // Already integrated, skip
1101
- return
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
- // Add import to .cursorrules
1105
- const newContent = cursorRulesContent +
1106
- (cursorRulesContent ? '\n\n' : '') +
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
- await fs.writeFile(mainCursorRulesPath, newContent, 'utf8')
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(` Added ${rulesFile} to .cursorrules`))
1115
- const trigger = manifest.bmad?.activation_trigger || `@${agentId}`
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
  */