@fontdata/ai-harness 3.0.0 → 3.1.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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "fontdata",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "mcpServers": {
5
- "banco_dados": { "command": "npx", "args": ["-y", "@fontdata/ai-harness@3.0.0", "banco-dados-mcp"] }
5
+ "banco_dados": { "command": "npx", "args": ["-y", "@fontdata/ai-harness@3.1.0", "banco-dados-mcp"] }
6
6
  },
7
7
  "description": "Harness de engenharia com IA da Fontdata para Claude Code",
8
8
  "author": { "name": "Fontdata" },
package/README.md CHANGED
@@ -129,15 +129,16 @@ da conexão e o nome da variável de ambiente (`dsn_env`), e cada dev guarda o D
129
129
  `.claude/settings.local.json` (fora do git), no `.env` ou no ambiente:
130
130
 
131
131
  ```bash
132
- npx @fontdata/ai-harness banco-dados adicionar erp --projeto # pergunta os dados, testa e grava ERP_DATABASE_URL
132
+ npx @fontdata/ai-harness banco-dados adicionar erp # na raiz do projeto: pergunta os dados, testa e grava ERP_DATABASE_URL
133
133
  npx @fontdata/ai-harness banco-dados testar
134
134
  ```
135
135
 
136
- O `adicionar --projeto` grava `{ "nome": "erp", "dsn_env": "ERP_DATABASE_URL" }` em `banco_dados.conexoes` e a variável
137
- no `.claude/settings.local.json`. Faça commit do `config.json`; cada colega roda o mesmo comando, que grava só a
138
- variável. `"producao": true` na entrada vale para a equipe toda. Quem prefere um cadastro por máquina
139
- (`~/.config/ai-harness/conexoes.json`) usa `banco-dados adicionar erp-dev` sem `--projeto` e `banco-dados usar erp-dev` no
140
- projeto.
136
+ O `adicionar` grava `{ "nome": "erp", "dsn_env": "ERP_DATABASE_URL" }` em `banco_dados.conexoes` e a variável no
137
+ `.claude/settings.local.json`; fora da raiz de um projeto (sem `.git` nem `.ai-harness/config.json`), ele recusa sem
138
+ gravar nada. Faça commit do `config.json`; cada colega roda o mesmo comando, que grava só a variável.
139
+ `"producao": true` na entrada vale para a equipe toda, e `banco-dados remover erp` tira a conexão do projeto. Quem
140
+ prefere um cadastro por máquina (`~/.config/ai-harness/conexoes.json`) usa `banco-dados adicionar erp-dev --global` e
141
+ `banco-dados usar erp-dev` no projeto.
141
142
 
142
143
  O servidor MCP `banco_dados` entrega ao Claude `listar_conexoes`, `listar_tabelas`, `descrever_tabela` e
143
144
  `consultar`, tudo somente leitura. Ele vem no plugin; sem plugin, o `init` e o `update` o registram no `.mcp.json`
@@ -81,12 +81,27 @@ export function gravarVariavelSettingsLocal(raiz, nome, valor) {
81
81
  const envAtual = ehObjeto(dados.env) ? dados.env : {};
82
82
  if (envAtual[nome] === valor)
83
83
  return { changed: false };
84
- const novo = { ...dados, env: { ...envAtual, [nome]: valor } };
85
84
  const modo = leitura.existe ? statSync(caminho).mode & 0o777 : 0o600;
86
85
  mkdirSync(dirname(caminho), { recursive: true });
86
+ gravarAtomico(caminho, { ...dados, env: { ...envAtual, [nome]: valor } }, modo);
87
+ return { changed: true };
88
+ }
89
+ /** Tira a variável do env do settings.local.json com a mesma gravação atômica; arquivo ou chave ausente não escreve. */
90
+ export function removerVariavelSettingsLocal(raiz, nome) {
91
+ const caminho = join(raiz, SETTINGS_LOCAL_PATH);
92
+ const leitura = lerSettings(caminho);
93
+ if ('erro' in leitura)
94
+ throw new Error(leitura.erro);
95
+ if (!leitura.existe || !ehObjeto(leitura.dados.env) || !Object.hasOwn(leitura.dados.env, nome))
96
+ return { changed: false };
97
+ const { [nome]: _removida, ...envRestante } = leitura.dados.env;
98
+ gravarAtomico(caminho, { ...leitura.dados, env: envRestante }, statSync(caminho).mode & 0o777);
99
+ return { changed: true };
100
+ }
101
+ function gravarAtomico(caminho, dados, modo) {
87
102
  const temporario = `${caminho}.${process.pid}.${Date.now()}.tmp`;
88
103
  try {
89
- writeFileSync(temporario, `${JSON.stringify(novo, null, 2)}\n`, { mode: modo });
104
+ writeFileSync(temporario, `${JSON.stringify(dados, null, 2)}\n`, { mode: modo });
90
105
  chmodSync(temporario, modo);
91
106
  renameSync(temporario, caminho);
92
107
  }
@@ -94,5 +109,4 @@ export function gravarVariavelSettingsLocal(raiz, nome, valor) {
94
109
  rmSync(temporario, { force: true });
95
110
  throw erro;
96
111
  }
97
- return { changed: true };
98
112
  }
