@fabioforest/openclaw 3.10.0 → 3.10.2

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
@@ -280,6 +280,7 @@ npx @fabioforest/openclaw ide install --apply --force
280
280
  │ ├── mission_control.json # Empresa de Agentes
281
281
  │ └── MEMORY.md # Memória do workspace
282
282
  └── workflows/ # Slash commands e runbooks
283
+ └── chat-first.md # Workflow default de roteamento inteligente
283
284
  ```
284
285
 
285
286
  ---
@@ -446,6 +447,7 @@ Além de skills isoladas, o OpenClaw traz **fluxos de trabalho completos** (runb
446
447
 
447
448
  | Workflow | Descrição | Comando Trigger |
448
449
  |----------|-----------|-----------------|
450
+ | **`chat-first`** | **Roteamento Seguro** via INSPECT e PLAN antes de agira | Workflow Padrão (Core) |
449
451
  | **`ai-capture`** | Captura inteligente de dados/tickets usando IA | *"Iniciar captura de dados"* |
450
452
  | **`doctor`** | Diagnóstico e reparo automático do ambiente | `openclaw doctor` |
451
453
  | **`healthcheck`** | Verificação rápida de saúde (API, DB, cache) | `openclaw healthcheck` |
@@ -458,15 +460,18 @@ Workflows são arquivos `.md` em `.agent/workflows/` que o agente lê e executa
458
460
 
459
461
  ## 🔒 Segurança
460
462
 
461
- O OpenClaw segue 3 princípios fundamentais:
463
+ O OpenClaw segue 4 princípios fundamentais:
462
464
 
463
465
  ### 1. Read-only por padrão
464
- Todo comando opera em **modo PLAN** (simulação). Nada é alterado sem `--apply`.
466
+ Todo comando opera em **modo PLAN** (simulação). Nada é alterado sem `--apply`. A flag `--apply` tem precedência absoluta, substituindo comportamento visual de planejamento.
465
467
 
466
468
  ### 2. Consent-first
467
469
  Antes de qualquer alteração, o sistema mostra exatamente o que vai fazer e pede confirmação. Ações destrutivas exigem **confirmação forte** (digitar frase específica).
468
470
 
469
- ### 3. Audit-first
471
+ ### 3. Scope Guard (Proteção Anti-Destruição)
472
+ Qualquer tentativa do CLI de criar, deletar ou sobrescrever arquivos que estejam **fora** da bolha de segurança `.agent/` falha por padrão com o Módulo Scope Guard em ação total para isolar agentes. Pode ser ignorado interativamente no terminal digitando senhas de perigo.
473
+
474
+ ### 4. Audit-first
470
475
  Toda ação gera log detalhado em `.agent/audit/` com timestamp, comando, modo, contexto e resultado.
471
476
 
472
477
  ### Proteções ativas
@@ -474,6 +479,7 @@ Toda ação gera log detalhado em `.agent/audit/` com timestamp, comando, modo,
474
479
  | Proteção | Como funciona |
475
480
  |----------|---------------|
476
481
  | **Hook pre-tool-use** | Bloqueia 12+ padrões destrutivos (`rm -rf`, `mkfs`, `dd`, `shutdown`) |
482
+ | **Scope Guard** | Protege arquivos/framework nativos do projeto/usuário host de reescritas inadvertidas CLI |
477
483
  | **VPN-first** | Sem VPN, sem acesso remoto |
478
484
  | **Bind localhost** | Serviços só acessíveis localmente por padrão |
479
485
  | **Auth token** | Token obrigatório para acesso |
package/lib/cli/ide.js CHANGED
@@ -14,7 +14,7 @@ const readline = require("readline");
14
14
  const { detectContext, getAuditHeader } = require("../context");
15
15
  const { copyDirRecursive } = require("./init");
16
16
  const { writeCliAudit } = require("../utils/audit-writer");
17
- const { guardPlan } = require("../utils/scope_guard");
17
+ const { executeAction } = require("../core/orchestrator");
18
18
 
19
19
  // Caminho dos templates do pacote
20
20
  const TEMPLATES_DIR = path.join(__dirname, "..", "..", "templates");
@@ -65,6 +65,9 @@ async function runInstall({ targetPath, flags }) {
65
65
  console.log(" 📦 COPY templates/.agent -> .agent/");
66
66
  }
67
67
 
68
+ const ideSrc = path.join(TEMPLATES_DIR, "ide");
69
+ console.log(" 🌟 ADDON Adaptadores de IDE (.cursorrules, copilot-instructions, .mdc)");
70
+
68
71
  // State templates (mission_control.json, MEMORY.md)
69
72
  const stateDir = path.join(agentDst, "state");
70
73
  if (!fs.existsSync(stateDir)) {
@@ -74,87 +77,64 @@ async function runInstall({ targetPath, flags }) {
74
77
  }
75
78
 
76
79
  // 2.5 Scope Guard
77
- const intents = { writes: [agentDst, stateDir], deletes: [], overwrites: [] };
78
- // Se for um force, significa que um overwrite/delete de diretório ocorrerá
79
- if (fs.existsSync(agentDst) && flags.force) {
80
- intents.deletes.push(agentDst);
81
- intents.overwrites.push(agentDst);
82
- }
83
-
84
- await guardPlan(targetPath, intents, flags);
85
-
86
- if (planMode) {
87
- console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
88
- console.log(" Para aplicar, rode: npx openclaw ide install --apply");
89
- return;
90
- }
91
-
92
- // Confirmação
93
- if (!flags.yes) {
94
- if (flags.force && fs.existsSync(agentDst)) {
95
- const phrase = await ask("⚠️ Digite 'DELETE .agent' para confirmar: ");
96
- if (phrase !== "DELETE .agent") {
97
- console.log("⏹️ Cancelado.");
98
- return;
80
+ const intents = {
81
+ writes: [
82
+ agentDst,
83
+ stateDir,
84
+ path.join(targetPath, ".cursorrules"),
85
+ path.join(targetPath, ".github"),
86
+ path.join(targetPath, ".cursor")
87
+ ],
88
+ deletes: [],
89
+ overwrites: []
90
+ };
91
+
92
+ const confirmationWord = (flags.force && fs.existsSync(agentDst)) ? "DELETE .agent" : null;
93
+
94
+ await executeAction({
95
+ actionName: "ide install",
96
+ context: ctx,
97
+ flags,
98
+ intents,
99
+ targetPath,
100
+ confirmationWord,
101
+ planFn: async () => { }, // O console.log inicial já fez o plan visual acima
102
+ executeFn: async () => {
103
+ if (fs.existsSync(agentDst) && flags.force) {
104
+ fs.rmSync(agentDst, { recursive: true, force: true });
99
105
  }
100
- } else {
101
- const ok = await ask("\nAplicar instalação IDE? (y/N): ");
102
- if (ok.toLowerCase() !== "y") {
103
- console.log("⏹️ Cancelado.");
104
- return;
105
- }
106
- }
107
- }
108
-
109
- // Execução
110
- try {
111
- console.log("\n🚀 Executando...");
112
-
113
- if (fs.existsSync(agentDst) && flags.force) {
114
- fs.rmSync(agentDst, { recursive: true, force: true });
115
- audit.push("- ACT: DELETED .agent/");
116
- }
117
106
 
118
- const isMerge = fs.existsSync(agentDst);
119
- const stats = copyDirRecursive(agentSrc, agentDst, undefined, isMerge);
120
- audit.push(`- ACT: ${isMerge ? "MERGED" : "COPIED"} templates (Files: ${stats.files}, Skipped: ${stats.skipped})`);
121
-
122
- // Criar state se necessário
123
- const stateTarget = path.join(agentDst, "state");
124
- if (!fs.existsSync(stateTarget)) {
125
- fs.mkdirSync(stateTarget, { recursive: true });
126
- // Criar mission_control.json default
127
- const mcDefault = {
128
- project_status: "active",
129
- project_name: path.basename(targetPath),
130
- sprint_goal: "",
131
- agents: [
132
- { id: "orchestrator", role: "orchestrator", active: true },
133
- { id: "researcher", role: "researcher", active: true },
134
- { id: "writer", role: "writer", active: true },
135
- ],
136
- task_queue: [],
137
- history: [],
138
- settings: {
139
- work_dir: "mission_control",
140
- max_tasks_per_tick: 2,
141
- default_priority: "medium",
142
- },
143
- };
144
- fs.writeFileSync(path.join(stateTarget, "mission_control.json"), JSON.stringify(mcDefault, null, 2));
145
- fs.writeFileSync(path.join(stateTarget, "MEMORY.md"), "# Memória Persistente\n\n(Adicione aqui resumos e decisões importantes)\n");
146
- audit.push("- ACT: CREATED .agent/state/ (mission_control.json + MEMORY.md)");
107
+ const isMerge = fs.existsSync(agentDst);
108
+ copyDirRecursive(agentSrc, agentDst, undefined, isMerge);
109
+ copyDirRecursive(ideSrc, targetPath, undefined, true); // Copiar/Merge ide adaptors
110
+
111
+ // Criar state se necessário
112
+ const stateTarget = path.join(agentDst, "state");
113
+ if (!fs.existsSync(stateTarget)) {
114
+ fs.mkdirSync(stateTarget, { recursive: true });
115
+ // Criar mission_control.json default
116
+ const mcDefault = {
117
+ project_status: "active",
118
+ project_name: path.basename(targetPath),
119
+ sprint_goal: "",
120
+ agents: [
121
+ { id: "orchestrator", role: "orchestrator", active: true },
122
+ { id: "researcher", role: "researcher", active: true },
123
+ { id: "writer", role: "writer", active: true },
124
+ ],
125
+ task_queue: [],
126
+ history: [],
127
+ settings: {
128
+ work_dir: "mission_control",
129
+ max_tasks_per_tick: 2,
130
+ default_priority: "medium",
131
+ },
132
+ };
133
+ fs.writeFileSync(path.join(stateTarget, "mission_control.json"), JSON.stringify(mcDefault, null, 2));
134
+ fs.writeFileSync(path.join(stateTarget, "MEMORY.md"), "# Memória Persistente\n\n(Adicione aqui resumos e decisões importantes)\n");
135
+ }
147
136
  }
148
-
149
- console.log("\n✨ IDE install concluído com sucesso!");
150
- writeAudit(targetPath, audit, flags);
151
-
152
- } catch (err) {
153
- console.error(`\n❌ Falha: ${err.message}`);
154
- audit.push(`\n## ERROR: ${err.message}`);
155
- writeAudit(targetPath, audit, flags);
156
- process.exit(1);
157
- }
137
+ });
158
138
  }
