dd-harness 0.32.1 → 0.33.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/dist/atualizar.d.ts +31 -0
- package/dist/atualizar.js +103 -0
- package/dist/bloco.d.ts +54 -0
- package/dist/bloco.js +100 -0
- package/dist/escreve-config.d.ts +20 -2
- package/dist/escreve-config.js +55 -27
- package/dist/index.js +121 -72
- package/dist/moldes-historicos.d.ts +11 -0
- package/dist/moldes-historicos.js +90 -0
- package/dist/skills-iniciais.d.ts +5 -2
- package/dist/skills-iniciais.js +117 -0
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O diagnostico de defasagem de um projeto que consome o dd-harness.
|
|
3
|
+
*
|
|
4
|
+
* Existe porque a atualizacao nao era automatica em lugar nenhum: o CLI e pacote global
|
|
5
|
+
* que fica na versao do dia da instalacao, e o bloco nos pontos de entrada era detectado
|
|
6
|
+
* de forma binaria — tem ou nao tem —, o que nunca responde "esta na versao atual?".
|
|
7
|
+
* Projeto em producao ficava para tras sem nada avisar.
|
|
8
|
+
*
|
|
9
|
+
* Aqui so DIAGNOSTICA. Aplicar e decisao de quem chama, porque parte do que sai daqui
|
|
10
|
+
* exige julgamento humano (bloco editado a mao) e parte nao (hook faltando).
|
|
11
|
+
*/
|
|
12
|
+
export type Item = {
|
|
13
|
+
o_que: string;
|
|
14
|
+
situacao: string;
|
|
15
|
+
acao: "aplicar" | "perguntar" | "em-dia" | "manual";
|
|
16
|
+
detalhe?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* `aplicar` e o que esta funcao pode fazer sozinha com seguranca; `perguntar` exige o dono
|
|
20
|
+
* do arquivo; `manual` e o que nao se resolve de dentro do repositorio (o CLI global e por
|
|
21
|
+
* maquina, nao por projeto).
|
|
22
|
+
*/
|
|
23
|
+
export declare function diagnosticaAtualizacao(raiz: string, versaoInstalada: string, versaoPublicada: string | null): Promise<Item[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Aplica so os itens marcados `aplicar`. Os de `perguntar` ficam intactos de proposito —
|
|
26
|
+
* quem decide sobre arquivo editado a mao e o dono dele.
|
|
27
|
+
*/
|
|
28
|
+
export declare function aplicaAtualizacao(raiz: string, itens: Item[]): Promise<string[]>;
|
|
29
|
+
/** A versao publicada no npm. Nunca lanca: diagnostico sem rede ainda vale para o resto. */
|
|
30
|
+
export declare function versaoPublicada(signal?: AbortSignal): Promise<string | null>;
|
|
31
|
+
export declare function versaoInstalada(url: string): Promise<string>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { analisa } from "./bloco.js";
|
|
4
|
+
import { MOLDES_HISTORICOS } from "./moldes-historicos.js";
|
|
5
|
+
import { COMANDO_DO_CINTO, COMANDO_DO_HOOK, SUGESTAO_AGENTS, VERSAO_DO_MOLDE, escreveHook, escrevePonteiro } from "./escreve-config.js";
|
|
6
|
+
import { versaoDoPacote } from "./versao.js";
|
|
7
|
+
/**
|
|
8
|
+
* `aplicar` e o que esta funcao pode fazer sozinha com seguranca; `perguntar` exige o dono
|
|
9
|
+
* do arquivo; `manual` e o que nao se resolve de dentro do repositorio (o CLI global e por
|
|
10
|
+
* maquina, nao por projeto).
|
|
11
|
+
*/
|
|
12
|
+
export async function diagnosticaAtualizacao(raiz, versaoInstalada, versaoPublicada) {
|
|
13
|
+
const itens = [];
|
|
14
|
+
// 1. O CLI global — por maquina, nao por projeto. Rodar em dez pastas nao muda nada.
|
|
15
|
+
if (versaoPublicada && versaoPublicada !== versaoInstalada) {
|
|
16
|
+
itens.push({
|
|
17
|
+
o_que: "CLI",
|
|
18
|
+
situacao: `instalado ${versaoInstalada}, publicado ${versaoPublicada}`,
|
|
19
|
+
acao: "manual",
|
|
20
|
+
detalhe: "npm i -g dd-harness@latest (por máquina, não por projeto)",
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
itens.push({ o_que: "CLI", situacao: `${versaoInstalada}`, acao: "em-dia" });
|
|
25
|
+
}
|
|
26
|
+
// 2. Os dois pontos de entrada. Espelhos: o mesmo bloco, a mesma versao.
|
|
27
|
+
for (const arquivo of ["CLAUDE.md", "AGENTS.md"]) {
|
|
28
|
+
const cru = await readFile(join(raiz, arquivo), "utf8").catch(() => null);
|
|
29
|
+
if (cru === null) {
|
|
30
|
+
itens.push({ o_que: arquivo, situacao: "ausente", acao: "aplicar", detalhe: "será criado" });
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const a = analisa(cru, [SUGESTAO_AGENTS, ...MOLDES_HISTORICOS]);
|
|
34
|
+
if (a.caso === "ambiguo") {
|
|
35
|
+
itens.push({ o_que: arquivo, situacao: "precisa de decisão", acao: "perguntar", detalhe: a.motivo });
|
|
36
|
+
}
|
|
37
|
+
else if (a.caso === "ausente") {
|
|
38
|
+
itens.push({ o_que: arquivo, situacao: "sem o bloco do harness", acao: "aplicar", detalhe: "entra no fim do arquivo" });
|
|
39
|
+
}
|
|
40
|
+
else if (a.caso === "migravel") {
|
|
41
|
+
itens.push({ o_que: arquivo, situacao: "bloco sem carimbo (instalado antes das marcas)", acao: "aplicar",
|
|
42
|
+
detalhe: `será marcado e carimbado ${VERSAO_DO_MOLDE}` });
|
|
43
|
+
}
|
|
44
|
+
else if (a.versao !== VERSAO_DO_MOLDE) {
|
|
45
|
+
itens.push({ o_que: arquivo, situacao: `bloco em ${a.versao}, atual ${VERSAO_DO_MOLDE}`, acao: "aplicar",
|
|
46
|
+
detalhe: "troca só o miolo do bloco; o resto do arquivo não é tocado" });
|
|
47
|
+
}
|
|
48
|
+
else if (a.corpo !== SUGESTAO_AGENTS.trim()) {
|
|
49
|
+
// Mesma versao, texto diferente: alguem editou dentro do bloco.
|
|
50
|
+
itens.push({ o_que: arquivo, situacao: `carimbado ${a.versao}, mas o texto foi editado`, acao: "perguntar",
|
|
51
|
+
detalhe: "o conteúdo dentro do bloco não é o do molde" });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
itens.push({ o_que: arquivo, situacao: `${a.versao}`, acao: "em-dia" });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 3. Hooks. `escreveHook` ja e idempotente e nao toca em hook alheio.
|
|
58
|
+
// Pelas constantes, nao por string repetida: o hook do cinto so entrou numa versao
|
|
59
|
+
// posterior, e um projeto antigo tem o SessionStart sem ele — que e o caso mais comum
|
|
60
|
+
// de defasagem, e o que mais custa, porque o cinto e o que avisa antes da edicao.
|
|
61
|
+
const settings = await readFile(join(raiz, ".claude/settings.json"), "utf8").catch(() => "");
|
|
62
|
+
const temOsDois = settings.includes(COMANDO_DO_HOOK) && settings.includes(COMANDO_DO_CINTO);
|
|
63
|
+
itens.push(temOsDois
|
|
64
|
+
? { o_que: "hooks", situacao: "sessão e cinto declarados", acao: "em-dia" }
|
|
65
|
+
: { o_que: "hooks", situacao: settings ? "incompletos ou legados" : "ausentes", acao: "aplicar",
|
|
66
|
+
detalhe: "acrescenta sem duplicar nem tocar em hook de terceiro" });
|
|
67
|
+
return itens;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Aplica so os itens marcados `aplicar`. Os de `perguntar` ficam intactos de proposito —
|
|
71
|
+
* quem decide sobre arquivo editado a mao e o dono dele.
|
|
72
|
+
*/
|
|
73
|
+
export async function aplicaAtualizacao(raiz, itens) {
|
|
74
|
+
const feitos = [];
|
|
75
|
+
for (const item of itens.filter(i => i.acao === "aplicar")) {
|
|
76
|
+
if (item.o_que === "CLAUDE.md" || item.o_que === "AGENTS.md") {
|
|
77
|
+
const r = await escrevePonteiro(raiz, item.o_que);
|
|
78
|
+
feitos.push(`${item.o_que}: ${r.estado}${r.de ? ` (de ${r.de} para ${VERSAO_DO_MOLDE})` : ""}`);
|
|
79
|
+
}
|
|
80
|
+
else if (item.o_que === "hooks") {
|
|
81
|
+
const r = await escreveHook(raiz);
|
|
82
|
+
// `ok: false` e settings.json invalido — nao foi escrito, e dizer "ok" aqui esconderia
|
|
83
|
+
// um projeto que continua sem o cinto.
|
|
84
|
+
feitos.push(r.ok ? `hooks: ${r.estado}` : `hooks: NÃO aplicado (${r.motivo})`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return feitos;
|
|
88
|
+
}
|
|
89
|
+
/** A versao publicada no npm. Nunca lanca: diagnostico sem rede ainda vale para o resto. */
|
|
90
|
+
export async function versaoPublicada(signal) {
|
|
91
|
+
try {
|
|
92
|
+
const r = await fetch("https://registry.npmjs.org/dd-harness/latest", { signal });
|
|
93
|
+
if (!r.ok)
|
|
94
|
+
return null;
|
|
95
|
+
return (await r.json()).version ?? null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export async function versaoInstalada(url) {
|
|
102
|
+
return versaoDoPacote(url, "dd-harness").catch(() => "desconhecida");
|
|
103
|
+
}
|
package/dist/bloco.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O bloco do harness dentro de um CLAUDE.md/AGENTS.md que pertence ao projeto.
|
|
3
|
+
*
|
|
4
|
+
* O arquivo e do repositorio, nao nosso — a decisao esta no Brain
|
|
5
|
+
* (`import-do-claude-md-falha-calado`): a parte gerenciada CONVIVE com o que o projeto
|
|
6
|
+
* tem de proprio, em vez de sobrescrever o arquivo de alguem. O que este modulo
|
|
7
|
+
* acrescenta e a fronteira explicita dessa convivencia: marcas de inicio e fim, com a
|
|
8
|
+
* versao carimbada.
|
|
9
|
+
*
|
|
10
|
+
* Sem a fronteira, atualizar e adivinhacao. A deteccao anterior era binaria — o arquivo
|
|
11
|
+
* contem `ler_artefato`, sim ou nao —, o que responde "ja foi instalado?" e nunca "esta
|
|
12
|
+
* na versao atual?". Foi assim que um projeto em producao ficou para tras: tinha o bloco,
|
|
13
|
+
* entao o init disse "ja-tinha" e nao tocou em nada, enquanto o texto do molde mudava.
|
|
14
|
+
*
|
|
15
|
+
* Com a fronteira, trocar o miolo e seguro por CONSTRUCAO: o que esta fora das marcas
|
|
16
|
+
* nunca e lido para decidir, muito menos reescrito. A regra do dono do projeto — "o
|
|
17
|
+
* CLAUDE.md e diferente para cada um; edite so a linha que e nossa" — deixa de depender
|
|
18
|
+
* da atencao de quem roda a atualizacao.
|
|
19
|
+
*/
|
|
20
|
+
export type Analise = {
|
|
21
|
+
caso: "ausente";
|
|
22
|
+
} | {
|
|
23
|
+
caso: "marcado";
|
|
24
|
+
versao: string;
|
|
25
|
+
corpo: string;
|
|
26
|
+
antes: string;
|
|
27
|
+
depois: string;
|
|
28
|
+
} | {
|
|
29
|
+
caso: "migravel";
|
|
30
|
+
corpo: string;
|
|
31
|
+
antes: string;
|
|
32
|
+
depois: string;
|
|
33
|
+
} | {
|
|
34
|
+
caso: "ambiguo";
|
|
35
|
+
motivo: string;
|
|
36
|
+
};
|
|
37
|
+
/** `<!-- dd-harness:inicio v1.3.0 -->` — a versao e o que responde "atualizado ate onde?". */
|
|
38
|
+
export declare function marcaDeInicio(versao: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Le o arquivo e diz em que caso ele esta. Nao decide nada e nao escreve: quem chama e
|
|
41
|
+
* que sabe se pode aplicar sozinho ou se precisa perguntar.
|
|
42
|
+
*
|
|
43
|
+
* `textoConhecido` e o molde de uma versao anterior, usado so para reconhecer um bloco
|
|
44
|
+
* que ainda nao tem marca — o caso de todo projeto instalado antes desta mudanca.
|
|
45
|
+
*/
|
|
46
|
+
export declare function analisa(arquivo: string, textoConhecido: string | string[]): Analise;
|
|
47
|
+
/** Monta o bloco com as marcas. Uma linha em branco de cada lado: markdown gruda. */
|
|
48
|
+
export declare function envolve(corpo: string, versao: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Devolve o arquivo com o bloco na versao nova, preservando tudo que esta fora dele.
|
|
51
|
+
*
|
|
52
|
+
* Nao decide se DEVE atualizar — so produz o texto. Caso ambiguo nem chega aqui.
|
|
53
|
+
*/
|
|
54
|
+
export declare function aplica(arquivo: string, corpo: string, versao: string, analise: Analise): string;
|
package/dist/bloco.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O bloco do harness dentro de um CLAUDE.md/AGENTS.md que pertence ao projeto.
|
|
3
|
+
*
|
|
4
|
+
* O arquivo e do repositorio, nao nosso — a decisao esta no Brain
|
|
5
|
+
* (`import-do-claude-md-falha-calado`): a parte gerenciada CONVIVE com o que o projeto
|
|
6
|
+
* tem de proprio, em vez de sobrescrever o arquivo de alguem. O que este modulo
|
|
7
|
+
* acrescenta e a fronteira explicita dessa convivencia: marcas de inicio e fim, com a
|
|
8
|
+
* versao carimbada.
|
|
9
|
+
*
|
|
10
|
+
* Sem a fronteira, atualizar e adivinhacao. A deteccao anterior era binaria — o arquivo
|
|
11
|
+
* contem `ler_artefato`, sim ou nao —, o que responde "ja foi instalado?" e nunca "esta
|
|
12
|
+
* na versao atual?". Foi assim que um projeto em producao ficou para tras: tinha o bloco,
|
|
13
|
+
* entao o init disse "ja-tinha" e nao tocou em nada, enquanto o texto do molde mudava.
|
|
14
|
+
*
|
|
15
|
+
* Com a fronteira, trocar o miolo e seguro por CONSTRUCAO: o que esta fora das marcas
|
|
16
|
+
* nunca e lido para decidir, muito menos reescrito. A regra do dono do projeto — "o
|
|
17
|
+
* CLAUDE.md e diferente para cada um; edite so a linha que e nossa" — deixa de depender
|
|
18
|
+
* da atencao de quem roda a atualizacao.
|
|
19
|
+
*/
|
|
20
|
+
/** Comentario HTML: invisivel no render, e o modelo que le o arquivo cru ignora sem ruido. */
|
|
21
|
+
const INICIO = "<!-- dd-harness:inicio";
|
|
22
|
+
const FIM = "<!-- dd-harness:fim -->";
|
|
23
|
+
/** `<!-- dd-harness:inicio v1.3.0 -->` — a versao e o que responde "atualizado ate onde?". */
|
|
24
|
+
export function marcaDeInicio(versao) {
|
|
25
|
+
return `${INICIO} ${versao} -->`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Le o arquivo e diz em que caso ele esta. Nao decide nada e nao escreve: quem chama e
|
|
29
|
+
* que sabe se pode aplicar sozinho ou se precisa perguntar.
|
|
30
|
+
*
|
|
31
|
+
* `textoConhecido` e o molde de uma versao anterior, usado so para reconhecer um bloco
|
|
32
|
+
* que ainda nao tem marca — o caso de todo projeto instalado antes desta mudanca.
|
|
33
|
+
*/
|
|
34
|
+
export function analisa(arquivo, textoConhecido) {
|
|
35
|
+
const conhecidos = (Array.isArray(textoConhecido) ? textoConhecido : [textoConhecido])
|
|
36
|
+
.map(t => t.trim()).filter(Boolean);
|
|
37
|
+
const i = arquivo.indexOf(INICIO);
|
|
38
|
+
if (i !== -1) {
|
|
39
|
+
const fimDaMarca = arquivo.indexOf("-->", i);
|
|
40
|
+
const f = arquivo.indexOf(FIM, i);
|
|
41
|
+
// Marca de inicio sem fim e arquivo truncado ou editado a mao. Mexer nele as cegas
|
|
42
|
+
// apagaria conteudo do projeto — exatamente o que este modulo existe para impedir.
|
|
43
|
+
if (fimDaMarca === -1 || f === -1) {
|
|
44
|
+
return { caso: "ambiguo", motivo: "marca de início sem marca de fim correspondente" };
|
|
45
|
+
}
|
|
46
|
+
if (arquivo.indexOf(INICIO, i + 1) !== -1) {
|
|
47
|
+
return { caso: "ambiguo", motivo: "mais de um bloco do dd-harness no arquivo" };
|
|
48
|
+
}
|
|
49
|
+
const versao = arquivo.slice(i + INICIO.length, fimDaMarca).trim();
|
|
50
|
+
return {
|
|
51
|
+
caso: "marcado",
|
|
52
|
+
versao,
|
|
53
|
+
corpo: arquivo.slice(fimDaMarca + 3, f).trim(),
|
|
54
|
+
antes: arquivo.slice(0, i),
|
|
55
|
+
depois: arquivo.slice(f + FIM.length),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Sem marca: procura o bloco pelo texto EXATO de alguma versao que ja existiu. Exato de
|
|
59
|
+
// proposito — encontrar "parecido" e o comeco de reescrever o que o dono escreveu.
|
|
60
|
+
//
|
|
61
|
+
// Varias versoes porque um projeto instalado ha meses tem o molde daquela epoca, e sem
|
|
62
|
+
// reconhece-lo ele cairia em "editado a mao": o caminho seguro, mas errado, porque
|
|
63
|
+
// ninguem editou nada. Projeto atrasado e o caso COMUM, e ele tem que se resolver sozinho.
|
|
64
|
+
for (const conhecido of conhecidos) {
|
|
65
|
+
const j = arquivo.indexOf(conhecido);
|
|
66
|
+
if (j !== -1) {
|
|
67
|
+
return {
|
|
68
|
+
caso: "migravel",
|
|
69
|
+
corpo: conhecido,
|
|
70
|
+
antes: arquivo.slice(0, j),
|
|
71
|
+
depois: arquivo.slice(j + conhecido.length),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Tem nosso protocolo, mas nao como o molde o escreveu: foi editado. Caso de perguntar,
|
|
76
|
+
// nunca de sobrescrever.
|
|
77
|
+
if (arquivo.includes("ler_artefato")) {
|
|
78
|
+
return { caso: "ambiguo", motivo: "o bloco existe mas foi editado; não bate com nenhum molde conhecido" };
|
|
79
|
+
}
|
|
80
|
+
return { caso: "ausente" };
|
|
81
|
+
}
|
|
82
|
+
/** Monta o bloco com as marcas. Uma linha em branco de cada lado: markdown gruda. */
|
|
83
|
+
export function envolve(corpo, versao) {
|
|
84
|
+
return `${marcaDeInicio(versao)}\n\n${corpo.trim()}\n\n${FIM}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Devolve o arquivo com o bloco na versao nova, preservando tudo que esta fora dele.
|
|
88
|
+
*
|
|
89
|
+
* Nao decide se DEVE atualizar — so produz o texto. Caso ambiguo nem chega aqui.
|
|
90
|
+
*/
|
|
91
|
+
export function aplica(arquivo, corpo, versao, analise) {
|
|
92
|
+
const bloco = envolve(corpo, versao);
|
|
93
|
+
if (analise.caso === "marcado" || analise.caso === "migravel") {
|
|
94
|
+
return `${analise.antes}${bloco}${analise.depois}`;
|
|
95
|
+
}
|
|
96
|
+
// Ausente: entra no fim, que e onde o molde sempre acrescentou.
|
|
97
|
+
if (arquivo.trim() === "")
|
|
98
|
+
return `${bloco}\n`;
|
|
99
|
+
return `${arquivo}${arquivo.endsWith("\n") ? "\n" : "\n\n"}${bloco}\n`;
|
|
100
|
+
}
|
package/dist/escreve-config.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export type ResultadoDaEscrita<T extends string> = {
|
|
|
19
19
|
motivo: "json-invalido";
|
|
20
20
|
caminho: string;
|
|
21
21
|
};
|
|
22
|
+
export declare const COMANDO_DO_HOOK = "dd-harness politica --hook";
|
|
23
|
+
export declare const COMANDO_DO_CINTO = "dd-harness cinto";
|
|
22
24
|
/**
|
|
23
25
|
* Acrescenta o hook do dd-harness a `.claude/settings.json`, sem tocar em outros hooks.
|
|
24
26
|
*
|
|
@@ -44,10 +46,26 @@ export declare function escreveMcp(raiz: string): Promise<ResultadoDaEscrita<"cr
|
|
|
44
46
|
* de objeto.
|
|
45
47
|
*/
|
|
46
48
|
export declare function escrevePonteiro(raiz: string, arquivo: "AGENTS.md" | "CLAUDE.md"): Promise<{
|
|
47
|
-
estado: "criado" | "ja-tinha" | "acrescentado";
|
|
49
|
+
estado: "criado" | "ja-tinha" | "acrescentado" | "atualizado" | "migrado" | "precisa-decisao";
|
|
50
|
+
de?: string;
|
|
51
|
+
motivo?: string;
|
|
48
52
|
}>;
|
|
49
53
|
/** Compatibilidade: `init` ainda chama pelo nome antigo. */
|
|
50
54
|
export declare const escreveAgents: (raiz: string) => Promise<{
|
|
51
|
-
estado: "criado" | "ja-tinha" | "acrescentado";
|
|
55
|
+
estado: "criado" | "ja-tinha" | "acrescentado" | "atualizado" | "migrado" | "precisa-decisao";
|
|
56
|
+
de?: string;
|
|
57
|
+
motivo?: string;
|
|
52
58
|
}>;
|
|
59
|
+
/**
|
|
60
|
+
* A versao do MOLDE, que nao e a do CLI.
|
|
61
|
+
*
|
|
62
|
+
* O CLI publica por correcao — 0.32.1 saiu de um fix que nao mudou uma linha do texto
|
|
63
|
+
* abaixo. Carimbar a versao do pacote faria todo projeto parecer desatualizado a cada
|
|
64
|
+
* publicacao, e "desatualizado" que aparece sem nada para fazer e o aviso que ensina a
|
|
65
|
+
* ignorar aviso.
|
|
66
|
+
*
|
|
67
|
+
* Suba este numero SO quando o texto do bloco mudar de fato. E o carimbo que um projeto
|
|
68
|
+
* em producao compara para saber se precisa de atualizacao.
|
|
69
|
+
*/
|
|
70
|
+
export declare const VERSAO_DO_MOLDE = "v1.3.0";
|
|
53
71
|
export declare const SUGESTAO_AGENTS = "## Protocolo do dd-harness\n\nEste projeto tem um protocolo de trabalho que **n\u00E3o est\u00E1 neste arquivo**.\n\n**ANTES de qualquer outra coisa**, chame a ferramenta MCP `ler_artefato` com\n`tipo: \"politica\"` e siga o que ela devolver. \u00C9 a primeira a\u00E7\u00E3o da sess\u00E3o, antes\nde ler c\u00F3digo, responder ou planejar.\n\n- Se a ferramenta n\u00E3o existir, o servidor MCP do dd-harness n\u00E3o est\u00E1 declarado:\n avise o usu\u00E1rio e **n\u00E3o modifique nada** at\u00E9 ele resolver.\n- Se ela devolver vazio, este projeto nunca foi briefado \u2014 diga isso ao usu\u00E1rio.\n\nLeia tamb\u00E9m o briefing com a mesma ferramenta (tipo briefing). Os dois s\u00E3o obrigat\u00F3rios.\n\nDepois, `ler_roadmap`: se houver uma fase **Agora**, \u00E9 dela que saem os passos\ndesta sess\u00E3o. Lista vazia significa que este projeto n\u00E3o usa roadmap, e isso \u00E9\nv\u00E1lido \u2014 n\u00E3o crie fase sem o usu\u00E1rio pedir.\n\nE `listar_skills`: s\u00E3o os procedimentos deste projeto. **Invoque a que couber\nANTES de fazer o trabalho, n\u00E3o depois** \u2014 skill lida no fim vira revis\u00E3o do que\nj\u00E1 saiu errado, e \u00E9 tarde.\n\nVale mesmo quando o pedido parece pequeno: \"\u00E9 s\u00F3 um ajuste\" \u00E9 exatamente a\nfrase que antecede pular o procedimento. A pol\u00EDtica diz quais s\u00E3o obrigat\u00F3rias\ne quando.";
|
package/dist/escreve-config.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { analisa, aplica } from "./bloco.js";
|
|
4
|
+
import { MOLDES_HISTORICOS } from "./moldes-historicos.js";
|
|
5
|
+
export const COMANDO_DO_HOOK = "dd-harness politica --hook";
|
|
6
|
+
export const COMANDO_DO_CINTO = "dd-harness cinto";
|
|
5
7
|
/**
|
|
6
8
|
* Acrescenta o hook do dd-harness a `.claude/settings.json`, sem tocar em outros hooks.
|
|
7
9
|
*
|
|
@@ -92,7 +94,6 @@ export async function escreveMcp(raiz) {
|
|
|
92
94
|
*/
|
|
93
95
|
export async function escrevePonteiro(raiz, arquivo) {
|
|
94
96
|
const caminho = join(raiz, arquivo);
|
|
95
|
-
const instrucao = SUGESTAO_AGENTS;
|
|
96
97
|
let atual = null;
|
|
97
98
|
try {
|
|
98
99
|
atual = await readFile(caminho, "utf8");
|
|
@@ -101,39 +102,66 @@ export async function escrevePonteiro(raiz, arquivo) {
|
|
|
101
102
|
// Sem arquivo: cria do zero.
|
|
102
103
|
}
|
|
103
104
|
if (atual === null) {
|
|
104
|
-
await writeFile(caminho, `${
|
|
105
|
+
await writeFile(caminho, `${aplica("", SUGESTAO_AGENTS, VERSAO_DO_MOLDE, { caso: "ausente" })}`, "utf8");
|
|
105
106
|
return { estado: "criado" };
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
+
const analise = analisa(atual, [SUGESTAO_AGENTS, ...MOLDES_HISTORICOS]);
|
|
109
|
+
// Bloco editado, truncado ou duplicado: quem decide e o dono do arquivo. Escrever aqui
|
|
110
|
+
// seria apagar o que alguem escreveu — o unico erro desta funcao que nao da para desfazer
|
|
111
|
+
// sem o git.
|
|
112
|
+
if (analise.caso === "ambiguo") {
|
|
113
|
+
return { estado: "precisa-decisao", motivo: analise.motivo };
|
|
114
|
+
}
|
|
115
|
+
// Ja esta na versao atual: nao reescreve, para o `start` nao sujar o git toda vez.
|
|
116
|
+
if (analise.caso === "marcado" && analise.versao === VERSAO_DO_MOLDE && analise.corpo === SUGESTAO_AGENTS.trim()) {
|
|
117
|
+
return { estado: "ja-tinha" };
|
|
118
|
+
}
|
|
119
|
+
const novo = aplica(atual, SUGESTAO_AGENTS, VERSAO_DO_MOLDE, analise);
|
|
120
|
+
if (novo === atual)
|
|
108
121
|
return { estado: "ja-tinha" };
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
await writeFile(caminho, novo, "utf8");
|
|
123
|
+
if (analise.caso === "marcado")
|
|
124
|
+
return { estado: "atualizado", de: analise.versao };
|
|
125
|
+
if (analise.caso === "migravel")
|
|
126
|
+
return { estado: "migrado" };
|
|
111
127
|
return { estado: "acrescentado" };
|
|
112
128
|
}
|
|
113
129
|
/** Compatibilidade: `init` ainda chama pelo nome antigo. */
|
|
114
130
|
export const escreveAgents = (raiz) => escrevePonteiro(raiz, "AGENTS.md");
|
|
131
|
+
/**
|
|
132
|
+
* A versao do MOLDE, que nao e a do CLI.
|
|
133
|
+
*
|
|
134
|
+
* O CLI publica por correcao — 0.32.1 saiu de um fix que nao mudou uma linha do texto
|
|
135
|
+
* abaixo. Carimbar a versao do pacote faria todo projeto parecer desatualizado a cada
|
|
136
|
+
* publicacao, e "desatualizado" que aparece sem nada para fazer e o aviso que ensina a
|
|
137
|
+
* ignorar aviso.
|
|
138
|
+
*
|
|
139
|
+
* Suba este numero SO quando o texto do bloco mudar de fato. E o carimbo que um projeto
|
|
140
|
+
* em producao compara para saber se precisa de atualizacao.
|
|
141
|
+
*/
|
|
142
|
+
export const VERSAO_DO_MOLDE = "v1.3.0";
|
|
115
143
|
export const SUGESTAO_AGENTS = `## Protocolo do dd-harness
|
|
116
|
-
|
|
117
|
-
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
118
|
-
|
|
119
|
-
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
120
|
-
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
121
|
-
de ler código, responder ou planejar.
|
|
122
|
-
|
|
123
|
-
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
124
|
-
avise o usuário e **não modifique nada** até ele resolver.
|
|
125
|
-
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
126
|
-
|
|
144
|
+
|
|
145
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
146
|
+
|
|
147
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
148
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
149
|
+
de ler código, responder ou planejar.
|
|
150
|
+
|
|
151
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
152
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
153
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
154
|
+
|
|
127
155
|
Leia também o briefing com a mesma ferramenta (tipo briefing). Os dois são obrigatórios.
|
|
128
156
|
|
|
129
157
|
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
130
|
-
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
131
|
-
válido — não crie fase sem o usuário pedir.
|
|
132
|
-
|
|
133
|
-
E \`listar_skills\`: são os procedimentos deste projeto. **Invoque a que couber
|
|
134
|
-
ANTES de fazer o trabalho, não depois** — skill lida no fim vira revisão do que
|
|
135
|
-
já saiu errado, e é tarde.
|
|
136
|
-
|
|
137
|
-
Vale mesmo quando o pedido parece pequeno: "é só um ajuste" é exatamente a
|
|
138
|
-
frase que antecede pular o procedimento. A política diz quais são obrigatórias
|
|
158
|
+
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
159
|
+
válido — não crie fase sem o usuário pedir.
|
|
160
|
+
|
|
161
|
+
E \`listar_skills\`: são os procedimentos deste projeto. **Invoque a que couber
|
|
162
|
+
ANTES de fazer o trabalho, não depois** — skill lida no fim vira revisão do que
|
|
163
|
+
já saiu errado, e é tarde.
|
|
164
|
+
|
|
165
|
+
Vale mesmo quando o pedido parece pequeno: "é só um ajuste" é exatamente a
|
|
166
|
+
frase que antecede pular o procedimento. A política diz quais são obrigatórias
|
|
139
167
|
e quando.`;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { diagnostico } from "./diagnostico.js";
|
|
3
|
+
import { aplicaAtualizacao, diagnosticaAtualizacao, versaoInstalada, versaoPublicada } from "./atualizar.js";
|
|
3
4
|
import { instalaHosts, selecionaHosts } from "./hosts.js";
|
|
4
5
|
import { achaRaiz } from "./config.js";
|
|
5
6
|
import { abreSessao, guardaSessao, saidaDaGuarda, saidaDoBoot } from "./sessao.js";
|
|
@@ -43,84 +44,89 @@ import { REGRA_DE_COMMITS } from "./regras-de-commit.js";
|
|
|
43
44
|
* em repositorio alheio tem que envelhecer bem, e cada dependencia e uma chance de nao
|
|
44
45
|
* envelhecer.
|
|
45
46
|
*/
|
|
46
|
-
const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
|
|
47
|
-
|
|
47
|
+
const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
|
|
48
|
+
|
|
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
|
|
49
55
|
dd-harness integrar --host todos instala MCP/regras/hooks em projeto existente
|
|
50
56
|
dd-harness sessao --host <host> hook de boot (stdin JSON)
|
|
51
57
|
dd-harness guarda --host <host> hook antes de ferramentas (stdin JSON)
|
|
52
|
-
dd-harness start [--host <host>] numa pasta vazia: conduz tudo (login,
|
|
53
|
-
espaço, projeto, config) numa tacada
|
|
54
|
-
dd-harness login --token <token> [--api <url>]
|
|
55
|
-
guarda a credencial desta máquina
|
|
56
|
-
dd-harness projeto <slug> --nome "<nome>" [--tenant <t>] [--api <url>]
|
|
57
|
-
cria o projeto no serviço (antes do init)
|
|
58
|
-
dd-harness init --tenant <t> --projeto <p> [--api <url>]
|
|
59
|
-
escreve .dd-harness.json; depois rode integrar
|
|
60
|
-
dd-harness pasta <slug> --definicao "o que entra e o que não entra"
|
|
61
|
-
cria a pasta que o gravar exige
|
|
62
|
-
dd-harness gravar <arquivo.md> registra uma memória a partir de um markdown
|
|
63
|
-
dd-harness editar <arquivo.md> corrige o que já está gravado
|
|
64
|
-
dd-harness arquivar <pasta>/<slug> --motivo <obsoleta|incorreta|fora_dos_filtros>
|
|
65
|
-
[--substituida-por <pasta>/<slug>]
|
|
66
|
-
tira de circulação sem apagar
|
|
67
|
-
dd-harness promover <pasta>/<slug>
|
|
68
|
-
torna a memória global: vale para TODO
|
|
69
|
-
projeto do espaço, inclusive os futuros
|
|
70
|
-
dd-harness despromover <pasta>/<slug>
|
|
71
|
-
traz de volta ao alcance dos vínculos
|
|
72
|
-
dd-harness apagar <pasta>/<slug> [--confirmar <espaço>]
|
|
73
|
-
apaga de vez, em cascata — sem desfazer.
|
|
74
|
-
Para tirar de circulação guardando o
|
|
75
|
-
conteúdo, use "arquivar"
|
|
76
|
-
dd-harness buscar "<pergunta>" acha memória por relevância, não por arquivo
|
|
77
|
-
dd-harness ler <pasta>/<slug> imprime a memória inteira, no formato de gravar
|
|
78
|
-
dd-harness reancorar <pasta>/<slug> --de "<alvo>" --para "<alvo>"
|
|
79
|
-
troca o alvo de uma âncora que mudou de lugar
|
|
80
|
-
dd-harness check [--commit <sha>] mede as âncoras e reporta a deriva
|
|
81
|
-
dd-harness status só lê: o tamanho do Brain e o que espera julgamento
|
|
82
|
-
dd-harness politica [--hook] imprime a política do serviço
|
|
83
|
-
saída 0 = veio; 3 = projeto sem política;
|
|
84
|
-
1 = não consegui buscar
|
|
85
|
-
--hook: fala o protocolo do SessionStart do
|
|
86
|
-
Claude Code, para pôr a política no contexto
|
|
87
|
-
dd-harness cinto o interceptador pré-voo: lê a edição no stdin
|
|
88
|
-
e devolve a memória que fala daquele trecho.
|
|
89
|
-
Quem chama é o hook PreToolUse, não você
|
|
90
|
-
dd-harness skills as skills deste projeto e quando cada uma serve
|
|
91
|
-
dd-harness skill <nome> o procedimento de uma delas (o mesmo que o
|
|
92
|
-
agente recebe ao invocá-la)
|
|
93
|
-
dd-harness roadmap as fases abertas: a atual inteira, as próximas
|
|
94
|
-
por título (opcional — projeto sem fase não tem)
|
|
95
|
-
dd-harness changelog [--versao <v>]
|
|
96
|
-
o que já foi concluído, agrupado por versão
|
|
97
|
-
dd-harness fase criar --titulo "<t>" [--conteudo <arquivo.md>] [--versao <v>]
|
|
98
|
-
[--status ideia|aberta|concluida] [--slug <s>]
|
|
99
|
-
dd-harness fase editar <slug> [--titulo "<t>"] [--conteudo <arquivo.md>]
|
|
100
|
-
[--versao <v> | --sem-versao] [--status <s>] [--ordem <n>]
|
|
101
|
-
concluir = --status concluida: a fase sai do
|
|
102
|
-
roadmap e entra no changelog, nada migra
|
|
103
|
-
dd-harness --help
|
|
104
|
-
dd-harness --version qual binário está instalado nesta máquina
|
|
105
|
-
|
|
58
|
+
dd-harness start [--host <host>] numa pasta vazia: conduz tudo (login,
|
|
59
|
+
espaço, projeto, config) numa tacada
|
|
60
|
+
dd-harness login --token <token> [--api <url>]
|
|
61
|
+
guarda a credencial desta máquina
|
|
62
|
+
dd-harness projeto <slug> --nome "<nome>" [--tenant <t>] [--api <url>]
|
|
63
|
+
cria o projeto no serviço (antes do init)
|
|
64
|
+
dd-harness init --tenant <t> --projeto <p> [--api <url>]
|
|
65
|
+
escreve .dd-harness.json; depois rode integrar
|
|
66
|
+
dd-harness pasta <slug> --definicao "o que entra e o que não entra"
|
|
67
|
+
cria a pasta que o gravar exige
|
|
68
|
+
dd-harness gravar <arquivo.md> registra uma memória a partir de um markdown
|
|
69
|
+
dd-harness editar <arquivo.md> corrige o que já está gravado
|
|
70
|
+
dd-harness arquivar <pasta>/<slug> --motivo <obsoleta|incorreta|fora_dos_filtros>
|
|
71
|
+
[--substituida-por <pasta>/<slug>]
|
|
72
|
+
tira de circulação sem apagar
|
|
73
|
+
dd-harness promover <pasta>/<slug>
|
|
74
|
+
torna a memória global: vale para TODO
|
|
75
|
+
projeto do espaço, inclusive os futuros
|
|
76
|
+
dd-harness despromover <pasta>/<slug>
|
|
77
|
+
traz de volta ao alcance dos vínculos
|
|
78
|
+
dd-harness apagar <pasta>/<slug> [--confirmar <espaço>]
|
|
79
|
+
apaga de vez, em cascata — sem desfazer.
|
|
80
|
+
Para tirar de circulação guardando o
|
|
81
|
+
conteúdo, use "arquivar"
|
|
82
|
+
dd-harness buscar "<pergunta>" acha memória por relevância, não por arquivo
|
|
83
|
+
dd-harness ler <pasta>/<slug> imprime a memória inteira, no formato de gravar
|
|
84
|
+
dd-harness reancorar <pasta>/<slug> --de "<alvo>" --para "<alvo>"
|
|
85
|
+
troca o alvo de uma âncora que mudou de lugar
|
|
86
|
+
dd-harness check [--commit <sha>] mede as âncoras e reporta a deriva
|
|
87
|
+
dd-harness status só lê: o tamanho do Brain e o que espera julgamento
|
|
88
|
+
dd-harness politica [--hook] imprime a política do serviço
|
|
89
|
+
saída 0 = veio; 3 = projeto sem política;
|
|
90
|
+
1 = não consegui buscar
|
|
91
|
+
--hook: fala o protocolo do SessionStart do
|
|
92
|
+
Claude Code, para pôr a política no contexto
|
|
93
|
+
dd-harness cinto o interceptador pré-voo: lê a edição no stdin
|
|
94
|
+
e devolve a memória que fala daquele trecho.
|
|
95
|
+
Quem chama é o hook PreToolUse, não você
|
|
96
|
+
dd-harness skills as skills deste projeto e quando cada uma serve
|
|
97
|
+
dd-harness skill <nome> o procedimento de uma delas (o mesmo que o
|
|
98
|
+
agente recebe ao invocá-la)
|
|
99
|
+
dd-harness roadmap as fases abertas: a atual inteira, as próximas
|
|
100
|
+
por título (opcional — projeto sem fase não tem)
|
|
101
|
+
dd-harness changelog [--versao <v>]
|
|
102
|
+
o que já foi concluído, agrupado por versão
|
|
103
|
+
dd-harness fase criar --titulo "<t>" [--conteudo <arquivo.md>] [--versao <v>]
|
|
104
|
+
[--status ideia|aberta|concluida] [--slug <s>]
|
|
105
|
+
dd-harness fase editar <slug> [--titulo "<t>"] [--conteudo <arquivo.md>]
|
|
106
|
+
[--versao <v> | --sem-versao] [--status <s>] [--ordem <n>]
|
|
107
|
+
concluir = --status concluida: a fase sai do
|
|
108
|
+
roadmap e entra no changelog, nada migra
|
|
109
|
+
dd-harness --help
|
|
110
|
+
dd-harness --version qual binário está instalado nesta máquina
|
|
111
|
+
|
|
106
112
|
Política e briefing chegam do serviço. O disco guarda configuração, ponteiros
|
|
107
113
|
para skills e estado descartável em ~/.dd-harness. Hosts: claude, codex,
|
|
108
|
-
antigravity, lista separada por vírgulas ou todos.
|
|
114
|
+
antigravity, lista separada por vírgulas ou todos.
|
|
109
115
|
`;
|
|
110
116
|
/**
|
|
111
117
|
* Os ganchos sao IMPRESSOS, nunca instalados. `.git/hooks` nao e versionado e nao e
|
|
112
118
|
* nosso: escrever la dentro sem a pessoa pedir e o mesmo tipo de invasao que
|
|
113
119
|
* sobrescrever o CLAUDE.md dela. Quem cola, decide.
|
|
114
120
|
*/
|
|
115
|
-
const GANCHOS = `
|
|
116
|
-
Opcional — o gancho que devolve a memória ao code review:
|
|
117
|
-
|
|
118
|
-
.git/hooks/post-commit (avisa quais memórias falam do que você mudou)
|
|
119
|
-
#!/bin/sh
|
|
120
|
-
dd-harness check --commit "$(git rev-parse HEAD)" || true
|
|
121
|
-
|
|
122
|
-
Termina em sucesso mesmo com deriva: avisa, não bloqueia.
|
|
123
|
-
|
|
121
|
+
const GANCHOS = `
|
|
122
|
+
Opcional — o gancho que devolve a memória ao code review:
|
|
123
|
+
|
|
124
|
+
.git/hooks/post-commit (avisa quais memórias falam do que você mudou)
|
|
125
|
+
#!/bin/sh
|
|
126
|
+
dd-harness check --commit "$(git rev-parse HEAD)" || true
|
|
127
|
+
|
|
128
|
+
Termina em sucesso mesmo com deriva: avisa, não bloqueia.
|
|
129
|
+
|
|
124
130
|
Instale os hooks de sessão e guarda com \`dd-harness integrar --host <host>\`.`;
|
|
125
131
|
function argumento(argv, nome) {
|
|
126
132
|
const i = argv.indexOf(`--${nome}`);
|
|
@@ -155,7 +161,7 @@ async function comandoSkill(argv) {
|
|
|
155
161
|
throw new Error("uso: dd-harness skill <nome>");
|
|
156
162
|
}
|
|
157
163
|
const s = await leSkill(process.cwd(), slug);
|
|
158
|
-
console.log(`# ${s.slug}
|
|
164
|
+
console.log(`# ${s.slug}
|
|
159
165
|
`);
|
|
160
166
|
console.log(s.descricao);
|
|
161
167
|
console.log("");
|
|
@@ -516,6 +522,40 @@ async function temWorkerConfigurado() {
|
|
|
516
522
|
const { workerRepo } = await leConfigDaMaquina();
|
|
517
523
|
return Boolean(workerRepo);
|
|
518
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Diagnostica (e opcionalmente aplica) a defasagem deste projeto.
|
|
527
|
+
*
|
|
528
|
+
* O padrao e SO RELATAR: comando que edita `CLAUDE.md` de projeto em producao nao faz isso
|
|
529
|
+
* por omissao. `--aplicar` escreve o que e seguro, e nunca o que exige decisao do dono.
|
|
530
|
+
*/
|
|
531
|
+
async function comandoAtualizar(argv) {
|
|
532
|
+
const raiz = await achaRaiz();
|
|
533
|
+
const itens = await diagnosticaAtualizacao(raiz, await versaoInstalada(import.meta.url), await versaoPublicada(AbortSignal.timeout(6000)));
|
|
534
|
+
const simbolo = { "em-dia": "ok ", aplicar: "-> ", perguntar: "?? ", manual: "! " };
|
|
535
|
+
for (const i of itens) {
|
|
536
|
+
console.log(`${simbolo[i.acao]}${i.o_que}: ${i.situacao}${i.detalhe ? ` — ${i.detalhe}` : ""}`);
|
|
537
|
+
}
|
|
538
|
+
const aAplicar = itens.filter(i => i.acao === "aplicar");
|
|
539
|
+
const aPerguntar = itens.filter(i => i.acao === "perguntar");
|
|
540
|
+
if (!argv.includes("--aplicar")) {
|
|
541
|
+
console.log(aAplicar.length
|
|
542
|
+
? `\n${aAplicar.length} item(ns) podem ser aplicados: dd-harness atualizar --aplicar`
|
|
543
|
+
: "\nNada a aplicar automaticamente.");
|
|
544
|
+
}
|
|
545
|
+
else if (aAplicar.length) {
|
|
546
|
+
console.log("");
|
|
547
|
+
for (const linha of await aplicaAtualizacao(raiz, itens))
|
|
548
|
+
console.log(linha);
|
|
549
|
+
}
|
|
550
|
+
// Estes ficam de fora do `--aplicar` de proposito: o arquivo foi editado a mao, e so o
|
|
551
|
+
// dono sabe se a edicao dele continua valendo depois da mudanca do molde.
|
|
552
|
+
if (aPerguntar.length) {
|
|
553
|
+
console.log(`\n${aPerguntar.length} item(ns) NÃO foram tocados por exigirem decisão sua:`);
|
|
554
|
+
for (const i of aPerguntar)
|
|
555
|
+
console.log(` ${i.o_que}: ${i.detalhe ?? i.situacao}`);
|
|
556
|
+
console.log(" Use a skill atualizar-harness para conduzir esses casos.");
|
|
557
|
+
}
|
|
558
|
+
}
|
|
519
559
|
async function comandoInit(argv) {
|
|
520
560
|
const tenant = argumento(argv, "tenant");
|
|
521
561
|
const projeto = argumento(argv, "projeto");
|
|
@@ -591,7 +631,7 @@ async function comandoApagar(argv) {
|
|
|
591
631
|
if (!r.apagou) {
|
|
592
632
|
console.log(r.detalhe);
|
|
593
633
|
if (r.confirmacaoEsperada) {
|
|
594
|
-
console.log(`
|
|
634
|
+
console.log(`
|
|
595
635
|
dd-harness apagar ${endereco} --confirmar ${r.confirmacaoEsperada}`);
|
|
596
636
|
}
|
|
597
637
|
// Sem exit diferente de zero: recusar por falta de confirmacao nao e falha, e o
|
|
@@ -644,7 +684,7 @@ async function comandoBuscar(argv) {
|
|
|
644
684
|
if (!r.semantica) {
|
|
645
685
|
console.log(" (só busca textual: sem provedor de embedding no serviço)");
|
|
646
686
|
}
|
|
647
|
-
avisaSobreAFila(r.esperandoIndexacao);
|
|
687
|
+
await avisaSobreAFila(r.esperandoIndexacao);
|
|
648
688
|
return;
|
|
649
689
|
}
|
|
650
690
|
console.log(r.semantica
|
|
@@ -654,19 +694,26 @@ async function comandoBuscar(argv) {
|
|
|
654
694
|
console.log(` ${a.endereco} — ${a.titulo}`);
|
|
655
695
|
console.log(` ${a.resumo}`);
|
|
656
696
|
}
|
|
657
|
-
avisaSobreAFila(r.esperandoIndexacao);
|
|
697
|
+
await avisaSobreAFila(r.esperandoIndexacao);
|
|
658
698
|
}
|
|
659
699
|
/**
|
|
660
700
|
* Memoria sem vetor nao aparece na busca semantica, e a resposta parece completa do
|
|
661
701
|
* mesmo jeito. `semantica: true` diz so que a CONSULTA foi vetorizada — a base pode
|
|
662
702
|
* estar inteira na fila, e ai a busca responde lexical com cara de semantica.
|
|
663
703
|
*/
|
|
664
|
-
function avisaSobreAFila(esperando) {
|
|
704
|
+
async function avisaSobreAFila(esperando) {
|
|
665
705
|
if (esperando <= 0)
|
|
666
706
|
return;
|
|
707
|
+
// Dispara em vez de pedir: indexar e trabalho da maquina. O comando so seria executavel
|
|
708
|
+
// dentro do monorepo do harness, e quem roda `buscar` esta no projeto dele.
|
|
709
|
+
const worker = await subiuOWorker(process.cwd(), esperando);
|
|
667
710
|
console.log("");
|
|
668
711
|
console.log(`ATENÇÃO: ${esperando} memória(s) ainda sem vetor — podem existir respostas`);
|
|
669
|
-
console.log(
|
|
712
|
+
console.log(worker.subiu
|
|
713
|
+
? " melhores que não apareceram aqui. Indexação disparada; repita a busca em instantes."
|
|
714
|
+
: worker.motivo === "sem-worker"
|
|
715
|
+
? " melhores que não apareceram aqui. Configure o worker com `dd-harness worker --configurar`."
|
|
716
|
+
: " melhores que não apareceram aqui. Não consegui disparar o worker automaticamente.");
|
|
670
717
|
}
|
|
671
718
|
async function comandoReancorar(argv) {
|
|
672
719
|
const endereco = argv[0];
|
|
@@ -1179,6 +1226,8 @@ async function principal() {
|
|
|
1179
1226
|
case "diagnostico":
|
|
1180
1227
|
console.log((await diagnostico(process.cwd(), resto.includes("--mcp"))).join("\n"));
|
|
1181
1228
|
break;
|
|
1229
|
+
case "atualizar":
|
|
1230
|
+
return comandoAtualizar(resto);
|
|
1182
1231
|
case "integrar": {
|
|
1183
1232
|
const hosts = selecionaHosts(argumento(resto, "host") ?? "todos");
|
|
1184
1233
|
for (const aviso of await instalaHosts(process.cwd(), hosts))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Os textos do molde que ja estiveram em projetos reais.
|
|
3
|
+
*
|
|
4
|
+
* GERADO por scripts/extrai-moldes-historicos.mjs a partir do historico do git. Serve a uma
|
|
5
|
+
* coisa so: reconhecer o bloco de um projeto que ficou para tras, para migra-lo sozinho em
|
|
6
|
+
* vez de perguntar. Sem isto, "projeto desatualizado" e "arquivo editado a mao" ficam
|
|
7
|
+
* indistinguiveis — e o primeiro, que e o caso comum, receberia o tratamento do segundo.
|
|
8
|
+
*
|
|
9
|
+
* Do mais novo para o mais antigo. Nao editar a mao: regenerar.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MOLDES_HISTORICOS: string[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Os textos do molde que ja estiveram em projetos reais.
|
|
3
|
+
*
|
|
4
|
+
* GERADO por scripts/extrai-moldes-historicos.mjs a partir do historico do git. Serve a uma
|
|
5
|
+
* coisa so: reconhecer o bloco de um projeto que ficou para tras, para migra-lo sozinho em
|
|
6
|
+
* vez de perguntar. Sem isto, "projeto desatualizado" e "arquivo editado a mao" ficam
|
|
7
|
+
* indistinguiveis — e o primeiro, que e o caso comum, receberia o tratamento do segundo.
|
|
8
|
+
*
|
|
9
|
+
* Do mais novo para o mais antigo. Nao editar a mao: regenerar.
|
|
10
|
+
*/
|
|
11
|
+
export const MOLDES_HISTORICOS = [
|
|
12
|
+
// ca1e529
|
|
13
|
+
`## Protocolo do dd-harness
|
|
14
|
+
|
|
15
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
16
|
+
|
|
17
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
18
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
19
|
+
de ler código, responder ou planejar.
|
|
20
|
+
|
|
21
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
22
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
23
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
24
|
+
|
|
25
|
+
Leia também o briefing com a mesma ferramenta (tipo briefing). Os dois são obrigatórios.
|
|
26
|
+
|
|
27
|
+
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
28
|
+
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
29
|
+
válido — não crie fase sem o usuário pedir.
|
|
30
|
+
|
|
31
|
+
E \`listar_skills\`: são os procedimentos deste projeto. **Invoque a que couber
|
|
32
|
+
ANTES de fazer o trabalho, não depois** — skill lida no fim vira revisão do que
|
|
33
|
+
já saiu errado, e é tarde.
|
|
34
|
+
|
|
35
|
+
Vale mesmo quando o pedido parece pequeno: "é só um ajuste" é exatamente a
|
|
36
|
+
frase que antecede pular o procedimento. A política diz quais são obrigatórias
|
|
37
|
+
e quando.`,
|
|
38
|
+
// 875342e
|
|
39
|
+
`## Protocolo do dd-harness
|
|
40
|
+
|
|
41
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
42
|
+
|
|
43
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
44
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
45
|
+
de ler código, responder ou planejar.
|
|
46
|
+
|
|
47
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
48
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
49
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
50
|
+
|
|
51
|
+
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
52
|
+
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
53
|
+
válido — não crie fase sem o usuário pedir.
|
|
54
|
+
|
|
55
|
+
E \`listar_skills\`: são os procedimentos deste projeto. **Invoque a que couber
|
|
56
|
+
ANTES de fazer o trabalho, não depois** — skill lida no fim vira revisão do que
|
|
57
|
+
já saiu errado, e é tarde.
|
|
58
|
+
|
|
59
|
+
Vale mesmo quando o pedido parece pequeno: "é só um ajuste" é exatamente a
|
|
60
|
+
frase que antecede pular o procedimento. A política diz quais são obrigatórias
|
|
61
|
+
e quando.`,
|
|
62
|
+
// f59da48
|
|
63
|
+
`## Protocolo do dd-harness
|
|
64
|
+
|
|
65
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
66
|
+
|
|
67
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
68
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
69
|
+
de ler código, responder ou planejar.
|
|
70
|
+
|
|
71
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
72
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
73
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
74
|
+
|
|
75
|
+
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
76
|
+
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
77
|
+
válido — não crie fase sem o usuário pedir.`,
|
|
78
|
+
// 5fb3f02
|
|
79
|
+
`## Protocolo do dd-harness
|
|
80
|
+
|
|
81
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
82
|
+
|
|
83
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
84
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
85
|
+
de ler código, responder ou planejar.
|
|
86
|
+
|
|
87
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
88
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
89
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.`,
|
|
90
|
+
];
|
|
@@ -11,10 +11,13 @@ import type { NovaSkillInicial } from "./skill.js";
|
|
|
11
11
|
* recebe nada: se alguem apagou uma delas, foi decisao — e recria-la a cada `start`
|
|
12
12
|
* desfaria a decisao em silencio, toda vez.
|
|
13
13
|
*
|
|
14
|
-
* GERADO a partir dos SKILL.md em .claude/skills
|
|
15
|
-
* regenere; editar este arquivo a mao faz a correcao se
|
|
14
|
+
* GERADO por scripts/gera-skills-iniciais.mjs a partir dos SKILL.md em .claude/skills
|
|
15
|
+
* deste repositorio. Corrija la e regenere; editar este arquivo a mao faz a correcao se
|
|
16
|
+
* perder na proxima geracao.
|
|
16
17
|
*/
|
|
17
18
|
export type SkillInicial = NovaSkillInicial & {
|
|
18
19
|
ferramentas?: string[];
|
|
20
|
+
so_por_comando?: boolean;
|
|
21
|
+
dica_de_argumento?: string;
|
|
19
22
|
};
|
|
20
23
|
export declare const SKILLS_INICIAIS: SkillInicial[];
|
package/dist/skills-iniciais.js
CHANGED
|
@@ -458,4 +458,121 @@ Se a decisão vier com uma razão que sobrevive ao dia de hoje — "escolhemos X
|
|
|
458
458
|
fornecedor limita Y" —, isso pode ser memória. Passe pelos três filtros antes de gravar;
|
|
459
459
|
"experimentamos e gostamos" não passa em nenhum deles.`,
|
|
460
460
|
},
|
|
461
|
+
{
|
|
462
|
+
slug: "atualizar-harness",
|
|
463
|
+
descricao: `Põe um projeto que consome o dd-harness na versão atual — CLI, hooks e o bloco do protocolo no CLAUDE.md/AGENTS.md — sem tocar no que é do projeto. Invoque quando o usuário pedir para atualizar ou alinhar um projeto ao harness atual, passando o caminho da pasta. Só por pedido explícito: escreve em OUTRO repositório.`,
|
|
464
|
+
ferramentas: ["mcp__dd-harness__ler_changelog", "Read", "Glob", "Grep", "Edit", "Bash"],
|
|
465
|
+
so_por_comando: true,
|
|
466
|
+
dica_de_argumento: "<caminho da pasta do projeto>",
|
|
467
|
+
conteudo: `# Atualizar o harness de um projeto
|
|
468
|
+
|
|
469
|
+
Põe um projeto que consome o dd-harness na versão atual: CLI, hooks, e o bloco do
|
|
470
|
+
protocolo nos pontos de entrada (\`CLAUDE.md\` e \`AGENTS.md\`).
|
|
471
|
+
|
|
472
|
+
**Entrada esperada:** o caminho da pasta do projeto. Se o usuário não passou, pergunte —
|
|
473
|
+
não presuma que é o diretório atual, porque esta skill quase sempre roda apontando para
|
|
474
|
+
OUTRO projeto.
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## 0. Antes de tudo: entenda o \`CLAUDE.md\` do alvo
|
|
479
|
+
|
|
480
|
+
**Este é o passo mais importante da skill, e o único que não dá para automatizar.** Faça-o
|
|
481
|
+
antes de rodar qualquer comando que escreva.
|
|
482
|
+
|
|
483
|
+
O \`CLAUDE.md\` **é do projeto, não do dd-harness**. Cada um escreve o seu: regras de
|
|
484
|
+
negócio, combinados da equipe, jeito de trabalhar daquele time. O harness ocupa ali um
|
|
485
|
+
bloco delimitado — e **só esse bloco é nosso**.
|
|
486
|
+
|
|
487
|
+
Leia o arquivo inteiro e responda, para você mesmo, três perguntas:
|
|
488
|
+
|
|
489
|
+
1. **O que ali é do harness?** O bloco entre \`<!-- dd-harness:inicio ... -->\` e
|
|
490
|
+
\`<!-- dd-harness:fim -->\`. Se não houver marcas, o bloco é o trecho que fala de
|
|
491
|
+
\`ler_artefato\`/\`ler_roadmap\`/\`listar_skills\` — o protocolo que o molde escreve.
|
|
492
|
+
|
|
493
|
+
2. **O que ali é do projeto?** Todo o resto. Regras próprias, seções inventadas pelo time,
|
|
494
|
+
uma linha que alguém acrescentou numa sexta-feira e não explicou. **Nada disso se toca.**
|
|
495
|
+
|
|
496
|
+
3. **Alguém escreveu dentro do bloco?** É o caso que exige você. Uma regra do projeto pode
|
|
497
|
+
ter sido acrescentada lá dentro por conveniência — e ela tem que sobreviver à
|
|
498
|
+
atualização. Perceber isso é a diferença entre atualizar e destruir.
|
|
499
|
+
|
|
500
|
+
> Já aconteceu: uma linha escrita à mão pelo dono do projeto foi tratada como texto do
|
|
501
|
+
> molde e sobrescrita. Ele teve que dizer "é pq eu botei la". O arquivo é dele; a régua é
|
|
502
|
+
> essa.
|
|
503
|
+
|
|
504
|
+
**Regra que resume tudo:** na dúvida sobre se um trecho é nosso ou do projeto, **é do
|
|
505
|
+
projeto**. Pergunte em vez de decidir.
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 1. Diagnostique
|
|
510
|
+
|
|
511
|
+
\`\`\`
|
|
512
|
+
cd <caminho-do-projeto>
|
|
513
|
+
dd-harness atualizar
|
|
514
|
+
\`\`\`
|
|
515
|
+
|
|
516
|
+
Ele relata, sem escrever nada, quatro coisas: a versão do CLI, o estado do bloco em
|
|
517
|
+
\`CLAUDE.md\` e \`AGENTS.md\`, e os hooks. Cada item vem com uma ação:
|
|
518
|
+
|
|
519
|
+
| Marca | Significa |
|
|
520
|
+
|---|---|
|
|
521
|
+
| \`ok\` | em dia, nada a fazer |
|
|
522
|
+
| \`->\` | pode ser aplicado com segurança |
|
|
523
|
+
| \`??\` | **exige decisão sua** — arquivo editado a mão |
|
|
524
|
+
| \`!\` | manual (o CLI global é por máquina, não por projeto) |
|
|
525
|
+
|
|
526
|
+
## 2. Descubra o que mudou
|
|
527
|
+
|
|
528
|
+
O bloco carimba a versão do molde (ex: \`v1.2.0\`). Compare com a atual e leia, no
|
|
529
|
+
\`CHANGELOG.md\` do dd-harness, o que mudou entre as duas. É isso que diz **o que** está
|
|
530
|
+
chegando ao projeto — e permite explicar ao usuário, em vez de só dizer "atualizei".
|
|
531
|
+
|
|
532
|
+
Se a diferença não mexe com o projeto, diga isso: atualização que não muda nada é
|
|
533
|
+
informação útil, não fracasso.
|
|
534
|
+
|
|
535
|
+
## 3. Aplique o seguro
|
|
536
|
+
|
|
537
|
+
\`\`\`
|
|
538
|
+
dd-harness atualizar --aplicar
|
|
539
|
+
\`\`\`
|
|
540
|
+
|
|
541
|
+
Isto escreve **só** os itens \`->\`: troca o miolo do bloco, acrescenta hooks que faltam,
|
|
542
|
+
cria o arquivo que não existe. O que está fora do bloco não é lido nem reescrito.
|
|
543
|
+
|
|
544
|
+
Os itens \`??\` ficam intactos de propósito — o comando não os toca.
|
|
545
|
+
|
|
546
|
+
## 4. Conduza os casos que exigem decisão
|
|
547
|
+
|
|
548
|
+
Para cada item \`??\`, faça o trabalho que o comando não pode fazer:
|
|
549
|
+
|
|
550
|
+
1. **Mostre ao usuário o que está lá** e o que o molde novo traz.
|
|
551
|
+
2. **Diga o que você acha que aconteceu** — "parece que você acrescentou esta linha
|
|
552
|
+
sobre o Slack dentro do nosso bloco".
|
|
553
|
+
3. **Proponha o encaixe**, que quase sempre é: manter a linha dele, atualizar o resto, e
|
|
554
|
+
sugerir mover a linha dele para FORA do bloco, para não conflitar de novo na próxima
|
|
555
|
+
versão. Essa sugestão é o que impede o problema de se repetir.
|
|
556
|
+
4. **Aguarde o OK.** Nunca edite um bloco \`??\` sem resposta explícita.
|
|
557
|
+
|
|
558
|
+
## 5. O CLI global
|
|
559
|
+
|
|
560
|
+
Se o diagnóstico marcou o CLI com \`!\`, o comando é:
|
|
561
|
+
|
|
562
|
+
\`\`\`
|
|
563
|
+
npm i -g dd-harness@latest
|
|
564
|
+
\`\`\`
|
|
565
|
+
|
|
566
|
+
Diga ao usuário que isso vale para **a máquina**, não para o projeto — rodar em cada pasta
|
|
567
|
+
não muda nada, e ele só precisa fazer isso uma vez.
|
|
568
|
+
|
|
569
|
+
## 6. Feche
|
|
570
|
+
|
|
571
|
+
Relate, em poucas linhas: o que foi atualizado, de que versão para qual, o que ficou
|
|
572
|
+
pendente de decisão e por quê. Se você tocou em \`CLAUDE.md\`, **diga explicitamente que o
|
|
573
|
+
que estava fora do bloco continua intacto** — é a garantia que o usuário quer ouvir.
|
|
574
|
+
|
|
575
|
+
Se o projeto tem git, sugira conferir o diff antes de commitar. Não commite: o projeto é
|
|
576
|
+
do usuário e as regras de commit dele são dele.`,
|
|
577
|
+
},
|
|
461
578
|
];
|
package/package.json
CHANGED