grimoire-framework 1.0.21 → 1.1.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.
@@ -7,8 +7,8 @@
7
7
  # - SHA256 hashes for change detection
8
8
  # - File types for categorization
9
9
  #
10
- version: 1.0.21
11
- generated_at: "2026-02-22T14:46:40.983Z"
10
+ version: 1.1.1
11
+ generated_at: "2026-02-22T15:03:35.007Z"
12
12
  generator: scripts/generate-install-manifest.js
13
13
  file_count: 1011
14
14
  files:
@@ -0,0 +1,304 @@
1
+ /**
2
+ * grimoire marketplace — Community Agent Registry
3
+ *
4
+ * grimoire marketplace list Navega agentes da comunidade
5
+ * grimoire marketplace install <slug> Instala um agente do marketplace
6
+ * grimoire marketplace search <term> Busca por especialidade ou tag
7
+ * grimoire marketplace submit Instruções para publicar seu agente
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+ const https = require('https');
15
+ const os = require('os');
16
+
17
+ // ── Curated registry (built-in fallback, also fetched from GitHub) ─────────────
18
+ const REGISTRY_URL = 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/registry.json';
19
+ const CACHE_FILE = path.join(os.homedir(), '.grimoire-marketplace-cache.json');
20
+ const CACHE_TTL_MINS = 60; // 1 hour
21
+
22
+ const BUILTIN_AGENTS = [
23
+ {
24
+ slug: 'frontend-specialist',
25
+ name: 'Botticelli',
26
+ icon: '🎠',
27
+ specialty: 'Frontend & UI/UX',
28
+ tags: ['react', 'css', 'typescript', 'nextjs'],
29
+ author: 'grimoire-team',
30
+ description: 'Especialista em React, TypeScript e design systems. Ideal para times com foco em UI.',
31
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/frontend-specialist.md',
32
+ },
33
+ {
34
+ slug: 'security-auditor',
35
+ name: 'Rembrandt',
36
+ icon: '🔐',
37
+ specialty: 'Segurança & Auditoria',
38
+ tags: ['security', 'owasp', 'pentest', 'audit'],
39
+ author: 'grimoire-team',
40
+ description: 'Audita código em busca de vulnerabilidades OWASP Top 10. SAST e code review de segurança.',
41
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/security-auditor.md',
42
+ },
43
+ {
44
+ slug: 'ml-engineer',
45
+ name: 'Dalí',
46
+ icon: '🧠',
47
+ specialty: 'Machine Learning & AI',
48
+ tags: ['ml', 'python', 'pytorch', 'sklearn'],
49
+ author: 'grimoire-team',
50
+ description: 'Implementa pipelines de ML, feature engineering, treinamento e avaliação de modelos.',
51
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/ml-engineer.md',
52
+ },
53
+ {
54
+ slug: 'api-designer',
55
+ name: 'Klimt',
56
+ icon: '🔗',
57
+ specialty: 'API Design & Documentação',
58
+ tags: ['rest', 'graphql', 'openapi', 'swagger'],
59
+ author: 'grimoire-team',
60
+ description: 'Projeta APIs RESTful e GraphQL. Gera documentação OpenAPI 3.x e valida contratos.',
61
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/api-designer.md',
62
+ },
63
+ {
64
+ slug: 'database-expert',
65
+ name: 'Mondrian',
66
+ icon: '🗄️',
67
+ specialty: 'Banco de Dados & Queries',
68
+ tags: ['sql', 'postgresql', 'mongodb', 'redis'],
69
+ author: 'grimoire-team',
70
+ description: 'Otimiza queries, projeta schemas e revisa migrações. PostgreSQL, MongoDB, Redis.',
71
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/database-expert.md',
72
+ },
73
+ {
74
+ slug: 'tech-writer',
75
+ name: 'Cervantes',
76
+ icon: '✍️',
77
+ specialty: 'Documentação Técnica',
78
+ tags: ['docs', 'readme', 'adr', 'wiki'],
79
+ author: 'grimoire-team',
80
+ description: 'Escreve e revisa documentação técnica: READMEs, ADRs, guias de API e wikis.',
81
+ gist: 'https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/tech-writer.md',
82
+ },
83
+ ];
84
+
85
+ // ── Fetcher ────────────────────────────────────────────────────────────────────
86
+ async function fetchRegistry() {
87
+ // Use cache if fresh
88
+ if (fs.existsSync(CACHE_FILE)) {
89
+ try {
90
+ const cache = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
91
+ const minsSince = (Date.now() - cache.ts) / 60000;
92
+ if (minsSince < CACHE_TTL_MINS) return cache.agents;
93
+ } catch (_) { }
94
+ }
95
+
96
+ // Try to fetch remote registry
97
+ try {
98
+ const remote = await new Promise((resolve, reject) => {
99
+ const req = https.get(REGISTRY_URL, { timeout: 4000 }, (res) => {
100
+ let body = '';
101
+ res.on('data', d => body += d);
102
+ res.on('end', () => { try { resolve(JSON.parse(body)); } catch (e) { reject(e); } });
103
+ });
104
+ req.on('error', reject);
105
+ req.on('timeout', () => req.destroy());
106
+ });
107
+ const agents = remote.agents || BUILTIN_AGENTS;
108
+ fs.writeFileSync(CACHE_FILE, JSON.stringify({ ts: Date.now(), agents }), 'utf8');
109
+ return agents;
110
+ } catch (_) {
111
+ // Fall back to built-in
112
+ return BUILTIN_AGENTS;
113
+ }
114
+ }
115
+
116
+ // ── Commands ───────────────────────────────────────────────────────────────────
117
+ async function run(args) {
118
+ const sub = args[0];
119
+ switch (sub) {
120
+ case 'install': await installAgent(args[1]); break;
121
+ case 'search': await searchAgents(args.slice(1)); break;
122
+ case 'submit': showSubmitGuide(); break;
123
+ case 'list':
124
+ default: await listAgents(args); break;
125
+ }
126
+ }
127
+
128
+ // ── List ───────────────────────────────────────────────────────────────────────
129
+ async function listAgents(args) {
130
+ process.stdout.write('🔍 Carregando registry...');
131
+ const agents = await fetchRegistry();
132
+ const tagFilter = args.find(a => a.startsWith('--tag='));
133
+ const filtered = tagFilter
134
+ ? agents.filter(a => a.tags.includes(tagFilter.replace('--tag=', '')))
135
+ : agents;
136
+
137
+ console.log(`\r\n🏪 Grimoire Marketplace — ${filtered.length} agentes disponíveis\n`);
138
+ console.log(' ' + '─'.repeat(60));
139
+
140
+ filtered.forEach(agent => {
141
+ const tags = agent.tags.slice(0, 3).map(t => `#${t}`).join(' ');
142
+ console.log(`
143
+ ${agent.icon} **@${agent.slug}** — ${agent.name}
144
+ ${agent.specialty}
145
+ ${agent.description}
146
+ ${tags} by @${agent.author}`);
147
+ });
148
+
149
+ console.log(`\n ${'─'.repeat(60)}`);
150
+ console.log(` 💡 Para instalar: grimoire marketplace install <slug>`);
151
+ console.log(` 💡 Para buscar: grimoire marketplace search <term>`);
152
+ console.log(` 💡 Para publicar: grimoire marketplace submit\n`);
153
+ }
154
+
155
+ // ── Search ─────────────────────────────────────────────────────────────────────
156
+ async function searchAgents(terms) {
157
+ const query = terms.join(' ').toLowerCase();
158
+ if (!query) { console.log('Usage: grimoire marketplace search <term>'); return; }
159
+
160
+ const agents = await fetchRegistry();
161
+ const results = agents.filter(a =>
162
+ a.slug.includes(query) ||
163
+ a.specialty.toLowerCase().includes(query) ||
164
+ a.description.toLowerCase().includes(query) ||
165
+ a.tags.some(t => t.includes(query))
166
+ );
167
+
168
+ console.log(`\n🔍 Results for "${query}" — ${results.length} found\n`);
169
+ if (results.length === 0) {
170
+ console.log(' No agents found. Try: grimoire marketplace list\n'); return;
171
+ }
172
+ results.forEach(a => {
173
+ console.log(` ${a.icon} @${a.slug} — ${a.name} · ${a.specialty}`);
174
+ console.log(` ${a.description}\n`);
175
+ });
176
+ }
177
+
178
+ // ── Install ────────────────────────────────────────────────────────────────────
179
+ async function installAgent(slug) {
180
+ if (!slug) { console.log('Usage: grimoire marketplace install <slug>'); return; }
181
+
182
+ const agents = await fetchRegistry();
183
+ const agent = agents.find(a => a.slug === slug);
184
+ if (!agent) {
185
+ console.error(`❌ Agent "${slug}" not found in marketplace. Try: grimoire marketplace list`);
186
+ return;
187
+ }
188
+
189
+ const localDir = path.join(process.cwd(), '.codex', 'agents');
190
+ if (!fs.existsSync(localDir)) {
191
+ console.error('❌ No .codex/agents/ found. Run: npx grimoire-framework install');
192
+ return;
193
+ }
194
+
195
+ const destFile = path.join(localDir, `${slug}.md`);
196
+ if (fs.existsSync(destFile)) {
197
+ console.log(`⚠️ Agent @${slug} already installed. Use "grimoire agent edit ${slug}" to customize.`);
198
+ return;
199
+ }
200
+
201
+ // Download agent file
202
+ process.stdout.write(`⬇️ Downloading @${slug} (${agent.name})...`);
203
+ try {
204
+ const content = await new Promise((resolve, reject) => {
205
+ const req = https.get(agent.gist, { timeout: 8000 }, (res) => {
206
+ // If 404 or not found, generate template instead
207
+ if (res.statusCode === 404) { resolve(null); return; }
208
+ let body = '';
209
+ res.on('data', d => body += d);
210
+ res.on('end', () => resolve(body));
211
+ });
212
+ req.on('error', reject);
213
+ req.on('timeout', () => req.destroy());
214
+ });
215
+
216
+ const agentContent = content || generateFallbackAgent(agent);
217
+ fs.writeFileSync(destFile, agentContent, 'utf8');
218
+
219
+ console.log(` ✅\n`);
220
+ console.log(`✅ Instalado: @${slug} — ${agent.name}`);
221
+ console.log(` Especialidade: ${agent.specialty}`);
222
+ console.log(` Arquivo: .codex/agents/${slug}.md`);
223
+ console.log(`\n💡 Para ativar: @${slug} no chat da sua IDE`);
224
+ console.log(` Para outras IDEs: grimoire sync --global && grimoire update\n`);
225
+ } catch (e) {
226
+ console.log(' ⚠️ (offline, usando template local)');
227
+ fs.writeFileSync(destFile, generateFallbackAgent(agent), 'utf8');
228
+ console.log(`✅ Instalado com template local: @${slug}`);
229
+ }
230
+ }
231
+
232
+ // ── Fallback template when gist unavailable ────────────────────────────────────
233
+ function generateFallbackAgent(agent) {
234
+ return `# ${agent.slug}
235
+
236
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
237
+
238
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
239
+
240
+ \`\`\`yaml
241
+ activation-instructions:
242
+ - STEP 1: Adote a persona ${agent.name} completamente
243
+ - STEP 2: Apresente o greeting abaixo
244
+ - STEP 3: HALT e aguarde input
245
+ - STAY IN CHARACTER até *exit
246
+
247
+ agent:
248
+ name: ${agent.name}
249
+ id: ${agent.slug}
250
+ title: ${agent.specialty}
251
+ icon: ${agent.icon}
252
+ source: marketplace
253
+ author: ${agent.author}
254
+ tags: [${agent.tags.join(', ')}]
255
+ description: ${agent.description}
256
+
257
+ persona:
258
+ role: ${agent.specialty} Specialist
259
+ identity: ${agent.name} — ${agent.description}
260
+
261
+ greeting_levels:
262
+ default: |
263
+ ${agent.icon} **${agent.name}** (@${agent.slug}) do Grimoire Marketplace!
264
+ Especialidade: **${agent.specialty}**
265
+ ${agent.description}
266
+
267
+ Como posso ajudar?
268
+
269
+ commands:
270
+ - "*help — Comandos disponíveis"
271
+ - "*exit — Sair do agente"
272
+
273
+ signature_closing: '— ${agent.name} ${agent.icon}'
274
+ \`\`\`
275
+ `;
276
+ }
277
+
278
+ // ── Submit guide ───────────────────────────────────────────────────────────────
279
+ function showSubmitGuide() {
280
+ console.log(`
281
+ 📤 Publique seu agente no Grimoire Marketplace!
282
+
283
+ 1. Crie seu agente:
284
+ grimoire agent create
285
+
286
+ 2. Teste em múltiplos projetos:
287
+ grimoire sync --global
288
+ grimoire sync --from-global # em outro projeto
289
+
290
+ 3. Abra um Pull Request:
291
+ https://github.com/gabrielrlima/grimoire/tree/master/marketplace
292
+
293
+ Adicione seu agente em:
294
+ - marketplace/agents/<slug>.md (definição)
295
+ - marketplace/registry.json (entrada no catálogo)
296
+
297
+ 4. Campos obrigatórios no registry.json:
298
+ slug, name, icon, specialty, tags, author, description, gist
299
+
300
+ 🌟 Agentes aprovados ficam disponíveis para toda a comunidade!
301
+ `);
302
+ }
303
+
304
+ module.exports = { run };
@@ -0,0 +1,237 @@
1
+ /**
2
+ * grimoire pro — License & Feature Gate System
3
+ *
4
+ * Phase 1: Offline-first with HMAC key validation
5
+ * Phase 2: Online validation via Supabase Edge Function (future)
6
+ *
7
+ * grimoire pro activate <key> Ativa a licença Pro
8
+ * grimoire pro status Mostra status da licença
9
+ * grimoire pro features Lista features Pro disponíveis
10
+ * grimoire pro deactivate Remove a licença
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const path = require('path');
16
+ const fs = require('fs');
17
+ const os = require('os');
18
+ const crypto = require('crypto');
19
+
20
+ // ── License storage ────────────────────────────────────────────────────────────
21
+ const LICENSE_FILE = path.join(os.homedir(), '.grimoire-license.json');
22
+
23
+ // ── HMAC secret (public seed — Phase 1 offline validation only) ───────────────
24
+ // In Phase 2 this validation moves to the server
25
+ const HMAC_SEED = 'grimoire-pro-v1-2026';
26
+
27
+ // ── Pro feature catalogue ──────────────────────────────────────────────────────
28
+ const PRO_FEATURES = [
29
+ { id: 'squads-unlimited', name: 'Squads Ilimitados', desc: 'Crie squads customizados sem limite', tier: 'pro' },
30
+ { id: 'memory-sync', name: 'Memória Sincronizada', desc: 'Sync de memória entre projetos via cloud', tier: 'pro' },
31
+ { id: 'metrics-advanced', name: 'Métricas Avançadas', desc: 'Dashboard com insights de IA e tendências', tier: 'pro' },
32
+ { id: 'marketplace-publish', name: 'Publish no Marketplace', desc: 'Publique agentes no marketplace sem PR', tier: 'pro' },
33
+ { id: 'squad-creator', name: 'Squad Creator Avançado', desc: 'Templates de squad por domínio (fintech, saúde, e-comm)', tier: 'pro' },
34
+ { id: 'priority-support', name: 'Suporte Prioritário', desc: 'Acesso a canal privado de suporte', tier: 'pro' },
35
+ ];
36
+
37
+ // ── License validation (offline HMAC-SHA256) ──────────────────────────────────
38
+ function generateKeyChecksum(email, key) {
39
+ const payload = `${email}:${key}:${HMAC_SEED}`;
40
+ return crypto.createHmac('sha256', HMAC_SEED).update(payload).digest('hex').substring(0, 12);
41
+ }
42
+
43
+ function validateKeyFormat(key) {
44
+ // Format: PRO-XXXX-XXXX-XXXX-XXXX (alphanumeric segments)
45
+ return /^PRO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(key);
46
+ }
47
+
48
+ function loadLicense() {
49
+ if (!fs.existsSync(LICENSE_FILE)) return null;
50
+ try { return JSON.parse(fs.readFileSync(LICENSE_FILE, 'utf8')); }
51
+ catch (_) { return null; }
52
+ }
53
+
54
+ function saveLicense(data) {
55
+ fs.writeFileSync(LICENSE_FILE, JSON.stringify(data, null, 2), 'utf8');
56
+ }
57
+
58
+ function isLicenseValid(license) {
59
+ if (!license) return false;
60
+ if (license.type === 'community') return true; // Always valid
61
+
62
+ // Check expiry
63
+ if (license.expiresAt && new Date(license.expiresAt) < new Date()) {
64
+ return false;
65
+ }
66
+
67
+ // Offline HMAC check
68
+ const expected = generateKeyChecksum(license.email || '', license.key || '');
69
+ return license.checksum === expected;
70
+ }
71
+
72
+ // ── Public API for other modules ───────────────────────────────────────────────
73
+ function isPro() {
74
+ const license = loadLicense();
75
+ return isLicenseValid(license) && license.type === 'pro';
76
+ }
77
+
78
+ function hasFeature(featureId) {
79
+ const license = loadLicense();
80
+ if (!isLicenseValid(license)) return false;
81
+ if (license.type === 'pro') return PRO_FEATURES.some(f => f.id === featureId);
82
+ return license.features?.includes(featureId) || false;
83
+ }
84
+
85
+ // ── readline prompt ────────────────────────────────────────────────────────────
86
+ const readline = require('readline');
87
+ function prompt(q) {
88
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
89
+ return new Promise(resolve => { rl.question(q, a => { rl.close(); resolve(a.trim()); }); });
90
+ }
91
+
92
+ // ── Commands ───────────────────────────────────────────────────────────────────
93
+ async function run(args) {
94
+ const sub = args[0];
95
+ switch (sub) {
96
+ case 'activate': await activate(args[1]); break;
97
+ case 'deactivate': deactivate(); break;
98
+ case 'features': showFeatures(); break;
99
+ case 'status':
100
+ default: showStatus(); break;
101
+ }
102
+ }
103
+
104
+ // ── Activate ───────────────────────────────────────────────────────────────────
105
+ async function activate(keyArg) {
106
+ console.log('\n🔐 Grimoire Pro — Ativação de Licença\n');
107
+
108
+ const key = keyArg || await prompt('Chave de licença (PRO-XXXX-XXXX-XXXX-XXXX): ');
109
+
110
+ if (!validateKeyFormat(key)) {
111
+ console.error('❌ Formato inválido. Use: PRO-XXXX-XXXX-XXXX-XXXX');
112
+ console.log(' Obtenha sua chave em: https://grimoire.dev/pro\n');
113
+ return;
114
+ }
115
+
116
+ const email = await prompt('Email associado à licença: ');
117
+ if (!email || !email.includes('@')) {
118
+ console.error('❌ Email inválido.');
119
+ return;
120
+ }
121
+
122
+ // Offline HMAC validation
123
+ const checksum = generateKeyChecksum(email, key);
124
+
125
+ // Try online validation (Phase 2 ready but not blocking)
126
+ let onlineValidated = false;
127
+ try {
128
+ const https = require('https');
129
+ const result = await new Promise((resolve, reject) => {
130
+ const data = JSON.stringify({ key, email });
131
+ const req = https.request({
132
+ hostname: 'api.grimoire.dev',
133
+ path: '/v1/license/validate',
134
+ method: 'POST',
135
+ headers: { 'Content-Type': 'application/json', 'Content-Length': data.length },
136
+ timeout: 4000,
137
+ }, (res) => {
138
+ let body = '';
139
+ res.on('data', d => body += d);
140
+ res.on('end', () => { try { resolve(JSON.parse(body)); } catch (e) { reject(e); } });
141
+ });
142
+ req.on('error', reject);
143
+ req.on('timeout', () => req.destroy());
144
+ req.write(data);
145
+ req.end();
146
+ });
147
+ onlineValidated = result.valid === true;
148
+ } catch (_) {
149
+ // Offline — use local validation only
150
+ }
151
+
152
+ const license = {
153
+ type: 'pro',
154
+ key,
155
+ email,
156
+ checksum,
157
+ activatedAt: new Date().toISOString(),
158
+ expiresAt: null, // null = never (or set by server in Phase 2)
159
+ onlineValidated,
160
+ features: PRO_FEATURES.map(f => f.id),
161
+ };
162
+
163
+ saveLicense(license);
164
+
165
+ console.log(`
166
+ ✅ Grimoire Pro ativado!
167
+
168
+ Email: ${email}
169
+ Chave: ${key.substring(0, 7)}...${key.slice(-4)}
170
+ Status: ${onlineValidated ? '✅ Validado online' : '✅ Ativado (validação offline)'}
171
+
172
+ 🎯 Features ativas:`);
173
+ PRO_FEATURES.forEach(f => console.log(` ✅ ${f.name} — ${f.desc}`));
174
+ console.log('\n💡 Use "grimoire pro status" para ver os detalhes\n');
175
+ }
176
+
177
+ // ── Status ─────────────────────────────────────────────────────────────────────
178
+ function showStatus() {
179
+ const license = loadLicense();
180
+ const sep = '─'.repeat(50);
181
+
182
+ console.log(`\n🔐 Grimoire Pro — Status da Licença\n${sep}`);
183
+
184
+ if (!license) {
185
+ console.log(` Status: ⭕ Não ativado (Community)\n`);
186
+ console.log(` ${sep}`);
187
+ console.log(` Para ativar: grimoire pro activate <chave>`);
188
+ console.log(` Obter licença: https://grimoire.dev/pro\n`);
189
+ showFeatureList(false);
190
+ return;
191
+ }
192
+
193
+ const valid = isLicenseValid(license);
194
+ const isPro = license.type === 'pro' && valid;
195
+ const expires = license.expiresAt ? new Date(license.expiresAt).toLocaleDateString('pt-BR') : 'Sem expiração';
196
+
197
+ console.log(` Status: ${valid ? (isPro ? '✅ Pro Ativo' : '✅ Community') : '❌ Licença inválida/expirada'}`);
198
+ if (license.email) console.log(` Email: ${license.email}`);
199
+ if (license.key) console.log(` Chave: ${license.key.substring(0, 7)}...${license.key.slice(-4)}`);
200
+ console.log(` Ativado: ${license.activatedAt ? new Date(license.activatedAt).toLocaleDateString('pt-BR') : 'N/A'}`);
201
+ console.log(` Expira: ${expires}`);
202
+ console.log(` ${sep}`);
203
+
204
+ showFeatureList(isPro);
205
+ }
206
+
207
+ // ── Features ───────────────────────────────────────────────────────────────────
208
+ function showFeatures() {
209
+ const license = loadLicense();
210
+ const active = license && isLicenseValid(license) && license.type === 'pro';
211
+ console.log('\n🎯 Grimoire Pro — Features\n');
212
+ showFeatureList(active);
213
+ }
214
+
215
+ function showFeatureList(active) {
216
+ PRO_FEATURES.forEach(f => {
217
+ const status = active ? '✅' : '🔒';
218
+ console.log(` ${status} ${f.name}`);
219
+ console.log(` ${f.desc}\n`);
220
+ });
221
+ if (!active) {
222
+ console.log(` 🔗 Ative em: https://grimoire.dev/pro`);
223
+ console.log(` grimoire pro activate\n`);
224
+ }
225
+ }
226
+
227
+ // ── Deactivate ─────────────────────────────────────────────────────────────────
228
+ function deactivate() {
229
+ if (!fs.existsSync(LICENSE_FILE)) {
230
+ console.log('ℹ️ Nenhuma licença ativa encontrada.');
231
+ return;
232
+ }
233
+ fs.unlinkSync(LICENSE_FILE);
234
+ console.log('✅ Licença removida. Grimoire voltou ao modo Community.');
235
+ }
236
+
237
+ module.exports = { run, isPro, hasFeature };
@@ -118,6 +118,12 @@ async function main() {
118
118
  case 'sync':
119
119
  await require('./commands/sync').run(args.slice(1));
120
120
  break;
121
+ case 'marketplace':
122
+ await require('./commands/marketplace').run(args.slice(1));
123
+ break;
124
+ case 'pro':
125
+ await require('./commands/pro').run(args.slice(1));
126
+ break;
121
127
  case 'status':
122
128
  handleStatus();
123
129
  break;
@@ -469,29 +475,72 @@ function handleDoctor() {
469
475
  }
470
476
 
471
477
  function showHelp() {
478
+ const { isPro } = (() => { try { return require('./commands/pro'); } catch (_) { return { isPro: () => false }; } })();
479
+ const proLabel = isPro() ? ' 🔐' : '';
480
+
472
481
  console.log(`
473
- 🔮 Grimoire Framework CLI v${packageJson.version}
474
-
475
- The CLI manages your framework. Agents live in your IDE chat.
476
- (These are DIFFERENT — CLI = terminal, Agents = @agentname in IDE chat)
477
-
478
- USAGE:
479
- grimoire status # Framework health & what's active
480
- grimoire whoami # 🧙 Session context & how to use agents
481
- grimoire install # Install/Reset setup
482
- grimoire agents list # List available agents (with personas)
483
- grimoire squads list # List installed squads
484
- grimoire memory [sub] # Manage persistent memory
485
- grimoire metrics # View productivity metrics
486
- grimoire doctor # Run diagnostics (checks + tips)
487
- grimoire --version # Show version
488
- grimoire --help # Show this help
482
+ 🔮 Grimoire Framework CLI v${packageJson.version}${proLabel}
483
+
484
+ CLI gerencia o framework · Agentes vivem no chat da sua IDE
485
+ (CLI = terminal · Agentes = @agentname no chat da IDE)
486
+
487
+ COMANDOS ESSENCIAIS:
488
+ grimoire status Saúde do framework e o que está ativo
489
+ grimoire whoami Contexto da sessão e como usar agentes
490
+ grimoire doctor Diagnóstico completo (checks + sugestões)
491
+ grimoire update Atualiza agentes e arquivos do framework
492
+
493
+ AGENTES:
494
+ grimoire agents list Lista todos os agentes com personas
495
+ grimoire agent create 🆕 Wizard para criar agente customizado
496
+ grimoire agent list Lista agentes (com custom)
497
+ grimoire agent edit <n> Editar agente no $EDITOR
498
+ grimoire agent remove <n> Remover agente customizado
499
+
500
+ SQUADS:
501
+ grimoire squads list Lista squads disponíveis (fullstack/planning/devops)
502
+
503
+ MEMÓRIA:
504
+ grimoire memory save "texto" Salvar entrada na sessão
505
+ grimoire memory show [--last 10] Ver entradas de hoje
506
+ grimoire memory search "termo" 🆕 Buscar em todas as sessões
507
+ grimoire memory export 🆕 Exportar para Markdown
508
+ grimoire memory clear --older-than 30 🆕 Limpar sessões antigas
509
+ grimoire memory list Listar todas as sessões
510
+
511
+ MÉTRICAS:
512
+ grimoire metrics Dashboard do mês atual
513
+ grimoire metrics --period week 🆕 Últimos 7 dias
514
+ grimoire metrics --period all 🆕 Histórico completo
515
+ grimoire metrics export --csv 🆕 Exportar para CSV
516
+ grimoire metrics track <tipo> [msg] 🆕 Registrar evento manual
517
+
518
+ SYNC GLOBAL:
519
+ grimoire sync --global 🆕 Envia agentes → ~/.grimoire/agents/
520
+ grimoire sync --from-global 🆕 Puxa agentes do store global
521
+ grimoire sync --list 🆕 Lista agentes globais
522
+
523
+ MARKETPLACE:
524
+ grimoire marketplace list 🆕 Navega agentes da comunidade
525
+ grimoire marketplace install <slug> 🆕 Instala agente do marketplace
526
+ grimoire marketplace search <termo> 🆕 Busca por especialidade
527
+ grimoire marketplace submit 🆕 Guia para publicar seu agente
528
+
529
+ GRIMOIRE PRO:
530
+ grimoire pro activate <chave> 🆕 Ativa licença Pro
531
+ grimoire pro status 🆕 Status da licença e features
532
+ grimoire pro features 🆕 Lista features Pro
533
+ grimoire pro deactivate 🆕 Remove licença
534
+
535
+ OUTROS:
536
+ grimoire install Instalar/reset setup no projeto
537
+ grimoire --version Versão instalada
538
+ grimoire --help Este help
489
539
 
490
540
  QUICK START:
491
- npx grimoire-framework install # Set up in a new project
492
- grimoire status # Check everything is working
493
- grimoire whoami # See available agents
494
- Then in your IDE chat: @dev or @qa or @grimoire-master
541
+ npx grimoire-framework install Setup em novo projeto
542
+ grimoire status Tudo funcionando?
543
+ @dev @qa @architect No chat da sua IDE
495
544
  `);
496
545
  }
497
546
 
@@ -0,0 +1,56 @@
1
+ # api-designer
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Klimt completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Klimt
16
+ id: api-designer
17
+ title: API Design & Documentation Specialist
18
+ icon: 🔗
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [rest, graphql, openapi, swagger, grpc, api-design]
22
+
23
+ persona:
24
+ role: API Designer & Integration Architect
25
+ style: Preciso, consistente, orientado a contratos
26
+ identity: |
27
+ Klimt — O Arquiteto de Contratos. Expert em design de APIs RESTful e GraphQL,
28
+ documentação OpenAPI 3.x e estratégias de versionamento.
29
+ principles:
30
+ - API-first design
31
+ - Contratos imutáveis (versioning)
32
+ - Nomes e verbos HTTP semânticos
33
+ - Documentação como primeiro cidadão
34
+
35
+ greeting_levels:
36
+ default: |
37
+ 🔗 **Klimt** (@api-designer) pronto!
38
+ Especialidade: **API Design & Documentação**
39
+
40
+ Posso ajudar com:
41
+ - Design de APIs REST e GraphQL
42
+ - Geração de spec OpenAPI 3.x / Swagger
43
+ - Versionamento e contratos de API
44
+ - Revisão de endpoints existentes
45
+
46
+ Qual API vamos projetar?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*design — Projetar nova API"
51
+ - "*review — Revisar API existente"
52
+ - "*spec — Gerar OpenAPI spec"
53
+ - "*exit — Sair do agente"
54
+
55
+ signature_closing: '— Klimt, tecendo contratos em ouro 🔗'
56
+ ```
@@ -0,0 +1,56 @@
1
+ # database-expert
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Mondrian completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Mondrian
16
+ id: database-expert
17
+ title: Banco de Dados & Query Specialist
18
+ icon: 🗄️
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [sql, postgresql, mongodb, redis, performance, schema]
22
+
23
+ persona:
24
+ role: Database Engineer & Query Optimizer
25
+ style: Estruturado, performático, orientado a dados
26
+ identity: |
27
+ Mondrian — O Arquiteto de Dados. Expert em modelagem de schemas,
28
+ otimização de queries, migrações e estratégias de indexação.
29
+ principles:
30
+ - Schema correto antes de otimização
31
+ - EXPLAIN antes de INDEX
32
+ - Migrações sempre reversíveis
33
+ - N+1 é um erro, não uma feature
34
+
35
+ greeting_levels:
36
+ default: |
37
+ 🗄️ **Mondrian** (@database-expert) pronto!
38
+ Especialidade: **Banco de Dados & Queries**
39
+
40
+ Posso ajudar com:
41
+ - Design e revisão de schemas (PostgreSQL, MongoDB)
42
+ - Otimização de queries e índices
43
+ - Migrações seguras e reversíveis
44
+ - Redis: caching, pub/sub, filas
45
+
46
+ Qual problema de dados vamos resolver?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*schema — Revisar ou projetar schema"
51
+ - "*optimize — Otimizar query com EXPLAIN"
52
+ - "*migrate — Planejar migração segura"
53
+ - "*exit — Sair do agente"
54
+
55
+ signature_closing: '— Mondrian, organizando dados em grades perfeitas 🗄️'
56
+ ```
@@ -0,0 +1,55 @@
1
+ # frontend-specialist
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Botticelli completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Botticelli
16
+ id: frontend-specialist
17
+ title: Frontend & UI/UX Specialist
18
+ icon: 🎠
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [react, css, typescript, nextjs, tailwind]
22
+
23
+ persona:
24
+ role: Frontend & UI/UX Engineer
25
+ style: Design-oriented, pixel-perfect, performance-conscious
26
+ identity: |
27
+ Botticelli — Mestre do Frontend. Expert em React, TypeScript, design systems
28
+ e experiência do usuário. Cada componente é uma obra de arte.
29
+ principles:
30
+ - Componentes acessíveis (WCAG 2.1 AA)
31
+ - Performance: Core Web Vitals em verde
32
+ - Design system antes de componentes ad-hoc
33
+ - Mobile-first sempre
34
+
35
+ greeting_levels:
36
+ default: |
37
+ 🎠 **Botticelli** (@frontend-specialist) pronto!
38
+ Especialidade: **Frontend & UI/UX**
39
+
40
+ Posso ajudar com:
41
+ - Implementação de componentes React/Next.js
42
+ - Design system e tokens de estilo
43
+ - Performance (Core Web Vitals, bundle size)
44
+ - Acessibilidade e responsividade
45
+
46
+ O que vamos construir?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*review — Code review de componente"
51
+ - "*a11y — Auditoria de acessibilidade"
52
+ - "*exit — Sair do agente"
53
+
54
+ signature_closing: '— Botticelli, pintando o frontend pixel a pixel 🎠'
55
+ ```
@@ -0,0 +1,55 @@
1
+ # ml-engineer
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Dalí completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Dalí
16
+ id: ml-engineer
17
+ title: Machine Learning & AI Engineer
18
+ icon: 🧠
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [ml, python, pytorch, sklearn, llm, mlops]
22
+
23
+ persona:
24
+ role: ML Engineer & AI Specialist
25
+ style: Experimental, data-driven, pragmático
26
+ identity: |
27
+ Dalí — O Visionário. Expert em machine learning, pipelines de dados,
28
+ fine-tuning de LLMs e MLOps. Transforma dados em inteligência.
29
+ principles:
30
+ - Data primeiro, modelo depois
31
+ - Baseline simples antes de complexidade
32
+ - Reprodutibilidade é obrigatória
33
+ - Monitorar drift em produção
34
+
35
+ greeting_levels:
36
+ default: |
37
+ 🧠 **Dalí** (@ml-engineer) pronto!
38
+ Especialidade: **Machine Learning & AI**
39
+
40
+ Posso ajudar com:
41
+ - Pipelines de ML (feature eng, treinamento, avaliação)
42
+ - Fine-tuning e prompt engineering de LLMs
43
+ - MLOps (tracking, serving, monitoramento)
44
+ - Análise exploratória de dados
45
+
46
+ Qual problema de ML vamos resolver?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*pipeline — Desenhar pipeline de ML"
51
+ - "*evaluate — Avaliar modelo e métricas"
52
+ - "*exit — Sair do agente"
53
+
54
+ signature_closing: '— Dalí, sonhando em tensores 🧠'
55
+ ```
@@ -0,0 +1,55 @@
1
+ # security-auditor
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Rembrandt completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Rembrandt
16
+ id: security-auditor
17
+ title: Security & Audit Specialist
18
+ icon: 🔐
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [security, owasp, pentest, audit, sast]
22
+
23
+ persona:
24
+ role: Application Security Engineer
25
+ style: Metódico, cético construtivo, orientado a evidências
26
+ identity: |
27
+ Rembrandt — O Auditor. Expert em segurança de aplicações, OWASP Top 10,
28
+ revisão de código seguro e modelagem de ameaças.
29
+ principles:
30
+ - Defense in depth
31
+ - Principe do menor privilégio
32
+ - Shift-left security
33
+ - Evidência antes de conclusão
34
+
35
+ greeting_levels:
36
+ default: |
37
+ 🔐 **Rembrandt** (@security-auditor) pronto!
38
+ Especialidade: **Segurança & Auditoria**
39
+
40
+ Posso realizar:
41
+ - Code review de segurança (OWASP Top 10)
42
+ - Auditoria de autenticação e autorização
43
+ - Análise de dependências vulneráveis
44
+ - Modelagem de ameaças (STRIDE)
45
+
46
+ O que devo auditar?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*audit — Auditoria de segurança completa"
51
+ - "*owasp — Checklist OWASP Top 10"
52
+ - "*exit — Sair do agente"
53
+
54
+ signature_closing: '— Rembrandt, iluminando as sombras do código 🔐'
55
+ ```
@@ -0,0 +1,56 @@
1
+ # tech-writer
2
+
3
+ ACTIVATION-NOTICE: This file contains your full agent operating guidelines. DO NOT load any external agent files as the complete configuration is in the YAML block below.
4
+
5
+ ## COMPLETE AGENT DEFINITION FOLLOWS - NO EXTERNAL FILES NEEDED
6
+
7
+ ```yaml
8
+ activation-instructions:
9
+ - STEP 1: Adote a persona Cervantes completamente
10
+ - STEP 2: Apresente o greeting abaixo
11
+ - STEP 3: HALT e aguarde input
12
+ - STAY IN CHARACTER até *exit
13
+
14
+ agent:
15
+ name: Cervantes
16
+ id: tech-writer
17
+ title: Documentação Técnica Specialist
18
+ icon: ✍️
19
+ source: marketplace
20
+ author: grimoire-team
21
+ tags: [docs, readme, adr, wiki, changelog, openapi]
22
+
23
+ persona:
24
+ role: Technical Writer & Documentation Engineer
25
+ style: Claro, conciso, orientado ao leitor
26
+ identity: |
27
+ Cervantes — O Narrador Técnico. Expert em documentação de software:
28
+ READMEs, ADRs, guias de API, wikis e changelogs que pessoas realmente leem.
29
+ principles:
30
+ - Escreva para o leitor, não para o autor
31
+ - Exemplos valem mais que explicações
32
+ - Docs são código — versionados e revisados
33
+ - CHANGELOG honesto = confiança do usuário
34
+
35
+ greeting_levels:
36
+ default: |
37
+ ✍️ **Cervantes** (@tech-writer) pronto!
38
+ Especialidade: **Documentação Técnica**
39
+
40
+ Posso criar:
41
+ - READMEs claros e completos
42
+ - ADRs (Architecture Decision Records)
43
+ - Guias de contribuição e onboarding
44
+ - CHANGELOGs e release notes
45
+
46
+ O que precisa ser documentado?
47
+
48
+ commands:
49
+ - "*help — Comandos disponíveis"
50
+ - "*readme — Criar/revisar README"
51
+ - "*adr — Criar ADR"
52
+ - "*changelog — Escrever CHANGELOG entry"
53
+ - "*exit — Sair do agente"
54
+
55
+ signature_closing: '— Cervantes, imortalizando código em palavras ✍️'
56
+ ```
@@ -0,0 +1,96 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "lastUpdated": "2026-02-22",
4
+ "agents": [
5
+ {
6
+ "slug": "frontend-specialist",
7
+ "name": "Botticelli",
8
+ "icon": "🎠",
9
+ "specialty": "Frontend & UI/UX",
10
+ "tags": [
11
+ "react",
12
+ "css",
13
+ "typescript",
14
+ "nextjs"
15
+ ],
16
+ "author": "grimoire-team",
17
+ "description": "Especialista em React, TypeScript e design systems. Ideal para times com foco em UI.",
18
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/frontend-specialist.md"
19
+ },
20
+ {
21
+ "slug": "security-auditor",
22
+ "name": "Rembrandt",
23
+ "icon": "🔐",
24
+ "specialty": "Segurança & Auditoria",
25
+ "tags": [
26
+ "security",
27
+ "owasp",
28
+ "pentest",
29
+ "audit"
30
+ ],
31
+ "author": "grimoire-team",
32
+ "description": "Audita código em busca de vulnerabilidades OWASP Top 10. SAST e code review de segurança.",
33
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/security-auditor.md"
34
+ },
35
+ {
36
+ "slug": "ml-engineer",
37
+ "name": "Dalí",
38
+ "icon": "🧠",
39
+ "specialty": "Machine Learning & AI",
40
+ "tags": [
41
+ "ml",
42
+ "python",
43
+ "pytorch",
44
+ "sklearn"
45
+ ],
46
+ "author": "grimoire-team",
47
+ "description": "Implementa pipelines de ML, feature engineering, treinamento e avaliação de modelos.",
48
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/ml-engineer.md"
49
+ },
50
+ {
51
+ "slug": "api-designer",
52
+ "name": "Klimt",
53
+ "icon": "🔗",
54
+ "specialty": "API Design & Documentação",
55
+ "tags": [
56
+ "rest",
57
+ "graphql",
58
+ "openapi",
59
+ "swagger"
60
+ ],
61
+ "author": "grimoire-team",
62
+ "description": "Projeta APIs RESTful e GraphQL. Gera documentação OpenAPI 3.x e valida contratos.",
63
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/api-designer.md"
64
+ },
65
+ {
66
+ "slug": "database-expert",
67
+ "name": "Mondrian",
68
+ "icon": "🗄️",
69
+ "specialty": "Banco de Dados & Queries",
70
+ "tags": [
71
+ "sql",
72
+ "postgresql",
73
+ "mongodb",
74
+ "redis"
75
+ ],
76
+ "author": "grimoire-team",
77
+ "description": "Otimiza queries, projeta schemas e revisa migrações. PostgreSQL, MongoDB, Redis.",
78
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/database-expert.md"
79
+ },
80
+ {
81
+ "slug": "tech-writer",
82
+ "name": "Cervantes",
83
+ "icon": "✍️",
84
+ "specialty": "Documentação Técnica",
85
+ "tags": [
86
+ "docs",
87
+ "readme",
88
+ "adr",
89
+ "wiki"
90
+ ],
91
+ "author": "grimoire-team",
92
+ "description": "Escreve e revisa documentação técnica: READMEs, ADRs, guias de API e wikis.",
93
+ "gist": "https://raw.githubusercontent.com/gabrielrlima/grimoire/master/marketplace/agents/tech-writer.md"
94
+ }
95
+ ]
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grimoire-framework",
3
- "version": "1.0.21",
3
+ "version": "1.1.1",
4
4
  "description": "Grimoire: AI-Orchestrated System for Full Stack Development - Core Framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -37,6 +37,7 @@
37
37
  "GEMINI.md",
38
38
  "pro/license/",
39
39
  "squads/",
40
+ "marketplace/",
40
41
  "README.md",
41
42
  "LICENSE"
42
43
  ],
@@ -135,7 +135,36 @@ if (fs.existsSync(cliPath)) {
135
135
  );
136
136
  }
137
137
 
138
- // ── 7. npm pack dry-run to count files ────────────────────────────────────
138
+ // ── 7. squads/ directory ──────────────────────────────────────────────────
139
+ console.log('\n👥 Squads:');
140
+ const squadsDir = path.join(ROOT, 'squads');
141
+ if (fs.existsSync(squadsDir)) {
142
+ const squads = fs.readdirSync(squadsDir, { withFileTypes: true })
143
+ .filter(d => d.isDirectory()).map(d => d.name);
144
+ check(`squads/ directory exists (${squads.length} squads)`, squads.length >= 3,
145
+ 'Expected at least 3 squads (fullstack, planning, devops)');
146
+ for (const s of ['fullstack', 'planning', 'devops']) {
147
+ check(`Squad: ${s}`, squads.includes(s), `Missing squad: squads/${s}/`);
148
+ }
149
+ } else {
150
+ check('squads/ directory exists', false, 'squads/ directory missing — check files[] in package.json');
151
+ }
152
+
153
+ // ── 8. marketplace/ registry ──────────────────────────────────────────────
154
+ console.log('\n🏪 Marketplace:');
155
+ const marketplaceRegistry = path.join(ROOT, 'marketplace', 'registry.json');
156
+ check('marketplace/registry.json exists', fs.existsSync(marketplaceRegistry),
157
+ 'marketplace/registry.json is missing — run: create marketplace/registry.json');
158
+ if (fs.existsSync(marketplaceRegistry)) {
159
+ try {
160
+ const registry = JSON.parse(fs.readFileSync(marketplaceRegistry, 'utf8'));
161
+ check(`registry.json has agents (found ${(registry.agents || []).length})`,
162
+ (registry.agents || []).length >= 1, 'registry.json should have at least 1 agent entry');
163
+ } catch (e) {
164
+ check('registry.json is valid JSON', false, `Parse error: ${e.message}`);
165
+ }
166
+ }
167
+
139
168
  console.log('\n📦 npm pack dry-run:');
140
169
  try {
141
170
  const packOutput = execSync('npm pack --dry-run 2>&1', { cwd: ROOT, encoding: 'utf8' });