159
139
 
160
140
  /**
package/lib/cli/init.js CHANGED
@@ -14,7 +14,7 @@ const readline = require("readline");
14
14
  const { initConfigDefaults, writeJsonSafe } = require("../config");
15
15
  const { detectContext, getAuditHeader } = require("../context");
16
16
  const { writeCliAudit } = require("../utils/audit-writer");
17
- const { guardPlan } = require("../utils/scope_guard");
17
+ const { executeAction } = require("../core/orchestrator");
18
18
 
19
19
  // Caminho dos templates incluídos no pacote
20
20
  const TEMPLATES_DIR = path.join(__dirname, "..", "..", "templates", ".agent");
@@ -117,87 +117,58 @@ async function run({ targetPath, flags }) {
117
117
  if (a.type === "COPY_DIR" || a.type === "MERGE_DIR") intents.writes.push(a.to);
118
118
  }
119
119
 
120
- await guardPlan(targetPath, intents, flags);
121
-
122
- // 3. Exibir Plano
123
- console.log(`\n🧭 Plano de Execução (${planMode ? "SIMULAÇÃO" : "APPLY"}):\n`);
124
- console.log(` Contexto: ${ctx.env} | IDE: ${ctx.ide}\n`);
125
-
126
- for (const a of actions) {
127
- if (a.type === "DELETE_DIR") console.log(` 🔥 DELETE ${safeRel(targetPath, a.path)} (${a.reason})`);
128
- if (a.type === "CREATE_DIR") console.log(` 📁 CREATE ${safeRel(targetPath, a.path)}`);
129
- if (a.type === "COPY_DIR") console.log(` 📦 COPY templates -> ${safeRel(targetPath, a.to)}`);
130
- if (a.type === "MERGE_DIR") console.log(` 🔄 MERGE templates -> ${safeRel(targetPath, a.to)} (Preservando existentes)`);
131
- if (a.type === "CREATE_FILE") console.log(` 📝 CREATE ${safeRel(targetPath, a.path)}`);
132
- if (a.type === "NOOP") console.log(` ✅ KEEP ${safeRel(targetPath, a.path)}`);
133
- }
134
-
135
- if (planMode) {
136
- console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
137
- console.log(" Para aplicar, rode o comando com --apply");
138
- return;
139
- }
140
-
141
- // 4. Confirmação
142
- if (!flags.yes) {
143
- if (actions.some(a => a.type === "DELETE_DIR")) {
144
- console.log("\n⚠️ PERIGO: Operação destrutiva detectada (--force).");
145
- const phrase = await ask("Digite 'DELETE .agent' para confirmar: ");
146
- if (phrase !== "DELETE .agent") {
147
- console.log("⏹️ Cancelado.");
148
- return;
120
+ // Definir Palavra de Confirmação Forte se houver Force Delete
121
+ const hasDelete = actions.some(a => a.type === "DELETE_DIR");
122
+ const confirmationWord = hasDelete ? "DELETE .agent" : null;
123
+
124
+ // Delegar todo o fluxo final (Guard, Confirm, Execute, Audit) para o Orchestrator
125
+ await executeAction({
126
+ actionName: "init",
127
+ context: ctx,
128
+ flags,
129
+ intents,
130
+ targetPath,
131
+ confirmationWord,
132
+ planFn: async () => {
133
+ console.log(`\n🧭 Plano de Execução:\n`);
134
+ console.log(` Contexto: ${ctx.env.platform} | IDE: ${ctx.ide}\n`);
135
+ for (const a of actions) {
136
+ if (a.type === "DELETE_DIR") console.log(` 🔥 DELETE ${safeRel(targetPath, a.path)} (${a.reason})`);
137
+ if (a.type === "CREATE_DIR") console.log(` 📁 CREATE ${safeRel(targetPath, a.path)}`);
138
+ if (a.type === "COPY_DIR") console.log(` 📦 COPY templates -> ${safeRel(targetPath, a.to)}`);
139
+ if (a.type === "MERGE_DIR") console.log(` 🔄 MERGE templates -> ${safeRel(targetPath, a.to)} (Preservando existentes)`);
140
+ if (a.type === "CREATE_FILE") console.log(` 📝 CREATE ${safeRel(targetPath, a.path)}`);
141
+ if (a.type === "NOOP") console.log(` ✅ KEEP ${safeRel(targetPath, a.path)}`);
149
142
  }
150
- } else {
151
- const ok = await ask("\nAplicar este plano? (y/N): ");
152
- if (ok.toLowerCase() !== "y") {
153
- console.log("⏹️ Cancelado.");
154
- return;
143
+ },
144
+ executeFn: async () => {
145
+ for (const a of actions) {
146
+ if (a.type === "DELETE_DIR") {
147
+ fs.rmSync(a.path, { recursive: true, force: true });
148
+ }
155
149
  }
156
- }
157
- }
158
150
 
159
- // 5. Execução
160
- try {
161
- console.log("\n🚀 Executando...");
162
-
163
- for (const a of actions) {
164
- if (a.type === "DELETE_DIR") {
165
- fs.rmSync(a.path, { recursive: true, force: true });
166
- audit.push(`- ACT: DELETED ${a.path}`);
151
+ // Executar cópia/merge se necessário
152
+ const copyAction = actions.find(a => a.type === "COPY_DIR" || a.type === "MERGE_DIR");
153
+ if (copyAction) {
154
+ const isMerge = copyAction.type === "MERGE_DIR";
155
+ copyDirRecursive(TEMPLATES_DIR, agentDir, undefined, isMerge);
156
+ console.log(` ✅ Templates processados.`);
167
157
  }
168
- }
169
158
 
170
- // Executar cópia/merge se necessário
171
- const copyAction = actions.find(a => a.type === "COPY_DIR" || a.type === "MERGE_DIR");
172
- if (copyAction) {
173
- const isMerge = copyAction.type === "MERGE_DIR";
174
- const stats = copyDirRecursive(TEMPLATES_DIR, agentDir, undefined, isMerge);
175
- audit.push(`- ACT: ${isMerge ? "MERGED" : "COPIED"} templates (Files: ${stats.files}, Skipped: ${stats.skipped})`);
176
- console.log(` ✅ Templates processados.`);
177
- }
159
+ // Criar config se necessário
160
+ if (actions.some(a => a.type === "CREATE_FILE" && a.path === configPath)) {
161
+ const defaults = initConfigDefaults({});
162
+ writeJsonSafe(configPath, defaults);
163
+ console.log(` ✅ Config criada.`);
164
+ }
178
165
 
179
- // Criar config se necessário
180
- if (actions.some(a => a.type === "CREATE_FILE" && a.path === configPath)) {
181
- const defaults = initConfigDefaults({});
182
- writeJsonSafe(configPath, defaults);
183
- audit.push(`- ACT: CREATED openclaw.json`);
184
- console.log(` ✅ Config criada.`);
166
+ // Gravar contexto se ainda não existe
167
+ const contextDir = path.join(agentDir, "context");
168
+ if (!fs.existsSync(contextDir)) fs.mkdirSync(contextDir, { recursive: true });
169
+ fs.writeFileSync(path.join(contextDir, "context.json"), JSON.stringify(ctx, null, 2));
185
170
  }
186
-
187
- // Gravar contexto se ainda não existe
188
- const contextDir = path.join(agentDir, "context");
189
- if (!fs.existsSync(contextDir)) fs.mkdirSync(contextDir, { recursive: true });
190
- fs.writeFileSync(path.join(contextDir, "context.json"), JSON.stringify(ctx, null, 2));
191
-
192
- console.log("\n✨ Concluído com sucesso!");
193
- writeAudit(targetPath, audit, flags);
194
-
195
- } catch (err) {
196
- console.error(`\n❌ Falha na execução: ${err.message}`);
197
- audit.push(`\n## ERROR: ${err.message}`);
198
- writeAudit(targetPath, audit, flags);
199
- process.exit(1);
200
- }
171
+ });
201
172
  }
202
173
 
203
174
  module.exports = { run, copyDirRecursive };
@@ -15,7 +15,7 @@ const fs = require("fs");
15
15
  const path = require("path");
16
16
  const readline = require("readline");
17
17
  const { detectContext, getAuditHeader } = require("../context");
18
- const { guardPlan } = require("../utils/scope_guard");
18
+ const { executeAction } = require("../core/orchestrator");
19
19
 
20
20
  function ask(q) {
21
21
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -104,96 +104,82 @@ async function run({ targetPath, flags }) {
104
104
  console.log(` 🔴 REMOVER openclaw.json`);
105
105
  }
106
106
 
107
- // Acionar Scope Guard para todos os deletes listados
107
+ // Acionar Orquestrador
108
108
  const intents = { writes: [], deletes: toRemove.map(i => i.path), overwrites: [] };
109
- await guardPlan(targetPath, intents, flags);
110
-
111
- // Verificar audit logs que seriam perdidos
112
- const auditDir = path.join(agentDir, "audit");
113
- if (fs.existsSync(auditDir)) {
114
- const auditCount = countFiles(auditDir);
115
- if (auditCount > 0) {
116
- console.log(`\n ⚠️ ${auditCount} log(s) de auditoria serão perdidos!`);
117
- }
118
- }
119
-
120
- // Verificar state que seria perdido
121
- const stateDir = path.join(agentDir, "state");
122
- if (fs.existsSync(stateDir)) {
123
- const stateCount = countFiles(stateDir);
124
- if (stateCount > 0) {
125
- console.log(` ⚠️ ${stateCount} arquivo(s) de estado serão perdidos (mission_control, MEMORY)!`);
126
- }
127
- }
128
-
129
- // Modo PLAN: não faz nada
130
- if (planMode) {
131
- console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
132
- console.log(" Para desinstalar, rode: npx @fabioforest/openclaw uninstall --apply");
133
- return;
134
- }
135
109
 
136
- // Modo APPLY: pedir confirmação forte
137
- console.log("");
138
- if (!flags.yes) {
139
- const confirm = await ask("⚠️ Digite 'UNINSTALL' para confirmar a remoção: ");
140
- if (confirm !== "UNINSTALL") {
141
- console.log("⏹️ Cancelado. Nada foi removido.");
142
- return;
143
- }
144
- }
110
+ await executeAction({
111
+ actionName: "uninstall",
112
+ context: ctx,
113
+ flags,
114
+ intents,
115
+ targetPath,
116
+ skipAudit: true, // Audit manual pós-remoção
117
+ confirmationWord: "UNINSTALL",
118
+ planFn: async () => {
119
+ // Verificar audit logs que seriam perdidos
120
+ const auditDir = path.join(agentDir, "audit");
121
+ if (fs.existsSync(auditDir)) {
122
+ const auditCount = countFiles(auditDir);
123
+ if (auditCount > 0) {
124
+ console.log(`\n ⚠️ ${auditCount} log(s) de auditoria serão perdidos!`);
125
+ }
126
+ }
145
127
 
146
- // Backup opcional
147
- if (!flags.force) {
148
- const doBackup = flags.yes ? "s" : await ask("💾 Fazer backup antes de remover? (S/n): ");
149
- if (doBackup.toLowerCase() !== "n") {
150
- const backupName = `.agent.backup-${Date.now()}`;
151
- const backupPath = path.join(targetPath, backupName);
152
- try {
153
- fs.cpSync(agentDir, backupPath, { recursive: true });
154
- console.log(` ✅ Backup criado: ${backupName}/`);
155
- } catch (err) {
156
- console.error(` ⚠️ Falha no backup: ${err.message}`);
157
- const cont = await ask(" Continuar sem backup? (y/N): ");
158
- if (cont.toLowerCase() !== "y") {
159
- console.log("⏹️ Cancelado.");
160
- return;
128
+ // Verificar state que seria perdido
129
+ const stateDir = path.join(agentDir, "state");
130
+ if (fs.existsSync(stateDir)) {
131
+ const stateCount = countFiles(stateDir);
132
+ if (stateCount > 0) {
133
+ console.log(` ⚠️ ${stateCount} arquivo(s) de estado serão perdidos (mission_control, MEMORY)!`);
134
+ }
135
+ }
136
+ },
137
+ executeFn: async () => {
138
+ // Backup opcional
139
+ if (!flags.force) {
140
+ const doBackup = flags.yes ? "s" : await ask("\n💾 Fazer backup antes de remover? (S/n): ");
141
+ if (doBackup.toLowerCase() !== "n") {
142
+ const backupName = `.agent.backup-${Date.now()}`;
143
+ const backupPath = path.join(targetPath, backupName);
144
+ try {
145
+ fs.cpSync(agentDir, backupPath, { recursive: true });
146
+ console.log(` ✅ Backup criado: ${backupName}/`);
147
+ } catch (err) {
148
+ console.error(` ⚠️ Falha no backup: ${err.message}`);
149
+ const cont = await ask(" Continuar sem backup? (y/N): ");
150
+ if (cont.toLowerCase() !== "y") {
151
+ throw new Error("Usuário abortou por falha no backup.");
152
+ }
153
+ }
161
154
  }
162
155
  }
163
- }
164
- }
165
156
 
166
- // Executar remoção
167
- const audit = [getAuditHeader(ctx, "uninstall", flags)];
157
+ const audit = [getAuditHeader(ctx, "uninstall", flags)];
168
158
 
169
- try {
170
- for (const item of toRemove) {
171
- if (item.isDir) {
172
- fs.rmSync(item.path, { recursive: true, force: true });
173
- } else {
174
- fs.unlinkSync(item.path);
159
+ for (const item of toRemove) {
160
+ if (item.isDir) {
161
+ fs.rmSync(item.path, { recursive: true, force: true });
162
+ } else {
163
+ fs.unlinkSync(item.path);
164
+ }
165
+ console.log(` ✅ Removido: ${item.label}`);
166
+ audit.push(`- ACT: REMOVED ${item.label}`);
175
167
  }
176
- console.log(` ✅ Removido: ${item.label}`);
177
- audit.push(`- ACT: REMOVED ${item.label}`);
178
- }
179
168
 
180
- console.log("\n✨ OpenClaw desinstalado com sucesso!");
181
- console.log(" Para reinstalar: npx @fabioforest/openclaw init --apply\n");
182
-
183
- // Gravar audit no diretório pai (já que .agent/ foi removido)
184
- if (flags.audit !== false) {
185
- const filename = `openclaw-uninstall-${new Date().toISOString().replace(/[:.]/g, "-")}.md`;
186
- const auditPath = path.join(targetPath, filename);
187
- try {
188
- fs.writeFileSync(auditPath, audit.join("\n") + "\n", "utf8");
189
- console.log(` 📝 Log de auditoria: ${filename}`);
190
- } catch (e) { /* silencioso */ }
169
+ console.log("\n✨ OpenClaw desinstalado com sucesso!");
170
+ console.log(" Para reinstalar: npx @fabioforest/openclaw init --apply\n");
171
+
172
+ // Gravar audit no diretório pai (já que .agent/ foi removido)
173
+ if (flags.audit !== false) {
174
+ const filename = `openclaw-uninstall-${new Date().toISOString().replace(/[:.]/g, "-")}.md`;
175
+ const auditPath = path.join(targetPath, filename);
176
+ try {
177
+ fs.writeFileSync(auditPath, audit.join("\n") + "\n", "utf8");
178
+ console.log(` 📝 Log de auditoria: ${filename}`);
179
+ } catch (e) { /* silencioso */ }
180
+ }
191
181
  }
