@fabioforest/openclaw 3.0.0 → 3.4.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.
Files changed (35) hide show
  1. package/bin/openclaw.js +37 -8
  2. package/lib/cli/assist.js +84 -0
  3. package/lib/cli/doctor.js +37 -3
  4. package/lib/cli/ide.js +218 -0
  5. package/lib/cli/init.js +135 -79
  6. package/lib/cli/inspect.js +58 -0
  7. package/lib/cli/orchestrate.js +43 -15
  8. package/lib/cli/update.js +113 -47
  9. package/lib/context/collector.js +104 -0
  10. package/lib/context/index.js +75 -0
  11. package/lib/router/match.js +107 -0
  12. package/lib/setup/config_wizard.js +2 -0
  13. package/package.json +2 -2
  14. package/templates/.agent/agents/workflow-automator.md +31 -0
  15. package/templates/.agent/rules/CONSENT_FIRST.md +24 -0
  16. package/templates/.agent/rules/DEV_MODE.md +18 -0
  17. package/templates/.agent/rules/ROUTER_PROTOCOL.md +22 -0
  18. package/templates/.agent/rules/WEB_AUTOMATION.md +52 -0
  19. package/templates/.agent/skills/content-sourcer/SKILL.md +48 -0
  20. package/templates/.agent/skills/context-flush/SKILL.md +30 -0
  21. package/templates/.agent/skills/drive-organizer/SKILL.md +40 -0
  22. package/templates/.agent/skills/linkedin-optimizer/SKILL.md +48 -0
  23. package/templates/.agent/skills/mission-control/SKILL.md +37 -0
  24. package/templates/.agent/skills/openclaw-assist/SKILL.md +30 -0
  25. package/templates/.agent/skills/openclaw-dev/SKILL.md +26 -0
  26. package/templates/.agent/skills/openclaw-inspect/SKILL.md +21 -0
  27. package/templates/.agent/skills/openclaw-installation-debugger/scripts/debug.js +16 -2
  28. package/templates/.agent/skills/openclaw-router/SKILL.md +34 -0
  29. package/templates/.agent/skills/openclaw-security/SKILL.md +21 -0
  30. package/templates/.agent/skills/site-tester/SKILL.md +49 -0
  31. package/templates/.agent/skills/smart-router/SKILL.md +116 -0
  32. package/templates/.agent/skills/web-scraper/SKILL.md +51 -0
  33. package/templates/.agent/state/MEMORY.md +8 -0
  34. package/templates/.agent/state/mission_control.json +34 -0
  35. package/templates/.agent/workflows/ai-capture.md +39 -0
package/bin/openclaw.js CHANGED
@@ -28,6 +28,9 @@ const COMMANDS = {
28
28
  doctor: "../lib/cli/doctor",
29
29
  debug: "../lib/cli/debug",
30
30
  check: "../lib/cli/orchestrate",
31
+ inspect: "../lib/cli/inspect",
32
+ assist: "../lib/cli/assist",
33
+ ide: "../lib/cli/ide",
31
34
  };
32
35
 
33
36
  /**
@@ -36,7 +39,10 @@ const COMMANDS = {
36
39
  * @returns {{ command: string|null, flags: object }}
37
40
  */
38
41
  function parseArgs(argv) {
39
- const flags = {};
42
+ const flags = {
43
+ plan: true, // Default: PLAN mode (read-only)
44
+ audit: true // Default: Generate audit logs
45
+ };
40
46
  let command = null;
41
47
 
42
48
  for (let i = 0; i < argv.length; i++) {
@@ -49,15 +55,28 @@ function parseArgs(argv) {
49
55
  } else if (arg === "--force" || arg === "-f") {
50
56
  flags.force = true;
51
57
  } else if (arg === "--path" || arg === "-p") {
52
- // Próximo argumento é o caminho
53
58
  flags.path = argv[++i] || ".";
54
59
  } else if (arg === "--quiet" || arg === "-q") {
55
60
  flags.quiet = true;
61
+ } else if (arg === "--apply") {
62
+ flags.apply = true;
63
+ flags.plan = false; // Apply overrides Plan default
64
+ } else if (arg === "--plan") {
65
+ flags.plan = true;
66
+ } else if (arg === "--yes" || arg === "-y") {
67
+ flags.yes = true;
68
+ } else if (arg === "--no-audit") {
69
+ flags.audit = false;
70
+ } else if (arg === "--merge") {
71
+ flags.merge = true;
56
72
  } else if (!arg.startsWith("-") && !command) {
57
73
  command = arg;
58
74
  }
59
75
  }
60
76
 
77
+ // Se apply foi passado, plan é false (a menos que forçado explicitamente, mas apply vence na lógica acima)
78
+ // Se o usuário não passar nada, plan=true (default)
79
+
61
80
  return { command, flags };
62
81
  }
