dd-harness 0.40.0 → 0.41.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/artefato.d.ts +30 -3
- package/dist/artefato.js +44 -1
- package/dist/sessao.js +78 -32
- package/package.json +44 -44
package/dist/artefato.d.ts
CHANGED
|
@@ -23,13 +23,40 @@ export declare function leArtefato(raiz: string, tipo: TipoDeArtefato): Promise<
|
|
|
23
23
|
existe: boolean;
|
|
24
24
|
atualizadaEm: string | null;
|
|
25
25
|
}>;
|
|
26
|
+
/** O que o `PUT` devolve. `sem_alteracao`: o texto era igual ao atual e nao virou versao. */
|
|
27
|
+
export type EscritaDeArtefato = {
|
|
28
|
+
artefato: string;
|
|
29
|
+
criou: boolean;
|
|
30
|
+
tamanho: number;
|
|
31
|
+
versao: number;
|
|
32
|
+
sem_alteracao: boolean;
|
|
33
|
+
};
|
|
26
34
|
/**
|
|
27
35
|
* Substituicao total, nao append: quem quer acrescentar um paragrafo le, concatena e
|
|
28
36
|
* reenvia. Conteudo vazio e valido e significa "apagar" — a linha fica no banco, guardando
|
|
29
37
|
* quem mexeu por ultimo.
|
|
38
|
+
*
|
|
39
|
+
* Toda escrita vira uma versao numerada no servico, e `resumo` e a linha que o historico
|
|
40
|
+
* guarda sobre ela: o que mudou e por que.
|
|
30
41
|
*/
|
|
31
|
-
export declare function escreveArtefato(raiz: string, tipo: TipoDeArtefato, conteudo: string, atualizadaEm: string | null): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
export declare function escreveArtefato(raiz: string, tipo: TipoDeArtefato, conteudo: string, atualizadaEm: string | null, resumo: string): Promise<EscritaDeArtefato>;
|
|
43
|
+
export type VersaoDeArtefato = {
|
|
44
|
+
versao: number;
|
|
45
|
+
resumo: string;
|
|
46
|
+
criada_em: string;
|
|
34
47
|
tamanho: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* O historico do artefato: a lista de versoes, da mais recente para a mais antiga. Nao
|
|
51
|
+
* entra no boot — chega so quando alguem precisa entender por que o texto esta assim.
|
|
52
|
+
*/
|
|
53
|
+
export declare function leVersoesDoArtefato(raiz: string, tipo: TipoDeArtefato): Promise<VersaoDeArtefato[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Uma linha por versao, e nao tabela: o resumo e texto livre, e um `|` dentro dele
|
|
56
|
+
* quebraria a tabela markdown que o agente le.
|
|
57
|
+
*/
|
|
58
|
+
export declare function formataHistorico(tipo: TipoDeArtefato, versoes: VersaoDeArtefato[]): string;
|
|
59
|
+
/** O texto integral de uma versao antiga, com o resumo do que ela mudou. */
|
|
60
|
+
export declare function leVersaoDoArtefato(raiz: string, tipo: TipoDeArtefato, versao: number): Promise<Omit<VersaoDeArtefato, "tamanho"> & {
|
|
61
|
+
conteudo: string;
|
|
35
62
|
}>;
|
package/dist/artefato.js
CHANGED
|
@@ -27,8 +27,11 @@ export async function leArtefato(raiz, tipo) {
|
|
|
27
27
|
* Substituicao total, nao append: quem quer acrescentar um paragrafo le, concatena e
|
|
28
28
|
* reenvia. Conteudo vazio e valido e significa "apagar" — a linha fica no banco, guardando
|
|
29
29
|
* quem mexeu por ultimo.
|
|
30
|
+
*
|
|
31
|
+
* Toda escrita vira uma versao numerada no servico, e `resumo` e a linha que o historico
|
|
32
|
+
* guarda sobre ela: o que mudou e por que.
|
|
30
33
|
*/
|
|
31
|
-
export async function escreveArtefato(raiz, tipo, conteudo, atualizadaEm) {
|
|
34
|
+
export async function escreveArtefato(raiz, tipo, conteudo, atualizadaEm, resumo) {
|
|
32
35
|
const { config, token } = await credencial(raiz);
|
|
33
36
|
const resposta = await pede(`${config.api}/api/v1/artefatos`, {
|
|
34
37
|
method: "PUT",
|
|
@@ -43,6 +46,7 @@ export async function escreveArtefato(raiz, tipo, conteudo, atualizadaEm) {
|
|
|
43
46
|
projeto: config.projeto,
|
|
44
47
|
tipo,
|
|
45
48
|
conteudo,
|
|
49
|
+
resumo,
|
|
46
50
|
}),
|
|
47
51
|
});
|
|
48
52
|
if (!resposta.ok)
|
|
@@ -52,3 +56,42 @@ export async function escreveArtefato(raiz, tipo, conteudo, atualizadaEm) {
|
|
|
52
56
|
});
|
|
53
57
|
return (await jsonDaEscrita(resposta));
|
|
54
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* O historico do artefato: a lista de versoes, da mais recente para a mais antiga. Nao
|
|
61
|
+
* entra no boot — chega so quando alguem precisa entender por que o texto esta assim.
|
|
62
|
+
*/
|
|
63
|
+
export async function leVersoesDoArtefato(raiz, tipo) {
|
|
64
|
+
const corpo = (await pedeHistorico(raiz, tipo));
|
|
65
|
+
return corpo.versoes;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Uma linha por versao, e nao tabela: o resumo e texto livre, e um `|` dentro dele
|
|
69
|
+
* quebraria a tabela markdown que o agente le.
|
|
70
|
+
*/
|
|
71
|
+
export function formataHistorico(tipo, versoes) {
|
|
72
|
+
if (versoes.length === 0)
|
|
73
|
+
return `O ${tipo} ainda não tem versões — nunca foi escrito.`;
|
|
74
|
+
return [
|
|
75
|
+
`Histórico do ${tipo} — ${versoes.length} versão(ões), da mais recente para a mais antiga:`,
|
|
76
|
+
"",
|
|
77
|
+
...versoes.map((v, i) => `- v${v.versao}${i === 0 ? " (atual)" : ""} · ${v.criada_em.slice(0, 16).replace("T", " ")} · ` +
|
|
78
|
+
`${v.tamanho} caractere(s) — ${v.resumo}`),
|
|
79
|
+
].join("\n");
|
|
80
|
+
}
|
|
81
|
+
/** O texto integral de uma versao antiga, com o resumo do que ela mudou. */
|
|
82
|
+
export async function leVersaoDoArtefato(raiz, tipo, versao) {
|
|
83
|
+
return (await pedeHistorico(raiz, tipo, versao));
|
|
84
|
+
}
|
|
85
|
+
async function pedeHistorico(raiz, tipo, versao) {
|
|
86
|
+
const { config, token } = await credencial(raiz);
|
|
87
|
+
const url = new URL(`${config.api}/api/v1/artefatos/historico`);
|
|
88
|
+
url.searchParams.set("tenant", config.tenant);
|
|
89
|
+
url.searchParams.set("projeto", config.projeto);
|
|
90
|
+
url.searchParams.set("tipo", tipo);
|
|
91
|
+
if (versao !== undefined)
|
|
92
|
+
url.searchParams.set("versao", String(versao));
|
|
93
|
+
const resposta = await pede(url, { headers: cabecalhos(token) });
|
|
94
|
+
if (!resposta.ok)
|
|
95
|
+
await recusa(resposta);
|
|
96
|
+
return resposta.json();
|
|
97
|
+
}
|
package/dist/sessao.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
4
|
import { credencial } from "./api.js";
|
|
5
5
|
import { achaRaiz } from "./config.js";
|
|
6
6
|
import { decideDoHook, guardaCache, leCache } from "./cinto.js";
|
|
7
7
|
import { edicoesDaChamada, normalizaEntrada } from "./edicoes.js";
|
|
8
|
-
import { estadoDoRepo, escreveAtomico, revisaoDoContexto } from "./estado-local.js";
|
|
8
|
+
import { diretorioDoUsuario, estadoDoRepo, escreveAtomico, revisaoDoContexto } from "./estado-local.js";
|
|
9
9
|
import { buscaPolitica } from "./politica.js";
|
|
10
10
|
import { blocoDeSessao } from "./roadmap.js";
|
|
11
11
|
import { leSkills, escrevePonteirosDeSkills } from "./skill.js";
|
|
@@ -14,21 +14,38 @@ import { subiuOWorker } from "./worker.js";
|
|
|
14
14
|
const PRAZO = 4 * 60 * 60 * 1000;
|
|
15
15
|
const hash = (s) => createHash("sha256").update(s).digest("hex");
|
|
16
16
|
const arquivo = (raiz, sessao, host) => join(estadoDoRepo(raiz), `sessao-${hash(host + sessao)}.json`);
|
|
17
|
+
const arquivoDaRaiz = (sessao, host) => join(diretorioDoUsuario(), "sessoes", `${hash(host + sessao)}.json`);
|
|
18
|
+
async function raizDaSessao(sessao, host) {
|
|
19
|
+
try {
|
|
20
|
+
const lido = JSON.parse(await readFile(arquivoDaRaiz(sessao, host), "utf8"));
|
|
21
|
+
return typeof lido.raiz === "string" ? lido.raiz : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const mesmaRaiz = (a, b) => process.platform === "win32" ? resolve(a).toLowerCase() === resolve(b).toLowerCase() : resolve(a) === resolve(b);
|
|
17
28
|
async function identidade(raiz) {
|
|
18
29
|
const c = await credencial(raiz);
|
|
19
30
|
return hash(JSON.stringify(c)); // inclui token sem expô-lo em disco/log.
|
|
20
31
|
}
|
|
21
|
-
async function
|
|
32
|
+
async function estadoConhecido(raiz, sessao, host) {
|
|
22
33
|
try {
|
|
23
34
|
const e = JSON.parse(await readFile(arquivo(raiz, sessao, host), "utf8"));
|
|
24
|
-
|
|
25
|
-
return null;
|
|
26
|
-
return e.identidade === await identidade(raiz) && Date.now() >= e.em && Date.now() - e.em < PRAZO ? e : null;
|
|
35
|
+
return e.identidade === await identidade(raiz) && Date.now() >= e.em ? e : null;
|
|
27
36
|
}
|
|
28
37
|
catch {
|
|
29
38
|
return null;
|
|
30
39
|
}
|
|
31
40
|
}
|
|
41
|
+
async function estadoAtual(raiz, sessao, host) {
|
|
42
|
+
const e = await estadoConhecido(raiz, sessao, host);
|
|
43
|
+
if (!e || Date.now() - e.em >= PRAZO)
|
|
44
|
+
return null;
|
|
45
|
+
if (e.estado === "ok" && e.revisao !== await revisaoDoContexto(raiz))
|
|
46
|
+
return null;
|
|
47
|
+
return e;
|
|
48
|
+
}
|
|
32
49
|
export function saidaDoBoot(host, contexto, ok) {
|
|
33
50
|
return host === "antigravity"
|
|
34
51
|
? { injectSteps: contexto ? [{ ephemeralMessage: contexto }] : [] }
|
|
@@ -39,7 +56,9 @@ export async function abreSessao(host, entrada) {
|
|
|
39
56
|
const c = normalizaEntrada(host, entrada);
|
|
40
57
|
if (!c.sessao)
|
|
41
58
|
throw new Error("hook sem identificador de sessão: não é possível validar o boot");
|
|
42
|
-
const raiz = await achaRaiz(c.raiz);
|
|
59
|
+
const raiz = await achaRaiz(c.raiz).catch(() => raizDaSessao(c.sessao, host));
|
|
60
|
+
if (!raiz)
|
|
61
|
+
throw new Error("dd-harness: projeto não encontrado. Abra a sessão a partir de um projeto configurado.");
|
|
43
62
|
const anterior = await estadoAtual(raiz, c.sessao, host);
|
|
44
63
|
// A mensagem do Antigravity é efêmera: não presumir que sobreviva à próxima inferência.
|
|
45
64
|
const inicio = host !== "antigravity" || Number(entrada.invocationNum) === 0 || anterior?.estado !== "ok";
|
|
@@ -85,6 +104,7 @@ export async function abreSessao(host, entrada) {
|
|
|
85
104
|
contexto = `PARE: não foi possível carregar a política e o briefing. ${r.motivo}. Corrija a conexão/configuração e reabra a sessão.`;
|
|
86
105
|
await escreveAtomico(arquivo(raiz, c.sessao, host), JSON.stringify({ identidade: id,
|
|
87
106
|
revisao, ciclo, estado: r.estado, em: Date.now() }));
|
|
107
|
+
await escreveAtomico(arquivoDaRaiz(c.sessao, host), JSON.stringify({ raiz }));
|
|
88
108
|
return saidaDoBoot(host, contexto, r.estado !== "inalcancavel");
|
|
89
109
|
}
|
|
90
110
|
export function saidaDaGuarda(host, motivo, contexto) {
|
|
@@ -96,7 +116,7 @@ export function saidaDaGuarda(host, motivo, contexto) {
|
|
|
96
116
|
}
|
|
97
117
|
// Só ferramentas conhecidas de leitura passam quando o boot falta. Shell não é classificado por regex.
|
|
98
118
|
const LEITURA = /^(Read|Glob|Grep|view_file|list_dir|find_by_name|grep_search|ask_question|AskUserQuestion|request_user_input)$/;
|
|
99
|
-
const LEITURA_MCP = /^mcp__dd[-_]harness__(ler_artefato|ler_roadmap|ler_changelog|listar_skills|ler_skill|ler_memoria|buscar_memoria)$/;
|
|
119
|
+
const LEITURA_MCP = /^mcp__dd[-_]harness__(ler_artefato|ler_historico_artefato|ler_roadmap|ler_changelog|listar_skills|ler_skill|ler_memoria|buscar_memoria)$/;
|
|
100
120
|
/**
|
|
101
121
|
* O que um projeto SEM politica precisa para ganhar uma.
|
|
102
122
|
*
|
|
@@ -113,44 +133,64 @@ const LEITURA_MCP = /^mcp__dd[-_]harness__(ler_artefato|ler_roadmap|ler_changelo
|
|
|
113
133
|
const ONBOARDING = /^(ToolSearch|mcp__dd[-_]harness__(escrever_artefato|criar_pasta|criar_projeto))$/;
|
|
114
134
|
export async function guardaSessao(host, entrada) {
|
|
115
135
|
const c = normalizaEntrada(host, entrada);
|
|
116
|
-
const
|
|
117
|
-
const
|
|
136
|
+
const vinculada = c.sessao ? await raizDaSessao(c.sessao, host) : null;
|
|
137
|
+
const atual = await achaRaiz(c.raiz).catch(() => null);
|
|
138
|
+
if (vinculada && atual && !mesmaRaiz(vinculada, atual)) {
|
|
139
|
+
return saidaDaGuarda(host, "dd-harness: esta sessão pertence a outro projeto. Abra uma sessão neste projeto para carregar sua política e seu briefing.");
|
|
140
|
+
}
|
|
141
|
+
const raiz = atual ?? vinculada;
|
|
142
|
+
if (!raiz) {
|
|
143
|
+
if (LEITURA.test(c.ferramenta) || LEITURA_MCP.test(c.ferramenta))
|
|
144
|
+
return saidaDaGuarda(host);
|
|
145
|
+
return saidaDaGuarda(host, "dd-harness: esta sessão não tem projeto associado. Volte ao projeto configurado e abra uma sessão nele; não rode `dd-harness start` na pasta de rascunho.");
|
|
146
|
+
}
|
|
147
|
+
const edicoes = edicoesDaChamada(c);
|
|
148
|
+
for (const edicao of edicoes) {
|
|
149
|
+
const projetoDoArquivo = await achaRaiz(edicao.arquivo).catch(() => null);
|
|
150
|
+
if (projetoDoArquivo && !mesmaRaiz(projetoDoArquivo, raiz)) {
|
|
151
|
+
return saidaDaGuarda(host, "dd-harness: o arquivo pertence a outro projeto. Abra uma sessão nesse projeto antes de editá-lo.");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let e = c.sessao ? await estadoAtual(raiz, c.sessao, host) : null;
|
|
155
|
+
let contextoAtualizado = "";
|
|
118
156
|
if (e?.estado !== "ok") {
|
|
119
157
|
if (LEITURA.test(c.ferramenta) || LEITURA_MCP.test(c.ferramenta))
|
|
120
158
|
return saidaDaGuarda(host);
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// distingue os dois — quem sabe e o SERVICO. Se ele diz que nao ha politica, este
|
|
125
|
-
// projeto ainda esta em onboarding e as ferramentas de escreve-lo passam.
|
|
159
|
+
const anterior = c.sessao ? await estadoConhecido(raiz, c.sessao, host) : null;
|
|
160
|
+
// Projeto novo so pode completar o briefing se as ferramentas que o escrevem passarem.
|
|
161
|
+
// Quem distingue onboarding de contexto indisponivel e o servico.
|
|
126
162
|
//
|
|
127
163
|
// Nao e afrouxamento: o que passa aqui e so o que CONSTROI o contexto obrigatorio, e
|
|
128
164
|
// so enquanto ele nao existe. Na primeira politica gravada, este caminho fecha sozinho.
|
|
165
|
+
const revisao = await revisaoDoContexto(raiz);
|
|
129
166
|
const r = await buscaPolitica(raiz).catch(() => null);
|
|
130
167
|
if (ONBOARDING.test(c.ferramenta) && r?.estado === "sem-politica")
|
|
131
168
|
return saidaDaGuarda(host);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (r?.estado === "ok") {
|
|
169
|
+
if (r?.estado === "ok" && (anterior?.estado === "ok" || anterior?.estado === "sem-politica")) {
|
|
170
|
+
if (revisao !== await revisaoDoContexto(raiz)) {
|
|
171
|
+
return saidaDaGuarda(host, "dd-harness: o contexto mudou durante a atualização. Repita a chamada para carregar a versão atual.");
|
|
172
|
+
}
|
|
173
|
+
await guardaCache(raiz, { memorias: r.memorias ?? [] });
|
|
174
|
+
e = { identidade: anterior.identidade, revisao, ciclo: randomUUID(), estado: "ok", em: Date.now() };
|
|
175
|
+
contextoAtualizado = "dd-harness: política e briefing atualizados nesta sessão. Este contexto substitui as versões anteriores:\n\n" +
|
|
176
|
+
r.conteudo + blocoDeSessao(r.roadmap);
|
|
177
|
+
}
|
|
178
|
+
else if (r?.estado === "ok") {
|
|
143
179
|
return saidaDaGuarda(host, "dd-harness: política e briefing JÁ EXISTEM no serviço, mas o boot " +
|
|
144
|
-
"desta sessão
|
|
180
|
+
"desta sessão não foi validado — por isso o contexto não chegou ao modelo. " +
|
|
145
181
|
"Nada falta gravar: **reabra a sessão** para o boot carregá-los. " +
|
|
146
182
|
"Enquanto isso, leitura (Read/Glob/Grep) e as ferramentas de leitura do dd-harness continuam liberadas.");
|
|
147
183
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
184
|
+
else if (r?.estado === "inalcancavel") {
|
|
185
|
+
return saidaDaGuarda(host, `dd-harness: não foi possível atualizar política e briefing: ${r.motivo}. Confira a conexão e repita a chamada.`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
return saidaDaGuarda(host, "dd-harness: política e briefing não foram carregados nesta sessão/projeto. " +
|
|
189
|
+
"Se este projeto é novo, conduza o briefing e grave os dois com `escrever_artefato`; " +
|
|
190
|
+
"se não, confira a conexão e reabra a sessão para o boot rodar.");
|
|
191
|
+
}
|
|
151
192
|
}
|
|
152
|
-
const
|
|
153
|
-
const avisos = [];
|
|
193
|
+
const avisos = contextoAtualizado ? [contextoAtualizado] : [];
|
|
154
194
|
if (edicoes.length && !await leCache(raiz)) {
|
|
155
195
|
const r = await buscaPolitica(raiz);
|
|
156
196
|
if (r.estado !== "ok") {
|
|
@@ -167,5 +207,11 @@ export async function guardaSessao(host, entrada) {
|
|
|
167
207
|
if (r.hookSpecificOutput.additionalContext)
|
|
168
208
|
avisos.push(r.hookSpecificOutput.additionalContext);
|
|
169
209
|
}
|
|
210
|
+
if (contextoAtualizado) {
|
|
211
|
+
if (e.revisao !== await revisaoDoContexto(raiz)) {
|
|
212
|
+
return saidaDaGuarda(host, "dd-harness: o contexto mudou durante a atualização. Repita a chamada para carregar a versão atual.");
|
|
213
|
+
}
|
|
214
|
+
await escreveAtomico(arquivo(raiz, c.sessao, host), JSON.stringify(e));
|
|
215
|
+
}
|
|
170
216
|
return saidaDaGuarda(host, undefined, avisos.join("\n\n"));
|
|
171
217
|
}
|
package/package.json
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dd-harness",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "Política, memória e integrações de Claude Code, Codex e Antigravity. CLI sem dependências de runtime.",
|
|
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.3.0"
|
|
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.41.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Política, memória e integrações de Claude Code, Codex e Antigravity. CLI sem dependências de runtime.",
|
|
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.3.0"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"typecheck": "tsc -p . --noEmit",
|
|
41
|
+
"build": "tsc -p tsconfig.build.json",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
}
|
|
44
|
+
}
|