192
-
193
- } catch (err) {
194
- console.error(`\n❌ Falha: ${err.message}`);
195
- process.exit(1);
196
- }
182
+ });
197
183
  }
198
184
 
199
185
  module.exports = { run };
package/lib/cli/update.js CHANGED
@@ -14,8 +14,7 @@ const path = require("path");
14
14
  const crypto = require("crypto");
15
15
  const readline = require("readline");
16
16
  const { detectContext, getAuditHeader } = require("../context");
17
- const { writeCliAudit } = require("../utils/audit-writer");
18
- const { guardPlan } = require("../utils/scope_guard");
17
+ const { executeAction } = require("../core/orchestrator");
19
18
 
20
19
  // Caminho dos templates incluídos no pacote
21
20
  const TEMPLATES_DIR = path.join(__dirname, "..", "..", "templates", ".agent");
@@ -29,10 +28,7 @@ function safeRel(targetPath, p) {
29
28
  return path.relative(targetPath, p);
30
29
  }
31
30
 
32
- // writeAudit extraído para lib/utils/audit-writer.js (DRY)
33
- function writeAudit(targetPath, lines, flags) {
34
- writeCliAudit(targetPath, lines, flags, "update");
35
- }
31
+ // Removida prop writeAudit (o orquestrador ou o executeFn fará isso manualmente ou deixaremos rolar)
36
32
 
