@fabioforest/openclaw 3.0.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 (43) hide show
  1. package/README.md +88 -0
  2. package/bin/openclaw.js +152 -0
  3. package/lib/channels.js +84 -0
  4. package/lib/cli/debug.js +12 -0
  5. package/lib/cli/doctor.js +266 -0
  6. package/lib/cli/init.js +145 -0
  7. package/lib/cli/orchestrate.js +43 -0
  8. package/lib/cli/status.js +128 -0
  9. package/lib/cli/update.js +122 -0
  10. package/lib/config.js +68 -0
  11. package/lib/detect.js +49 -0
  12. package/lib/ops/audit.js +156 -0
  13. package/lib/ops/enroll.js +133 -0
  14. package/lib/ops/exec.js +140 -0
  15. package/lib/ops/healthcheck.js +167 -0
  16. package/lib/ops/policy.js +153 -0
  17. package/lib/ops/transfer.js +152 -0
  18. package/lib/ops/update-safe.js +173 -0
  19. package/lib/ops/vpn.js +131 -0
  20. package/lib/security.js +48 -0
  21. package/lib/setup/config_wizard.js +186 -0
  22. package/package.json +47 -0
  23. package/templates/.agent/agents/setup-specialist.md +24 -0
  24. package/templates/.agent/agents/sysadmin-proativo.md +31 -0
  25. package/templates/.agent/hooks/pre-tool-use.js +109 -0
  26. package/templates/.agent/rules/SECURITY.md +7 -0
  27. package/templates/.agent/skills/openclaw-installation-debugger/SKILL.md +37 -0
  28. package/templates/.agent/skills/openclaw-installation-debugger/scripts/debug.js +165 -0
  29. package/templates/.agent/skills/openclaw-ops/01-openclaw-vpn-wireguard/SKILL.md +20 -0
  30. package/templates/.agent/skills/openclaw-ops/02-openclaw-enroll-host/SKILL.md +14 -0
  31. package/templates/.agent/skills/openclaw-ops/03-openclaw-policy-baseline/SKILL.md +17 -0
  32. package/templates/.agent/skills/openclaw-ops/04-openclaw-remote-exec-runbooks/SKILL.md +13 -0
  33. package/templates/.agent/skills/openclaw-ops/05-openclaw-file-transfer-safe/SKILL.md +10 -0
  34. package/templates/.agent/skills/openclaw-ops/06-openclaw-audit-logging/SKILL.md +13 -0
  35. package/templates/.agent/skills/openclaw-ops/07-openclaw-safe-update/SKILL.md +9 -0
  36. package/templates/.agent/skills/openclaw-ops/08-openclaw-healthchecks/SKILL.md +10 -0
  37. package/templates/.agent/skills/universal-setup/SKILL.md +26 -0
  38. package/templates/.agent/workflows/doctor.md +20 -0
  39. package/templates/.agent/workflows/healthcheck.md +22 -0
  40. package/templates/.agent/workflows/healthcheck.runbook.md +9 -0
  41. package/templates/.agent/workflows/restart.md +20 -0
  42. package/templates/.agent/workflows/restart.runbook.md +8 -0
  43. package/templates/.agent/workflows/setup.md +18 -0
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenClaw OS - Universal Setup Wizard
4
+ *
5
+ * Orquestrador principal que delega para os módulos lib/:
6
+ * - detect.js → detecção de ambiente (Docker/WSL2/Mac/Linux/VPS)
7
+ * - config.js → leitura/escrita JSON atômica + defaults
8
+ * - security.js → tokens, masking e verificação de porta
9
+ * - channels.js → validação e configuração de canais
10
+ *
11
+ * Princípios:
12
+ * - Seguro por padrão: bind localhost + auth token
13
+ * - Cross-platform: detecção automática de ambiente
14
+ * - Não destrutivo: nunca sobrescreve sem confirmação
15
+ *
16
+ * @module config_wizard
17
+ * @version 2.0.0
18
+ * @author OpenClaw DevOps
19
+ */
20
+ const fs = require("fs");
21
+ const os = require("os");
22
+ const path = require("path");
23
+ const readline = require("readline");
24
+
25
+ // Módulos extraídos para lib/ — cada um com responsabilidade única
26
+ const { detectEnvironment } = require("../detect");
27
+ const { readJsonSafe, writeJsonSafe, ensureFile, initConfigDefaults } = require("../config");
28
+ const { mask, generateToken, portInUse } = require("../security");
29
+ const { supportedChannels, configureChannel } = require("../channels");
30
+
31
+ /** Interface readline para perguntas interativas */
32
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
33
+
34
+ /**
35
+ * Faz uma pergunta ao usuário via stdin e retorna a resposta trimada.
36
+ * @param {string} q - A pergunta a ser exibida
37
+ * @returns {Promise<string>} Resposta do usuário (trimada)
38
+ */
39
+ function ask(q) { return new Promise(res => rl.question(q, ans => res(ans.trim()))); }
40
+
41
+ /**
42
+ * Função principal do wizard de setup.
43
+ * Orquestra todo o fluxo interativo:
44
+ * 1. Detecta ambiente
45
+ * 2. Configura gateway (bind + auth)
46
+ * 3. Gera/solicita token de autenticação
47
+ * 4. Sugere sandbox em VPS
48
+ * 5. Configura canais (Telegram/Discord/WhatsApp)
49
+ * 6. Configura allowlist de filesystem
50
+ * 7. Cria arquivos de persistência (MEMORY.md, SOUL.md, AGENTS.md)
51
+ * 8. Verifica porta 18789
52
+ * 9. Sugere hardening em VPS
53
+ * @returns {Promise<void>}
54
+ */
55
+ async function main() {
56
+ console.log("\n🧠 OpenClaw OS — Universal Setup Wizard\n");
57
+
58
+ // --- 1. Detecção de ambiente (delegado para lib/detect) ---
59
+ const env = detectEnvironment();
60
+ console.log(`Ambiente detectado: ${env}`);
61
+
62
+ const base = process.cwd();
63
+ const configPath = path.join(base, "openclaw.json");
64
+
65
+ // --- 2. Leitura da configuração existente (delegado para lib/config) ---
66
+ let config = {};
67
+ if (fs.existsSync(configPath)) {
68
+ const parsed = readJsonSafe(configPath);
69
+ if (!parsed) {
70
+ console.error("✖ openclaw.json existe mas não é um JSON válido. Corrija e rode novamente.");
71
+ process.exit(2);
72
+ }
73
+ config = parsed;
74
+ }
75
+
76
+ // Inicializa seções padrão sem sobrescrever existentes
77
+ config = initConfigDefaults(config);
78
+
79
+ let needWrite = !fs.existsSync(configPath);
80
+
81
+ // --- 3. gateway.bind: segurança por padrão (localhost only) ---
82
+ const desiredBind = "127.0.0.1";
83
+ if (config.gateway.bind !== desiredBind) {
84
+ const ans = await ask(`gateway.bind está "${config.gateway.bind ?? "(vazio)"}". Ajustar para "${desiredBind}"? (y/n): `);
85
+ if (ans.toLowerCase() === "y") { config.gateway.bind = desiredBind; needWrite = true; }
86
+ } else {
87
+ console.log("✔ gateway.bind já está seguro (127.0.0.1)");
88
+ }
89
+
90
+ // --- 4. auth.mode: token obrigatório ---
91
+ const desiredAuthMode = "token";
92
+ if (config.auth.mode !== desiredAuthMode) {
93
+ const ans = await ask(`auth.mode está "${config.auth.mode ?? "(vazio)"}". Ajustar para "${desiredAuthMode}"? (y/n): `);
94
+ if (ans.toLowerCase() === "y") { config.auth.mode = desiredAuthMode; needWrite = true; }
95
+ } else {
96
+ console.log("✔ auth.mode já está em token");
97
+ }
98
+
99
+ // --- 5. Geração de token de autenticação (delegado para lib/security) ---
100
+ if (config.auth.mode === "token") {
101
+ config.auth.token = config.auth.token || "";
102
+ if (!config.auth.token) {
103
+ const ans = await ask("Nenhum token encontrado. Gerar um token seguro automaticamente? (y/n): ");
104
+ if (ans.toLowerCase() === "y") {
105
+ config.auth.token = generateToken();
106
+ console.log(`✔ Token gerado: ${mask(config.auth.token)} (salvo no openclaw.json)`);
107
+ needWrite = true;
108
+ } else {
109
+ const manual = await ask("Cole um token: ");
110
+ if (manual) { config.auth.token = manual; needWrite = true; }
111
+ }
112
+ } else {
113
+ console.log(`✔ Token já configurado (${mask(config.auth.token)})`);
114
+ }
115
+ }
116
+
117
+ // --- 6. Sandbox: sugestão para VPS rodando como root ---
118
+ if (env === "linux-vps-root") {
119
+ if (config.sandbox.mode !== "non-main") {
120
+ const ans = await ask(`Detectei VPS/root. Ativar sandbox mode "non-main" para isolar execuções? (y/n): `);
121
+ if (ans.toLowerCase() === "y") { config.sandbox.mode = "non-main"; needWrite = true; }
122
+ }
123
+ }
124
+
125
+ // --- 7. Configuração de canais (delegado para lib/channels) ---
126
+ console.log("\n📣 Canais (opcional)");
127
+ const channelList = supportedChannels().join("/");
128
+ const ch = await ask(`Ativar agora? (${channelList}/nenhum): `);
129
+ const channelChoice = ch.toLowerCase();
130
+
131
+ if (supportedChannels().includes(channelChoice)) {
132
+ // configureChannel recebe uma função ask injetável (testável)
133
+ const configured = await configureChannel(config, channelChoice, ask);
134
+ if (configured) needWrite = true;
135
+ } else {
136
+ console.log("↪ Pulando canais.");
137
+ }
138
+
139
+ // --- 8. Filesystem allowlist: princípio do menor privilégio ---
140
+ console.log("\n📁 Acesso a arquivos locais (mínimo necessário)");
141
+ console.log("Adicione apenas pastas que o OpenClaw realmente precisa acessar.");
142
+ const addPath = await ask("Adicionar uma pasta allowlist agora? (caminho ou ENTER para pular): ");
143
+ if (addPath) {
144
+ const resolved = addPath.replace(/^~\//, os.homedir() + path.sep);
145
+ config.filesystem.allowlist.push(resolved);
146
+ needWrite = true;
147
+ console.log(`✔ Allowlist adicionada: ${resolved}`);
148
+ }
149
+
150
+ // --- 9. Arquivos de persistência (delegado para lib/config.ensureFile) ---
151
+ ensureFile(path.join(base, "MEMORY.md"), "# MEMORY.md\n\n- Preferências e notas persistentes do OpenClaw.\n");
152
+ ensureFile(path.join(base, "SOUL.md"), "# SOUL.md\n\n- Identidade e regras de comportamento (ver AGENTS.md).\n");
153
+ ensureFile(path.join(base, "AGENTS.md"), "# AGENTS.md\n\nVocê é um SysAdmin Proativo. Use VPN-first, bind localhost e token.\n");
154
+
155
+ // --- 10. Checagem de porta (delegado para lib/security.portInUse) ---
156
+ const port = 18789;
157
+ console.log("\n🔎 Checagens rápidas");
158
+ const inUse = await portInUse("127.0.0.1", port);
159
+ if (inUse) console.log(`ℹ Porta ${port} respondeu em 127.0.0.1 (ok se OpenClaw está rodando).`);
160
+ else console.log(`ℹ Porta ${port} não respondeu em 127.0.0.1 (ok se ainda não iniciou).`);
161
+
162
+ // --- 11. Hardening: recomendações para VPS ---
163
+ if (env === "linux-vps-root") {
164
+ console.log("\n🛡 Hardening (recomendado)");
165
+ console.log("- Crie um usuário não-root (ex: clawuser) e desative login por senha no SSH.");
166
+ console.log("- Ative firewall (UFW) e fail2ban.");
167
+ console.log("- Exponha publicamente apenas WireGuard (UDP) se usar VPN.");
168
+ }
169
+
170
+ // --- 12. Persistência da configuração (delegado para lib/config.writeJsonSafe) ---
171
+ if (needWrite) {
172
+ writeJsonSafe(configPath, config);
173
+ console.log("\n✔ openclaw.json atualizado/criado com segurança.");
174
+ } else {
175
+ console.log("\n✔ Nenhuma alteração necessária no openclaw.json.");
176
+ }
177
+
178
+ console.log("\n✅ Setup finalizado.");
179
+ console.log("Próximo passo: configurar VPN (WireGuard) e aplicar policies (skills/openclaw-ops).");
180
+ rl.close();
181
+ }
182
+
183
+ main().catch((e) => {
184
+ console.error("✖ Erro:", e && e.message ? e.message : e);
185
+ process.exit(1);
186
+ });
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@fabioforest/openclaw",
3
+ "version": "3.0.0",
4
+ "description": "CLI e starter kit para configuração segura do OpenClaw em VPS, Mac, Windows e Docker",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "bin/openclaw.js",
9
+ "bin": {
10
+ "openclaw": "./bin/openclaw.js"
11
+ },
12
+ "files": [
13
+ "bin/",
14
+ "lib/",
15
+ "templates/"
16
+ ],
17
+ "scripts": {
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:coverage": "vitest run --coverage",
21
+ "setup": "node lib/setup/config_wizard.js",
22
+ "docker:build": "docker build -t openclaw -f docker/Dockerfile ."
23
+ },
24
+ "keywords": [
25
+ "openclaw",
26
+ "agent",
27
+ "security",
28
+ "devops",
29
+ "cli",
30
+ "wireguard",
31
+ "vpn",
32
+ "sysadmin"
33
+ ],
34
+ "author": "Fabio Figueiredo",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/fabioffigueiredo/openclaw-agents"
39
+ },
40
+ "devDependencies": {
41
+ "@vitest/coverage-v8": "^4.0.18",
42
+ "vitest": "^4.0.18"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ }
47
+ }
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: setup-specialist
3
+ role: Especialista em Instalação e Troubleshooting
4
+ description: Agente focado em resolver problemas de ambiente, rede e dependências durante a instalação do OpenClaw.
5
+ skills:
6
+ - openclaw-installation-debugger
7
+ personality:
8
+ tone: Técnico, direto e solícito.
9
+ style: Prioriza a resolução de erros antes de qualquer outra tarefa.
10
+ ---
11
+
12
+ # Setup Specialist
13
+
14
+ Você é o especialista designado para garantir que o OpenClaw seja instalado e configurado corretamente. Sua prioridade máxima é identificar e corrigir bloqueios.
15
+
16
+ ## Responsabilidades
17
+ 1. **Diagnosticar**: Usar a skill `openclaw-installation-debugger` para verificar rede, permissões e versões.
18
+ 2. **Corrigir**: Sugerir comandos exatos para resolver problemas (ex: instalar Docker, configurar proxy npm, corrigir permissões).
19
+ 3. **Verificar**: Após a correção, rodar novamente o diagnóstico para confirmar o sucesso.
20
+
21
+ ## Instruções
22
+ - Se o usuário relatar "erro na instalação", execute imediatamente o script `debug.js` da skill `openclaw-installation-debugger`.
23
+ - Analise a saída do script. Se a rede falhar, verifique proxy/firewall. Se permisão falhar, sugira `sudo` ou `chown`.
24
+ - Não tente configurar VPN ou Policies até que o ambiente base esteja saudável (Node, NPM, Docker, Rede).
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: sysadmin-proativo
3
+ description: Operador padrão (seguro) para manter OpenClaw saudável e auditável.
4
+ model: default
5
+ ---
6
+
7
+ # Persona
8
+ Você é um SysAdmin proativo e cauteloso. Sua prioridade é **segurança, auditabilidade e estabilidade**.
9
+
10
+ ## Modo de Operação
11
+ - Trabalhe em passos curtos e verificáveis.
12
+ - Prefira runbooks e skills catalogadas.
13
+ - Peça confirmação antes de ações arriscadas ou irreversíveis.
14
+ - Nunca execute comandos fora do escopo do runbook ativo.
15
+
16
+ ## Tools Permitidas
17
+ - `run_command` — apenas para comandos listados nos runbooks ou allowlist
18
+ - `read_file` / `write_file` — dentro dos diretórios autorizados
19
+ - `list_dir` — sem restrição
20
+ - `view_file` — sem restrição
21
+
22
+ ## Limites
23
+ - **Timeout por comando**: 30s (padrão), 120s (operações longas com `--long`)
24
+ - **Retry máximo**: 3 tentativas antes de escalar para humano
25
+ - **Circuit breaker**: Suspende execuções se 2+ falhas consecutivas
26
+ - **Break-glass**: Requer aprovação explícita + auditoria completa
27
+
28
+ ## Comandos Bloqueados (ver hooks/pre-tool-use.js)
29
+ - `rm -rf /`, `mkfs`, `dd if=`, `shutdown`, `reboot`
30
+ - Qualquer comando com `> /dev/sda` ou pipe para dispositivos de bloco
31
+ - `chmod 777`, `chown root` sem aprovação
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * Hook PreToolUse — bloqueia comandos destrutivos antes da execução.
6
+ *
7
+ * Este hook é chamado pelo agente antes de executar qualquer tool.
8
+ * Se o comando for considerado perigoso, retorna { blocked: true, reason }.
9
+ *
10
+ * Integra-se com a policy de break-glass: se o break-glass estiver ativo
11
+ * e aprovado, o comando é liberado com auditoria completa.
12
+ */
13
+
14
+ // Padrões de comandos destrutivos que requerem bloqueio
15
+ const BLOCKED_PATTERNS = [
16
+ { pattern: /rm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+)?\/(\s|$)/, reason: "rm -rf / detectado — remoção da raiz bloqueada" },
17
+ { pattern: /rm\s+-[a-zA-Z]*r[a-zA-Z]*f/, reason: "rm recursivo com force — requer aprovação" },
18
+ { pattern: /mkfs/, reason: "mkfs — formatação de disco bloqueada" },
19
+ { pattern: /dd\s+if=/, reason: "dd if= — escrita direta em dispositivo bloqueada" },
20
+ { pattern: /shutdown/, reason: "shutdown — desligamento requer aprovação humana" },
21
+ { pattern: /reboot/, reason: "reboot — reinicialização requer aprovação humana" },
22
+ { pattern: />\s*\/dev\/[sh]d[a-z]/, reason: "Redirecionamento para dispositivo de bloco bloqueado" },
23
+ { pattern: /chmod\s+777/, reason: "chmod 777 — permissão aberta demais, requer aprovação" },
24
+ { pattern: /chown\s+root/, reason: "chown root — mudança de proprietário para root requer aprovação" },
25
+ { pattern: /:(){ :\|:& };:/, reason: "Fork bomb detectada — execução bloqueada" },
26
+ { pattern: /curl\s+.*\|\s*(ba)?sh/, reason: "Pipe de URL para shell — execução remota bloqueada" },
27
+ { pattern: /wget\s+.*\|\s*(ba)?sh/, reason: "Pipe de URL para shell — execução remota bloqueada" },
28
+ ];
29
+
30
+ // Lista de diretórios protegidos (não podem ser alvo de write/delete)
31
+ const PROTECTED_PATHS = [
32
+ "/etc/passwd",
33
+ "/etc/shadow",
34
+ "/etc/sudoers",
35
+ "/boot",
36
+ "/usr/bin",
37
+ "/usr/sbin",
38
+ ];
39
+
40
+ /**
41
+ * Verifica se um comando deve ser bloqueado.
42
+ * @param {string} command — o comando a ser verificado
43
+ * @param {object} [options] — opções adicionais
44
+ * @param {boolean} [options.breakGlassActive] — se break-glass está ativo
45
+ * @returns {{ blocked: boolean, reason?: string, requiresApproval?: boolean }}
46
+ */
47
+ function checkCommand(command, options = {}) {
48
+ if (!command || typeof command !== "string") {
49
+ return { blocked: false };
50
+ }
51
+
52
+ const normalized = command.trim().toLowerCase();
53
+
54
+ // Verifica padrões destrutivos
55
+ for (const { pattern, reason } of BLOCKED_PATTERNS) {
56
+ if (pattern.test(command)) {
57
+ // Se break-glass ativo, permite mas marca como requiring approval
58
+ if (options.breakGlassActive) {
59
+ return {
60
+ blocked: false,
61
+ requiresApproval: true,
62
+ reason: `[BREAK-GLASS] ${reason} — liberado com auditoria`,
63
+ };
64
+ }
65
+ return { blocked: true, reason };
66
+ }
67
+ }
68
+
69
+ // Verifica caminhos protegidos
70
+ for (const protectedPath of PROTECTED_PATHS) {
71
+ if (command.includes(protectedPath) && /write|delete|rm|mv|cp.*>/.test(normalized)) {
72
+ return {
73
+ blocked: true,
74
+ reason: `Operação em caminho protegido: ${protectedPath}`,
75
+ };
76
+ }
77
+ }
78
+
79
+ return { blocked: false };
80
+ }
81
+
82
+ /**
83
+ * Verifica se um caminho de arquivo é seguro para operações de escrita.
84
+ * @param {string} filePath — caminho do arquivo
85
+ * @returns {{ allowed: boolean, reason?: string }}
86
+ */
87
+ function checkFilePath(filePath) {
88
+ if (!filePath || typeof filePath !== "string") {
89
+ return { allowed: true };
90
+ }
91
+
92
+ for (const protectedPath of PROTECTED_PATHS) {
93
+ if (filePath.startsWith(protectedPath)) {
94
+ return {
95
+ allowed: false,
96
+ reason: `Escrita em caminho protegido bloqueada: ${protectedPath}`,
97
+ };
98
+ }
99
+ }
100
+
101
+ return { allowed: true };
102
+ }
103
+
104
+ module.exports = {
105
+ checkCommand,
106
+ checkFilePath,
107
+ BLOCKED_PATTERNS,
108
+ PROTECTED_PATHS,
109
+ };
@@ -0,0 +1,7 @@
1
+ # Guardrails de Segurança (OpenClaw OS)
2
+ - bind localhost (127.0.0.1) por padrão
3
+ - auth token obrigatório
4
+ - VPN-first para acesso remoto
5
+ - bloquear comandos destrutivos (rm -rf, mkfs, dd if=, shutdown/reboot) sem aprovação
6
+
7
+ Este arquivo é uma referência de políticas para sua integração em hooks (VS Code/Cursor) ou no Policy Engine do OpenClaw core.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: openclaw-installation-debugger
3
+ description: Diagnóstico profundo de falhas na instalação, conectividade e integridade do OpenClaw. Verifica rede (NPM/GitHub), proxy, versões e integridade de arquivos.
4
+ version: 1.0
5
+ author: Fabioforest
6
+ ---
7
+
8
+ # OpenClaw Installation Debugger
9
+
10
+ Esta skill fornece ferramentas avançadas para diagnosticar por que uma instalação falhou ou por que o agente não está operando corretamente.
11
+
12
+ ## Scripts Disponíveis
13
+
14
+ ### `debug.js`
15
+ Executa uma bateria de testes detalhados e gera um relatório JSON/Texto.
16
+
17
+ **Verificações:**
18
+ 1. **Ambiente**: SO, Node.js version, NPM version, Docker (se disponível).
19
+ 2. **Rede**:
20
+ - Ping para `registry.npmjs.org` (verifica bloqueio de firewall/proxy).
21
+ - Ping para `github.com`.
22
+ - Resolução DNS.
23
+ 3. **Instalação**:
24
+ - Integridade da pasta `.agent/` (arquivos esperados vs encontrados).
25
+ - Permissões de escrita no diretório atual.
26
+ - Validade do `openclaw.json` (se existir).
27
+
28
+ ## Como usar
29
+ Execute via CLI (se disponível):
30
+ ```bash
31
+ npx @fabioforest/openclaw debug
32
+ ```
33
+
34
+ Ou diretamente via node se estiver debugando o pacote local:
35
+ ```bash
36
+ node templates/.agent/skills/openclaw-installation-debugger/scripts/debug.js
37
+ ```
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const os = require("os");
6
+ const dns = require("dns").promises;
7
+ const https = require("https");
8
+ const { execSync } = require("child_process");
9
+
10
+ /**
11
+ * Utilitário de log colorido
12
+ */
13
+ const colors = {
14
+ reset: "\x1b[0m",
15
+ red: "\x1b[31m",
16
+ green: "\x1b[32m",
17
+ yellow: "\x1b[33m",
18
+ blue: "\x1b[34m",
19
+ bold: "\x1b[1m"
20
+ };
21
+
22
+ function log(msg, color = colors.reset) {
23
+ console.log(`${color}${msg}${colors.reset}`);
24
+ }
25
+
26
+ function success(msg) { log(`✅ ${msg}`, colors.green); }
27
+ function warn(msg) { log(`⚠️ ${msg}`, colors.yellow); }
28
+ function fail(msg) { log(`❌ ${msg}`, colors.red); }
29
+ function info(msg) { log(`ℹ️ ${msg}`, colors.blue); }
30
+
31
+ /**
32
+ * Verifica conectividade HTTP
33
+ */
34
+ function checkHttp(url) {
35
+ return new Promise((resolve) => {
36
+ const req = https.get(url, { timeout: 5000 }, (res) => {
37
+ if (res.statusCode >= 200 && res.statusCode < 400) {
38
+ resolve({ ok: true, status: res.statusCode });
39
+ } else {
40
+ resolve({ ok: false, status: res.statusCode });
41
+ }
42
+ });
43
+ req.on("error", (err) => resolve({ ok: false, error: err.message }));
44
+ req.on("timeout", () => { req.destroy(); resolve({ ok: false, error: "timeout" }); });
45
+ });
46
+ }
47
+
48
+ async function runDebug() {
49
+ log("\n🔍 OpenClaw Installation Debugger\n", colors.bold);
50
+
51
+ const report = {
52
+ timestamp: new Date().toISOString(),
53
+ system: {},
54
+ network: {},
55
+ installation: {}
56
+ };
57
+
58
+ // 1. Sistema
59
+ info("Checando sistema...");
60
+ try {
61
+ report.system.platform = os.platform();
62
+ report.system.release = os.release();
63
+ report.system.arch = os.arch();
64
+ report.system.node = process.version;
65
+
66
+ try {
67
+ report.system.npm = execSync("npm -v").toString().trim();
68
+ } catch (e) { report.system.npm = "não encontrado"; }
69
+
70
+ try {
71
+ execSync("docker -v", { stdio: "ignore" });
72
+ report.system.docker = "instalado";
73
+ } catch (e) { report.system.docker = "não encontrado"; }
74
+
75
+ success(`Node: ${report.system.node}, NPM: ${report.system.npm}, OS: ${report.system.platform}`);
76
+ } catch (err) {
77
+ fail(`Erro ao ler sistema: ${err.message}`);
78
+ }
79
+
80
+ // 2. Rede
81
+ info("\nChecando rede...");
82
+
83
+ // DNS
84
+ try {
85
+ await dns.lookup("google.com");
86
+ success("DNS Resolution: OK");
87
+ report.network.dns = "ok";
88
+ } catch (err) {
89
+ fail(`DNS Resolution falhou: ${err.message}`);
90
+ report.network.dns = "falhou";
91
+ }
92
+
93
+ // NPM Registry
94
+ const npmCheck = await checkHttp("https://registry.npmjs.org/");
95
+ if (npmCheck.ok) {
96
+ success("NPM Registry (https): OK");
97
+ report.network.npm = "ok";
98
+ } else {
99
+ fail(`NPM Registry inacessível: ${npmCheck.error || npmCheck.status}`);
100
+ report.network.npm = "falhou";
101
+ warn(" -> Verifique se há proxy ou firewall bloqueando o NPM.");
102
+ }
103
+
104
+ // GitHub
105
+ const githubCheck = await checkHttp("https://github.com/");
106
+ if (githubCheck.ok) {
107
+ success("GitHub (https): OK");
108
+ report.network.github = "ok";
109
+ } else {
110
+ fail(`GitHub inacessível: ${githubCheck.error || githubCheck.status}`);
111
+ report.network.github = "falhou";
112
+ }
113
+
114
+ // 3. Instalação Local
115
+ info("\nChecando instalação local (.agent/)...");
116
+ const agentDir = path.resolve(".agent");
117
+ if (fs.existsSync(agentDir)) {
118
+ success(".agent/ encontrado.");
119
+ report.installation.found = true;
120
+
121
+ // Verificar permissões de escrita
122
+ try {
123
+ const testFile = path.join(agentDir, ".perm_check");
124
+ fs.writeFileSync(testFile, "ok");
125
+ fs.unlinkSync(testFile);
126
+ success("Permissão de escrita em .agent/: OK");
127
+ report.installation.write_perm = "ok";
128
+ } catch (err) {
129
+ fail(`Sem permissão de escrita em .agent/: ${err.message}`);
130
+ report.installation.write_perm = "falhou";
131
+ }
132
+
133
+ } else {
134
+ warn(".agent/ NÃO encontrado no diretório atual.");
135
+ report.installation.found = false;
136
+ info(" -> Execute 'npx @fabioforest/openclaw init' para instalar.");
137
+ }
138
+
139
+ // 4. Configuração Global (npm)
140
+ info("\nChecando configuração global do NPM...");
141
+ try {
142
+ const proxy = execSync("npm config get proxy").toString().trim();
143
+ const httpsProxy = execSync("npm config get https-proxy").toString().trim();
144
+ const registry = execSync("npm config get registry").toString().trim();
145
+
146
+ if (proxy !== "null") warn(`Proxy HTTP configurado: ${proxy}`);
147
+ if (httpsProxy !== "null") warn(`Proxy HTTPS configurado: ${httpsProxy}`);
148
+ success(`Registry atual: ${registry}`);
149
+ } catch (e) {
150
+ warn("Não foi possível ler configurações do NPM.");
151
+ }
152
+
153
+ log("\n🏁 Debug concluído.", colors.bold);
154
+ return report;
155
+ }
156
+
157
+ // Executar se chamado diretamente
158
+ if (require.main === module) {
159
+ runDebug().catch(err => {
160
+ console.error("Erro fatal no debugger:", err);
161
+ process.exit(1);
162
+ });
163
+ }
164
+
165
+ module.exports = { runDebug };
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: openclaw-vpn-wireguard
3
+ description: Provisiona WireGuard entre VPS e hosts para que o OpenClaw opere somente via rede privada. Inclui hardening, checklist e validação.
4
+ version: 1.0
5
+ ---
6
+ # Objetivo
7
+ Criar VPN WireGuard (VPN-first). Sem VPN, sem acesso remoto.
8
+
9
+ # Checklist (alto nível)
10
+ - Instalar WireGuard (VPS e host)
11
+ - Gerar chaves por host (nunca reutilizar)
12
+ - Configurar wg0 na VPS (10.60.0.1/24)
13
+ - Adicionar peers com AllowedIPs /32
14
+ - Validar handshake e ping dentro da VPN
15
+ - Definir procedimento de revogação (remover peer)
16
+
17
+ # Hardening
18
+ - Expor publicamente apenas UDP do WireGuard
19
+ - Não usar 0.0.0.0/0 por padrão
20
+ - Registrar auditoria de add/remove peer
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: openclaw-enroll-host
3
+ description: Onboarding seguro de host na malha WireGuard + OpenClaw com aprovação humana, identidade e revogação rápida.
4
+ version: 1.0
5
+ ---
6
+ # Objetivo
7
+ Registrar host com aprovação e aplicar policy baseline.
8
+
9
+ # Checklist
10
+ - Gerar host_id + fingerprint
11
+ - Registrar host (pending)
12
+ - Aprovar manualmente
13
+ - Aplicar policy baseline
14
+ - Testar revogação (remover peer WireGuard)
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: openclaw-policy-baseline
3
+ description: Define RBAC e allowlists (deny-by-default) para execução remota via VPN com break-glass expirável.
4
+ version: 1.0
5
+ ---
6
+ # Objetivo
7
+ Políticas antes do poder. Deny-by-default.
8
+
9
+ # Perfis
10
+ - viewer: leitura
11
+ - operator: runbooks permitidos
12
+ - admin: ações elevadas com confirmação extra e auditoria
13
+
14
+ # Break-glass
15
+ - janela curta
16
+ - expiração automática
17
+ - alerta e auditoria
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: openclaw-remote-exec-runbooks
3
+ description: Estrutura execução remota via VPN usando runbooks idempotentes, com timeout, cancel e trilha auditável.
4
+ version: 1.0
5
+ ---
6
+ # Objetivo
7
+ Evitar 'shell solto'. Preferir runbooks nomeados.
8
+
9
+ # Regras
10
+ - validar entradas
11
+ - capturar stdout/stderr
12
+ - timeout/cancel
13
+ - assinar request (request_id)