nex-framework-cli 1.0.20 → 1.0.22

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.19', '-v, --version', 'Mostra a versão')
31
+ .version('1.0.21', '-v, --version', 'Mostra a versão')
32
32
  .addHelpText('before', chalk.bold.cyan(`
33
33
  ╔════════════════════════════════════════════════════════════════╗
34
34
  ║ NEX Framework - CLI v1.0.9 ║
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nex-framework-cli",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
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",
@@ -116,7 +116,7 @@ export async function runSetup(force = false) {
116
116
  enabled: answers.cursorIntegration
117
117
  },
118
118
  installedAt: new Date().toISOString(),
119
- version: '1.0.19'
119
+ version: '1.0.21'
120
120
  }
121
121
 
122
122
  // Save config
@@ -132,48 +132,39 @@ export async function runSetup(force = false) {
132
132
  console.log(chalk.cyan('\n💡 Dica: Para reconfigurar, execute: nex config reset\n'))
133
133
  }
134
134
 
135
- // Check if running in interactive mode (TTY available)
136
- const isInteractive = process.stdin.isTTY && process.stdout.isTTY && process.stderr.isTTY
137
- const isCI = process.env.CI === 'true'
138
- const skipSetup = process.env.NEX_SKIP_SETUP === 'true'
139
-
140
- // Only run interactive setup if:
141
- // 1. Not in CI
142
- // 2. Not explicitly skipped
143
- // 3. Running in interactive mode (TTY)
144
- if (!isCI && !skipSetup && isInteractive) {
145
- runSetup().catch((error) => {
146
- console.error(chalk.red('\n❌ Erro ao configurar NEX CLI:'))
147
- console.error(chalk.red(error.message))
148
- console.log(chalk.yellow('\n💡 Você pode configurar manualmente depois executando: nex config reset\n'))
149
- process.exit(0) // Don't fail the install
150
- })
151
- } else {
152
- // Non-interactive mode: create default config silently
153
- const configPath = getGlobalConfigPath()
154
- const configDir = path.dirname(configPath)
155
- const defaultConfig = {
156
- user: {
157
- name: process.env.USER || process.env.USERNAME || 'Developer',
158
- conversationLanguage: 'pt-BR',
159
- documentLanguage: 'pt-BR'
160
- },
135
+ // Always create default config silently (fast, non-blocking)
136
+ // User can configure later with: nex config reset
137
+ const configPath = getGlobalConfigPath()
138
+ const configDir = path.dirname(configPath)
139
+ const defaultConfig = {
140
+ user: {
141
+ name: process.env.USER || process.env.USERNAME || 'Developer',
142
+ conversationLanguage: 'pt-BR',
143
+ documentLanguage: 'pt-BR'
144
+ },
161
145
  cursor: {
162
146
  enabled: false
163
147
  },
164
148
  installedAt: new Date().toISOString(),
165
- version: '1.0.19'
149
+ version: '1.0.21'
166
150
  }
167
-
168
- fs.ensureDir(configDir)
169
- .then(() => fs.writeJSON(configPath, defaultConfig, { spaces: 2 }))
170
- .then(() => {
171
- if (!isCI && isInteractive) {
172
- console.log(chalk.green('\n✅ NEX CLI instalado com configuração padrão'))
173
- console.log(chalk.gray(' Para configurar: nex config reset\n'))
174
- }
175
- })
176
- .catch(() => {
177
- // Silently fail in non-interactive mode
178
- })
179
- }
151
+
152
+ // Create config asynchronously without blocking
153
+ fs.ensureDir(configDir)
154
+ .then(() => fs.writeJSON(configPath, defaultConfig, { spaces: 2 }))
155
+ .then(() => {
156
+ // Only show message if in interactive mode and not CI
157
+ const isInteractive = process.stdin.isTTY && process.stdout.isTTY && process.stderr.isTTY
158
+ const isCI = process.env.CI === 'true'
159
+ if (!isCI && isInteractive) {
160
+ console.log(chalk.green('\n✅ NEX CLI instalado com configuração padrão'))
161
+ console.log(chalk.gray(' Para configurar: nex config reset\n'))
162
+ }
163
+ })
164
+ .catch(() => {
165
+ // Silently fail - don't block installation
166
+ })
167
+ .finally(() => {
168
+ // Always exit successfully to not block npm install
169
+ process.exit(0)
170
+ })
@@ -1021,98 +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
1099
  }
1077
1100
 
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 agentTrigger = manifest.bmad?.activation_trigger || `@${agentId}`
1091
- const agentComment = `# Use: ${agentTrigger} <command>`
1092
-
1093
- let cursorRulesContent = ''
1094
- if (await fs.pathExists(mainCursorRulesPath)) {
1095
- cursorRulesContent = await fs.readFile(mainCursorRulesPath, 'utf8')
1096
- }
1097
-
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
- console.log(chalk.gray(` Use: ${agentTrigger} <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`))
1116
1121
 
1117
1122
  } catch (error) {
1118
1123
  console.log(chalk.yellow(`\n⚠️ Cursor integration failed: ${error.message}`))
@@ -1120,6 +1125,76 @@ export default class NEXMarketplace {
1120
1125
  }
1121
1126
  }
1122
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
+
1123
1198
  /**
1124
1199
  * Get latest version of agent
1125
1200
  */