@fabioforest/openclaw 3.4.1 → 3.5.0

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/README.md CHANGED
@@ -44,6 +44,7 @@ npx @fabioforest/openclaw ide install --apply
44
44
  |----------|---------|-----------|
45
45
  | Primeira vez no projeto | `init --apply` | Cria `.agent/` com templates |
46
46
  | Atualizar skills/rules | `update --apply` | Atualiza preservando customizações |
47
+ | Desinstalar do projeto | `uninstall --apply` | Remove `.agent/` com backup |
47
48
  | Ver o que está instalado | `status` | Lista componentes e config |
48
49
  | Algo não funciona | `doctor` | Diagnóstico completo |
49
50
  | Quero entender meu ambiente | `inspect` | Análise 100% read-only |
@@ -113,6 +114,54 @@ npx @fabioforest/openclaw update --apply --merge
113
114
 
114
115
  ---
115
116
 
117
+ ---
118
+
119
+ ### `openclaw uninstall` — Desinstalar do projeto
120
+
121
+ **Quando usar:** Quando quiser remover completamente o OpenClaw de um projeto.
122
+
123
+ ```bash
124
+ # 1. Simula a remoção (mostra o que seria deletado)
125
+ npx @fabioforest/openclaw uninstall
126
+ # → Mostra tree de .agent/ e openclaw.json
127
+ # → Alerta sobre audit logs e state que seriam perdidos
128
+ # → Nenhum arquivo é removido
129
+
130
+ # 2. Aplica a remoção (com backup automático)
131
+ npx @fabioforest/openclaw uninstall --apply
132
+ # → Pede para digitar "UNINSTALL" como confirmação
133
+ # → Oferece fazer backup (.agent.backup-<timestamp>/)
134
+ # → Remove .agent/ e openclaw.json
135
+ # → Salva log de auditoria no diretório
136
+
137
+ # 3. Remoção forçada (sem backup, com --yes pula confirmação)
138
+ npx @fabioforest/openclaw uninstall --apply --force --yes
139
+ ```
140
+
141
+ **Saída de exemplo (modo PLAN):**
142
+
143
+ ```
144
+ 🗑️ OpenClaw Uninstall
145
+
146
+ 📂 Diretório: /home/user/meu-projeto
147
+
148
+ 🔴 REMOVER .agent/ (25 arquivos)
149
+ 📁 agents (3 arquivos)
150
+ 📁 audit (1 arquivos)
151
+ 📁 hooks (1 arquivos)
152
+ 📁 rules (5 arquivos)
153
+ 📁 skills (11 arquivos)
154
+ 📁 workflows (7 arquivos)
155
+ 🔴 REMOVER openclaw.json
156
+
157
+ ⚠️ 1 log(s) de auditoria serão perdidos!
158
+
159
+ 🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.
160
+ Para desinstalar, rode: npx @fabioforest/openclaw uninstall --apply
161
+ ```
162
+
163
+ ---
164
+
116
165
  ### `openclaw inspect` — Analisar ambiente (read-only)
117
166
 
118
167
  **Quando usar:** Antes de qualquer ação, para entender o contexto. 100% read-only — nunca altera nada.
@@ -419,6 +468,155 @@ npx @fabioforest/openclaw assist
419
468
 
420
469
  ---
421
470
 
