dd-harness 0.37.0 → 0.38.1

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/dist/index.js CHANGED
@@ -44,94 +44,94 @@ import { REGRA_DE_COMMITS } from "./regras-de-commit.js";
44
44
  * em repositorio alheio tem que envelhecer bem, e cada dependencia e uma chance de nao
45
45
  * envelhecer.
46
46
  */
47
- const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
48
-
49
- dd-harness diagnostico [--mcp] confere projeto, contexto e conexão MCP
50
- dd-harness atualizar [--aplicar] diz o que neste projeto ficou para trás do
51
- harness atual (CLI, hooks, bloco do
52
- CLAUDE.md/AGENTS.md) e, com --aplicar,
53
- atualiza o que é seguro. O que está FORA
54
- do bloco é do projeto e nunca é tocado
55
- dd-harness integrar --host todos instala MCP/regras/hooks em projeto existente
56
- dd-harness sessao --host <host> hook de boot (stdin JSON)
57
- dd-harness guarda --host <host> hook antes de ferramentas (stdin JSON)
58
- dd-harness start [--host <host>] numa pasta vazia: conduz tudo (login,
59
- espaço, projeto, config) numa tacada.
60
- Instala os TRÊS hosts por padrão (claude,
61
- codex, antigravity) — cada um escreve no
62
- arquivo que a sua ferramenta lê, sem
63
- conflito. Use --host claude,codex para
64
- limitar
65
- dd-harness login --token <token> [--api <url>]
66
- guarda a credencial desta máquina
67
- dd-harness projeto <slug> --nome "<nome>" [--tenant <t>] [--api <url>]
68
- cria o projeto no serviço (antes do init)
69
- dd-harness init --tenant <t> --projeto <p> [--api <url>]
70
- escreve .dd-harness.json; depois rode integrar
71
- dd-harness pasta <slug> --definicao "o que entra e o que não entra"
72
- cria a pasta que o gravar exige
73
- dd-harness gravar <arquivo.md> registra uma memória a partir de um markdown
74
- dd-harness editar <arquivo.md> corrige o que já está gravado
75
- dd-harness arquivar <pasta>/<slug> --motivo <obsoleta|incorreta|fora_dos_filtros>
76
- [--substituida-por <pasta>/<slug>]
77
- tira de circulação sem apagar
78
- dd-harness promover <pasta>/<slug>
79
- torna a memória global: vale para TODO
80
- projeto do espaço, inclusive os futuros
81
- dd-harness despromover <pasta>/<slug>
82
- traz de volta ao alcance dos vínculos
83
- dd-harness apagar <pasta>/<slug> [--confirmar <espaço>]
84
- apaga de vez, em cascata — sem desfazer.
85
- Para tirar de circulação guardando o
86
- conteúdo, use "arquivar"
87
- dd-harness buscar "<pergunta>" acha memória por relevância, não por arquivo
88
- dd-harness ler <pasta>/<slug> imprime a memória inteira, no formato de gravar
89
- dd-harness reancorar <pasta>/<slug> --de "<alvo>" --para "<alvo>"
90
- troca o alvo de uma âncora que mudou de lugar
91
- dd-harness check [--commit <sha>] mede as âncoras e reporta a deriva
92
- dd-harness status só lê: o tamanho do Brain e o que espera julgamento
93
- dd-harness politica [--hook] imprime a política do serviço
94
- saída 0 = veio; 3 = projeto sem política;
95
- 1 = não consegui buscar
96
- --hook: fala o protocolo do SessionStart do
97
- Claude Code, para pôr a política no contexto
98
- dd-harness cinto o interceptador pré-voo: lê a edição no stdin
99
- e devolve a memória que fala daquele trecho.
100
- Quem chama é o hook PreToolUse, não você
101
- dd-harness skills as skills deste projeto e quando cada uma serve
102
- dd-harness skill <nome> o procedimento de uma delas (o mesmo que o
103
- agente recebe ao invocá-la)
104
- dd-harness roadmap as fases abertas: a atual inteira, as próximas
105
- por título (opcional — projeto sem fase não tem)
106
- dd-harness changelog [--versao <v>]
107
- o que já foi concluído, agrupado por versão
108
- dd-harness fase criar --titulo "<t>" [--conteudo <arquivo.md>] [--versao <v>]
109
- [--status ideia|aberta|concluida] [--slug <s>]
110
- dd-harness fase editar <slug> [--titulo "<t>"] [--conteudo <arquivo.md>]
111
- [--versao <v> | --sem-versao] [--status <s>] [--ordem <n>]
112
- concluir = --status concluida: a fase sai do
113
- roadmap e entra no changelog, nada migra
114
- dd-harness --help
115
- dd-harness --version qual binário está instalado nesta máquina
116
-
117
- Política e briefing chegam do serviço. O disco guarda configuração, ponteiros
118
- para skills e estado descartável em ~/.dd-harness. Hosts: claude, codex,
119
- antigravity, lista separada por vírgulas ou todos.
47
+ const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
48
+
49
+ dd-harness diagnostico [--mcp] confere projeto, contexto e conexão MCP
50
+ dd-harness atualizar [--aplicar] diz o que neste projeto ficou para trás do
51
+ harness atual (CLI, hooks, bloco do
52
+ CLAUDE.md/AGENTS.md) e, com --aplicar,
53
+ atualiza o que é seguro. O que está FORA
54
+ do bloco é do projeto e nunca é tocado
55
+ dd-harness integrar --host todos instala MCP/regras/hooks em projeto existente
56
+ dd-harness sessao --host <host> hook de boot (stdin JSON)
57
+ dd-harness guarda --host <host> hook antes de ferramentas (stdin JSON)
58
+ dd-harness start [--host <host>] numa pasta vazia: conduz tudo (login,
59
+ espaço, projeto, config) numa tacada.
60
+ Instala os TRÊS hosts por padrão (claude,
61
+ codex, antigravity) — cada um escreve no
62
+ arquivo que a sua ferramenta lê, sem
63
+ conflito. Use --host claude,codex para
64
+ limitar
65
+ dd-harness login --token <token> [--api <url>]
66
+ guarda a credencial desta máquina
67
+ dd-harness projeto <slug> --nome "<nome>" [--tenant <t>] [--api <url>]
68
+ cria o projeto no serviço (antes do init)
69
+ dd-harness init --tenant <t> --projeto <p> [--api <url>]
70
+ escreve .dd-harness.json; depois rode integrar
71
+ dd-harness pasta <slug> --definicao "o que entra e o que não entra"
72
+ cria a pasta que o gravar exige
73
+ dd-harness gravar <arquivo.md> registra uma memória a partir de um markdown
74
+ dd-harness editar <arquivo.md> corrige o que já está gravado
75
+ dd-harness arquivar <pasta>/<slug> --motivo <obsoleta|incorreta|fora_dos_filtros>
76
+ [--substituida-por <pasta>/<slug>]
77
+ tira de circulação sem apagar
78
+ dd-harness promover <pasta>/<slug>
79
+ torna a memória global: vale para TODO
80
+ projeto do espaço, inclusive os futuros
81
+ dd-harness despromover <pasta>/<slug>
82
+ traz de volta ao alcance dos vínculos
83
+ dd-harness apagar <pasta>/<slug> [--confirmar <espaço>]
84
+ apaga de vez, em cascata — sem desfazer.
85
+ Para tirar de circulação guardando o
86
+ conteúdo, use "arquivar"
87
+ dd-harness buscar "<pergunta>" acha memória por relevância, não por arquivo
88
+ dd-harness ler <pasta>/<slug> imprime a memória inteira, no formato de gravar
89
+ dd-harness reancorar <pasta>/<slug> --de "<alvo>" --para "<alvo>"
90
+ troca o alvo de uma âncora que mudou de lugar
91
+ dd-harness check [--commit <sha>] mede as âncoras e reporta a deriva
92
+ dd-harness status só lê: o tamanho do Brain e o que espera julgamento
93
+ dd-harness politica [--hook] imprime a política do serviço
94
+ saída 0 = veio; 3 = projeto sem política;
95
+ 1 = não consegui buscar
96
+ --hook: fala o protocolo do SessionStart do
97
+ Claude Code, para pôr a política no contexto
98
+ dd-harness cinto o interceptador pré-voo: lê a edição no stdin
99
+ e devolve a memória que fala daquele trecho.
100
+ Quem chama é o hook PreToolUse, não você
101
+ dd-harness skills as skills deste projeto e quando cada uma serve
102
+ dd-harness skill <nome> o procedimento de uma delas (o mesmo que o
103
+ agente recebe ao invocá-la)
104
+ dd-harness roadmap as fases abertas: a atual inteira, as próximas
105
+ por título (opcional — projeto sem fase não tem)
106
+ dd-harness changelog [--versao <v>]
107
+ o que já foi concluído, agrupado por versão
108
+ dd-harness fase criar --titulo "<t>" [--conteudo <arquivo.md>] [--versao <v>]
109
+ [--status ideia|aberta|concluida] [--slug <s>]
110
+ dd-harness fase editar <slug> [--titulo "<t>"] [--conteudo <arquivo.md>]
111
+ [--versao <v> | --sem-versao] [--status <s>] [--ordem <n>]
112
+ concluir = --status concluida: a fase sai do
113
+ roadmap e entra no changelog, nada migra
114
+ dd-harness --help
115
+ dd-harness --version qual binário está instalado nesta máquina
116
+
117
+ Política e briefing chegam do serviço. O disco guarda configuração, ponteiros
118
+ para skills e estado descartável em ~/.dd-harness. Hosts: claude, codex,
119
+ antigravity, lista separada por vírgulas ou todos.
120
120
  `;
121
121
  /**
122
122
  * Os ganchos sao IMPRESSOS, nunca instalados. `.git/hooks` nao e versionado e nao e
123
123
  * nosso: escrever la dentro sem a pessoa pedir e o mesmo tipo de invasao que
124
124
  * sobrescrever o CLAUDE.md dela. Quem cola, decide.
125
125
  */
126
- const GANCHOS = `
127
- Opcional — o gancho que devolve a memória ao code review:
128
-
129
- .git/hooks/post-commit (avisa quais memórias falam do que você mudou)
130
- #!/bin/sh
131
- dd-harness check --commit "$(git rev-parse HEAD)" || true
132
-
133
- Termina em sucesso mesmo com deriva: avisa, não bloqueia.
134
-
126
+ const GANCHOS = `
127
+ Opcional — o gancho que devolve a memória ao code review:
128
+
129
+ .git/hooks/post-commit (avisa quais memórias falam do que você mudou)
130
+ #!/bin/sh
131
+ dd-harness check --commit "$(git rev-parse HEAD)" || true
132
+
133
+ Termina em sucesso mesmo com deriva: avisa, não bloqueia.
134
+
135
135
  Instale os hooks de sessão e guarda com \`dd-harness integrar --host <host>\`.`;
