dd-harness 0.20.0 → 0.22.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/cinto.d.ts +15 -0
- package/dist/cinto.js +35 -0
- package/dist/gravar.js +13 -0
- package/dist/index.js +48 -5
- package/package.json +1 -1
package/dist/cinto.d.ts
CHANGED
|
@@ -30,6 +30,21 @@ export type CacheDeAncoras = {
|
|
|
30
30
|
gravado_em: string;
|
|
31
31
|
memorias: Pick<Memoria, "pasta" | "slug" | "titulo" | "resumo" | "status" | "ancoras">[];
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Acrescenta UMA memoria ao cache, sem esperar a proxima sessao.
|
|
35
|
+
*
|
|
36
|
+
* Existe por um furo medido na rodada 006: o cache so era escrito pelo `SessionStart`, e
|
|
37
|
+
* memoria gravada no meio da sessao ficava invisivel ao cinto ate a sessao seguinte —
|
|
38
|
+
* justo no fluxo mais natural, que e gravar a memoria e ser avisado minutos depois se
|
|
39
|
+
* alguem tentar desfazer o que ela protege. A memoria nascia sem proteger nada.
|
|
40
|
+
*
|
|
41
|
+
* Escreve so o que ja esta na mao de quem gravou: sem rede, porque nao ha payload novo a
|
|
42
|
+
* buscar, e uma requisicao a mais no caminho de escrita nao se justifica para atualizar
|
|
43
|
+
* um cache que a proxima sessao reconstroi inteiro de qualquer jeito.
|
|
44
|
+
*
|
|
45
|
+
* Idempotente pelo endereco: regravar a mesma memoria substitui a entrada, nunca duplica.
|
|
46
|
+
*/
|
|
47
|
+
export declare function acrescentaAoCache(raiz: string, memoria: Pick<Memoria, "pasta" | "slug" | "titulo" | "resumo" | "status" | "ancoras">): Promise<void>;
|
|
33
48
|
/** Guarda as ancoras do Brain para o hook consultar sem rede. Falha em silencio: cache e otimizacao, nao contrato. */
|
|
34
49
|
export declare function guardaCache(raiz: string, brain: Brain): Promise<void>;
|
|
35
50
|
export declare function leCache(raiz: string): Promise<CacheDeAncoras | null>;
|
package/dist/cinto.js
CHANGED
|
@@ -25,6 +25,41 @@ import { memoriasNoConteudo } from "./diff.js";
|
|
|
25
25
|
export function caminhoDoCache(raiz) {
|
|
26
26
|
return join(raiz, ".claude", "dd-harness-ancoras.json");
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Acrescenta UMA memoria ao cache, sem esperar a proxima sessao.
|
|
30
|
+
*
|
|
31
|
+
* Existe por um furo medido na rodada 006: o cache so era escrito pelo `SessionStart`, e
|
|
32
|
+
* memoria gravada no meio da sessao ficava invisivel ao cinto ate a sessao seguinte —
|
|
33
|
+
* justo no fluxo mais natural, que e gravar a memoria e ser avisado minutos depois se
|
|
34
|
+
* alguem tentar desfazer o que ela protege. A memoria nascia sem proteger nada.
|
|
35
|
+
*
|
|
36
|
+
* Escreve so o que ja esta na mao de quem gravou: sem rede, porque nao ha payload novo a
|
|
37
|
+
* buscar, e uma requisicao a mais no caminho de escrita nao se justifica para atualizar
|
|
38
|
+
* um cache que a proxima sessao reconstroi inteiro de qualquer jeito.
|
|
39
|
+
*
|
|
40
|
+
* Idempotente pelo endereco: regravar a mesma memoria substitui a entrada, nunca duplica.
|
|
41
|
+
*/
|
|
42
|
+
export async function acrescentaAoCache(raiz, memoria) {
|
|
43
|
+
if (memoria.ancoras.length === 0)
|
|
44
|
+
return;
|
|
45
|
+
const atual = (await leCache(raiz)) ?? { gravado_em: "", memorias: [] };
|
|
46
|
+
const endereco = `${memoria.pasta}/${memoria.slug}`;
|
|
47
|
+
const cache = {
|
|
48
|
+
gravado_em: new Date().toISOString(),
|
|
49
|
+
memorias: [
|
|
50
|
+
...atual.memorias.filter((m) => `${m.pasta}/${m.slug}` !== endereco),
|
|
51
|
+
memoria,
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
const caminho = caminhoDoCache(raiz);
|
|
56
|
+
await mkdir(dirname(caminho), { recursive: true });
|
|
57
|
+
await writeFile(caminho, `${JSON.stringify(cache)}\n`, "utf8");
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Mesmo motivo do `guardaCache`: cache e otimizacao, nao contrato.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
28
63
|
/** Guarda as ancoras do Brain para o hook consultar sem rede. Falha em silencio: cache e otimizacao, nao contrato. */
|
|
29
64
|
export async function guardaCache(raiz, brain) {
|
|
30
65
|
const cache = {
|
package/dist/gravar.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { recusaPorAcentuacao } from "./acentuacao.js";
|
|
3
3
|
import { cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
4
|
+
import { acrescentaAoCache } from "./cinto.js";
|
|
4
5
|
const OBRIGATORIOS = ["name", "titulo", "description", "pasta"];
|
|
5
6
|
/**
|
|
6
7
|
* Frontmatter simples: `chave: valor` por linha. Sem lib de YAML — nao ha aninhamento.
|
|
@@ -188,6 +189,18 @@ export async function grava(raiz, caminho) {
|
|
|
188
189
|
if (!resposta.ok)
|
|
189
190
|
await recusa(resposta);
|
|
190
191
|
const { endereco } = (await resposta.json());
|
|
192
|
+
// O cinto passa a enxergar esta memoria AGORA, nao na proxima sessao. Sem isto, a
|
|
193
|
+
// memoria recem-gravada nao protegia nada ate a sessao seguinte — medido na rodada 006,
|
|
194
|
+
// e justamente no fluxo mais comum: gravar a decisao e, minutos depois, alguem tentar
|
|
195
|
+
// desfazer o que ela guarda.
|
|
196
|
+
await acrescentaAoCache(raiz, {
|
|
197
|
+
pasta: memoria.pasta,
|
|
198
|
+
slug: memoria.slug,
|
|
199
|
+
titulo: memoria.titulo,
|
|
200
|
+
resumo: memoria.resumo,
|
|
201
|
+
status: "ativa",
|
|
202
|
+
ancoras: memoria.ancoras.map((valor) => ({ tipo: "caminho", valor, sha: null })),
|
|
203
|
+
});
|
|
191
204
|
return {
|
|
192
205
|
endereco,
|
|
193
206
|
ancoras: memoria.ancoras.length,
|
package/dist/index.js
CHANGED
|
@@ -180,6 +180,10 @@ async function comandoFase(argv) {
|
|
|
180
180
|
* primeira conexao do Claude Code. Sem isto, a primeira instalacao acontecia so quando
|
|
181
181
|
* o host tentava conectar ao servidor MCP, e o handshake tem timeout curto demais para
|
|
182
182
|
* esperar o download: a sessao real via `CONNECTION_CLOSED` em vez de "instalando".
|
|
183
|
+
*
|
|
184
|
+
* Roda em TODO `start`, nao so no primeiro: e tambem o ponto em que o cache do npx e
|
|
185
|
+
* renovado para a versao mais recente. Um projeto ja configurado que roda `start` de novo
|
|
186
|
+
* sai dali com CLI e MCP frescos, sem ninguem precisar lembrar de atualizar nada.
|
|
183
187
|
*/
|
|
184
188
|
function instalaMcp() {
|
|
185
189
|
return new Promise((resolve) => {
|
|
@@ -187,7 +191,14 @@ function instalaMcp() {
|
|
|
187
191
|
// segundos) e, se falhar, ve POR QUE — em vez do "nao consegui" mudo que nao dava
|
|
188
192
|
// pista nenhuma para diagnosticar. O DEP0190 que isto dispara e suprimido no topo
|
|
189
193
|
// do arquivo (`process.removeAllListeners("warning")`).
|
|
190
|
-
|
|
194
|
+
//
|
|
195
|
+
// `@latest` EXPLICITO, e nao `dd-harness-mcp` pelado: sem a tag, o npx serve a copia
|
|
196
|
+
// que ja estiver no cache dele e nem consulta o registro. Medido na rodada 006 — a
|
|
197
|
+
// cobaia rodou uma sessao inteira contra um MCP defasado sem nada denunciar. O
|
|
198
|
+
// `.mcp.json` continua declarando o pacote SEM versao, de proposito: o que precisa
|
|
199
|
+
// estar fresco e o cache, e fixar versao no arquivo obrigaria a reescrever config em
|
|
200
|
+
// todo repositorio a cada publicacao.
|
|
201
|
+
const p = spawn("npx", ["-y", "dd-harness-mcp@latest", "--help"], {
|
|
191
202
|
shell: process.platform === "win32",
|
|
192
203
|
stdio: "inherit",
|
|
193
204
|
});
|
|
@@ -221,6 +232,32 @@ async function versaoDesatualizada() {
|
|
|
221
232
|
return null;
|
|
222
233
|
}
|
|
223
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Instala a versao mais nova do CLI globalmente, de dentro do proprio wizard.
|
|
237
|
+
*
|
|
238
|
+
* Ate aqui o `start` so AVISAVA e mandava o usuario rodar `npm i -g` e recomecar — e
|
|
239
|
+
* "comece de novo" no meio de um wizard e o tipo de instrucao que ninguem segue. A
|
|
240
|
+
* rodada 006 mostrou o custo: a sessao inteira rodou contra um CLI defasado, com o
|
|
241
|
+
* relatorio registrando "ja instalado, nao atualizado" como se fosse normal.
|
|
242
|
+
*
|
|
243
|
+
* O binario EM EXECUCAO continua sendo o antigo ate este processo terminar — nao ha como
|
|
244
|
+
* trocar codigo de baixo de si mesmo. Isso e seguro aqui porque o que resta do wizard so
|
|
245
|
+
* escreve configuracao (JSON e markdown), nada que dependa de correcao nova; e do
|
|
246
|
+
* proximo comando em diante tudo ja e a versao nova.
|
|
247
|
+
*
|
|
248
|
+
* Nunca lanca: falhar em atualizar nao pode travar o `start`. Sem permissao para escrever
|
|
249
|
+
* no diretorio global (o caso mais comum), o wizard segue e o aviso continua valendo.
|
|
250
|
+
*/
|
|
251
|
+
function atualizaCli(ultima) {
|
|
252
|
+
return new Promise((resolve) => {
|
|
253
|
+
const p = spawn("npm", ["install", "-g", `dd-harness@${ultima}`], {
|
|
254
|
+
shell: process.platform === "win32",
|
|
255
|
+
stdio: "inherit",
|
|
256
|
+
});
|
|
257
|
+
p.on("exit", (code) => resolve(code === 0));
|
|
258
|
+
p.on("error", () => resolve(false));
|
|
259
|
+
});
|
|
260
|
+
}
|
|
224
261
|
/**
|
|
225
262
|
* Tenta abrir o navegador padrao. Nunca lanca — falhar em abrir nao pode travar o
|
|
226
263
|
* wizard, so degrada para "aqui esta a URL, abra voce mesmo".
|
|
@@ -271,9 +308,14 @@ async function comandoStart() {
|
|
|
271
308
|
// pre-instalacao do MCP, passo 5.5 abaixo, numa versao anterior a ela existir).
|
|
272
309
|
const desatualizado = await versaoDesatualizada();
|
|
273
310
|
if (desatualizado) {
|
|
274
|
-
console.log(`
|
|
275
|
-
|
|
276
|
-
|
|
311
|
+
console.log(`Atualizando o dd-harness: ${desatualizado.atual} → ${desatualizado.ultima}...`);
|
|
312
|
+
const atualizou = await atualizaCli(desatualizado.ultima);
|
|
313
|
+
console.log(atualizou
|
|
314
|
+
? `Pronto — ${desatualizado.ultima} instalada. O wizard segue na ${desatualizado.atual} ` +
|
|
315
|
+
"(o binário em execução não troca sozinho); do próximo comando em diante, a nova.\n"
|
|
316
|
+
: `Não consegui atualizar (sem permissão de escrita global?). Você está na ` +
|
|
317
|
+
`${desatualizado.atual} e a mais recente é ${desatualizado.ultima} — rode ` +
|
|
318
|
+
"`npm install -g dd-harness@latest` quando puder. O start segue assim mesmo.\n");
|
|
277
319
|
}
|
|
278
320
|
// 1. Credencial. Sem ela nada do resto e possivel — nem listar tenant.
|
|
279
321
|
// O estado aparece SEMPRE, mesmo quando ja existe credencial: antes o passo era
|
|
@@ -366,7 +408,8 @@ async function comandoStart() {
|
|
|
366
408
|
}[mcp.estado]);
|
|
367
409
|
}
|
|
368
410
|
if (mcp.ok) {
|
|
369
|
-
console.log("\nInstalando
|
|
411
|
+
console.log("\nInstalando a versão mais recente do servidor dd-harness-mcp " +
|
|
412
|
+
"(a primeira vez pode demorar um pouco)...");
|
|
370
413
|
const { ok: instalou, erro: erroInstalacao } = await instalaMcp();
|
|
371
414
|
console.log(instalou
|
|
372
415
|
? "dd-harness-mcp instalado — a próxima sessão do Claude Code conecta na hora."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Cliente do dd-harness: politica no inicio da sessao, e memoria por busca — nada em disco. Sem dependencia: fetch, crypto e fs sao do Node.",
|
|
6
6
|
"license": "UNLICENSED",
|