471
+ ## 💬 Exemplo Real: Usando o OpenClaw na IDE (Chat)
472
+
473
+ O OpenClaw funciona como agente via chat na IDE. Aqui está uma simulação de como seria o fluxo real:
474
+
475
+ ### Exemplo 1: Otimizar perfil do LinkedIn
476
+
477
+ ```
478
+ 👤 Você (chat na IDE):
479
+ "Quero otimizar meu perfil do LinkedIn para vagas de AI Engineer"
480
+
481
+ 🤖 Agente (openclaw-router detecta: linkedin-optimizer):
482
+ 📋 INSPECT ─ Coletando contexto:
483
+ • Objetivo: otimizar perfil LinkedIn para AI Engineer
484
+ • Idioma: pt-BR
485
+ • Skills instaladas: linkedin-optimizer ✅
486
+
487
+ 📝 PLAN ─ Proposta de ações:
488
+ 1. Analisar headline atual e propor 2 versões A/B
489
+ 2. Reescrever seção "Sobre" com keywords de AI/MLOps
490
+ 3. Sugerir ajustes nas experiências com métricas
491
+ 4. Gerar checklist de publicação
492
+
493
+ ⚠️ RESTRIÇÃO: LinkedIn proíbe automação. Todo conteúdo
494
+ será gerado como rascunho para aplicação manual.
495
+
496
+ Deseja prosseguir? (S/n)
497
+
498
+ 👤 Você: "S"
499
+
500
+ 🤖 Agente:
501
+ ✅ APPLY ─ Rascunhos salvos em .agent/state/linkedin/drafts.md
502
+
503
+ ## Headline (opção A)
504
+ "AI Engineer | MLOps | Python | RAG & LLMs | Open Source"
505
+
506
+ ## Headline (opção B)
507
+ "Engenheiro de IA | Construindo pipelines de ML em produção"
508
+
509
+ 📝 AUDIT ─ log salvo em .agent/audit/
510
+ ```
511
+
512
+ ### Exemplo 2: Testar performance de um site
513
+
514
+ ```
515
+ 👤 Você:
516
+ "Testa a performance do meu site https://meu-portfolio.dev"
517
+
518
+ 🤖 Agente (openclaw-router detecta: site-tester):
519
+ 📋 INSPECT:
520
+ • URL: https://meu-portfolio.dev
521
+ • robots.txt: verificado ✅
522
+ • Ferramentas disponíveis: PageSpeed Insights API
523
+
524
+ 📝 PLAN:
525
+ 1. Rodar Lighthouse via PageSpeed Insights (sem infra local)
526
+ 2. Coletar métricas: Performance, SEO, Acessibilidade, PWA
527
+ 3. Listar as 5 principais oportunidades de melhoria
528
+ 4. Salvar relatório em .agent/state/site-tests/
529
+
530
+ Confirmar execução?
531
+
532
+ 👤 Você: "sim"
533
+
534
+ 🤖 Agente:
535
+ ✅ Resultados:
536
+ • Performance: 87 → otimizar imagens (ganho estimado: +8pts)
537
+ • SEO: 95 ✅
538
+ • Acessibilidade: 72 → falta alt em 3 imagens + contraste baixo
539
+ • PWA: 60 → falta manifest.json e service worker
540
+
541
+ 📊 Relatório salvo em .agent/state/site-tests/2026-02-19.json
542
+ 📝 Audit salvo
543
+ ```
544
+
545
+ ### Exemplo 3: Atualizar skills após nova versão
546
+
547
+ ```
548
+ 👤 Você:
549
+ "Saiu versão nova do OpenClaw, como atualizo?"
550
+
551
+ 🤖 Agente (openclaw-router detecta: assist):
552
+ Recomendo o seguinte fluxo:
553
+
554
+ 1. Primeiro, veja o que mudaria (modo PLAN, seguro):
555
+ $ npx @fabioforest/openclaw update
556
+
557
+ 2. Se estiver tudo OK, aplique:
558
+ $ npx @fabioforest/openclaw update --apply
559
+
560
+ 3. Para preservar customizações:
561
+ $ npx @fabioforest/openclaw update --apply --merge
562
+
563
+ O update faz backup automático de arquivos customizados
564
+ antes de sobrescrever, e copia novos templates.
565
+
566
+ Quer que eu execute o passo 1 agora?
567
+ ```
568
+
569
+ ### Exemplo 4: Desinstalar o OpenClaw de um projeto
570
+
571
+ ```
572
+ 👤 Você:
573
+ "Quero remover o OpenClaw deste projeto"
574
+
575
+ 🤖 Agente:
576
+ Vou simular a remoção primeiro (modo PLAN, seguro):
577
+
578
+ $ npx @fabioforest/openclaw uninstall
579
+
580
+ 🗑️ PLAN — Seria removido:
581
+ .agent/ (25 arquivos, 15 skills, 5 rules)
582
+ openclaw.json
583
+ ⚠️ 3 logs de auditoria seriam perdidos
584
+
585
+ Para aplicar de fato:
586
+ $ npx @fabioforest/openclaw uninstall --apply
587
+
588
+ O sistema vai pedir que você digite "UNINSTALL"
589
+ e oferecerá fazer backup antes de remover.
590
+
591
+ Quer que eu execute?
592
+ ```
593
+
594
+ ---
595
+
596
+ ## 🔄 Ciclo de Vida Completo
597
+
598
+ ```
599
+ 📦 INSTALAR → npx @fabioforest/openclaw init --apply
600
+ ou: npx @fabioforest/openclaw ide install --apply
601
+
602
+ 🔍 INSPECIONAR → npx @fabioforest/openclaw inspect
603
+ npx @fabioforest/openclaw status
604
+
605
+ 🛠️ USAR → Chat na IDE (skills + router fazem o resto)
606
+ ou: npx @fabioforest/openclaw assist
607
+
608
+ 🔄 ATUALIZAR → npx @fabioforest/openclaw update --apply
609
+ (preserva customizações com --merge)
610
+
611
+ 🏥 DIAGNOSTICAR → npx @fabioforest/openclaw doctor
612
+ npx @fabioforest/openclaw debug
613
+
614
+ 🗑️ DESINSTALAR → npx @fabioforest/openclaw uninstall --apply
615
+ (backup automático + confirmação forte)
616
+ ```
617
+
618
+ ---
619
+
422
620
  ## 🛠️ Desenvolvimento