63
82
 
@@ -78,19 +97,29 @@ function showHelp() {
78
97
  setup Roda wizard interativo de configuração
79
98
  debug Diagnóstico avançado de instalação e rede
80
99
  check Orquestrador inteligente (instala ou repara)
100
+ inspect Analisa ambiente e contexto (100% read-only)
101
+ assist Assistente geral com roteamento de skills
102
+ ide Instala AI OS na IDE (ide install / ide doctor)
81
103
 
82
- Opções:
104
+ Opções Globais:
83
105
  --path, -p <dir> Diretório alvo (padrão: ./)
84
- --force, -f Sobrescreve .agent/ existente (init)
106
+ --plan Modo Simulação (PADRÃO): Mostra o que será feito sem alterar nada
107
+ --apply Modo Execução: Aplica as alterações propostas
108
+ --yes, -y Confirma automaticamente (skip prompts)
109
+ --force, -f Permite operações destrutivas (exige confirmação forte)
110
+ --no-audit Desabilita geração de logs de auditoria
111
+ --merge Atualização segura (não sobrescreve customizações)
85
112
  --quiet, -q Saída mínima
86
113
  --help, -h Mostra esta ajuda
87
114
  --version, -v Mostra a versão
88
115
 
89
116
  Exemplos:
90
- npx openclaw init
91
- npx openclaw init --force --path ./meu-projeto
92
- npx openclaw doctor
93
- npx openclaw status
117
+ npx openclaw init --plan (Simula instalação)
118
+ npx openclaw init --apply (Instala de fato)
119
+ npx openclaw check (Orquestrador seguro)
120
+ npx openclaw inspect (Analisa contexto)
121
+ npx openclaw assist (Assistente geral)
122
+ npx openclaw ide install --apply (Instala AI OS na IDE)
94
123
  `);
95
124
  }
96
125
 
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Comando CLI: assist
5
+ *
6
+ * Assistente geral do OpenClaw AI OS.
7
+ * Detecta contexto, roteia para a skill correta e apresenta plano.
8
+ * Funciona tanto via terminal quanto como "cérebro" para IDEs (chat-first).
9
+ */
10
+
11
+ const path = require("path");
12
+ const readline = require("readline");
13
+ const collectContext = require("../context/collector");
14
+ const { matchSkill } = require("../router/match");
15
+
16
+ // Caminho dos templates e skills do pacote
17
+ const TEMPLATES_DIR = path.join(__dirname, "..", "..", "templates");
18
+ const SKILLS_DIR = path.join(TEMPLATES_DIR, ".agent", "skills");
19
+
20
+ function ask(q) {
21
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
22
+ return new Promise((res) => rl.question(q, (ans) => { rl.close(); res(ans.trim()); }));
23
+ }
24
+
25
+ /**
26
+ * Executa o comando assist (menu interativo com roteamento de skills).
27
+ * @param {object} options
28
+ * @param {string} options.targetPath — diretório alvo
29
+ * @param {object} options.flags — flags do CLI
30
+ */
31
+ async function run({ targetPath, flags }) {
32
+ // 1. Coletar contexto (read-only)
33
+ const ctx = collectContext({
34
+ targetPath,
35
+ templatesDir: TEMPLATES_DIR,
36
+ });
37
+
38
+ console.log("\n🧠 OpenClaw Assist — Modo PLAN por padrão (seguro)\n");
39
+ console.log(` IDE: ${ctx.ide} | OpenClaw: ${ctx.openclaw.hasAgentDir ? "instalado" : "não instalado"}`);
40
+ console.log(` Plataforma: ${ctx.env.platform} | Docker: ${ctx.env.docker}\n`);
41
+
42
+ // 2. Se não tem OpenClaw instalado, sugerir instalação
43
+ if (!ctx.openclaw.hasAgentDir) {
44
+ console.log("⚠️ OpenClaw não detectado neste workspace.");
45
+ console.log(" Rode: npx openclaw init --apply (para instalar)\n");
46
+ return;
47
+ }
48
+
49
+ // 3. Pedir solicitação do usuário
50
+ console.log("Descreva o que deseja fazer:");
51
+ console.log(" (ex: 'criar skill', 'melhorar segurança', 'mission control tick')\n");
52
+ const request = await ask("> ");
53
+
54
+ if (!request) {
55
+ console.log("⏹️ Nenhuma solicitação. Saindo.");
56
+ return;
57
+ }
58
+
59
+ // 4. Rotear para skill correta
60
+ const match = matchSkill({ skillsDir: SKILLS_DIR, userText: request });
61
+
62
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
63
+ if (match.chosen) {
64
+ console.log(`🎯 Skill selecionada: ${match.chosen.name}`);
65
+ console.log(` Descrição: ${match.chosen.description}`);
66
+ } else {
67
+ console.log("❓ Nenhuma skill correspondente encontrada.");
68
+ console.log(" Tente reformular a solicitação ou use 'openclaw inspect' para ver skills disponíveis.");
69
+ }
70
+
71
+ if (match.alternatives.length > 0) {
72
+ console.log(`\n Alternativas:`);
73
+ match.alternatives.forEach(a => console.log(` • ${a.name}: ${a.description}`));
74
+ }
75
+
76
+ console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
77
+ console.log("\n✅ Protocolo recomendado:");
78
+ console.log(" 1) Rodar INSPECT (read-only) e revisar o contexto");
79
+ console.log(" 2) Descrever exatamente o que quer alterar");
80
+ console.log(" 3) Confirmar APPLY para executar");
81
+ console.log(" 4) Tudo será registrado em .agent/audit/\n");
82
+ }
83
+
84
+ module.exports = { run };
package/lib/cli/doctor.js CHANGED
@@ -166,12 +166,16 @@ async function checkPort() {
166
166
  try {
167
167
  const inUse = await portInUse(18789, "127.0.0.1");
168
168
  if (inUse) {
169
- return { name: "porta 18789", status: "ok", message: "Serviço respondendo em localhost:18789" };
169
+ return {
170
+ name: "porta 18789",
171
+ status: "ok",
172
+ message: "✅ Control UI acessível em http://127.0.0.1:18789"
173
+ };
170
174
  }
171
175
  return {
172
176
  name: "porta 18789",
173
177
  status: "warn",
174
- message: "Porta livre — serviço OpenClaw pode estar parado",
178
+ message: "Porta livre — serviço OpenClaw pode estar parado (UI indisponível)",
175
179
  };
176
180
  } catch {
177
181
  return {
@@ -182,6 +186,30 @@ async function checkPort() {
182
186
  }
183
187
  }
184
188
 
189
+ /**
190
+ * Verifica interfaces de rede para detectar VPN WireGuard ativa (Linux only).
191
+ * @returns {CheckResult}
192
+ */
193
+ function checkVpnInterface() {
194
+ const osType = require("os").type();
195
+ if (osType !== "Linux") {
196
+ return { name: "vpn interface", status: "ok", message: "N/A (não é Linux)" };
197
+ }
198
+
199
+ try {
200
+ const interfaces = require("os").networkInterfaces();
201
+ const wgInterface = Object.keys(interfaces).find(iface => iface.startsWith("wg"));
202
+
203
+ if (wgInterface) {
204
+ return { name: "vpn interface", status: "ok", message: `Detectada: ${wgInterface}` };
205
+ } else {
206
+ return { name: "vpn interface", status: "warn", message: "Nenhuma interface wg* encontrada" };
207
+ }
208
+ } catch (e) {
209
+ return { name: "vpn interface", status: "warn", message: "Erro ao listar interfaces" };
210
+ }
211
+ }
212
+
185
213
  /**
186
214
  * Verifica ambiente detectado.
187
215
  * @returns {CheckResult}
@@ -252,6 +280,12 @@ async function run({ targetPath, flags }) {
252
280
  // 4. .agent/
253
281
  results.push(...checkAgentDir(agentDir));
254
282
 
283
+ // 5. VPN (se Linux)
284
+ const vpnCheck = checkVpnInterface();
285
+ if (vpnCheck.message !== "N/A (não é Linux)") {
286
+ results.push(vpnCheck);
287
+ }
288
+
255
289
  // Exibir relatório
256
290
  printReport(results);
257
291
  console.log("");
@@ -263,4 +297,4 @@ async function run({ targetPath, flags }) {
263
297
  }
264
298
  }
265
299
 
266
- module.exports = { run, checkConfig, checkAgentDir, checkPort, checkEnvironment };
300
+ module.exports = { run, checkConfig, checkAgentDir, checkPort, checkEnvironment, checkVpnInterface };
package/lib/cli/ide.js ADDED
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Comando CLI: ide
5
+ *
6
+ * Gerencia a instalação do OpenClaw AI OS em IDEs.
7
+ * Sub-comandos: install (plan/apply), doctor.
8
+ * Sempre segue o protocolo consent-first.
9
+ */
10
+
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const readline = require("readline");
14
+ const { detectContext, getAuditHeader } = require("../context");
15
+ const { copyDirRecursive } = require("./init");
16
+
17
+ // Caminho dos templates do pacote
18
+ const TEMPLATES_DIR = path.join(__dirname, "..", "..", "templates");
19
+
20
+ function ask(q) {
21
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
22
+ return new Promise((res) => rl.question(q, (ans) => { rl.close(); res(ans.trim()); }));
23
+ }
24
+
25
+ /**
26
+ * Grava log de auditoria para o comando ide.
27
+ */
28
+ function writeAudit(targetPath, lines, flags) {
29
+ if (flags.audit === false) return;
30
+ const auditDir = path.join(targetPath, ".agent", "audit");
31
+ if (!fs.existsSync(auditDir)) {
32
+ try { fs.mkdirSync(auditDir, { recursive: true }); } catch (e) { }
33
+ }
34
+ const filename = `ide-${new Date().toISOString().replace(/[:.]/g, "-")}.md`;
35
+ try {
36
+ fs.writeFileSync(path.join(auditDir, filename), lines.join("\n") + "\n", "utf8");
37
+ } catch (e) {
38
+ console.error("⚠️ Falha ao gravar auditoria:", e.message);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Executa o comando ide.
44
+ * Uso: openclaw ide install [--apply] [--force]
45
+ * openclaw ide doctor
46
+ *
47
+ * @param {object} options
48
+ * @param {string} options.targetPath — diretório alvo
49
+ * @param {object} options.flags — flags do CLI
50
+ */
51
+ async function run({ targetPath, flags }) {
52
+ // Detectar sub-comando a partir de args restantes
53
+ // O bin/openclaw.js passa o comando "ide", então precisamos
54
+ // verificar os args para o sub-comando
55
+ const args = process.argv.slice(3);
56
+ const subCmd = args.find(a => !a.startsWith("-")) || "install";
57
+
58
+ if (subCmd === "doctor") {
59
+ return runDoctor({ targetPath, flags });
60
+ }
61
+
62
+ return runInstall({ targetPath, flags });
63
+ }
64
+
65
+ /**
66
+ * Sub-comando: ide install
67
+ * Instala .agent/ no projeto para uso em IDEs (plan/apply).
68
+ */
69
+ async function runInstall({ targetPath, flags }) {
70
+ const agentDst = path.join(targetPath, ".agent");
71
+ const agentSrc = path.join(TEMPLATES_DIR, ".agent");
72
+ const ctx = detectContext(targetPath);
73
+ const planMode = !flags.apply;
74
+ const audit = [getAuditHeader(ctx, "ide install", flags)];
75
+
76
+ console.log(`\n🧭 IDE Install — Plano (${planMode ? "SIMULAÇÃO" : "APPLY"}):\n`);
77
+ console.log(` Contexto: ${ctx.env} | IDE: ${ctx.ide}\n`);
78
+
79
+ if (fs.existsSync(agentDst) && !flags.force) {
80
+ console.log(" ✅ KEEP .agent/ (já existe)");
81
+ console.log(" 📦 MERGE Novos templates serão adicionados (preservando existentes)");
82
+ } else if (fs.existsSync(agentDst) && flags.force) {
83
+ console.log(" 🔥 DELETE .agent/ (--force)");
84
+ console.log(" 📦 COPY templates/.agent -> .agent/");
85
+ } else {
86
+ console.log(" 📁 CREATE .agent/");
87
+ console.log(" 📦 COPY templates/.agent -> .agent/");
88
+ }
89
+
90
+ // State templates (mission_control.json, MEMORY.md)
91
+ const stateDir = path.join(agentDst, "state");
92
+ if (!fs.existsSync(stateDir)) {
93
+ console.log(" 📁 CREATE .agent/state/ (Mission Control + MEMORY)");
94
+ } else {
95
+ console.log(" ✅ KEEP .agent/state/ (já existe)");
96
+ }
97
+
98
+ if (planMode) {
99
+ console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
100
+ console.log(" Para aplicar, rode: npx openclaw ide install --apply");
101
+ return;
102
+ }
103
+
104
+ // Confirmação
105
+ if (!flags.yes) {
106
+ if (flags.force && fs.existsSync(agentDst)) {
107
+ const phrase = await ask("⚠️ Digite 'DELETE .agent' para confirmar: ");
108
+ if (phrase !== "DELETE .agent") {
109
+ console.log("⏹️ Cancelado.");
110
+ return;
111
+ }
112
+ } else {
113
+ const ok = await ask("\nAplicar instalação IDE? (y/N): ");
114
+ if (ok.toLowerCase() !== "y") {
115
+ console.log("⏹️ Cancelado.");
116
+ return;
117
+ }
118
+ }
119
+ }
120
+
121
+ // Execução
122
+ try {
123
+ console.log("\n🚀 Executando...");
124
+
125
+ if (fs.existsSync(agentDst) && flags.force) {
126
+ fs.rmSync(agentDst, { recursive: true, force: true });
127
+ audit.push("- ACT: DELETED .agent/");
128
+ }
129
+
130
+ const isMerge = fs.existsSync(agentDst);
131
+ const stats = copyDirRecursive(agentSrc, agentDst, undefined, isMerge);
132
+ audit.push(`- ACT: ${isMerge ? "MERGED" : "COPIED"} templates (Files: ${stats.files}, Skipped: ${stats.skipped})`);
133
+
134
+ // Criar state se necessário
135
+ const stateTarget = path.join(agentDst, "state");
136
+ if (!fs.existsSync(stateTarget)) {
137
+ fs.mkdirSync(stateTarget, { recursive: true });
138
+ // Criar mission_control.json default
139
+ const mcDefault = {
140
+ project_status: "active",
141
+ project_name: path.basename(targetPath),
142
+ sprint_goal: "",
143
+ agents: [
144
+ { id: "orchestrator", role: "orchestrator", active: true },
145
+ { id: "researcher", role: "researcher", active: true },
146
+ { id: "writer", role: "writer", active: true },
147
+ ],
148
+ task_queue: [],
149
+ history: [],
150
+ settings: {
151
+ work_dir: "mission_control",
152
+ max_tasks_per_tick: 2,
153
+ default_priority: "medium",
154
+ },
155
+ };
156
+ fs.writeFileSync(path.join(stateTarget, "mission_control.json"), JSON.stringify(mcDefault, null, 2));
157
+ fs.writeFileSync(path.join(stateTarget, "MEMORY.md"), "# Memória Persistente\n\n(Adicione aqui resumos e decisões importantes)\n");
158
+ audit.push("- ACT: CREATED .agent/state/ (mission_control.json + MEMORY.md)");
159
+ }
160
+
161
+ console.log("\n✨ IDE install concluído com sucesso!");
162
+ writeAudit(targetPath, audit, flags);
163
+
164
+ } catch (err) {
165
+ console.error(`\n❌ Falha: ${err.message}`);
166
+ audit.push(`\n## ERROR: ${err.message}`);
167
+ writeAudit(targetPath, audit, flags);
168
+ process.exit(1);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Sub-comando: ide doctor
174
+ * Verifica se a IDE está "armada" com regras, hooks e skills.
175
+ */
176
+ async function runDoctor({ targetPath }) {
177
+ const agentDir = path.join(targetPath, ".agent");
178
+ const checks = [];
179
+
180
+ console.log("\n🏥 IDE Doctor — Verificando instalação para IDE:\n");
181
+
182
+ // Verificar .agent/
183
+ checks.push({ name: ".agent/", ok: fs.existsSync(agentDir) });
184
+
185
+ // Verificar rules
186
+ const rulesDir = path.join(agentDir, "rules");
187
+ const requiredRules = ["CONSENT_FIRST.md", "ROUTER_PROTOCOL.md"];
188
+ for (const rule of requiredRules) {
189
+ checks.push({ name: `rules/${rule}`, ok: fs.existsSync(path.join(rulesDir, rule)) });
190
+ }
191
+
192
+ // Verificar skills críticas
193
+ const skillsDir = path.join(agentDir, "skills");
194
+ const criticalSkills = ["openclaw-router", "openclaw-inspect", "openclaw-dev"];
195
+ for (const skill of criticalSkills) {
196
+ checks.push({ name: `skills/${skill}/SKILL.md`, ok: fs.existsSync(path.join(skillsDir, skill, "SKILL.md")) });
197
+ }
198
+
199
+ // Verificar hooks
200
+ const hooksDir = path.join(agentDir, "hooks");
201
+ checks.push({ name: "hooks/pre-tool-use.js", ok: fs.existsSync(path.join(hooksDir, "pre-tool-use.js")) });
202
+
203
+ // Exibir resultado
204
+ let allOk = true;
205
+ for (const c of checks) {
206
+ const icon = c.ok ? "✅" : "❌";
207
+ console.log(` ${icon} ${c.name}`);
208
+ if (!c.ok) allOk = false;
209
+ }
210
+
211
+ if (allOk) {
212
+ console.log("\n🎉 IDE está totalmente configurada!");
213
+ } else {
214
+ console.log("\n⚠️ Componentes ausentes. Rode: npx openclaw ide install --apply");
215
+ }
216
+ }
217
+
218
+ module.exports = { run };