@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.
- package/bin/openclaw.js +37 -8
- package/lib/cli/assist.js +84 -0
- package/lib/cli/doctor.js +37 -3
- package/lib/cli/ide.js +218 -0
- package/lib/cli/init.js +135 -79
- package/lib/cli/inspect.js +58 -0
- package/lib/cli/orchestrate.js +43 -15
- package/lib/cli/update.js +113 -47
- package/lib/context/collector.js +104 -0
- package/lib/context/index.js +75 -0
- package/lib/router/match.js +107 -0
- package/lib/setup/config_wizard.js +2 -0
- package/package.json +2 -2
- package/templates/.agent/agents/workflow-automator.md +31 -0
- package/templates/.agent/rules/CONSENT_FIRST.md +24 -0
- package/templates/.agent/rules/DEV_MODE.md +18 -0
- package/templates/.agent/rules/ROUTER_PROTOCOL.md +22 -0
- package/templates/.agent/rules/WEB_AUTOMATION.md +52 -0
- package/templates/.agent/skills/content-sourcer/SKILL.md +48 -0
- package/templates/.agent/skills/context-flush/SKILL.md +30 -0
- package/templates/.agent/skills/drive-organizer/SKILL.md +40 -0
- package/templates/.agent/skills/linkedin-optimizer/SKILL.md +48 -0
- package/templates/.agent/skills/mission-control/SKILL.md +37 -0
- package/templates/.agent/skills/openclaw-assist/SKILL.md +30 -0
- package/templates/.agent/skills/openclaw-dev/SKILL.md +26 -0
- package/templates/.agent/skills/openclaw-inspect/SKILL.md +21 -0
- package/templates/.agent/skills/openclaw-installation-debugger/scripts/debug.js +16 -2
- package/templates/.agent/skills/openclaw-router/SKILL.md +34 -0
- package/templates/.agent/skills/openclaw-security/SKILL.md +21 -0
- package/templates/.agent/skills/site-tester/SKILL.md +49 -0
- package/templates/.agent/skills/smart-router/SKILL.md +116 -0
- package/templates/.agent/skills/web-scraper/SKILL.md +51 -0
- package/templates/.agent/state/MEMORY.md +8 -0
- package/templates/.agent/state/mission_control.json +34 -0
- 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
|
-
--
|
|
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 --
|
|
92
|
-
npx openclaw
|
|
93
|
-
npx openclaw
|
|
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 {
|
|
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 };
|