423
621
 
424
622
  ```bash
@@ -445,8 +643,8 @@ Todas as flags funcionam com qualquer comando:
445
643
  |------|-----------|--------|
446
644
  | `--plan` | Modo simulação (read-only) | **Sim** |
447
645
  | `--apply` | Modo execução (aplica alterações) | Não |
448
- | `--yes, -y` | Pula confirmações | Não |
449
- | `--force, -f` | Permite operações destrutivas | Não |
646
+ | `--yes, -y` | Pula confirmações interativas | Não |
647
+ | `--force, -f` | Permite operações destrutivas (sem backup no uninstall) | Não |
450
648
  | `--path, -p <dir>` | Diretório alvo | `./` |
451
649
  | `--quiet, -q` | Saída mínima | Não |
452
650
  | `--no-audit` | Desabilita logs de auditoria | Não |
package/bin/openclaw.js CHANGED
@@ -24,6 +24,7 @@ const pkg = require("../package.json");
24
24
  const COMMANDS = {
25
25
  init: "../lib/cli/init",
26
26
  update: "../lib/cli/update",
27
+ uninstall: "../lib/cli/uninstall",
27
28
  status: "../lib/cli/status",
28
29
  doctor: "../lib/cli/doctor",
29
30
  debug: "../lib/cli/debug",
@@ -92,6 +93,7 @@ function showHelp() {
92
93
  Comandos:
93
94
  init Instala templates .agent/ no projeto atual
94
95
  update Atualiza templates preservando customizações
96
+ uninstall Remove .agent/ e openclaw.json (com backup)
95
97
  status Mostra status da instalação
96
98
  doctor Healthcheck automatizado do ambiente
97
99
  setup Roda wizard interativo de configuração
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Comando CLI: uninstall
5
+ *
6
+ * Remove a instalação do OpenClaw (.agent/) de um projeto.
7
+ * Segue o protocolo consent-first:
8
+ * - Modo PLAN por padrão (mostra o que seria removido)
9
+ * - Exige --apply para executar
10
+ * - Exige confirmação forte (digitar frase)
11
+ * - Backup opcional antes de remover
12
+ */
13
+
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+ const readline = require("readline");
17
+ const { detectContext, getAuditHeader } = require("../context");
18
+
19
+ function ask(q) {
20
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
21
+ return new Promise((res) => rl.question(q, (ans) => { rl.close(); res(ans.trim()); }));
22
+ }
23
+
24
+ /**
25
+ * Conta arquivos recursivamente em um diretório.
26
+ */
27
+ function countFiles(dir) {
28
+ let count = 0;
29
+ if (!fs.existsSync(dir)) return 0;
30
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
31
+ if (entry.isDirectory()) {
32
+ count += countFiles(path.join(dir, entry.name));
33
+ } else {
34
+ count++;
35
+ }
36
+ }
37
+ return count;
38
+ }
39
+
40
+ /**
41
+ * Lista o conteúdo de um diretório de forma visual (tree).
42
+ */
43
+ function listTree(dir, prefix = "") {
44
+ const lines = [];
45
+ if (!fs.existsSync(dir)) return lines;
46
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
47
+ entries.forEach((entry, i) => {
48
+ const isLast = i === entries.length - 1;
49
+ const connector = isLast ? "└── " : "├── ";
50
+ const icon = entry.isDirectory() ? "📁" : "📄";
51
+ lines.push(`${prefix}${connector}${icon} ${entry.name}`);
52
+ if (entry.isDirectory()) {
53
+ const childPrefix = prefix + (isLast ? " " : "│ ");
54
+ lines.push(...listTree(path.join(dir, entry.name), childPrefix));
55
+ }
56
+ });
57
+ return lines;
58
+ }
59
+
60
+ /**
61
+ * Executa o comando uninstall.
62
+ * @param {object} options
63
+ * @param {string} options.targetPath — diretório alvo
64
+ * @param {object} options.flags — flags do CLI
65
+ */
66
+ async function run({ targetPath, flags }) {
67
+ const agentDir = path.join(targetPath, ".agent");
68
+ const configFile = path.join(targetPath, "openclaw.json");
69
+ const planMode = !flags.apply;
70
+ const ctx = detectContext(targetPath);
71
+
72
+ console.log("\n🗑️ OpenClaw Uninstall\n");
73
+
74
+ // Verificar se existe instalação
75
+ if (!fs.existsSync(agentDir) && !fs.existsSync(configFile)) {
76
+ console.log("ℹ️ Nenhuma instalação do OpenClaw encontrada neste diretório.");
77
+ console.log(` Path: ${targetPath}`);
78
+ return;
79
+ }
80
+
81
+ // Mostrar o que será removido
82
+ console.log(` 📂 Diretório: ${targetPath}`);
83
+ console.log("");
84
+
85
+ const toRemove = [];
86
+
87
+ if (fs.existsSync(agentDir)) {
88
+ const fileCount = countFiles(agentDir);
89
+ toRemove.push({ path: agentDir, label: ".agent/", files: fileCount, isDir: true });
90
+ console.log(` 🔴 REMOVER .agent/ (${fileCount} arquivos)`);
91
+
92
+ // Mostrar tree resumido (primeiro nível)
93
+ const entries = fs.readdirSync(agentDir, { withFileTypes: true });
94
+ entries.forEach(e => {
95
+ const icon = e.isDirectory() ? "📁" : "📄";
96
+ const subCount = e.isDirectory() ? ` (${countFiles(path.join(agentDir, e.name))} arquivos)` : "";
97
+ console.log(` ${icon} ${e.name}${subCount}`);
98
+ });
99
+ }
100
+
101
+ if (fs.existsSync(configFile)) {
102
+ toRemove.push({ path: configFile, label: "openclaw.json", isDir: false });
103
+ console.log(` 🔴 REMOVER openclaw.json`);
104
+ }
105
+
106
+ // Verificar audit logs que seriam perdidos
107
+ const auditDir = path.join(agentDir, "audit");
108
+ if (fs.existsSync(auditDir)) {
109
+ const auditCount = countFiles(auditDir);
110
+ if (auditCount > 0) {
111
+ console.log(`\n ⚠️ ${auditCount} log(s) de auditoria serão perdidos!`);
112
+ }
113
+ }
114
+
115
+ // Verificar state que seria perdido
116
+ const stateDir = path.join(agentDir, "state");
117
+ if (fs.existsSync(stateDir)) {
118
+ const stateCount = countFiles(stateDir);
119
+ if (stateCount > 0) {
120
+ console.log(` ⚠️ ${stateCount} arquivo(s) de estado serão perdidos (mission_control, MEMORY)!`);
121
+ }
122
+ }
123
+
124
+ // Modo PLAN: não faz nada
125
+ if (planMode) {
126
+ console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
127
+ console.log(" Para desinstalar, rode: npx @fabioforest/openclaw uninstall --apply");
128
+ return;
129
+ }
130
+
131
+ // Modo APPLY: pedir confirmação forte
132
+ console.log("");
133
+ if (!flags.yes) {
134
+ const confirm = await ask("⚠️ Digite 'UNINSTALL' para confirmar a remoção: ");
135
+ if (confirm !== "UNINSTALL") {
136
+ console.log("⏹️ Cancelado. Nada foi removido.");
137
+ return;
138
+ }
139
+ }
140
+
141
+ // Backup opcional
142
+ if (!flags.force) {
143
+ const doBackup = flags.yes ? "s" : await ask("💾 Fazer backup antes de remover? (S/n): ");
144
+ if (doBackup.toLowerCase() !== "n") {
145
+ const backupName = `.agent.backup-${Date.now()}`;
146
+ const backupPath = path.join(targetPath, backupName);
147
+ try {
148
+ fs.cpSync(agentDir, backupPath, { recursive: true });
149
+ console.log(` ✅ Backup criado: ${backupName}/`);
150
+ } catch (err) {
151
+ console.error(` ⚠️ Falha no backup: ${err.message}`);
152
+ const cont = await ask(" Continuar sem backup? (y/N): ");
153
+ if (cont.toLowerCase() !== "y") {
154
+ console.log("⏹️ Cancelado.");
155
+ return;
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ // Executar remoção
162
+ const audit = [getAuditHeader(ctx, "uninstall", flags)];
163
+
164
+ try {
165
+ for (const item of toRemove) {
166
+ if (item.isDir) {
167
+ fs.rmSync(item.path, { recursive: true, force: true });
168
+ } else {
169
+ fs.unlinkSync(item.path);
170
+ }
171
+ console.log(` ✅ Removido: ${item.label}`);
172
+ audit.push(`- ACT: REMOVED ${item.label}`);
173
+ }
174
+
175
+ console.log("\n✨ OpenClaw desinstalado com sucesso!");
176
+ console.log(" Para reinstalar: npx @fabioforest/openclaw init --apply\n");
177
+
178
+ // Gravar audit no diretório pai (já que .agent/ foi removido)
179
+ if (flags.audit !== false) {
180
+ const filename = `openclaw-uninstall-${new Date().toISOString().replace(/[:.]/g, "-")}.md`;
181
+ const auditPath = path.join(targetPath, filename);
182
+ try {
183
+ fs.writeFileSync(auditPath, audit.join("\n") + "\n", "utf8");
184
+ console.log(` 📝 Log de auditoria: ${filename}`);
185
+ } catch (e) { /* silencioso */ }
186
+ }
187
+
188
+ } catch (err) {
189
+ console.error(`\n❌ Falha: ${err.message}`);
190
+ process.exit(1);
191
+ }
192
+ }
193
+
194
+ module.exports = { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabioforest/openclaw",
3
- "version": "3.4.1",
3
+ "version": "3.5.0",
4
4
  "description": "Agentes autônomos para engenharia de software",
5
5
  "publishConfig": {
6
6
  "access": "public"