136
136
  function argumento(argv, nome) {
137
137
  const i = argv.indexOf(`--${nome}`);
@@ -166,7 +166,7 @@ async function comandoSkill(argv) {
166
166
  throw new Error("uso: dd-harness skill <nome>");
167
167
  }
168
168
  const s = await leSkill(process.cwd(), slug);
169
- console.log(`# ${s.slug}
169
+ console.log(`# ${s.slug}
170
170
  `);
171
171
  console.log(s.descricao);
172
172
  console.log("");
@@ -260,13 +260,17 @@ function instalaMcp() {
260
260
  // pista nenhuma para diagnosticar. O DEP0190 que isto dispara e suprimido no topo
261
261
  // do arquivo (`process.removeAllListeners("warning")`).
262
262
  //
263
- // `@latest` EXPLICITO, e nao `dd-harness-mcp` pelado: sem a tag, o npx serve a copia
264
- // que ja estiver no cache dele e nem consulta o registro. Medido na rodada 006 — a
265
- // cobaia rodou uma sessao inteira contra um MCP defasado sem nada denunciar. O
266
- // `.mcp.json` continua declarando o pacote SEM versao, de proposito: o que precisa
267
- // estar fresco e o cache, e fixar versao no arquivo obrigaria a reescrever config em
268
- // todo repositorio a cada publicacao.
269
- const p = spawn("npx", ["-y", "dd-harness-mcp@latest", "--help"], {
263
+ // INSTALA, nao aquece cache do npx: o `.mcp.json` passou a declarar `node <caminho>`
264
+ // em vez de `npx`, porque o host lanca o servidor sem shell e ali nao ha forma de
265
+ // `npx` que suba no Windows (ENOENT pelado, EINVAL com .cmd). Com o pacote instalado
266
+ // ha o que apontar, e `integrar` resolve o caminho a partir dele.
267
+ //
268
+ // `@latest` EXPLICITO continua valendo, por outro motivo: sem a tag o npm pode dar por
269
+ // satisfeita a copia que ja esta instalada. Medido na rodada 006 — a cobaia rodou uma
270
+ // sessao inteira contra um MCP defasado sem nada denunciar. A contrapartida e que a
271
+ // versao agora fica congelada no caminho declarado: atualizar exige `integrar` de
272
+ // novo, que e o que o menu de edicao do `start` faz em seguida.
273
+ const p = spawn("npm", ["install", "-g", "dd-harness-mcp@latest"], {
270
274
  shell: process.platform === "win32",
271
275
  stdio: "inherit",
272
276
  });
@@ -347,6 +351,59 @@ function tentaAbrirNavegador(url) {
347
351
  function mascara(token) {
348
352
  return token.length <= 16 ? "***" : `${token.slice(0, 12)}...${token.slice(-4)}`;
349
353
  }
354
+ /**
355
+ * `dd-harness start` num repositorio que ja tem config: mostra o estado e edita o que for
356
+ * escolhido. Nada e reescrito sem a pessoa pedir — "Sair" e uma opcao, e o menu nao tem
357
+ * acao destrutiva.
358
+ */
359
+ async function editaProjeto(hosts) {
360
+ const c = await leConfigDoRepo(process.cwd());
361
+ const token = await leToken(c.api);
362
+ console.log(`Projeto: ${c.tenant}/${c.projeto}`);
363
+ console.log(`Credencial: ${token ? mascara(token) : "ausente"}`);
364
+ console.log(`API: ${c.api}\n`);
365
+ const acao = await escolha("O que você quer fazer?", [
366
+ { rotulo: "Atualizar CLI e MCP", valor: "atualizar" },
367
+ { rotulo: token ? "Trocar a credencial" : "Colar uma credencial", valor: "token" },
368
+ { rotulo: "Reinstalar integrações dos hosts", valor: "integrar" },
369
+ { rotulo: "Sair", valor: "sair" },
370
+ ]);
371
+ if (acao === "sair")
372
+ return;
373
+ if (acao === "token") {
374
+ const url = `${c.api}/tokens`;
375
+ console.log(`\nCrie um token pessoal em ${url} — abrindo no navegador...`);
376
+ tentaAbrirNavegador(url);
377
+ const novo = await pergunta("Cole o token aqui: ");
378
+ if (!novo)
379
+ throw new Error("nenhum token colado — nada foi alterado.");
380
+ await guardaToken(c.api, novo);
381
+ console.log("Credencial guardada.");
382
+ return;
383
+ }
384
+ if (acao === "atualizar") {
385
+ const desatualizado = await versaoDesatualizada();
386
+ if (desatualizado) {
387
+ console.log(`CLI: ${desatualizado.atual} → ${desatualizado.ultima}...`);
388
+ const ok = await atualizaCli(desatualizado.ultima);
389
+ console.log(ok
390
+ ? `CLI atualizado. Este processo segue na ${desatualizado.atual}; do próximo comando em diante, a nova.`
391
+ : "Não consegui atualizar o CLI — o npm explicou o motivo acima.");
392
+ }
393
+ else {
394
+ console.log("CLI já está na versão mais recente.");
395
+ }
396
+ console.log("\nMCP:");
397
+ const mcp = await instalaMcp();
398
+ console.log(mcp.ok ? "MCP atualizado." : `AVISO: não consegui instalar o MCP (${mcp.erro ?? "sem detalhe"}).`);
399
+ }
400
+ // Tanto "integrar" quanto "atualizar" terminam aqui: depois de instalar uma versao nova
401
+ // do MCP, o caminho declarado nos arquivos dos hosts aponta para a instalacao antiga ate
402
+ // alguem regravar. Atualizar sem isto deixaria o projeto rodando o servidor velho.
403
+ for (const aviso of await instalaHosts(process.cwd(), hosts))
404
+ console.log("AVISO: " + aviso);
405
+ console.log("Integrações regravadas: " + hosts.join(", "));
406
+ }
350
407
  /**
351
408
  * `dd-harness start` — o wizard para pasta vazia.
352
409
  *
@@ -367,16 +424,13 @@ async function comandoStart(argv) {
367
424
  // aceitando a lista explicita para quem quiser menos.
368
425
  const hosts = selecionaHosts(argumento(argv, "host") ?? "todos");
369
426
  const caminhoConfig = join(process.cwd(), CAMINHO_CONFIG);
370
- try {
371
- await access(caminhoConfig);
372
- throw new Error(`este repositório já tem ${CAMINHO_CONFIG} — start é só para pasta vazia. ` +
373
- "Use `dd-harness init` para ajustar um projeto já existente.");
374
- }
375
- catch (erro) {
376
- if (erro instanceof Error && erro.message.includes("já tem"))
377
- throw erro;
378
- // ENOENT: exatamente o caso esperado, segue.
379
- }
427
+ // Com config no repositorio, `start` EDITA em vez de recusar. Antes ele mandava usar
428
+ // `init`, o que exigia saber de cor qual dos quatro comandos serve para que — e o
429
+ // `start` existe justamente para nao exigir isso. O que se edita e so o que e editavel:
430
+ // um repositorio E um projeto, entao tenant/projeto nao entram no menu.
431
+ const jaConfigurado = await access(caminhoConfig).then(() => true, () => false);
432
+ if (jaConfigurado)
433
+ return editaProjeto(hosts);
380
434
  console.log("Iniciando o dd-harness nesta pasta.\n");
381
435
  // 0. Versao. `start` e o comando de bootstrap: rodar velho aqui significa perder
382
436
  // correcoes deste proprio wizard sem nenhum aviso (foi o que aconteceu com a
@@ -392,27 +446,21 @@ async function comandoStart(argv) {
392
446
  `${desatualizado.atual}, e a mais recente é ${desatualizado.ultima}: rode ` +
393
447
  "`npm install -g dd-harness@latest` quando puder. O start continua assim mesmo.\n");
394
448
  }
395
- // 1. Credencial. Sem ela nada do resto e possivel — nem listar tenant.
396
- // O estado aparece SEMPRE, mesmo quando ja existe credencial: antes o passo era
397
- // pulado em silencio, e quem rodava `start` com um token velho (ou de outra conta)
398
- // nao tinha como perceber — o wizard so falhava depois, ao listar espacos.
399
- let token = await leToken(API_PADRAO);
400
- if (token) {
401
- console.log(`Credencial: ${mascara(token)} (${API_PADRAO})`);
402
- const troca = await pergunta("Usar esta credencial? [S/n]: ");
403
- if (/^n/i.test(troca))
404
- token = null;
405
- }
406
- if (!token) {
407
- const url = `${API_PADRAO}/tokens`;
408
- console.log(`\nCrie um token pessoal em ${url} — abrindo no navegador...`);
409
- tentaAbrirNavegador(url);
410
- token = await pergunta("Cole o token aqui: ");
411
- if (!token)
412
- throw new Error("sem token não dá para seguir: `start` fala com o serviço em todos os passos.");
413
- await guardaToken(API_PADRAO, token);
414
- console.log("Credencial guardada.");
415
- }
449
+ // 1. Credencial. SEMPRE digitada, mesmo havendo uma guardada nesta maquina.
450
+ //
451
+ // Oferecer a credencial salva como opcao de menu transformava o segredo num clique:
452
+ // quem tivesse acesso ao terminal comecava a operar como o dono da conta sem nunca
453
+ // provar posse do token. Guardar para os comandos seguintes e outra coisa — ali a
454
+ // pessoa ja demonstrou que o tem. O `start` e a porta, e a porta pede a chave.
455
+ const url = `${API_PADRAO}/tokens`;
456
+ console.log(`Cole o seu token de ${API_PADRAO}.`);
457
+ console.log(`Crie um em ${url} — abrindo no navegador...`);
458
+ tentaAbrirNavegador(url);
459
+ const token = await pergunta("Token: ");
460
+ if (!token)
461
+ throw new Error("sem token não dá para seguir: `start` fala com o serviço em todos os passos.");
462
+ await guardaToken(API_PADRAO, token);
463
+ console.log("Credencial guardada.");
416
464
  console.log("");
417
465
  // 2. Espaco (tenant). Criar um e ato de dono — nunca por aqui — mas ESCOLHER entre
418
466
  // os que ja existem e so leitura, e e o que faltava para nao exigir o slug de memoria.
@@ -479,13 +527,16 @@ async function comandoStart(argv) {
479
527
  // 4. Config do repositorio — o unico arquivo que `init` tambem escreveria.
480
528
  const r = await init(process.cwd(), { tenant, projeto: resultadoProjeto.projeto, api: API_PADRAO });
481
529
  console.log(r.config === "criada" ? `criado ${CAMINHO_CONFIG}` : `mantido ${CAMINHO_CONFIG}`);
530
+ // O MCP vem ANTES das integracoes: `instalaHosts` declara `node <caminho do pacote>`, e
531
+ // o caminho so existe depois da instalacao. Na ordem inversa a primeira execucao caia no
532
+ // fallback `npx`, que nao sobe no Windows — e so um segundo `integrar` consertava.
533
+ const instalacao = await instalaMcp();
534
+ if (!instalacao.ok)
535
+ console.log('AVISO: MCP não pré-instalado; execute diagnostico antes de usar.');
482
536
  const avisos = await instalaHosts(process.cwd(), hosts);
483
537
  console.log('Integrações instaladas: ' + hosts.join(', '));
484
538
  for (const aviso of avisos)
485
539
  console.log('AVISO: ' + aviso);
486
- const instalacao = await instalaMcp();
487
- if (!instalacao.ok)
488
- console.log('AVISO: MCP não pré-instalado; execute diagnostico antes de usar.');
489
540
  // 6.5. Os ponteiros das skills do projeto.
490
541
  //
491
542
  // O Claude Code descobre skill lendo `.claude/skills/*/SKILL.md` na ABERTURA da sessao,
@@ -653,7 +704,7 @@ async function comandoApagar(argv) {
653
704
  if (!r.apagou) {
654
705
  console.log(r.detalhe);
655
706
  if (r.confirmacaoEsperada) {
656
- console.log(`
707
+ console.log(`
657
708
  dd-harness apagar ${endereco} --confirmar ${r.confirmacaoEsperada}`);
658
709
  }
659
710
  // Sem exit diferente de zero: recusar por falta de confirmacao nao e falha, e o
package/dist/init.js CHANGED
@@ -8,13 +8,13 @@ import { CAMINHO_CONFIG } from "./config.js";
8
8
  * onde falha silenciosa nasce — entrada errada nao da erro, a ferramenta so nao aparece.
9
9
  * Quem cola sabe o que colou.
10
10
  */
11
- export const SUGESTAO_MCP = `{
12
- "mcpServers": {
13
- "dd-harness": {
14
- "command": "npx",
15
- "args": ["-y", "dd-harness-mcp"]
16
- }
17
- }
11
+ export const SUGESTAO_MCP = `{
12
+ "mcpServers": {
13
+ "dd-harness": {
14
+ "command": "npx",
15
+ "args": ["-y", "dd-harness-mcp"]
16
+ }
17
+ }
18
18
  }`;
19
19
  /**
20
20
  * Os dois hooks do dd-harness, pelas duas razoes que nenhuma instrucao em markdown
@@ -33,31 +33,31 @@ export const SUGESTAO_MCP = `{
33
33
  *
34
34
  * Sugerido e nao escrito, pelo mesmo motivo do `.mcp.json`.
35
35
  */
36
- export const SUGESTAO_HOOK = `{
37
- "hooks": {
38
- "SessionStart": [
39
- {
40
- "hooks": [
41
- {
42
- "type": "command",
43
- "command": "dd-harness politica --hook",
44
- "statusMessage": "Carregando a política do dd-harness..."
45
- }
46
- ]
47
- }
48
- ],
49
- "PreToolUse": [
50
- {
51
- "matcher": "Edit|Write|MultiEdit",
52
- "hooks": [
53
- {
54
- "type": "command",
55
- "command": "dd-harness cinto"
56
- }
57
- ]
58
- }
59
- ]
60
- }
36
+ export const SUGESTAO_HOOK = `{
37
+ "hooks": {
38
+ "SessionStart": [
39
+ {
40
+ "hooks": [
41
+ {
42
+ "type": "command",
43
+ "command": "dd-harness politica --hook",
44
+ "statusMessage": "Carregando a política do dd-harness..."
45
+ }
46
+ ]
47
+ }
48
+ ],
49
+ "PreToolUse": [
50
+ {
51
+ "matcher": "Edit|Write|MultiEdit",
52
+ "hooks": [
53
+ {
54
+ "type": "command",
55
+ "command": "dd-harness cinto"
56
+ }
57
+ ]
58
+ }
59
+ ]
60
+ }
61
61
  }`;
62
62
  /**
63
63
  * O que escrever num `AGENTS.md`, para agente que NAO e o Claude Code.
@@ -71,19 +71,19 @@ export const SUGESTAO_HOOK = `{
71
71
  * simplesmente nunca perguntar pela politica. Dai esta linha, que e curta de proposito —
72
72
  * ela manda buscar a regra, nao repete a regra.
73
73
  */
74
- export const SUGESTAO_AGENTS = `# AGENTS.md
75
-
76
- Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
77
-
78
- **ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
79
- \`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
80
- de ler código, responder ou planejar.
81
-
82
- - Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
83
- avise o usuário e **não modifique nada** até ele resolver.
84
- - Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
85
-
86
- O Claude Code carrega a política sozinho, por hook. Nas outras ferramentas, a
74
+ export const SUGESTAO_AGENTS = `# AGENTS.md
75
+
76
+ Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
77
+
78
+ **ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
79
+ \`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
80
+ de ler código, responder ou planejar.
81
+
82
+ - Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
83
+ avise o usuário e **não modifique nada** até ele resolver.
84
+ - Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
85
+
86
+ O Claude Code carrega a política sozinho, por hook. Nas outras ferramentas, a
87
87
  chamada acima é o que substitui esse hook.`;
88
88
  async function declaraMcp(raiz) {
89
89
  try {
@@ -28,14 +28,9 @@ function secaoDeFiltros(m) {
28
28
  ].join("\n");
29
29
  }
30
30
  export function arquivoDaMemoria(m) {
31
- // `titulo` vai no frontmatter porque `gravar` e `editar` o exigem la: sem ele o arquivo
32
- // materializado nao volta pelo `editar`, e o ciclo "sincroniza, corrige, manda de volta"
33
- // — que e como o agente cura memoria — para com "frontmatter sem `titulo`". O titulo
34
- // tambem aparece no indice, mas indice nao e o que se edita.
35
31
  const frontmatter = [
36
32
  "---",
37
33
  `name: ${m.slug}`,
38
- `titulo: ${m.titulo.replace(/\n/g, " ")}`,
39
34
  `description: ${m.resumo.replace(/\n/g, " ")}`,
40
35
  `pasta: ${m.pasta}`,
41
36
  ...(m.revisar_ate ? [`revisar-ate: ${m.revisar_ate.slice(0, 10)}`] : []),