@@ -2,24 +2,28 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { EOL } from 'node:os';
3
3
  import { join, resolve } from 'node:path';
4
4
  import * as p from '@clack/prompts';
5
- import { comSecaoBanco, CONFIG_PATH, gravarConexaoProjeto, readConfig, REGRA_DSN_ENV, REGRA_NOME_CONEXAO, secaoBanco, validarConfigParaEscrita, writeDefaultConfig, } from '../config/config.js';
5
+ import { comSecaoBanco, CONFIG_PATH, gravarConexaoProjeto, readConfig, removerConexaoProjeto, REGRA_DSN_ENV, REGRA_NOME_CONEXAO, secaoBanco, validarConfigParaEscrita, writeDefaultConfig, } from '../config/config.js';
6
6
  import { suggestFlag } from '../install/flags.js';
7
7
  import { caminhoCadastro, lerCadastro, ocultarSenha, removerConexao, resumirConexao, salvarConexao, TIPOS_BANCO, } from './cadastro.js';
8
- import { gravarVariavelSettingsLocal, lerEnvSettingsLocal, lerVariavel, SETTINGS_LOCAL_PATH, validarSettingsLocal } from './ambiente.js';
8
+ import { gravarVariavelSettingsLocal, lerEnvSettingsLocal, lerVariavel, removerVariavelSettingsLocal, SETTINGS_LOCAL_PATH, validarSettingsLocal, } from './ambiente.js';
9
9
  import { interpretarDsn, resolverConexoes } from './conexao.js';
10
10
  import { criarDriver as criarDriverPadrao } from './drivers/index.js';
11
11
  const AJUDA = [
12
12
  'Uso: ai-harness banco-dados <subcomando>',
13
13
  '',
14
- ' adicionar <nome> [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]',
15
- ' cadastra a conexão nesta máquina (sem --dsn, pergunta os dados)',
16
- ' adicionar <nome> --projeto [--env <VAR>] [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]',
17
- ' grava o DSN na variável <NOME>_DATABASE_URL (ou --env) do .claude/settings.local.json',
14
+ ' adicionar <nome> [--env <VAR>] [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]',
15
+ ' grava no projeto: o DSN na variável <NOME>_DATABASE_URL (ou --env) do .claude/settings.local.json',
18
16
  ' e a conexão { nome, dsn_env } em banco_dados.conexoes do .ai-harness/config.json',
17
+ ' (sem --dsn, pergunta os dados)',
18
+ ' adicionar <nome> --global [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]',
19
+ ' cadastra a conexão nesta máquina',
19
20
  ' listar mostra as conexões cadastradas e as do projeto, sem a senha',
20
21
  ' testar [nome] testa a conexão pedida ou todas as do projeto',
21
- ' usar <nome...> grava banco_dados.conexoes no .ai-harness/config.json (mantém as entradas { nome, dsn_env })',
22
- ' remover <nome> apaga a conexão do cadastro',
22
+ ' usar <nome...> grava banco_dados.conexoes no .ai-harness/config.json, para conexões do cadastro global',
23
+ ' (mantém as entradas { nome, dsn_env })',
24
+ ' remover <nome> [--global]',
25
+ ' tira a conexão do projeto e a variável dela do .claude/settings.local.json;',
26
+ ' com --global, apaga a conexão do cadastro desta máquina',
23
27
  ].join(EOL);
