dd-harness 0.3.0 → 0.5.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/brain.d.ts +55 -0
- package/dist/brain.js +9 -0
- package/dist/buscar.d.ts +11 -4
- package/dist/buscar.js +6 -1
- package/dist/check.d.ts +7 -2
- package/dist/check.js +21 -5
- package/dist/curar.d.ts +38 -0
- package/dist/curar.js +39 -29
- package/dist/diff.d.ts +60 -3
- package/dist/diff.js +74 -16
- package/dist/index.js +217 -121
- package/dist/init.d.ts +40 -4
- package/dist/init.js +97 -43
- package/dist/politica.d.ts +7 -1
- package/dist/politica.js +3 -2
- package/dist/reancorar.d.ts +16 -0
- package/dist/reancorar.js +48 -0
- package/dist/worker.d.ts +37 -0
- package/dist/worker.js +65 -0
- package/package.json +44 -44
package/dist/init.js
CHANGED
|
@@ -1,37 +1,72 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { CAMINHO_CONFIG } from "./config.js";
|
|
4
|
-
import { LINHA_DE_IMPORT } from "./materializa.js";
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* O `.mcp.json` e sugerido, nunca escrito.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* uma linha, e nao um ritual de mover arquivo.
|
|
7
|
+
* O arquivo e do repositorio, pode ja declarar outros servidores, e mesclar JSON alheio e
|
|
8
|
+
* onde falha silenciosa nasce — entrada errada nao da erro, a ferramenta so nao aparece.
|
|
9
|
+
* Quem cola sabe o que colou.
|
|
12
10
|
*/
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
export const SUGESTAO_MCP = `{
|
|
12
|
+
"mcpServers": {
|
|
13
|
+
"dd-harness": {
|
|
14
|
+
"command": "npx",
|
|
15
|
+
"args": ["-y", "dd-harness-mcp"]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}`;
|
|
20
19
|
/**
|
|
21
|
-
* O
|
|
20
|
+
* O hook que carrega a politica no inicio de cada sessao.
|
|
21
|
+
*
|
|
22
|
+
* E a garantia de que nenhuma sessao abre sem protocolo — o papel que antes era do
|
|
23
|
+
* arquivo materializado mais a linha de import. Vive num hook, e nao numa instrucao no
|
|
24
|
+
* `CLAUDE.md`, porque instrucao o modelo pode pular: o import quebrado falhava em
|
|
25
|
+
* silencio, e isso foi medido.
|
|
22
26
|
*
|
|
23
|
-
*
|
|
24
|
-
* outros servidores, e mesclar JSON alheio e onde falha silenciosa nasce — entrada errada
|
|
25
|
-
* nao da erro, a ferramenta so nao aparece. Quem cola sabe o que colou.
|
|
27
|
+
* Sugerido e nao escrito, pelo mesmo motivo do `.mcp.json`.
|
|
26
28
|
*/
|
|
27
|
-
export const
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
export const SUGESTAO_HOOK = `{
|
|
30
|
+
"hooks": {
|
|
31
|
+
"SessionStart": [
|
|
32
|
+
{
|
|
33
|
+
"hooks": [
|
|
34
|
+
{
|
|
35
|
+
"type": "command",
|
|
36
|
+
"command": "dd-harness politica --hook",
|
|
37
|
+
"statusMessage": "Carregando a política do dd-harness..."
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
34
43
|
}`;
|
|
44
|
+
/**
|
|
45
|
+
* O que escrever num `AGENTS.md`, para agente que NAO e o Claude Code.
|
|
46
|
+
*
|
|
47
|
+
* O hook de `SessionStart` e um mecanismo do Claude Code: Codex, Cursor, Gemini CLI e
|
|
48
|
+
* Windsurf nao o executam. Nessas ferramentas nada carrega a politica sozinho — e o
|
|
49
|
+
* resultado e a mesma falha de sempre, a sessao abrindo sem protocolo sem avisar.
|
|
50
|
+
*
|
|
51
|
+
* O que resta la e o servidor MCP, que essas ferramentas suportam. Mas ferramenta
|
|
52
|
+
* disponivel nao e ferramenta chamada: sem uma instrucao explicita, o agente pode
|
|
53
|
+
* simplesmente nunca perguntar pela politica. Dai esta linha, que e curta de proposito —
|
|
54
|
+
* ela manda buscar a regra, nao repete a regra.
|
|
55
|
+
*/
|
|
56
|
+
export const SUGESTAO_AGENTS = `# AGENTS.md
|
|
57
|
+
|
|
58
|
+
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
59
|
+
|
|
60
|
+
**ANTES de qualquer outra coisa**, chame a ferramenta MCP \`ler_artefato\` com
|
|
61
|
+
\`tipo: "politica"\` e siga o que ela devolver. É a primeira ação da sessão, antes
|
|
62
|
+
de ler código, responder ou planejar.
|
|
63
|
+
|
|
64
|
+
- Se a ferramenta não existir, o servidor MCP do dd-harness não está declarado:
|
|
65
|
+
avise o usuário e **não modifique nada** até ele resolver.
|
|
66
|
+
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
67
|
+
|
|
68
|
+
O Claude Code carrega a política sozinho, por hook. Nas outras ferramentas, a
|
|
69
|
+
chamada acima é o que substitui esse hook.`;
|
|
35
70
|
async function declaraMcp(raiz) {
|
|
36
71
|
try {
|
|
37
72
|
const cru = await readFile(join(raiz, ".mcp.json"), "utf8");
|
|
@@ -43,6 +78,26 @@ async function declaraMcp(raiz) {
|
|
|
43
78
|
return "a-declarar";
|
|
44
79
|
}
|
|
45
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* O hook ja esta declarado?
|
|
83
|
+
*
|
|
84
|
+
* Procura pelo COMANDO, nao pela forma: `settings.json` aceita varios formatos de
|
|
85
|
+
* matcher, e quem ja tem o hook pode te-lo escrito de outro jeito. O que importa e se
|
|
86
|
+
* `dd-harness politica` roda no inicio da sessao.
|
|
87
|
+
*/
|
|
88
|
+
async function declaraHook(raiz) {
|
|
89
|
+
for (const arquivo of [".claude/settings.json", ".claude/settings.local.json"]) {
|
|
90
|
+
try {
|
|
91
|
+
const cru = await readFile(join(raiz, arquivo), "utf8");
|
|
92
|
+
if (cru.includes("dd-harness politica"))
|
|
93
|
+
return "ja-declarado";
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Sem arquivo: segue para o proximo.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return "a-declarar";
|
|
100
|
+
}
|
|
46
101
|
export async function init(raiz, dados) {
|
|
47
102
|
const caminhoConfig = join(raiz, CAMINHO_CONFIG);
|
|
48
103
|
let config = "ja-existia";
|
|
@@ -58,27 +113,26 @@ export async function init(raiz, dados) {
|
|
|
58
113
|
await writeFile(caminhoConfig, `${JSON.stringify(conteudo, null, 2)}\n`, "utf8");
|
|
59
114
|
config = "criada";
|
|
60
115
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
116
|
+
return {
|
|
117
|
+
config,
|
|
118
|
+
mcp: await declaraMcp(raiz),
|
|
119
|
+
hook: await declaraHook(raiz),
|
|
120
|
+
agents: await apontaNoAgents(raiz),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* O `AGENTS.md` ja manda buscar a politica?
|
|
125
|
+
*
|
|
126
|
+
* Procura pela CHAMADA (`ler_artefato`), nao por uma frase exata: quem ja escreveu a
|
|
127
|
+
* instrucao pode te-la redigido de outro jeito, e sugerir de novo por causa de palavra
|
|
128
|
+
* diferente e ruido.
|
|
129
|
+
*/
|
|
130
|
+
async function apontaNoAgents(raiz) {
|
|
64
131
|
try {
|
|
65
|
-
|
|
132
|
+
const cru = await readFile(join(raiz, "AGENTS.md"), "utf8");
|
|
133
|
+
return cru.includes("ler_artefato") ? "ja-aponta" : "a-apontar";
|
|
66
134
|
}
|
|
67
135
|
catch {
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
if (atual === null) {
|
|
71
|
-
await writeFile(caminhoClaude, `${CABECALHO}\n${LINHA_DE_IMPORT}\n`, "utf8");
|
|
72
|
-
claudeMd = "criado";
|
|
73
|
-
}
|
|
74
|
-
else if (atual.includes(LINHA_DE_IMPORT)) {
|
|
75
|
-
claudeMd = "ja-tinha-a-linha";
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
// Acrescenta no fim, sem reescrever nada do que ja estava la.
|
|
79
|
-
const separador = atual.endsWith("\n") ? "\n" : "\n\n";
|
|
80
|
-
await writeFile(caminhoClaude, `${atual}${separador}${LINHA_DE_IMPORT}\n`, "utf8");
|
|
81
|
-
claudeMd = "linha-acrescentada";
|
|
136
|
+
return "a-apontar";
|
|
82
137
|
}
|
|
83
|
-
return { config, claudeMd, mcp: await declaraMcp(raiz) };
|
|
84
138
|
}
|
package/dist/politica.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* A diferenca entre as duas ultimas e o que o `GET /api/v1/artefatos` responde: `404` e
|
|
16
16
|
* "nao ha projeto"; `200` com `politica` nula e "existe, nunca briefado".
|
|
17
17
|
*/
|
|
18
|
-
export type ResultadoDaPolitica = {
|
|
18
|
+
export type ResultadoDaPolitica = ({
|
|
19
19
|
estado: "ok";
|
|
20
20
|
conteudo: string;
|
|
21
21
|
} | {
|
|
@@ -23,5 +23,11 @@ export type ResultadoDaPolitica = {
|
|
|
23
23
|
} | {
|
|
24
24
|
estado: "inalcancavel";
|
|
25
25
|
motivo: string;
|
|
26
|
+
}) & {
|
|
27
|
+
/**
|
|
28
|
+
* Memorias esperando o worker. Vem de carona no mesmo payload da politica — o hook ja
|
|
29
|
+
* faz esta chamada, entao saber o estado da fila custa zero requisicao.
|
|
30
|
+
*/
|
|
31
|
+
esperandoIndexacao?: number;
|
|
26
32
|
};
|
|
27
33
|
export declare function buscaPolitica(raiz: string): Promise<ResultadoDaPolitica>;
|
package/dist/politica.js
CHANGED
|
@@ -23,10 +23,11 @@ export async function buscaPolitica(raiz) {
|
|
|
23
23
|
}
|
|
24
24
|
const payload = (await resposta.json());
|
|
25
25
|
const conteudo = payload.politica?.trim();
|
|
26
|
+
const esperandoIndexacao = payload.esperando_indexacao ?? 0;
|
|
26
27
|
// Vazio e nulo sao a mesma coisa aqui, e os dois significam "nunca foi escrita".
|
|
27
28
|
if (!conteudo)
|
|
28
|
-
return { estado: "sem-politica" };
|
|
29
|
-
return { estado: "ok", conteudo };
|
|
29
|
+
return { estado: "sem-politica", esperandoIndexacao };
|
|
30
|
+
return { estado: "ok", conteudo, esperandoIndexacao };
|
|
30
31
|
}
|
|
31
32
|
catch (erro) {
|
|
32
33
|
return { estado: "inalcancavel", motivo: mensagem(erro) };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trocar o alvo de uma ancora, sem reescrever a memoria.
|
|
3
|
+
*
|
|
4
|
+
* O caso: uma refatoracao move um arquivo, e toda memoria ancorada nele passa a acusar
|
|
5
|
+
* "alvo ausente". O `check --commit` cruza isso com os renames do git e diz para onde o
|
|
6
|
+
* conteudo foi; este comando aplica a troca.
|
|
7
|
+
*
|
|
8
|
+
* Separado de `editar` de proposito: editar exige o markdown inteiro e mexe no conteudo,
|
|
9
|
+
* que nao e o que mudou aqui. Reancorar troca um endereco e mais nada — misturar as duas
|
|
10
|
+
* coisas convidaria a reescrever o corpo de memoria enquanto se conserta um caminho.
|
|
11
|
+
*/
|
|
12
|
+
export declare function reancora(raiz: string, endereco: string, de: string, para: string): Promise<{
|
|
13
|
+
endereco: string;
|
|
14
|
+
de: string;
|
|
15
|
+
para: string;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
2
|
+
import {} from "./curar.js";
|
|
3
|
+
/**
|
|
4
|
+
* Trocar o alvo de uma ancora, sem reescrever a memoria.
|
|
5
|
+
*
|
|
6
|
+
* O caso: uma refatoracao move um arquivo, e toda memoria ancorada nele passa a acusar
|
|
7
|
+
* "alvo ausente". O `check --commit` cruza isso com os renames do git e diz para onde o
|
|
8
|
+
* conteudo foi; este comando aplica a troca.
|
|
9
|
+
*
|
|
10
|
+
* Separado de `editar` de proposito: editar exige o markdown inteiro e mexe no conteudo,
|
|
11
|
+
* que nao e o que mudou aqui. Reancorar troca um endereco e mais nada — misturar as duas
|
|
12
|
+
* coisas convidaria a reescrever o corpo de memoria enquanto se conserta um caminho.
|
|
13
|
+
*/
|
|
14
|
+
export async function reancora(raiz, endereco, de, para) {
|
|
15
|
+
const { config, token } = await credencial(raiz);
|
|
16
|
+
const url = new URL(`${config.api}/api/v1/memorias/${endereco}`);
|
|
17
|
+
url.searchParams.set("tenant", config.tenant);
|
|
18
|
+
url.searchParams.set("projeto", config.projeto);
|
|
19
|
+
const leitura = await pede(url, { headers: cabecalhos(token) });
|
|
20
|
+
if (!leitura.ok)
|
|
21
|
+
await recusa(leitura);
|
|
22
|
+
const memoria = (await leitura.json());
|
|
23
|
+
if (!memoria.ancoras.some((a) => a.valor === de)) {
|
|
24
|
+
throw new Error(`${endereco} não tem âncora em "${de}". Âncoras atuais: ` +
|
|
25
|
+
(memoria.ancoras.map((a) => a.valor).join(", ") || "nenhuma"));
|
|
26
|
+
}
|
|
27
|
+
const novas = memoria.ancoras.map((a) => (a.valor === de ? { ...a, valor: para } : a));
|
|
28
|
+
// Reaproveita o PATCH de edicao: ele recebe a memoria inteira, entao mandamos o que ja
|
|
29
|
+
// estava la com a ancora trocada. Uma porta so para escrever memoria, e nao duas.
|
|
30
|
+
const envio = await pede(`${config.api}/api/v1/memorias/${endereco}`, {
|
|
31
|
+
method: "PATCH",
|
|
32
|
+
headers: cabecalhos(token, true),
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
tenant: config.tenant,
|
|
35
|
+
projeto: config.projeto,
|
|
36
|
+
titulo: memoria.titulo,
|
|
37
|
+
resumo: memoria.resumo,
|
|
38
|
+
corpo: memoria.corpo,
|
|
39
|
+
dano: memoria.dano,
|
|
40
|
+
invisibilidade: memoria.invisibilidade,
|
|
41
|
+
externalidade: memoria.externalidade,
|
|
42
|
+
ancoras: novas.map((a) => a.valor),
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
if (!envio.ok)
|
|
46
|
+
await recusa(envio);
|
|
47
|
+
return { endereco, de, para };
|
|
48
|
+
}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subir o worker de embeddings quando ha fila esperando.
|
|
3
|
+
*
|
|
4
|
+
* O worker nao esta hospedado (decisao de custo, registrada no ROADMAP): roda local, a
|
|
5
|
+
* mao. O problema disso e a degradacao SILENCIOSA — a memoria e gravada, a busca responde
|
|
6
|
+
* `semantica: true` porque a CONSULTA foi vetorizada, e mesmo assim nao acha nada, porque
|
|
7
|
+
* a BASE ainda nao tem vetor. Quem procura conclui "nao existe" quando o certo era
|
|
8
|
+
* "ainda nao indexei".
|
|
9
|
+
*
|
|
10
|
+
* Por isso o hook de sessao sobe o worker sozinho. Duas travas, e as duas importam:
|
|
11
|
+
*
|
|
12
|
+
* - **So sobe quando ha fila.** O hook roda em TODA sessao, inclusive nas que so leem
|
|
13
|
+
* codigo. Subir com a fila vazia gastaria chamada de embedding sem ninguem ter pedido.
|
|
14
|
+
* - **So no repositorio que TEM o worker.** Ele vive neste monorepo, nao no repositorio
|
|
15
|
+
* consumidor: la o `pnpm worker` nao existe, e tentar rodar daria erro a cada sessao.
|
|
16
|
+
*/
|
|
17
|
+
/** O worker vive aqui dentro. Noutro repositorio, nao ha o que subir. */
|
|
18
|
+
export declare function temWorkerLocal(raiz: string): Promise<boolean>;
|
|
19
|
+
export type Subida = {
|
|
20
|
+
subiu: true;
|
|
21
|
+
} | {
|
|
22
|
+
subiu: false;
|
|
23
|
+
motivo: "sem-fila" | "sem-worker" | "falhou";
|
|
24
|
+
detalhe?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Dispara um lote e devolve na hora — nao espera terminar.
|
|
28
|
+
*
|
|
29
|
+
* `--uma-vez` e nao o modo continuo: o hook de sessao nao pode deixar processo de pe que
|
|
30
|
+
* ninguem mandou subir, e um lote basta para o caso comum (as memorias gravadas na sessao
|
|
31
|
+
* anterior). Fila grande volta a aparecer na proxima sessao, e ai o numero cresce em vez
|
|
32
|
+
* de sumir — que e o sinal de que esta na hora de hospedar de verdade.
|
|
33
|
+
*
|
|
34
|
+
* `unref()` solta o processo do pai: sem isso o hook so retornaria quando o worker
|
|
35
|
+
* terminasse, e a sessao ficaria esperando embedding para abrir.
|
|
36
|
+
*/
|
|
37
|
+
export declare function subiuOWorker(raiz: string, esperando: number): Promise<Subida>;
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Subir o worker de embeddings quando ha fila esperando.
|
|
6
|
+
*
|
|
7
|
+
* O worker nao esta hospedado (decisao de custo, registrada no ROADMAP): roda local, a
|
|
8
|
+
* mao. O problema disso e a degradacao SILENCIOSA — a memoria e gravada, a busca responde
|
|
9
|
+
* `semantica: true` porque a CONSULTA foi vetorizada, e mesmo assim nao acha nada, porque
|
|
10
|
+
* a BASE ainda nao tem vetor. Quem procura conclui "nao existe" quando o certo era
|
|
11
|
+
* "ainda nao indexei".
|
|
12
|
+
*
|
|
13
|
+
* Por isso o hook de sessao sobe o worker sozinho. Duas travas, e as duas importam:
|
|
14
|
+
*
|
|
15
|
+
* - **So sobe quando ha fila.** O hook roda em TODA sessao, inclusive nas que so leem
|
|
16
|
+
* codigo. Subir com a fila vazia gastaria chamada de embedding sem ninguem ter pedido.
|
|
17
|
+
* - **So no repositorio que TEM o worker.** Ele vive neste monorepo, nao no repositorio
|
|
18
|
+
* consumidor: la o `pnpm worker` nao existe, e tentar rodar daria erro a cada sessao.
|
|
19
|
+
*/
|
|
20
|
+
/** O worker vive aqui dentro. Noutro repositorio, nao ha o que subir. */
|
|
21
|
+
export async function temWorkerLocal(raiz) {
|
|
22
|
+
try {
|
|
23
|
+
await access(join(raiz, "src", "worker", "indexador.ts"));
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dispara um lote e devolve na hora — nao espera terminar.
|
|
32
|
+
*
|
|
33
|
+
* `--uma-vez` e nao o modo continuo: o hook de sessao nao pode deixar processo de pe que
|
|
34
|
+
* ninguem mandou subir, e um lote basta para o caso comum (as memorias gravadas na sessao
|
|
35
|
+
* anterior). Fila grande volta a aparecer na proxima sessao, e ai o numero cresce em vez
|
|
36
|
+
* de sumir — que e o sinal de que esta na hora de hospedar de verdade.
|
|
37
|
+
*
|
|
38
|
+
* `unref()` solta o processo do pai: sem isso o hook so retornaria quando o worker
|
|
39
|
+
* terminasse, e a sessao ficaria esperando embedding para abrir.
|
|
40
|
+
*/
|
|
41
|
+
export async function subiuOWorker(raiz, esperando) {
|
|
42
|
+
if (esperando <= 0)
|
|
43
|
+
return { subiu: false, motivo: "sem-fila" };
|
|
44
|
+
if (!(await temWorkerLocal(raiz))) {
|
|
45
|
+
return { subiu: false, motivo: "sem-worker" };
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const filho = spawn("npx", ["pnpm@latest", "worker", "--uma-vez"], {
|
|
49
|
+
cwd: raiz,
|
|
50
|
+
detached: true,
|
|
51
|
+
stdio: "ignore",
|
|
52
|
+
shell: process.platform === "win32",
|
|
53
|
+
windowsHide: true,
|
|
54
|
+
});
|
|
55
|
+
filho.unref();
|
|
56
|
+
return { subiu: true };
|
|
57
|
+
}
|
|
58
|
+
catch (erro) {
|
|
59
|
+
return {
|
|
60
|
+
subiu: false,
|
|
61
|
+
motivo: "falhou",
|
|
62
|
+
detalhe: erro instanceof Error ? erro.message : String(erro),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
package/package.json
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dd-harness",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "
|
|
6
|
-
"license": "UNLICENSED",
|
|
7
|
-
"author": "Diego Dias",
|
|
8
|
-
"keywords": [
|
|
9
|
-
"claude-code",
|
|
10
|
-
"ai-agents",
|
|
11
|
-
"memory",
|
|
12
|
-
"brain",
|
|
13
|
-
"cli"
|
|
14
|
-
],
|
|
15
|
-
"homepage": "https://dd-harness.vercel.app",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/diegodias93/dd-harness-online.git",
|
|
19
|
-
"directory": "packages/cli"
|
|
20
|
-
},
|
|
21
|
-
"bin": {
|
|
22
|
-
"dd-harness": "dist/index.js"
|
|
23
|
-
},
|
|
24
|
-
"//exports": "Aponta para `dist` porque quem IMPORTA isto em tempo de execucao e o Node, que nao executa TypeScript. Nao aponte para `src`: o Node segue os imports relativos de dentro do arquivo e tenta abrir `./api.js` ao lado do `.ts`, que nao existe. Quem consome no workspace e o `packages/mcp`, e ele compila o fonte do CLI junto (ver o tsconfig.build.json dele) em vez de depender deste campo — assim o build funciona num checkout limpo, sem `dist` previo.",
|
|
25
|
-
"exports": {
|
|
26
|
-
"./api": "./dist/api.js",
|
|
27
|
-
"./buscar": "./dist/buscar.js",
|
|
28
|
-
"./curar": "./dist/curar.js",
|
|
29
|
-
"./gravar": "./dist/gravar.js",
|
|
30
|
-
"./pasta": "./dist/pasta.js",
|
|
31
|
-
"./projeto": "./dist/projeto.js"
|
|
32
|
-
},
|
|
33
|
-
"files": [
|
|
34
|
-
"dist"
|
|
35
|
-
],
|
|
36
|
-
"engines": {
|
|
37
|
-
"node": ">=20"
|
|
38
|
-
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"typecheck": "tsc -p . --noEmit",
|
|
41
|
-
"build": "tsc -p tsconfig.build.json",
|
|
42
|
-
"prepublishOnly": "npm run build"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dd-harness",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"type": "module",
|
|
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
|
+
"license": "UNLICENSED",
|
|
7
|
+
"author": "Diego Dias",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"claude-code",
|
|
10
|
+
"ai-agents",
|
|
11
|
+
"memory",
|
|
12
|
+
"brain",
|
|
13
|
+
"cli"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://dd-harness.vercel.app",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/diegodias93/dd-harness-online.git",
|
|
19
|
+
"directory": "packages/cli"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"dd-harness": "dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"//exports": "Aponta para `dist` porque quem IMPORTA isto em tempo de execucao e o Node, que nao executa TypeScript. Nao aponte para `src`: o Node segue os imports relativos de dentro do arquivo e tenta abrir `./api.js` ao lado do `.ts`, que nao existe. Quem consome no workspace e o `packages/mcp`, e ele compila o fonte do CLI junto (ver o tsconfig.build.json dele) em vez de depender deste campo — assim o build funciona num checkout limpo, sem `dist` previo.",
|
|
25
|
+
"exports": {
|
|
26
|
+
"./api": "./dist/api.js",
|
|
27
|
+
"./buscar": "./dist/buscar.js",
|
|
28
|
+
"./curar": "./dist/curar.js",
|
|
29
|
+
"./gravar": "./dist/gravar.js",
|
|
30
|
+
"./pasta": "./dist/pasta.js",
|
|
31
|
+
"./projeto": "./dist/projeto.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"typecheck": "tsc -p . --noEmit",
|
|
41
|
+
"build": "tsc -p tsconfig.build.json",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
}
|
|
44
|
+
}
|