37
33
  /**
38
34
  * Calcula o SHA-256 de um arquivo (Utilitário mantido)
@@ -124,112 +120,113 @@ async function run({ targetPath, flags }) {
124
120
  process.exit(1);
125
121
  }
126
122
 
127
- // 1. Planejar
123
+ // 1. Planejar arrays
128
124
  const actions = planUpdates(TEMPLATES_DIR, agentDir);
129
- const audit = [getAuditHeader(ctx, "update", flags)];
130
125
 
131
- // 1.5 Acionar Scope Guard
126
+ // Mapear intencionalidades
132
127
  const intents = { writes: [], deletes: [], overwrites: [] };
133
128
  for (const a of actions.added) intents.writes.push(a.dest);
134
129
  for (const a of actions.updated) intents.overwrites.push(a.dest);
135
- await guardPlan(targetPath, intents, flags);
136
-
137
- // 2. Exibir Plano
138
- console.log(`\n🧭 Plano de Atualização (${planMode ? "SIMULAÇÃO" : "APPLY"}):\n`);
139
- console.log(` Contexto: ${ctx.env} | IDE: ${ctx.ide}\n`);
140
130
 
141
- if (actions.added.length > 0) {
142
- console.log(`📄 Novos (${actions.added.length}):`);
143
- actions.added.forEach(a => console.log(` + CREATE ${safeRel(targetPath, a.dest)}`));
144
- }
145
- if (actions.updated.length > 0) {
146
- console.log(`\n🔄 Modificados (${actions.updated.length}):`);
147
- actions.updated.forEach(a => {
148
- console.log(` ~ UPDATE ${safeRel(targetPath, a.dest)} (Exige confirmação interativa)`);
149
- });
150
- }
151
- if (actions.skipped.length > 0) {
152
- console.log(`\n⏭️ Ignorados (${actions.skipped.length} arquivos idênticos)`);
153
- }
131
+ await executeAction({
132
+ actionName: "update",
133
+ context: ctx,
134
+ flags,
135
+ intents,
136
+ targetPath,
137
+ skipConfirm: true, // Manter o loop de override manual
138
+ skipAudit: true, // Escrevemos manual no final por causa dos arquivos "skipped" interativos
139
+ planFn: async () => {
140
+ console.log(`\n🧭 Plano de Atualização:\n`);
141
+ console.log(` Contexto: ${ctx.env.platform} | IDE: ${ctx.ide}\n`);
142
+
143
+ if (actions.added.length > 0) {
144
+ console.log(`📄 Novos (${actions.added.length}):`);
145
+ actions.added.forEach(a => console.log(` + CREATE ${safeRel(targetPath, a.dest)}`));
146
+ }
147
+ if (actions.updated.length > 0) {
148
+ console.log(`\n🔄 Modificados (${actions.updated.length}):`);
149
+ actions.updated.forEach(a => {
150
+ console.log(` ~ UPDATE ${safeRel(targetPath, a.dest)} (Exige confirmação interativa)`);
151
+ });
152
+ }
153
+ if (actions.skipped.length > 0) {
154
+ console.log(`\n⏭️ Ignorados (${actions.skipped.length} arquivos idênticos)`);
155
+ }
154
156
 
155
- if (actions.added.length === 0 && actions.updated.length === 0) {
156
- console.log("\n✅ Tudo atualizado. Nenhuma alteração necessária.");
157
- return;
158
- }
157
+ if (actions.added.length === 0 && actions.updated.length === 0) {
158
+ console.log("\n✅ Tudo atualizado. Nenhuma alteração necessária.");
159
+ }
160
+ },
161
+ executeFn: async () => {
162
+ if (actions.added.length === 0 && actions.updated.length === 0) {
163
+ return; // Nothing to apply
164
+ }
159
165
 
160
- if (planMode) {
161
- console.log("\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.");
162
- console.log(" Dica: a opção --merge foi desativada no modo interativo para forçar diff por arquivo.");
163
- console.log(" Para aplicar e resolver conflitos: npx openclaw update --apply");
164
- return;
165
- }
166
+ // Confirmação inicial (se customizado)
167
+ if (!flags.yes && actions.updated.length === 0) {
168
+ const ok = await ask("\nAplicar e copiar arquivos novos? (y/N): ");
169
+ if (ok.toLowerCase() !== "y") {
170
+ console.log("⏹️ Cancelado.");
171
+ return;
172
+ }
173
+ }
166
174
 
167
- // 3. Confirmação inicial
168
- if (!flags.yes && actions.updated.length === 0) {
169
- const ok = await ask("\nAplicar e copiar arquivos novos? (y/N): ");
170
- if (ok.toLowerCase() !== "y") {
171
- console.log("⏹️ Cancelado.");
172
- return;
173
- }
174
- }
175
+ // Criar diretórios necessários
176
+ function ensureDir(p) {
177
+ const dir = path.dirname(p);
178
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
179
+ }
175
180
 
176
- // 4. Execução Interativa Segura (Conflitos file-by-file)
177
- try {
178
- console.log("\n🚀 Executando atualizações...");
181
+ const audit = [getAuditHeader(ctx, "update", flags)];
179
182
 
180
- // Criar diretórios necessários
181
- function ensureDir(p) {
182
- const dir = path.dirname(p);
183
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
184
- }
183
+ // Action: Added
184
+ for (const action of actions.added) {
185
+ ensureDir(action.dest);
186
+ fs.copyFileSync(action.src, action.dest);
187
+ audit.push(`- ACT: CREATED ${safeRel(targetPath, action.dest)}`);
188
+ }
185
189
 
186
- // Action: Added
187
- for (const action of actions.added) {
188
- ensureDir(action.dest);
189
- fs.copyFileSync(action.src, action.dest);
190
- audit.push(`- ACT: CREATED ${safeRel(targetPath, action.dest)}`);
191
- }
190
+ // Action: Updated (Conflict Resolver)
191
+ for (const action of actions.updated) {
192
+ ensureDir(action.dest);
193
+ const rPath = safeRel(targetPath, action.dest);
192
194
 
193
- // Action: Updated (Conflict Resolver)
194
- for (const action of actions.updated) {
195
- ensureDir(action.dest);
196
- const rPath = safeRel(targetPath, action.dest);
195
+ let overwrite = flags.yes || flags.force;
197
196
 
198
- let overwrite = flags.yes || flags.force;
197
+ if (!overwrite) {
198
+ console.log(`\n⚠️ CONFLITO DETECTADO: ${rPath}`);
199
+ console.log("------------------------------------------------");
200
+ const oldContent = fs.readFileSync(action.dest, "utf-8");
201
+ const newContent = fs.readFileSync(action.src, "utf-8");
202
+ console.log(simpleDiff(oldContent, newContent));
203
+ console.log("------------------------------------------------");
199
204
 
200
- if (!overwrite) {
201
- console.log(`\n⚠️ CONFLITO DETECTADO: ${rPath}`);
202
- console.log("------------------------------------------------");
203
- const oldContent = fs.readFileSync(action.dest, "utf-8");
204
- const newContent = fs.readFileSync(action.src, "utf-8");
205
- console.log(simpleDiff(oldContent, newContent));
206
- console.log("------------------------------------------------");
205
+ const ans = await ask(`Substituir a sua versão de ${rPath} pelo código acima? [y/N]: `);
206
+ overwrite = ans.toLowerCase() === "y";
207
+ }
207
208
 
208
- const ans = await ask(`Substituir a sua versão de ${rPath} pelo código acima? [y/N]: `);
209
- overwrite = ans.toLowerCase() === "y";
209
+ if (overwrite) {
210
+ const backupPath = action.dest + ".bak";
211
+ fs.copyFileSync(action.dest, backupPath);
212
+ fs.copyFileSync(action.src, action.dest);
213
+ console.log(`✅ Sobrescrito: ${rPath} (Backup guardado localmente: .bak)`);
214
+ audit.push(`- ACT: UPDATED ${rPath} (Backup: ${path.basename(backupPath)})`);
215
+ } else {
216
+ console.log(`⏭️ Ignorado (Mantido customização em ${rPath})`);
217
+ audit.push(`- ACT: SKIPPED UPDATE FOR CUSTOMIZED FILE ${rPath}`);
218
+ }
210
219
  }
211
220
 
212
- if (overwrite) {
213
- const backupPath = action.dest + ".bak";
214
- fs.copyFileSync(action.dest, backupPath);
215
- fs.copyFileSync(action.src, action.dest);
216
- console.log(`✅ Sobrescrito: ${rPath} (Backup guardado localmente: .bak)`);
217
- audit.push(`- ACT: UPDATED ${rPath} (Backup: ${path.basename(backupPath)})`);
218
- } else {
219
- console.log(`⏭️ Ignorado (Mantido customização em ${rPath})`);
220
- audit.push(`- ACT: SKIPPED UPDATE FOR CUSTOMIZED FILE ${rPath}`);
221
+ console.log("\n✨ Atualização concluída com sucesso!");
222
+
223
+ // Auditing manual
224
+ if (flags.audit !== false) {
225
+ const { writeCliAudit } = require("../utils/audit-writer");
226
+ writeCliAudit(targetPath, audit, flags, "update");
221
227
  }
222
228
  }
223
-
224
- console.log("\n✨ Atualização concluída com sucesso!");
225
- writeAudit(targetPath, audit, flags);
226
-
227
- } catch (err) {
228
- console.error(`\n❌ Falha na execução: ${err.message}`);
229
- audit.push(`\n## ERROR: ${err.message}`);
230
- writeAudit(targetPath, audit, flags);
231
- process.exit(1);
232
- }
229
+ });
233
230
  }
234
231
 
235
232
  module.exports = { run, fileHash };
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Context Engine do OpenClaw AI OS
5
+ *
6
+ * Responsável por gerenciar, carregar e persistir o conhecimento e estado de operação:
7
+ * 1. system.json - Variáveis de ambiente, config, OS, Docker
8
+ * 2. workspace.json - Mapeamento de linguagens, dependências, arquivos principais, histórico de testes
9
+ * 3. user.json - Preferências, IDE, token settings, perfil de agressividade do AI
10
+ */
11
+
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+
15
+ class ContextEngine {
16
+ /**
17
+ * @param {string} projectRoot - Raiz do projeto (onde fica .agent/)
18
+ */
19
+ constructor(projectRoot) {
20
+ this.projectRoot = projectRoot;
21
+ this.contextDir = path.join(projectRoot, ".agent", "context");
22
+
23
+ // Cria o diretório de contexto caso não exista (independente do init)
24
+ if (!fs.existsSync(this.contextDir)) {
25
+ try {
26
+ fs.mkdirSync(this.contextDir, { recursive: true });
27
+ } catch (err) {
28
+ // Ignorar em diretórios hostis onde openclaw não está armado
29
+ }
30
+ }
31
+ }
32
+
33
+ _getFilePath(type) {
34
+ return path.join(this.contextDir, `${type}.json`);
35
+ }
36
+
37
+ /**
38
+ * Carrega um fragmento do contexto ou retorna defaults
39
+ * @param {string} type - "system", "workspace" ou "user"
40
+ */
41
+ load(type) {
42
+ const file = this._getFilePath(type);
43
+ if (fs.existsSync(file)) {
44
+ try {
45
+ return JSON.parse(fs.readFileSync(file, "utf-8"));
46
+ } catch (err) {
47
+ // Falha de parse, retorna default seguro
48
+ return {};
49
+ }
50
+ }
51
+ return {};
52
+ }
53
+
54
+ /**
55
+ * Salva ou sobrepõe as flags no contexto
56
+ * @param {string} type - "system", "workspace" ou "user"
57
+ * @param {Object} data - Objeto de dados (será feito um object merge shallow com key overwrites)
58
+ */
59
+ save(type, data) {
60
+ // Se .agent não existe ou não foi inicializado, silenciosamente bypass (para CLI cmds sujos antes do IDE_INSTALL)
61
+ if (!fs.existsSync(this.contextDir)) return false;
62
+
63
+ const current = this.load(type);
64
+ const merged = { ...current, ...data };
65
+
66
+ try {
67
+ fs.writeFileSync(this._getFilePath(type), JSON.stringify(merged, null, 2), "utf-8");
68
+ return true;
69
+ } catch (err) {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Agrega todos os arquivos de contexto para compor a mentalidade da query.
76
+ */
77
+ getFullContext() {
78
+ return {
79
+ system: this.load("system"),
80
+ workspace: this.load("workspace"),
81
+ user: this.load("user"),
82
+ meta: {
83
+ timestamp: new Date().toISOString()
84
+ }
85
+ };
86
+ }
87
+ }
88
+
89
+ module.exports = ContextEngine;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Core Orchestrator do OpenClaw AI OS
5
+ *
6
+ * Atua como o "Kernel" do sistema, centralizando o ciclo de vida:
7
+ * INSPECT -> PLAN -> CONSENT -> APPLY -> AUDIT
8
+ */
9
+
10
+ const readline = require("readline");
11
+ const fs = require("fs");
12
+ const path = require("path");
13
+ const { guardPlan } = require("../utils/scope_guard");
14
+ const { writeCliAudit } = require("../utils/audit-writer");
15
+
16
+ function ask(q) {
17
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
18
+ return new Promise((res) => rl.question(q, (ans) => { rl.close(); res(ans.trim()); }));
19
+ }
20
+
21
+ /**
22
+ * Executa uma ação unificada no OpenClaw AI OS.
23
+ * Garante que regras de segurança, escopo e auditoria sejam aplicadas.
24
+ *
25
+ * @param {Object} options
26
+ * @param {string} options.actionName - Nome da ação (ex: "ide install", "uninstall")
27
+ * @param {Object} options.context - Contexto do workspace/módulo coletado
28
+ * @param {Object} options.flags - Flags da CLI (--apply, --force, --yes)
29
+ * @param {Object} options.intents - { writes: [], deletes: [], overwrites: [] }
30
+ * @param {Function} options.executeFn - Função assíncrona que aplica as mudanças de fato
31
+ * @param {Function} options.planFn - Função de exibição do plano (read-only)
32
+ * @param {string} options.targetPath - Root path do projeto
33
+ * @param {boolean} options.skipAudit - Se true, não grava o audit log no .agent/audit (útil para uninstall)
34
+ * @param {boolean} options.skipConfirm - Se true, pula o prompt padrão de apply (útil para per-file diff loops)
35
+ * @returns {boolean} true se executado, false se cancelado ou em modo plan
36
+ */
37
+ async function executeAction({
38
+ actionName,
39
+ context,
40
+ flags,
41
+ intents = { writes: [], deletes: [], overwrites: [] },
42
+ executeFn,
43
+ planFn,
44
+ confirmationWord = null,
45
+ targetPath,
46
+ skipAudit = false,
47
+ skipConfirm = false
48
+ }) {
49
+ const planMode = !flags.apply;
50
+
51
+ // 1. INSPECT / PLAN - Scope Guard
52
+ await guardPlan(targetPath, intents, flags);
53
+
54
+ // Exibir o plano real
55
+ if (planFn && typeof planFn === "function") {
56
+ await planFn();
57
+ }
58
+
59
+ if (planMode) {
60
+ console.log(`\n🔒 Modo PLAN (Read-Only). Nenhuma alteração feita.`);
61
+ console.log(` Para aplicar, rode com a flag --apply`);
62
+ return false;
63
+ }
64
+
65
+ // 2. CONSENT
66
+ if (!flags.yes && !skipConfirm) {
67
+ if (confirmationWord) {
68
+ const confirm = await ask(`\n⚠️ Ação destrutiva requer confirmação forte. Digite '${confirmationWord}' para confirmar: `);
69
+ if (confirm !== confirmationWord) {
70
+ console.log("⏹️ Cancelado. Nenhuma alteração feita.");
71
+ return false;
72
+ }
73
+ } else {
74
+ const confirm = await ask(`\n⚠️ Deseja APLICAR as alterações acima? (s/N): `);
75
+ if (confirm.toLowerCase() !== "s") {
76
+ console.log("⏹️ Cancelado. Nenhuma alteração feita.");
77
+ return false;
78
+ }
79
+ }
80
+ }
81
+
82
+ // 3. APPLY
83
+ console.log(`\n⚙️ Executando [${actionName}]...`);
84
+ try {
85
+ await executeFn();
86
+ console.log(`✅ Ação [${actionName}] concluída com sucesso.`);
87
+ } catch (err) {
88
+ console.error(`❌ Erro ao executar [${actionName}]:`, err.message);
89
+ throw err;
90
+ }
91
+
92
+ // 4. AUDIT
93
+ if (!skipAudit && flags.audit !== false) {
94
+ try {
95
+ const auditPayload = [
96
+ `--- AUDIT LOG: ${actionName} ---`,
97
+ `Date: ${new Date().toISOString()}`,
98
+ `User Flags: ${JSON.stringify(flags)}`,
99
+ `Intents: writes=${intents.writes.length} overwrites=${intents.overwrites.length} deletes=${intents.deletes.length}`,
100
+ `Status: SUCCESS`
101
+ ];
102
+
103
+ // Reutiliza a função de escrita de log da CLI
104
+ writeCliAudit(targetPath, auditPayload, flags, actionName);
105
+ } catch (e) {
106
+ console.log("⚠️ Não foi possível escrever o audit log.");
107
+ }
108
+ }
109
+
110
+ return true;
111
+ }
112
+
113
+ module.exports = { executeAction };
@@ -36,8 +36,19 @@ function isPathInSafeScope(targetPath, fileToMutate) {
36
36
  // allow openclaw.json default config
37
37
  if (absoluteMutate === path.join(targetPath, "openclaw.json")) return true;
38
38
 
39
+ // permitemos as configs nativas da IDE copiadas no install
40
+ const safeIdioms = [
41
+ path.join(targetPath, ".cursorrules"),
42
+ path.join(targetPath, ".github"),
43
+ path.join(targetPath, ".cursor")
44
+ ];
45
+
46
+ if (safeIdioms.some(idiom => absoluteMutate.startsWith(idiom))) return true;
47
+
39
48
  // Retorna true se começa com o caminho the escopo.
40
- return absoluteMutate.startsWith(safeScope);
49
+ if (absoluteMutate.startsWith(safeScope)) return true;
50
+
51
+ return false;
41
52
  }
42
53
 
43
54
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabioforest/openclaw",
3
- "version": "3.10.0",
3
+ "version": "3.10.2",
4
4
  "description": "Agentes autônomos para engenharia de software",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: Criação de um snapshot do contexto do workspace atual para o router
3
+ ---
4
+
5
+ # Workspace Snapshot
6
+
7
+ ## Objetivo
8
+ Analisar e capturar o estado global do projeto (stack, dependências, rotas, testes e pontos cegos) gerando um artefato `context.json` otimizado. Isso alimenta os roteadores de agentes reduzindo solicitações repetitivas de entendimento e consumos de Token por scans demorados.
9
+
10
+ ## Fluxo
11
+ 1. Ler `.gitignore` e `package.json` (ou similares de outras linguagens).
12
+ 2. Escanear diretórios chave (src, lib, tests, config).
13
+ 3. Detectar frameworks, bibliotecas primárias e scripts customizados.
14
+ 4. Identificar zonas de risco (pastas legacy, componentes em migração, vulnerabilidades).
15
+ 5. Escrever/Atualizar `.agent/context/context.json` e notificar roteadores.
16
+
17
+ ## Regras
18
+ - Nunca ler arquivos grandes ignorados como `node_modules` e pastas compiladas.
19
+ - O resultado no JSON não deve passar de 5kb (resumo em alto nível) para manter os tokens baixos no contexto das prompts do LLM.
20
+ - Exigir aprovação de Apply para gravar a imagem do Snapshot.
@@ -0,0 +1,19 @@
1
+ # OpenClaw - Chat Router Workflow
2
+ # Roteamento de Entrada para o Chat da IDE
3
+
4
+ **description**: Workflow de entrada padrão para o modelo ao iniciar um chat. Força o reconhecimento de contexto antes de qualquer ação.
5
+
6
+ ## 1. Inspect
7
+ Sempre comece investigando o estado atual do repositório, procurando pelas regras e diretrizes estabelecidas no `.agent/rules/`. Leia `openclaw.json` para definir o `targetPath` base.
8
+
9
+ ## 2. Plan & Select Skill
10
+ Com base no seu objetivo e nas skills ativas listadas em `.agent/skills/`, escolha a melhor abordagem e desenvolva um rascunho. Comunique o plano detalhado no chat.
11
+
12
+ ## 3. Consent
13
+ Nunca modifique arquivos críticos, delete diretórios ou crie instâncias de serviço sem perguntar ativamente e aguardar o "Sim" explicíto do usuário sobre o Plano (Consent-First).
14
+
15
+ ## 4. Apply
16
+ Proceda com a implementação guiando-se estritamente pela sua proposta. Mantenha os arquivos enxutos (pequenos) e faça checagens consistentes.
17
+
18
+ ## 5. Audit
19
+ Deixe um sumário claro do que foi modificado como prova da sessão de alterações. Utilize `lib/utils/audit-writer.js` se for chamado via OpenClaw CLI ou relate concisamente.
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: openclaw-global-system-rules
3
+ globs: *
4
+ ---
5
+ # OpenClaw AI OS - Global Rules
6
+ Você é controlado pelo sistema OpenClaw AI OS instalado neste workspace. Seu comportamento principal deve ser "Consent-First".
7
+
8
+ - Ler as políticas do diretório `.agent/rules` ANTES de agir.
9
+ - Seguir o workflow padrão `.agent/workflows/chat-router.md` de Roteamento (Inspect -> Plan -> Consent -> Apply -> Audit).
10
+ - Jamais mutar, deletar ou sobrescrever arquivos sem o DEVIDO Consentimento do Usuário atestado em Plano de Ação.
11
+ - Consultar e preservar `.agent/state/MEMORY.md` com as decisões de projeto.
@@ -0,0 +1,7 @@
1
+ # OpenClaw AI OS - Global Rules
2
+ Você é controlado pelo sistema OpenClaw AI OS instalado neste workspace. Seu comportamento principal deve ser "Consent-First".
3
+
4
+ - Ler as políticas do diretório `.agent/rules` ANTES de agir.
5
+ - Seguir o workflow padrão `.agent/workflows/chat-router.md` de Roteamento (Inspect -> Plan -> Consent -> Apply -> Audit).
6
+ - Jamais mutar, deletar ou sobrescrever arquivos sem o DEVIDO Consentimento do Usuário atestado em Plano de Ação.
7
+ - Consultar e preservar `.agent/state/MEMORY.md` com as decisões de projeto.
@@ -0,0 +1,11 @@
1
+ # OpenClaw AI OS - Copilot Instructions
2
+ Você faz parte do ecosistema OpenClaw instalado neste projeto, que reforça arquiteturas de agentes seguras.
3
+
4
+ ## 1. Safety Protocols
5
+ Respeite e leia a diretriz de Consentimento: `.agent/rules/CONSENT_FIRST.md`. Todas as mutações do projeto exigem aprovações prévias visuais baseadas em um Plano (Inspect -> Plan -> Consent -> Apply -> Audit).
6
+
7
+ ## 2. Tools & Skills
8
+ Sempre verifique extensões instaladas e documentação do projeto via `.agent/skills/` ou referências locais do diretório `.agent` para aplicar soluções sob o escopo esperado do mantenedor.
9
+
10
+ ## 3. Comportamento
11
+ Preserve a integridade do sistema do usuário e nunca faça deleções não solicitadas em arquivos da pipeline e fora das permissões.