24
28
  const PORTA_PADRAO = { postgres: '5432', mariadb: '3306' };
25
29
  const ESQUEMA = { postgres: 'postgres', mariadb: 'mysql' };
@@ -118,14 +122,15 @@ function conexaoDoDsn(dsn, cwd, producao) {
118
122
  return conexao;
119
123
  }
120
124
  async function adicionar(ctx, argv) {
121
- const { posicionais, marcadas, valores } = lerArgumentos(argv, ['--producao', '--sem-testar', '--substituir', '--projeto'], ['--dsn', '--env']);
125
+ const { posicionais, marcadas, valores } = lerArgumentos(argv, ['--producao', '--sem-testar', '--substituir', '--global'], ['--dsn', '--env']);
122
126
  const [nome, ...sobra] = posicionais;
123
- if (!nome || sobra.length > 0)
124
- throw new Error('Uso: ai-harness banco-dados adicionar <nome> [--projeto [--env <VAR>]] [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]');
125
- if (marcadas.has('--projeto'))
127
+ if (!nome || sobra.length > 0) {
128
+ throw new Error('Uso: ai-harness banco-dados adicionar <nome> [--global | --env <VAR>] [--dsn <dsn>] [--producao] [--sem-testar] [--substituir]');
129
+ }
130
+ if (!marcadas.has('--global'))
126
131
  return adicionarNoProjeto(ctx, nome, marcadas, valores);
127
132
  if (valores['--env'] !== undefined)
128
- throw new Error('--env só vale com --projeto.');
133
+ throw new Error('--env não vale com --global.');
129
134
  const substituir = marcadas.has('--substituir');
130
135
  if (!substituir && nome in lerCadastro(ctx.cadastro).conexoes) {
131
136
  ctx.erro(`A conexão ${nome} já existe em ${ctx.cadastro}. Use --substituir para trocá-la.`);
@@ -169,6 +174,10 @@ function variavelPadrao(nome) {
169
174
  return `${nome.toUpperCase().replace(/-/g, '_')}_DATABASE_URL`;
170
175
  }
171
176
  async function adicionarNoProjeto(ctx, nome, marcadas, valores) {
177
+ if (!existsSync(join(ctx.cwd, '.git')) && !existsSync(join(ctx.cwd, CONFIG_PATH))) {
178
+ ctx.erro(`Nenhum projeto em ${ctx.cwd} (sem .git nem ${CONFIG_PATH}). Rode na raiz do projeto ou use --global para cadastrar nesta máquina.`);
179
+ return 1;
180
+ }
172
181
  const substituir = marcadas.has('--substituir');
173
182
  if (!REGRA_NOME_CONEXAO.test(nome)) {
174
183
  ctx.erro(`Nome de conexão inválido: ${JSON.stringify(nome)}; use só minúsculas, dígitos, - e _, começando por minúscula ou dígito.`);
@@ -260,7 +269,7 @@ function listar(ctx, argv) {
260
269
  const doProjeto = config.banco_dados.conexoes.flatMap((nome) => config.banco_dados.projeto[nome] ?? []);
261
270
  const nomes = Object.keys(conexoes).sort();
262
271
  if (nomes.length === 0 && doProjeto.length === 0) {
263
- ctx.log(`Nenhuma conexão cadastrada em ${ctx.cadastro}. Cadastre com: npx @fontdata/ai-harness banco-dados adicionar <nome>`);
272
+ ctx.log('Nenhuma conexão. Na raiz do projeto, rode: npx @fontdata/ai-harness banco-dados adicionar <nome>');
264
273
  return 0;
265
274
  }
266
275
  for (const nome of nomes) {
@@ -313,7 +322,7 @@ async function testar(ctx, argv) {
313
322
  for (const problema of resolvidas.problemas)
314
323
  ctx.erro(problema);
315
324
  for (const faltando of resolvidas.faltando.filter((item) => nome === undefined || item === nome)) {
316
- ctx.erro(`Conexão ${faltando} não encontrada nesta máquina; rode banco-dados adicionar ${faltando}.`);
325
+ ctx.erro(`Conexão ${faltando} não encontrada nesta máquina; rode banco-dados adicionar ${faltando} --global.`);
317
326
  ok = false;
318
327
  }
319
328
  for (const ausente of resolvidas.variaveisAusentes.filter(pedida)) {
@@ -327,7 +336,7 @@ async function testar(ctx, argv) {
327
336
  }
328
337
  alvos = resolvidas.conexoes.filter(pedida);
329
338
  if (alvos.length === 0 && ok) {
330
- ctx.erro('Nenhuma conexão de banco configurada neste projeto; rode npx @fontdata/ai-harness banco-dados usar <nome>.');
339
+ ctx.erro('Nenhuma conexão de banco configurada neste projeto; rode npx @fontdata/ai-harness banco-dados adicionar <nome>.');
331
340
  return 1;
332
341
  }
333
342
  }
@@ -371,15 +380,17 @@ function usar(ctx, argv) {
371
380
  const { conexoes } = lerCadastro(ctx.cadastro);
372
381
  const ausentes = unicos.filter((nome) => !(nome in conexoes) && !objetos.has(nome));
373
382
  if (ausentes.length > 0) {
374
- ctx.erro(`Aviso: sem cadastro nesta máquina para ${ausentes.join(', ')}; rode banco-dados adicionar <nome> para cada uma.`);
383
+ ctx.erro(`Aviso: sem cadastro nesta máquina para ${ausentes.join(', ')}; rode banco-dados adicionar <nome> --global para cada uma.`);
375
384
  }
376
385
  return 0;
377
386
  }
378
387
  function remover(ctx, argv) {
379
- const { posicionais } = lerArgumentos(argv, []);
388
+ const { posicionais, marcadas } = lerArgumentos(argv, ['--global']);
380
389
  const [nome, ...sobra] = posicionais;
381
390
  if (!nome || sobra.length > 0)
382
- throw new Error('Uso: ai-harness banco-dados remover <nome>');
391
+ throw new Error('Uso: ai-harness banco-dados remover <nome> [--global]');
392
+ if (!marcadas.has('--global'))
393
+ return removerDoProjeto(ctx, nome);
383
394
  if (!removerConexao(nome, ctx.cadastro)) {
384
395
  ctx.erro(`Conexão ${nome} não existe em ${ctx.cadastro}.`);
385
396
  return 1;
@@ -387,7 +398,34 @@ function remover(ctx, argv) {
387
398
  ctx.log(`Conexão ${nome} removida de ${ctx.cadastro}.`);
388
399
  return 0;
389
400
  }
390
- /** `ai-harness banco-dados <subcomando>`: cadastro de conexões da máquina e escolha das conexões do projeto. */
401
+ function removerDoProjeto(ctx, nome) {
402
+ validarSettingsLocal(ctx.cwd);
403
+ validarConfigParaEscrita(ctx.cwd);
404
+ const removida = removerConexaoProjeto(ctx.cwd, nome);
405
+ if (removida === null) {
406
+ const noCadastro = nome in lerCadastro(ctx.cadastro).conexoes;
407
+ ctx.erro(`Conexão ${nome} não está em banco_dados.conexoes de ${CONFIG_PATH}.${noCadastro ? ` Para o cadastro desta máquina, use remover ${nome} --global.` : ''}`);
408
+ return 1;
409
+ }
410
+ ctx.log(`Conexão ${nome} removida de banco_dados.conexoes de ${CONFIG_PATH}.`);
411
+ const variavel = typeof removida === 'string' ? undefined : removida.dsn_env;
412
+ if (variavel === undefined)
413
+ return 0;
414
+ const atual = lerEnvSettingsLocal(ctx.cwd)[variavel];
415
+ if (atual !== undefined)
416
+ ctx.sensiveis.push(sensivel(atual));
417
+ const outra = Object.values(readConfig(ctx.cwd).config.banco_dados.projeto).find((conexao) => conexao.dsn_env === variavel);
418
+ if (outra)
419
+ ctx.log(`Variável ${variavel} mantida em ${SETTINGS_LOCAL_PATH}: a conexão ${outra.nome} também a usa.`);
420
+ else if (removerVariavelSettingsLocal(ctx.cwd, variavel).changed)
421
+ ctx.log(`Variável ${variavel} removida de ${SETTINGS_LOCAL_PATH}.`);
422
+ ctx.log(`Se ${variavel} estiver definida no .env ou no ambiente, ela não foi tocada.`);
423
+ return 0;
424
+ }
425
+ /**
426
+ * `ai-harness banco-dados <subcomando>`: conexões do projeto (padrão), cadastro global de conexões da máquina
427
+ * (`--global`) e escolha das conexões do cadastro que o projeto usa.
428
+ */
391
429
  export async function runBancoCommand(argv, opcoes = {}) {
392
430
  const saida = opcoes.saida ?? { log: (texto) => console.log(texto), erro: (texto) => console.error(texto) };
393
431
  const cadastro = opcoes.caminhoCadastro ?? caminhoCadastro();
@@ -118,7 +118,7 @@ export function resolverConexoes(raiz, opcoes = {}) {
118
118
  }
119
119
  export function escolherConexao(resolvidas, nome) {
120
120
  if (resolvidas.length === 0) {
121
- throw new Error('Nenhuma conexão de banco configurada neste projeto; rode npx @fontdata/ai-harness banco-dados usar <nome>');
121
+ throw new Error('Nenhuma conexão de banco configurada neste projeto; rode npx @fontdata/ai-harness banco-dados adicionar <nome> na raiz do projeto');
122
122
  }
123
123
  const escolhida = nome === undefined ? resolvidas[0] : resolvidas.find((conexao) => conexao.nome === nome);
124
124
  if (!escolhida)
@@ -55,16 +55,15 @@ export const INSTRUCOES = [
55
55
  'Use estas ferramentas para ler o banco de dados do projeto; o acesso é somente leitura.',
56
56
  'Nunca peça nem repita credenciais, senhas ou DSNs no chat.',
57
57
  'As conexões vêm do cadastro da máquina ou do projeto: uma conexão do projeto é declarada em banco_dados.conexoes do .ai-harness/config.json com dsn_env (o nome da variável), e o valor da variável fica no .claude/settings.local.json, no .env ou no ambiente.',
58
- 'Sem conexão configurada, oriente o usuário a rodar no terminal `npx @fontdata/ai-harness banco-dados adicionar <nome>` e, no projeto, `npx @fontdata/ai-harness banco-dados usar <nome>`.',
58
+ 'Sem conexão configurada, oriente o usuário a rodar na raiz do projeto `npx @fontdata/ai-harness banco-dados adicionar <nome>`.',
59
59
  'Se a variável de uma conexão do projeto não estiver definida, oriente a defini-la no .claude/settings.local.json, no .env ou no ambiente.',
60
60
  'Antes de consultar, rode listar_tabelas e descrever_tabela para conhecer o esquema.',
61
61
  'Em consultar, selecione só as colunas necessárias e filtre as linhas; evite SELECT *.',
62
62
  'Somente leitura: comandos que alteram dados ou esquema são recusados.',
63
63
  'Os dados pessoais (CPF, e-mail, telefone, nome e afins) vêm mascarados, e o rodapé de consultar diz o que foi mascarado. Não tente contornar o mascaramento: não concatene, fatie, converta nem compare valores para reconstruir o original. Peça só as colunas necessárias.',
64
64
  ].join('\n');
65
- const ORIENTACAO_USAR = 'rode npx @fontdata/ai-harness banco-dados usar <nome> no projeto';
66
65
  function orientarAdicionar(nome) {
67
- return `Conexão ${nome} não encontrada nesta máquina; rode npx @fontdata/ai-harness banco-dados adicionar ${nome}`;
66
+ return `Conexão ${nome} não encontrada nesta máquina; rode npx @fontdata/ai-harness banco-dados adicionar ${nome} --global`;
68
67
  }
69
68
  function orientarVariavel(nome, variavel) {
70
69
  return `A variável ${variavel} da conexão ${nome} não está definida; defina-a no .claude/settings.local.json, no .env ou no ambiente`;
@@ -173,7 +172,7 @@ async function executar(nome, args, contexto, banco, resolvidas) {
173
172
  if (descartadas.length > 0)
174
173
  dados.descartadas = descartadas;
175
174
  if (conexoes.length + faltando.length + variaveisAusentes.length + descartadas.length === 0) {
176
- dados.orientacao = `Nenhuma conexão configurada; rode npx @fontdata/ai-harness banco-dados adicionar <nome> e ${ORIENTACAO_USAR}`;
175
+ dados.orientacao = 'Nenhuma conexão configurada; rode npx @fontdata/ai-harness banco-dados adicionar <nome> na raiz do projeto';
177
176
  }
178
177
  if (resolvidas.problemas.length > 0)
179
178
  dados.problemas = resolvidas.problemas;
@@ -301,6 +301,30 @@ export function gravarConexaoProjeto(root, conexao, { substituir = false } = {})
301
301
  const base = raw ?? lerJsonParaEscrita(file, 'banco_dados.conexoes');
302
302
  writeFileSync(file, `${JSON.stringify(comSecaoBanco(base, { ...banco, conexoes: proximas }), null, 2)}\n`);
303
303
  }
304
+ /**
305
+ * Tira de `banco_dados.conexoes` a primeira entrada com o nome (objeto, mesmo inválido, ou texto), preservando
306
+ * o resto do JSON, e devolve o que leu. Sem config ou sem o nome, devolve null e não escreve.
307
+ * JSON inválido ou `conexoes` que não é lista lança sem tocar no arquivo.
308
+ */
309
+ export function removerConexaoProjeto(root, nome) {
310
+ const file = join(root, CONFIG_PATH);
311
+ if (!existsSync(file))
312
+ return null;
313
+ const raw = lerJsonParaEscrita(file, 'banco_dados.conexoes');
314
+ const banco = secaoBanco(raw);
315
+ const conexoes = banco.conexoes === undefined ? [] : banco.conexoes;
316
+ if (!Array.isArray(conexoes))
317
+ throw new Error(`banco_dados.conexoes em ${CONFIG_PATH} não é uma lista; corrija-o antes de remover a conexão ${nome}.`);
318
+ const posicao = conexoes.findIndex((entrada) => (isObject(entrada) ? entrada.nome : entrada) === nome);
319
+ if (posicao === -1)
320
+ return null;
321
+ const entrada = conexoes[posicao];
322
+ const proximas = conexoes.filter((_atual, i) => i !== posicao);
323
+ writeFileSync(file, `${JSON.stringify(comSecaoBanco(raw, { ...banco, conexoes: proximas }), null, 2)}\n`);
324
+ if (!isObject(entrada))
325
+ return nome;
326
+ return typeof entrada.dsn_env === 'string' ? { nome, dsn_env: entrada.dsn_env } : { nome };
327
+ }
304
328
  /**
305
329
  * Grava só `banco_dados.registrar_mcp`, preservando o resto do JSON; sem config, cria uma com os padrões
306
330
  * e essa chave. JSON inválido é recusado sem tocar no arquivo.
@@ -425,7 +425,7 @@ function checkBancoProjeto(root, config, env) {
425
425
  id: 'banco-variavel-ausente',
426
426
  severidade: 'aviso',
427
427
  mensagem: `A conexão ${nome}, declarada em banco_dados.conexoes de ${join(root, CONFIG_PATH)}, lê o DSN da variável ${dsn_env}, que não está definida no ambiente, em ${SETTINGS_LOCAL_PATH} nem no .env.`,
428
- correcao: `Defina ${dsn_env} com \`npx @fontdata/ai-harness banco-dados adicionar ${nome} --projeto\` ou no ambiente do terminal.`,
428
+ correcao: `Defina ${dsn_env} com \`npx @fontdata/ai-harness banco-dados adicionar ${nome}\` ou no ambiente do terminal.`,
429
429
  });
430
430
  }
431
431
  const envLocal = lerEnvSettingsLocal(root);
@@ -487,7 +487,7 @@ export function checkBanco(root, config, env = process.env) {
487
487
  id: 'banco-conexao-ausente',
488
488
  severidade: 'aviso',
489
489
  mensagem: `A conexão ${nome}, citada em banco_dados.conexoes de ${join(root, CONFIG_PATH)}, não está no cadastro desta máquina (${caminho}).`,
490
- correcao: `Cadastre-a com \`npx @fontdata/ai-harness banco-dados adicionar ${nome}\`.`,
490
+ correcao: `Cadastre-a com \`npx @fontdata/ai-harness banco-dados adicionar ${nome} --global\`.`,
491
491
  });
492
492
  }
493
493
  for (const nome of doCadastro.filter((nome) => conexoes[nome]?.mascaramento === false)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fontdata/ai-harness",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Harness de engenharia com IA da Fontdata para Claude Code: roda os slash commands direto na pasta do projeto via npx, sem instalar nada — ou instala-os em .claude/commands.",
5
5
  "type": "module",
6
6
  "bin": {