nex-framework-cli 1.0.1
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/LICENSE +51 -0
- package/README.md +484 -0
- package/cli/nex-cli.js +321 -0
- package/package.json +56 -0
- package/registry/.meta/registry.yaml +72 -0
- package/registry/README.md +181 -0
- package/registry/bmad/README.md +433 -0
- package/registry/bmad/ada/manifest.yaml +205 -0
- package/registry/bmad/rex/manifest.yaml +242 -0
- package/registry/bmad/vex/README.md +500 -0
- package/registry/bmad/vex/manifest.yaml +242 -0
- package/registry/planning/anx/CHANGELOG.md +63 -0
- package/registry/planning/anx/README.md +224 -0
- package/registry/planning/anx/manifest.yaml +172 -0
- package/registry/planning/arx/manifest.yaml +98 -0
- package/registry/planning/pmx/manifest.yaml +96 -0
- package/src/services/nex-installer/agentLoader.js +108 -0
- package/src/services/nex-installer/agentValidator.js +93 -0
- package/src/services/nex-installer/dependencyResolver.js +59 -0
- package/src/services/nex-installer/installer.js +226 -0
- package/src/services/nex-installer/registry.js +75 -0
- package/src/services/nex-marketplace/NEXMarketplace.js +964 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# NEX Agent Manifest
|
|
2
|
+
id: arx
|
|
3
|
+
name: "ARX - Architecture Expert"
|
|
4
|
+
tagline: "System Architecture & Technical Design"
|
|
5
|
+
icon: "🏗️"
|
|
6
|
+
type: planning
|
|
7
|
+
category: planning
|
|
8
|
+
subcategory: OPX
|
|
9
|
+
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
semantic_version:
|
|
12
|
+
major: 1
|
|
13
|
+
minor: 0
|
|
14
|
+
patch: 0
|
|
15
|
+
|
|
16
|
+
author:
|
|
17
|
+
name: INOSX
|
|
18
|
+
email: contact@inosx.com
|
|
19
|
+
github: INOSX
|
|
20
|
+
organization: INOSX
|
|
21
|
+
|
|
22
|
+
description: |
|
|
23
|
+
Expert em arquitetura de sistemas e design técnico.
|
|
24
|
+
Projeta soluções escaláveis e manuteníveis.
|
|
25
|
+
|
|
26
|
+
long_description: |
|
|
27
|
+
ARX é o arquiteto especialista do NEX Framework.
|
|
28
|
+
Cria designs de arquitetura completos, diagramas, decisões técnicas
|
|
29
|
+
e documentação de infraestrutura baseada em requisitos e PRDs.
|
|
30
|
+
|
|
31
|
+
tags:
|
|
32
|
+
- architecture
|
|
33
|
+
- system-design
|
|
34
|
+
- technical-design
|
|
35
|
+
- infrastructure
|
|
36
|
+
- scalability
|
|
37
|
+
- patterns
|
|
38
|
+
|
|
39
|
+
compatibility:
|
|
40
|
+
nex_version: ">=1.0.0"
|
|
41
|
+
node_version: ">=18.0.0"
|
|
42
|
+
os: ["windows", "macos", "linux"]
|
|
43
|
+
|
|
44
|
+
dependencies:
|
|
45
|
+
agents:
|
|
46
|
+
- pmx # Recebe PRDs
|
|
47
|
+
tools:
|
|
48
|
+
- supabase
|
|
49
|
+
- ai-provider
|
|
50
|
+
optional_agents:
|
|
51
|
+
- dvx
|
|
52
|
+
|
|
53
|
+
capabilities:
|
|
54
|
+
- Architecture design
|
|
55
|
+
- System diagrams generation
|
|
56
|
+
- Technology stack recommendation
|
|
57
|
+
- Database schema design
|
|
58
|
+
- API design
|
|
59
|
+
- Infrastructure planning
|
|
60
|
+
- Scalability analysis
|
|
61
|
+
- Security architecture
|
|
62
|
+
|
|
63
|
+
commands:
|
|
64
|
+
- trigger: design
|
|
65
|
+
description: Criar design de arquitetura completo
|
|
66
|
+
- trigger: diagram
|
|
67
|
+
description: Gerar diagramas técnicos
|
|
68
|
+
- trigger: stack
|
|
69
|
+
description: Recomendar tech stack
|
|
70
|
+
|
|
71
|
+
installation:
|
|
72
|
+
size_mb: 2.5
|
|
73
|
+
install_time_minutes: 1
|
|
74
|
+
complexity: simple
|
|
75
|
+
|
|
76
|
+
pricing:
|
|
77
|
+
model: free
|
|
78
|
+
price: 0
|
|
79
|
+
license: PROPRIETARY
|
|
80
|
+
|
|
81
|
+
stats:
|
|
82
|
+
installs: 0
|
|
83
|
+
stars: 0
|
|
84
|
+
rating: 0
|
|
85
|
+
last_updated: "2026-01-09"
|
|
86
|
+
|
|
87
|
+
links:
|
|
88
|
+
repository: https://github.com/INOSX/nex-agents
|
|
89
|
+
documentation: https://docs.inosx.com/nex/agents/arx
|
|
90
|
+
homepage: https://inosx.com/nex
|
|
91
|
+
|
|
92
|
+
metadata:
|
|
93
|
+
is_official: true
|
|
94
|
+
is_verified: true
|
|
95
|
+
maturity: stable
|
|
96
|
+
support_level: full
|
|
97
|
+
language: javascript
|
|
98
|
+
framework: NEX
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# NEX Agent Manifest
|
|
2
|
+
id: pmx
|
|
3
|
+
name: "PMX - Product Management Expert"
|
|
4
|
+
tagline: "Strategic Product Planning & PRD Generation"
|
|
5
|
+
icon: "📊"
|
|
6
|
+
type: planning
|
|
7
|
+
category: planning
|
|
8
|
+
subcategory: FLX
|
|
9
|
+
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
semantic_version:
|
|
12
|
+
major: 1
|
|
13
|
+
minor: 0
|
|
14
|
+
patch: 0
|
|
15
|
+
|
|
16
|
+
author:
|
|
17
|
+
name: INOSX
|
|
18
|
+
email: contact@inosx.com
|
|
19
|
+
github: INOSX
|
|
20
|
+
organization: INOSX
|
|
21
|
+
|
|
22
|
+
description: |
|
|
23
|
+
Expert em gestão de produto e criação de Product Requirements Documents (PRDs).
|
|
24
|
+
Transforma análises em estratégias de produto executáveis.
|
|
25
|
+
|
|
26
|
+
long_description: |
|
|
27
|
+
PMX é o especialista em Product Management do NEX Framework.
|
|
28
|
+
Trabalha em conjunto com ANX para transformar análises de requisitos
|
|
29
|
+
em PRDs completos, roadmaps e estratégias de produto.
|
|
30
|
+
|
|
31
|
+
tags:
|
|
32
|
+
- product-management
|
|
33
|
+
- prd
|
|
34
|
+
- strategy
|
|
35
|
+
- planning
|
|
36
|
+
- roadmap
|
|
37
|
+
- product-strategy
|
|
38
|
+
|
|
39
|
+
compatibility:
|
|
40
|
+
nex_version: ">=1.0.0"
|
|
41
|
+
node_version: ">=18.0.0"
|
|
42
|
+
os: ["windows", "macos", "linux"]
|
|
43
|
+
|
|
44
|
+
dependencies:
|
|
45
|
+
agents:
|
|
46
|
+
- anx # Recebe input do Analysis Expert
|
|
47
|
+
tools:
|
|
48
|
+
- supabase
|
|
49
|
+
- ai-provider
|
|
50
|
+
optional_agents:
|
|
51
|
+
- arx
|
|
52
|
+
|
|
53
|
+
capabilities:
|
|
54
|
+
- PRD generation
|
|
55
|
+
- Product strategy definition
|
|
56
|
+
- Roadmap creation
|
|
57
|
+
- Feature prioritization
|
|
58
|
+
- Success metrics definition
|
|
59
|
+
- Go-to-market planning
|
|
60
|
+
|
|
61
|
+
commands:
|
|
62
|
+
- trigger: create-prd
|
|
63
|
+
description: Gerar PRD completo
|
|
64
|
+
- trigger: create-roadmap
|
|
65
|
+
description: Criar roadmap de produto
|
|
66
|
+
- trigger: prioritize
|
|
67
|
+
description: Priorizar features
|
|
68
|
+
|
|
69
|
+
installation:
|
|
70
|
+
size_mb: 2.3
|
|
71
|
+
install_time_minutes: 1
|
|
72
|
+
complexity: simple
|
|
73
|
+
|
|
74
|
+
pricing:
|
|
75
|
+
model: free
|
|
76
|
+
price: 0
|
|
77
|
+
license: PROPRIETARY
|
|
78
|
+
|
|
79
|
+
stats:
|
|
80
|
+
installs: 0
|
|
81
|
+
stars: 0
|
|
82
|
+
rating: 0
|
|
83
|
+
last_updated: "2026-01-09"
|
|
84
|
+
|
|
85
|
+
links:
|
|
86
|
+
repository: https://github.com/INOSX/nex-agents
|
|
87
|
+
documentation: https://docs.inosx.com/nex/agents/pmx
|
|
88
|
+
homepage: https://inosx.com/nex
|
|
89
|
+
|
|
90
|
+
metadata:
|
|
91
|
+
is_official: true
|
|
92
|
+
is_verified: true
|
|
93
|
+
maturity: stable
|
|
94
|
+
support_level: full
|
|
95
|
+
language: javascript
|
|
96
|
+
framework: NEX
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Loader - Carrega agentes instalados
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs-extra'
|
|
5
|
+
import path from 'path'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = path.dirname(__filename)
|
|
10
|
+
|
|
11
|
+
export default class AgentLoader {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.agentsDir = path.join(process.cwd(), '.nex-core', 'agents')
|
|
14
|
+
this.loadedAgents = new Map()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Carrega agente instalado
|
|
19
|
+
*/
|
|
20
|
+
async loadAgent(agentId) {
|
|
21
|
+
if (this.loadedAgents.has(agentId)) {
|
|
22
|
+
return this.loadedAgents.get(agentId)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const agentDir = path.join(this.agentsDir, agentId)
|
|
26
|
+
|
|
27
|
+
if (!await fs.pathExists(agentDir)) {
|
|
28
|
+
throw new Error(`Agente ${agentId} não encontrado`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Ler manifest
|
|
32
|
+
const manifestPath = path.join(agentDir, 'manifest.json')
|
|
33
|
+
const manifest = await fs.readJSON(manifestPath)
|
|
34
|
+
|
|
35
|
+
// Encontrar arquivo principal
|
|
36
|
+
const mainFile = await this.findMainFile(agentDir)
|
|
37
|
+
|
|
38
|
+
// Carregar módulo
|
|
39
|
+
const agentModule = await import(mainFile)
|
|
40
|
+
const AgentClass = agentModule.default || agentModule[manifest.name]
|
|
41
|
+
|
|
42
|
+
if (!AgentClass) {
|
|
43
|
+
throw new Error(`Classe do agente não encontrada em ${mainFile}`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const agent = new AgentClass()
|
|
47
|
+
|
|
48
|
+
// Armazenar em cache
|
|
49
|
+
this.loadedAgents.set(agentId, {
|
|
50
|
+
agent,
|
|
51
|
+
manifest,
|
|
52
|
+
path: agentDir
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
agent,
|
|
57
|
+
manifest,
|
|
58
|
+
path: agentDir
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Encontra arquivo principal do agente
|
|
64
|
+
*/
|
|
65
|
+
async findMainFile(agentDir) {
|
|
66
|
+
const possibleFiles = ['agent.js', 'index.js', 'main.js', `${path.basename(agentDir)}.js`]
|
|
67
|
+
|
|
68
|
+
for (const file of possibleFiles) {
|
|
69
|
+
const filePath = path.join(agentDir, file)
|
|
70
|
+
if (await fs.pathExists(filePath)) {
|
|
71
|
+
return filePath
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
throw new Error('Arquivo principal do agente não encontrado')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Lista agentes disponíveis para carregar
|
|
80
|
+
*/
|
|
81
|
+
async listAvailable() {
|
|
82
|
+
if (!await fs.pathExists(this.agentsDir)) {
|
|
83
|
+
return []
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const dirs = await fs.readdir(this.agentsDir)
|
|
87
|
+
const agents = []
|
|
88
|
+
|
|
89
|
+
for (const dir of dirs) {
|
|
90
|
+
const agentDir = path.join(this.agentsDir, dir)
|
|
91
|
+
const stat = await fs.stat(agentDir)
|
|
92
|
+
|
|
93
|
+
if (stat.isDirectory()) {
|
|
94
|
+
const manifestPath = path.join(agentDir, 'manifest.json')
|
|
95
|
+
if (await fs.pathExists(manifestPath)) {
|
|
96
|
+
const manifest = await fs.readJSON(manifestPath)
|
|
97
|
+
agents.push({
|
|
98
|
+
id: dir,
|
|
99
|
+
...manifest
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return agents
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Validator - Valida agentes antes da instalação
|
|
3
|
+
*/
|
|
4
|
+
export default class AgentValidator {
|
|
5
|
+
/**
|
|
6
|
+
* Valida estrutura do agente
|
|
7
|
+
*/
|
|
8
|
+
async validate(agentData) {
|
|
9
|
+
const errors = []
|
|
10
|
+
|
|
11
|
+
// Validar campos obrigatórios
|
|
12
|
+
if (!agentData.id) {
|
|
13
|
+
errors.push('ID do agente é obrigatório')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!agentData.version) {
|
|
17
|
+
errors.push('Versão do agente é obrigatória')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!agentData.name) {
|
|
21
|
+
errors.push('Nome do agente é obrigatório')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validar formato do ID
|
|
25
|
+
if (agentData.id && !/^[a-z0-9-_]+$/i.test(agentData.id)) {
|
|
26
|
+
errors.push('ID do agente contém caracteres inválidos')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Validar versão (semver)
|
|
30
|
+
if (agentData.version && !this.isValidVersion(agentData.version)) {
|
|
31
|
+
errors.push('Versão inválida (deve seguir semver)')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Validar arquivos
|
|
35
|
+
if (!agentData.files || Object.keys(agentData.files).length === 0) {
|
|
36
|
+
errors.push('Agente deve conter pelo menos um arquivo')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Validar que há um arquivo principal
|
|
40
|
+
const hasMainFile = Object.keys(agentData.files || {}).some(f =>
|
|
41
|
+
f.includes('agent.js') || f.includes('index.js') || f.includes('main.js')
|
|
42
|
+
)
|
|
43
|
+
if (!hasMainFile) {
|
|
44
|
+
errors.push('Agente deve conter arquivo principal (agent.js, index.js ou main.js)')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
valid: errors.length === 0,
|
|
49
|
+
errors
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Valida versão semver
|
|
55
|
+
*/
|
|
56
|
+
isValidVersion(version) {
|
|
57
|
+
if (version === 'latest') return true
|
|
58
|
+
return /^\d+\.\d+\.\d+(-.+)?$/.test(version)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Valida dependências
|
|
63
|
+
*/
|
|
64
|
+
validateDependencies(dependencies) {
|
|
65
|
+
const errors = []
|
|
66
|
+
|
|
67
|
+
if (!Array.isArray(dependencies)) {
|
|
68
|
+
errors.push('Dependências devem ser um array')
|
|
69
|
+
return { valid: false, errors }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const dep of dependencies) {
|
|
73
|
+
if (typeof dep === 'string') {
|
|
74
|
+
if (!/^[a-z0-9-_]+(@.+)?$/i.test(dep)) {
|
|
75
|
+
errors.push(`Dependência inválida: ${dep}`)
|
|
76
|
+
}
|
|
77
|
+
} else if (typeof dep === 'object') {
|
|
78
|
+
if (!dep.id) {
|
|
79
|
+
errors.push('Dependência deve ter ID')
|
|
80
|
+
}
|
|
81
|
+
if (dep.version && !this.isValidVersion(dep.version)) {
|
|
82
|
+
errors.push(`Versão de dependência inválida: ${dep.version}`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
valid: errors.length === 0,
|
|
89
|
+
errors
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Resolver - Resolve dependências de agentes
|
|
3
|
+
*/
|
|
4
|
+
import Registry from './registry.js'
|
|
5
|
+
|
|
6
|
+
export default class DependencyResolver {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.registry = new Registry()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve dependências
|
|
13
|
+
*/
|
|
14
|
+
async resolve(dependencies) {
|
|
15
|
+
const resolved = []
|
|
16
|
+
const missing = []
|
|
17
|
+
|
|
18
|
+
for (const dep of dependencies) {
|
|
19
|
+
const depId = typeof dep === 'string' ? dep.split('@')[0] : dep.id
|
|
20
|
+
const installed = await this.registry.isInstalled(depId)
|
|
21
|
+
|
|
22
|
+
if (installed) {
|
|
23
|
+
resolved.push({
|
|
24
|
+
id: depId,
|
|
25
|
+
installed: true,
|
|
26
|
+
version: installed.version
|
|
27
|
+
})
|
|
28
|
+
} else {
|
|
29
|
+
missing.push(depId)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
resolved,
|
|
35
|
+
missing,
|
|
36
|
+
allResolved: missing.length === 0
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Instala dependências faltando
|
|
42
|
+
*/
|
|
43
|
+
async installMissing(missing, installer) {
|
|
44
|
+
const results = []
|
|
45
|
+
|
|
46
|
+
for (const depId of missing) {
|
|
47
|
+
try {
|
|
48
|
+
console.log(`[DependencyResolver] 📦 Instalando dependência: ${depId}`)
|
|
49
|
+
const result = await installer.installFromURL(`nex://install?agentId=${depId}`)
|
|
50
|
+
results.push({ id: depId, success: true, result })
|
|
51
|
+
} catch (error) {
|
|
52
|
+
results.push({ id: depId, success: false, error: error.message })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return results
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEX Agent Installer - Sistema de instalação de agentes
|
|
3
|
+
* Suporta protocolo nex://install?agentId=xxx&version=1.0.0
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
8
|
+
import AgentValidator from './agentValidator.js'
|
|
9
|
+
import DependencyResolver from './dependencyResolver.js'
|
|
10
|
+
import AgentLoader from './agentLoader.js'
|
|
11
|
+
import Registry from './registry.js'
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
14
|
+
const __dirname = path.dirname(__filename)
|
|
15
|
+
|
|
16
|
+
export default class AgentInstaller {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.agentsDir = path.join(process.cwd(), '.nex-core', 'agents')
|
|
19
|
+
this.validator = new AgentValidator()
|
|
20
|
+
this.dependencyResolver = new DependencyResolver()
|
|
21
|
+
this.loader = new AgentLoader()
|
|
22
|
+
this.registry = new Registry()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Instala agente a partir de URL nex://
|
|
27
|
+
*/
|
|
28
|
+
async installFromURL(nexURL) {
|
|
29
|
+
console.log('[Installer] 📦 Instalando agente de:', nexURL)
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
// Parsear URL nex://
|
|
33
|
+
const params = this.parseNexURL(nexURL)
|
|
34
|
+
const { agentId, version } = params
|
|
35
|
+
|
|
36
|
+
if (!agentId) {
|
|
37
|
+
throw new Error('agentId é obrigatório na URL')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Baixar agente da NEX Store
|
|
41
|
+
const agentData = await this.downloadAgent(agentId, version)
|
|
42
|
+
|
|
43
|
+
// Instalar agente
|
|
44
|
+
return await this.installAgent(agentData, agentId, version)
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('[Installer] ❌ Erro ao instalar agente:', error)
|
|
47
|
+
throw error
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Instala agente a partir de dados
|
|
53
|
+
*/
|
|
54
|
+
async installAgent(agentData, agentId, version = 'latest') {
|
|
55
|
+
console.log(`[Installer] 📦 Instalando agente: ${agentId}@${version}`)
|
|
56
|
+
|
|
57
|
+
// Validar agente
|
|
58
|
+
const validation = await this.validator.validate(agentData)
|
|
59
|
+
if (!validation.valid) {
|
|
60
|
+
throw new Error(`Agente inválido: ${validation.errors.join(', ')}`)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Resolver dependências
|
|
64
|
+
const dependencies = await this.dependencyResolver.resolve(agentData.dependencies || [])
|
|
65
|
+
if (dependencies.missing.length > 0) {
|
|
66
|
+
console.warn(`[Installer] ⚠️ Dependências faltando: ${dependencies.missing.join(', ')}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Criar diretório do agente
|
|
70
|
+
const agentDir = path.join(this.agentsDir, agentId)
|
|
71
|
+
await fs.ensureDir(agentDir)
|
|
72
|
+
|
|
73
|
+
// Salvar arquivos do agente
|
|
74
|
+
await this.saveAgentFiles(agentDir, agentData)
|
|
75
|
+
|
|
76
|
+
// Registrar agente
|
|
77
|
+
await this.registry.register({
|
|
78
|
+
id: agentId,
|
|
79
|
+
version: version,
|
|
80
|
+
installedAt: new Date().toISOString(),
|
|
81
|
+
path: agentDir,
|
|
82
|
+
dependencies: agentData.dependencies || [],
|
|
83
|
+
metadata: agentData.metadata || {}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
console.log(`[Installer] ✅ Agente ${agentId} instalado com sucesso!`)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
success: true,
|
|
90
|
+
agentId,
|
|
91
|
+
version,
|
|
92
|
+
path: agentDir
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove agente
|
|
98
|
+
*/
|
|
99
|
+
async uninstallAgent(agentId) {
|
|
100
|
+
console.log(`[Installer] 🗑️ Removendo agente: ${agentId}`)
|
|
101
|
+
|
|
102
|
+
const agentDir = path.join(this.agentsDir, agentId)
|
|
103
|
+
|
|
104
|
+
if (!await fs.pathExists(agentDir)) {
|
|
105
|
+
throw new Error(`Agente ${agentId} não encontrado`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Remover diretório
|
|
109
|
+
await fs.remove(agentDir)
|
|
110
|
+
|
|
111
|
+
// Remover do registro
|
|
112
|
+
await this.registry.unregister(agentId)
|
|
113
|
+
|
|
114
|
+
console.log(`[Installer] ✅ Agente ${agentId} removido com sucesso!`)
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
success: true,
|
|
118
|
+
agentId
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Atualiza agente
|
|
124
|
+
*/
|
|
125
|
+
async updateAgent(agentId, newVersion) {
|
|
126
|
+
console.log(`[Installer] 🔄 Atualizando agente: ${agentId} para ${newVersion}`)
|
|
127
|
+
|
|
128
|
+
// Baixar nova versão
|
|
129
|
+
const agentData = await this.downloadAgent(agentId, newVersion)
|
|
130
|
+
|
|
131
|
+
// Remover versão antiga
|
|
132
|
+
await this.uninstallAgent(agentId)
|
|
133
|
+
|
|
134
|
+
// Instalar nova versão
|
|
135
|
+
return await this.installAgent(agentData, agentId, newVersion)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Parseia URL nex://
|
|
140
|
+
*/
|
|
141
|
+
parseNexURL(url) {
|
|
142
|
+
if (!url.startsWith('nex://')) {
|
|
143
|
+
throw new Error('URL deve começar com nex://')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const urlObj = new URL(url.replace('nex://', 'http://'))
|
|
147
|
+
const params = {}
|
|
148
|
+
|
|
149
|
+
for (const [key, value] of urlObj.searchParams.entries()) {
|
|
150
|
+
params[key] = value
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// agentId pode estar no path ou query
|
|
154
|
+
if (urlObj.pathname && urlObj.pathname !== '/') {
|
|
155
|
+
params.agentId = urlObj.pathname.replace('/', '')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return params
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Baixa agente da NEX Store
|
|
163
|
+
*/
|
|
164
|
+
async downloadAgent(agentId, version) {
|
|
165
|
+
console.log(`[Installer] 📥 Baixando agente: ${agentId}@${version}`)
|
|
166
|
+
|
|
167
|
+
// TODO: Implementar download real da NEX Store API
|
|
168
|
+
// Por enquanto, retorna estrutura mock
|
|
169
|
+
return {
|
|
170
|
+
id: agentId,
|
|
171
|
+
version: version,
|
|
172
|
+
name: agentId,
|
|
173
|
+
description: `Agente ${agentId}`,
|
|
174
|
+
category: 'general',
|
|
175
|
+
dependencies: [],
|
|
176
|
+
files: {
|
|
177
|
+
'agent.js': `export default class ${agentId}Agent {
|
|
178
|
+
constructor() {
|
|
179
|
+
this.name = '${agentId}'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async execute() {
|
|
183
|
+
return { success: true }
|
|
184
|
+
}
|
|
185
|
+
}`
|
|
186
|
+
},
|
|
187
|
+
metadata: {
|
|
188
|
+
author: 'NEX Community',
|
|
189
|
+
license: 'PROPRIETARY'
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Salva arquivos do agente
|
|
196
|
+
*/
|
|
197
|
+
async saveAgentFiles(agentDir, agentData) {
|
|
198
|
+
if (agentData.files) {
|
|
199
|
+
for (const [filePath, content] of Object.entries(agentData.files)) {
|
|
200
|
+
const fullPath = path.join(agentDir, filePath)
|
|
201
|
+
await fs.ensureDir(path.dirname(fullPath))
|
|
202
|
+
await fs.writeFile(fullPath, content, 'utf-8')
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Salvar manifest
|
|
207
|
+
const manifest = {
|
|
208
|
+
id: agentData.id,
|
|
209
|
+
version: agentData.version,
|
|
210
|
+
name: agentData.name,
|
|
211
|
+
description: agentData.description,
|
|
212
|
+
category: agentData.category,
|
|
213
|
+
dependencies: agentData.dependencies || [],
|
|
214
|
+
metadata: agentData.metadata || {}
|
|
215
|
+
}
|
|
216
|
+
await fs.writeJSON(path.join(agentDir, 'manifest.json'), manifest, { spaces: 2 })
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Lista agentes instalados
|
|
221
|
+
*/
|
|
222
|
+
async listInstalled() {
|
|
223
|
+
return await this.registry.list()
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|