dd-harness 0.38.2 → 0.40.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/README.md +103 -103
- package/dist/artefato.d.ts +9 -4
- package/dist/artefato.js +16 -8
- package/dist/atualizar.d.ts +2 -0
- package/dist/atualizar.js +1 -1
- package/dist/brain.d.ts +20 -4
- package/dist/check.js +18 -4
- package/dist/curar.d.ts +6 -1
- package/dist/curar.js +6 -2
- package/dist/escreve-config.js +24 -24
- package/dist/gravar.d.ts +1 -0
- package/dist/gravar.js +1 -0
- package/dist/index.js +49 -12
- package/dist/init.js +45 -45
- package/dist/materializa.d.ts +70 -0
- package/dist/materializa.js +5 -0
- package/dist/moldes-historicos.js +70 -70
- package/dist/payload-cache.d.ts +31 -0
- package/dist/payload-cache.js +62 -0
- package/dist/politica.js +20 -3
- package/dist/reancorar.js +19 -1
- package/dist/skill.d.ts +5 -0
- package/dist/skill.js +37 -3
- package/dist/skills-iniciais.js +10 -4
- package/dist/sync.d.ts +59 -0
- package/dist/sync.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
# dd-harness
|
|
2
|
-
|
|
3
|
-
Política e briefing carregados do serviço; memória consultada por MCP ou CLI.
|
|
4
|
-
A fonte dos artefatos continua no serviço. O cliente mantém configuração, ponteiros
|
|
5
|
-
para skills e estado descartável fora do repositório.
|
|
6
|
-
|
|
7
|
-
Requer Node >=20.3.0. CLI sem dependências de runtime.
|
|
8
|
-
|
|
9
|
-
## Instalação e configuração
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
npm install -g dd-harness@latest
|
|
13
|
-
npx -y dd-harness-mcp@latest --help
|
|
14
|
-
dd-harness start --host todos
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Para um projeto já criado no serviço:
|
|
18
|
-
|
|
19
|
-
```sh
|
|
20
|
-
dd-harness init --tenant meu-espaco --projeto meu-projeto
|
|
21
|
-
dd-harness login --token <token>
|
|
22
|
-
dd-harness integrar --host claude,codex,antigravity
|
|
23
|
-
dd-harness diagnostico --mcp
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
`start` usa Claude por padrão. `--host` aceita `claude`, `codex`,
|
|
27
|
-
`antigravity`, uma lista separada por vírgulas ou `todos`.
|
|
28
|
-
`integrar` instala nos três por padrão e preserva configurações alheias.
|
|
29
|
-
O token nasce em /tokens e fica em ~/.dd-harness/credentials.json, por origem de API.
|
|
30
|
-
Para serviço local, use `init --api http://localhost:3000` antes do login.
|
|
31
|
-
|
|
32
|
-
## Hosts
|
|
33
|
-
|
|
34
|
-
| Host | MCP | Boot e guarda | Skills |
|
|
35
|
-
|---|---|---|---|
|
|
36
|
-
| Claude Code | .mcp.json | .claude/settings.json | .claude/skills |
|
|
37
|
-
| Codex | .codex/config.toml | .codex/hooks.json | .agents/skills |
|
|
38
|
-
| Antigravity | .agents/mcp_config.json | .agents/hooks.json | .agents/skills |
|
|
39
|
-
|
|
40
|
-
Codex exige revisão/confiança dos hooks em /hooks. Instalação não comprova ativação.
|
|
41
|
-
Antigravity usa PreInvocation e mensagem efêmera: política e briefing são consultados
|
|
42
|
-
antes de cada inferência. Sua guarda usa `ask` para respeitar concessões já existentes;
|
|
43
|
-
ela pode acrescentar confirmações. Não amplia permissões automaticamente.
|
|
44
|
-
|
|
45
|
-
Sem boot válido, a guarda recusa ferramentas cobertas, inclusive shell. Leitura conhecida
|
|
46
|
-
e onboarding controlado continuam possíveis. Os hooks precisam estar ativos: não são
|
|
47
|
-
sandbox nem controlam ferramentas que o aplicativo não encaminha a eles.
|
|
48
|
-
Após boot válido, shell não tem análise de diff antecipada; avisos por âncora cobrem
|
|
49
|
-
edições estruturadas, patches, remoções e renomeações.
|
|
50
|
-
|
|
51
|
-
Configurações MCP novas levam DD_HARNESS_ROOT explícito. Ao copiar/mover um checkout,
|
|
52
|
-
confira essa raiz com diagnostico. O MCP recusa divergência entre a raiz explícita e
|
|
53
|
-
o projeto identificado no diretório de execução. Corrija a configuração e reinicie o host.
|
|
54
|
-
|
|
55
|
-
## Uso diário
|
|
56
|
-
|
|
57
|
-
```sh
|
|
58
|
-
dd-harness politica
|
|
59
|
-
dd-harness buscar "contrato de integração"
|
|
60
|
-
dd-harness ler regras/contrato
|
|
61
|
-
dd-harness gravar memoria.md
|
|
62
|
-
dd-harness editar memoria.md
|
|
63
|
-
dd-harness arquivar regras/contrato --motivo obsoleta
|
|
64
|
-
dd-harness status
|
|
65
|
-
dd-harness skills
|
|
66
|
-
dd-harness roadmap
|
|
67
|
-
dd-harness changelog
|
|
68
|
-
dd-harness --help
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
`check` mede e grava observações de deriva; `status` só consulta.
|
|
72
|
-
O antigo comando `sync` não faz parte do CLI atual.
|
|
73
|
-
`politica --hook` e `cinto` permanecem como compatibilidade legada;
|
|
74
|
-
use `integrar` para instalar `sessao` e `guarda`.
|
|
75
|
-
|
|
76
|
-
## Estado e conflitos
|
|
77
|
-
|
|
78
|
-
- Política/briefing não são materializados. Âncoras/resumos, sessão e manifestos ficam
|
|
79
|
-
em ~/.dd-harness/repos, isolados por caminho/projeto/credencial quando aplicável.
|
|
80
|
-
- DD_HARNESS_HOME permite isolamento explícito em testes. Nunca aponte testes ao estado pessoal.
|
|
81
|
-
- Uma sessão validada expira em quatro horas. Boot, retomada e compactação revalidam.
|
|
82
|
-
Alterações locais de política/briefing via MCP invalidam a sessão; reabra depois de editar.
|
|
83
|
-
Alterações remotas feitas por outro cliente são percebidas no próximo boot/revalidação.
|
|
84
|
-
- Curadoria invalida as âncoras do checkout atual. A próxima edição as consulta novamente.
|
|
85
|
-
- Só ponteiros registrados e intactos são atualizados/removidos. Skills manuais, editadas
|
|
86
|
-
ou redirecionadas por links são preservadas e aparecem como conflitos.
|
|
87
|
-
- Skills marcadas só por comando não são instaladas para descoberta automática em
|
|
88
|
-
.agents; use listar_skills/ler_skill após pedido explícito. Metadados próprios do
|
|
89
|
-
Claude não são prometidos como portáveis.
|
|
90
|
-
- Se há fila e worker local configurado, o boot solicita um lote. O log fica em
|
|
91
|
-
~/.dd-harness/worker.log; solicitar não significa que a indexação concluiu.
|
|
92
|
-
|
|
93
|
-
## Escritas e commits
|
|
94
|
-
|
|
95
|
-
Só GET/HEAD têm retry automático (até três tentativas, timeout por tentativa).
|
|
96
|
-
POST/PATCH/PUT/DELETE não são repetidos. Falha de conexão, 5xx ou resposta incompleta
|
|
97
|
-
em escrita exige consultar o estado antes de tentar novamente.
|
|
98
|
-
|
|
99
|
-
A política entregue exige `[IDENTIFICAÇÃO] - tipo: descrição` nos commits de agentes:
|
|
100
|
-
`[CODEX] - feat: ...`, `[CLAUDE] - fix: ...`, `[GEMINI] - docs: ...`.
|
|
101
|
-
Identifique quem realmente commitou, inclusive ao usar outro editor. A regra não altera
|
|
102
|
-
Git author nem concede autorização de commit/push. É regra de trabalho do agente,
|
|
103
|
-
não inferência automática de identidade nem hook que renomeia commits humanos.
|
|
1
|
+
# dd-harness
|
|
2
|
+
|
|
3
|
+
Política e briefing carregados do serviço; memória consultada por MCP ou CLI.
|
|
4
|
+
A fonte dos artefatos continua no serviço. O cliente mantém configuração, ponteiros
|
|
5
|
+
para skills e estado descartável fora do repositório.
|
|
6
|
+
|
|
7
|
+
Requer Node >=20.3.0. CLI sem dependências de runtime.
|
|
8
|
+
|
|
9
|
+
## Instalação e configuração
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install -g dd-harness@latest
|
|
13
|
+
npx -y dd-harness-mcp@latest --help
|
|
14
|
+
dd-harness start --host todos
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Para um projeto já criado no serviço:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
dd-harness init --tenant meu-espaco --projeto meu-projeto
|
|
21
|
+
dd-harness login --token <token>
|
|
22
|
+
dd-harness integrar --host claude,codex,antigravity
|
|
23
|
+
dd-harness diagnostico --mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`start` usa Claude por padrão. `--host` aceita `claude`, `codex`,
|
|
27
|
+
`antigravity`, uma lista separada por vírgulas ou `todos`.
|
|
28
|
+
`integrar` instala nos três por padrão e preserva configurações alheias.
|
|
29
|
+
O token nasce em /tokens e fica em ~/.dd-harness/credentials.json, por origem de API.
|
|
30
|
+
Para serviço local, use `init --api http://localhost:3000` antes do login.
|
|
31
|
+
|
|
32
|
+
## Hosts
|
|
33
|
+
|
|
34
|
+
| Host | MCP | Boot e guarda | Skills |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| Claude Code | .mcp.json | .claude/settings.json | .claude/skills |
|
|
37
|
+
| Codex | .codex/config.toml | .codex/hooks.json | .agents/skills |
|
|
38
|
+
| Antigravity | .agents/mcp_config.json | .agents/hooks.json | .agents/skills |
|
|
39
|
+
|
|
40
|
+
Codex exige revisão/confiança dos hooks em /hooks. Instalação não comprova ativação.
|
|
41
|
+
Antigravity usa PreInvocation e mensagem efêmera: política e briefing são consultados
|
|
42
|
+
antes de cada inferência. Sua guarda usa `ask` para respeitar concessões já existentes;
|
|
43
|
+
ela pode acrescentar confirmações. Não amplia permissões automaticamente.
|
|
44
|
+
|
|
45
|
+
Sem boot válido, a guarda recusa ferramentas cobertas, inclusive shell. Leitura conhecida
|
|
46
|
+
e onboarding controlado continuam possíveis. Os hooks precisam estar ativos: não são
|
|
47
|
+
sandbox nem controlam ferramentas que o aplicativo não encaminha a eles.
|
|
48
|
+
Após boot válido, shell não tem análise de diff antecipada; avisos por âncora cobrem
|
|
49
|
+
edições estruturadas, patches, remoções e renomeações.
|
|
50
|
+
|
|
51
|
+
Configurações MCP novas levam DD_HARNESS_ROOT explícito. Ao copiar/mover um checkout,
|
|
52
|
+
confira essa raiz com diagnostico. O MCP recusa divergência entre a raiz explícita e
|
|
53
|
+
o projeto identificado no diretório de execução. Corrija a configuração e reinicie o host.
|
|
54
|
+
|
|
55
|
+
## Uso diário
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
dd-harness politica
|
|
59
|
+
dd-harness buscar "contrato de integração"
|
|
60
|
+
dd-harness ler regras/contrato
|
|
61
|
+
dd-harness gravar memoria.md
|
|
62
|
+
dd-harness editar memoria.md
|
|
63
|
+
dd-harness arquivar regras/contrato --motivo obsoleta
|
|
64
|
+
dd-harness status
|
|
65
|
+
dd-harness skills
|
|
66
|
+
dd-harness roadmap
|
|
67
|
+
dd-harness changelog
|
|
68
|
+
dd-harness --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`check` mede e grava observações de deriva; `status` só consulta.
|
|
72
|
+
O antigo comando `sync` não faz parte do CLI atual.
|
|
73
|
+
`politica --hook` e `cinto` permanecem como compatibilidade legada;
|
|
74
|
+
use `integrar` para instalar `sessao` e `guarda`.
|
|
75
|
+
|
|
76
|
+
## Estado e conflitos
|
|
77
|
+
|
|
78
|
+
- Política/briefing não são materializados. Âncoras/resumos, sessão e manifestos ficam
|
|
79
|
+
em ~/.dd-harness/repos, isolados por caminho/projeto/credencial quando aplicável.
|
|
80
|
+
- DD_HARNESS_HOME permite isolamento explícito em testes. Nunca aponte testes ao estado pessoal.
|
|
81
|
+
- Uma sessão validada expira em quatro horas. Boot, retomada e compactação revalidam.
|
|
82
|
+
Alterações locais de política/briefing via MCP invalidam a sessão; reabra depois de editar.
|
|
83
|
+
Alterações remotas feitas por outro cliente são percebidas no próximo boot/revalidação.
|
|
84
|
+
- Curadoria invalida as âncoras do checkout atual. A próxima edição as consulta novamente.
|
|
85
|
+
- Só ponteiros registrados e intactos são atualizados/removidos. Skills manuais, editadas
|
|
86
|
+
ou redirecionadas por links são preservadas e aparecem como conflitos.
|
|
87
|
+
- Skills marcadas só por comando não são instaladas para descoberta automática em
|
|
88
|
+
.agents; use listar_skills/ler_skill após pedido explícito. Metadados próprios do
|
|
89
|
+
Claude não são prometidos como portáveis.
|
|
90
|
+
- Se há fila e worker local configurado, o boot solicita um lote. O log fica em
|
|
91
|
+
~/.dd-harness/worker.log; solicitar não significa que a indexação concluiu.
|
|
92
|
+
|
|
93
|
+
## Escritas e commits
|
|
94
|
+
|
|
95
|
+
Só GET/HEAD têm retry automático (até três tentativas, timeout por tentativa).
|
|
96
|
+
POST/PATCH/PUT/DELETE não são repetidos. Falha de conexão, 5xx ou resposta incompleta
|
|
97
|
+
em escrita exige consultar o estado antes de tentar novamente.
|
|
98
|
+
|
|
99
|
+
A política entregue exige `[IDENTIFICAÇÃO] - tipo: descrição` nos commits de agentes:
|
|
100
|
+
`[CODEX] - feat: ...`, `[CLAUDE] - fix: ...`, `[GEMINI] - docs: ...`.
|
|
101
|
+
Identifique quem realmente commitou, inclusive ao usar outro editor. A regra não altera
|
|
102
|
+
Git author nem concede autorização de commit/push. É regra de trabalho do agente,
|
|
103
|
+
não inferência automática de identidade nem hook que renomeia commits humanos.
|
package/dist/artefato.d.ts
CHANGED
|
@@ -6,24 +6,29 @@
|
|
|
6
6
|
* tenha escrito nela que o CLI existe — e era justamente ela que estava fora de alcance.
|
|
7
7
|
*/
|
|
8
8
|
export type TipoDeArtefato = "politica" | "briefing";
|
|
9
|
+
export declare function artefatoDoPayload(payload: Record<string, unknown>, tipo: TipoDeArtefato): {
|
|
10
|
+
conteudo: string;
|
|
11
|
+
existe: boolean;
|
|
12
|
+
atualizadaEm: string | null;
|
|
13
|
+
};
|
|
9
14
|
/**
|
|
10
15
|
* O `GET` devolve o payload inteiro (politica, briefing, pastas e memorias); aqui so o
|
|
11
16
|
* artefato pedido interessa.
|
|
12
17
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* e a pergunta real.
|
|
18
|
+
* Conteúdo vazio ainda pode ser uma linha existente. A versão é o que distingue esse caso
|
|
19
|
+
* de um artefato que nunca foi criado e define qual precondição a próxima escrita envia.
|
|
16
20
|
*/
|
|
17
21
|
export declare function leArtefato(raiz: string, tipo: TipoDeArtefato): Promise<{
|
|
18
22
|
conteudo: string;
|
|
19
23
|
existe: boolean;
|
|
24
|
+
atualizadaEm: string | null;
|
|
20
25
|
}>;
|
|
21
26
|
/**
|
|
22
27
|
* Substituicao total, nao append: quem quer acrescentar um paragrafo le, concatena e
|
|
23
28
|
* reenvia. Conteudo vazio e valido e significa "apagar" — a linha fica no banco, guardando
|
|
24
29
|
* quem mexeu por ultimo.
|
|
25
30
|
*/
|
|
26
|
-
export declare function escreveArtefato(raiz: string, tipo: TipoDeArtefato, conteudo: string): Promise<{
|
|
31
|
+
export declare function escreveArtefato(raiz: string, tipo: TipoDeArtefato, conteudo: string, atualizadaEm: string | null): Promise<{
|
|
27
32
|
artefato: string;
|
|
28
33
|
criou: boolean;
|
|
29
34
|
tamanho: number;
|
package/dist/artefato.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { jsonDaEscrita, cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
2
2
|
import { invalidaContexto } from "./estado-local.js";
|
|
3
|
+
export function artefatoDoPayload(payload, tipo) {
|
|
4
|
+
const conteudo = typeof payload[tipo] === "string" ? payload[tipo] : "";
|
|
5
|
+
const versoes = payload.artefatos_atualizados_em;
|
|
6
|
+
const atualizadaEm = typeof versoes?.[tipo] === "string" ? versoes[tipo] : null;
|
|
7
|
+
return { conteudo, existe: atualizadaEm !== null || conteudo.length > 0, atualizadaEm };
|
|
8
|
+
}
|
|
3
9
|
/**
|
|
4
10
|
* O `GET` devolve o payload inteiro (politica, briefing, pastas e memorias); aqui so o
|
|
5
11
|
* artefato pedido interessa.
|
|
6
12
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* e a pergunta real.
|
|
13
|
+
* Conteúdo vazio ainda pode ser uma linha existente. A versão é o que distingue esse caso
|
|
14
|
+
* de um artefato que nunca foi criado e define qual precondição a próxima escrita envia.
|
|
10
15
|
*/
|
|
11
16
|
export async function leArtefato(raiz, tipo) {
|
|
12
17
|
const { config, token } = await credencial(raiz);
|
|
@@ -16,20 +21,23 @@ export async function leArtefato(raiz, tipo) {
|
|
|
16
21
|
const resposta = await pede(url, { headers: cabecalhos(token) });
|
|
17
22
|
if (!resposta.ok)
|
|
18
23
|
await recusa(resposta);
|
|
19
|
-
|
|
20
|
-
const conteudo = typeof payload[tipo] === "string" ? payload[tipo] : "";
|
|
21
|
-
return { conteudo, existe: conteudo.length > 0 };
|
|
24
|
+
return artefatoDoPayload((await resposta.json()), tipo);
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Substituicao total, nao append: quem quer acrescentar um paragrafo le, concatena e
|
|
25
28
|
* reenvia. Conteudo vazio e valido e significa "apagar" — a linha fica no banco, guardando
|
|
26
29
|
* quem mexeu por ultimo.
|
|
27
30
|
*/
|
|
28
|
-
export async function escreveArtefato(raiz, tipo, conteudo) {
|
|
31
|
+
export async function escreveArtefato(raiz, tipo, conteudo, atualizadaEm) {
|
|
29
32
|
const { config, token } = await credencial(raiz);
|
|
30
33
|
const resposta = await pede(`${config.api}/api/v1/artefatos`, {
|
|
31
34
|
method: "PUT",
|
|
32
|
-
headers:
|
|
35
|
+
headers: {
|
|
36
|
+
...cabecalhos(token, true),
|
|
37
|
+
...(atualizadaEm
|
|
38
|
+
? { "If-Match": atualizadaEm }
|
|
39
|
+
: { "If-None-Match": "*" }),
|
|
40
|
+
},
|
|
33
41
|
body: JSON.stringify({
|
|
34
42
|
tenant: config.tenant,
|
|
35
43
|
projeto: config.projeto,
|
package/dist/atualizar.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export type Item = {
|
|
|
21
21
|
* maquina, nao por projeto).
|
|
22
22
|
*/
|
|
23
23
|
export declare function diagnosticaAtualizacao(raiz: string, versaoInstalada: string, versaoPublicada: string | null): Promise<Item[]>;
|
|
24
|
+
/** Reescreve em disco os ponteiros das skills que o serviço tem. */
|
|
25
|
+
export declare function reescrevePonteiros(raiz: string): Promise<string>;
|
|
24
26
|
/**
|
|
25
27
|
* Incorpora ao projeto as skills iniciais escolhidas pelo usuario.
|
|
26
28
|
*
|
package/dist/atualizar.js
CHANGED
|
@@ -140,7 +140,7 @@ export async function diagnosticaAtualizacao(raiz, versaoInstalada, versaoPublic
|
|
|
140
140
|
return itens;
|
|
141
141
|
}
|
|
142
142
|
/** Reescreve em disco os ponteiros das skills que o serviço tem. */
|
|
143
|
-
async function reescrevePonteiros(raiz) {
|
|
143
|
+
export async function reescrevePonteiros(raiz) {
|
|
144
144
|
const destinos = [...new Set((await hostsInstalados(raiz))
|
|
145
145
|
.map(h => h === "claude" ? ".claude" : ".agents"))];
|
|
146
146
|
const r = await escrevePonteirosDeSkills(raiz, await leSkills(raiz), destinos.length ? destinos : [".claude"]);
|
package/dist/brain.d.ts
CHANGED
|
@@ -11,21 +11,30 @@ export type Ancora = {
|
|
|
11
11
|
valor: string;
|
|
12
12
|
sha: string | null;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* A memoria como o payload de sessao a entrega — o indice dela, nao o conteudo.
|
|
16
|
+
*
|
|
17
|
+
* Sem `corpo` e sem as tres justificativas de proposito: quem precisa do texto integral
|
|
18
|
+
* busca a memoria individual (`MemoriaDoServico`, em `curar.ts`), e e uma memoria por vez.
|
|
19
|
+
* Aqui vem TODAS as do projeto a cada abertura de sessao, entao cada campo custa
|
|
20
|
+
* multiplicado pelo acervo.
|
|
21
|
+
*/
|
|
14
22
|
export type Memoria = {
|
|
15
23
|
pasta: string;
|
|
16
24
|
slug: string;
|
|
17
25
|
titulo: string;
|
|
18
26
|
resumo: string;
|
|
19
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Sempre `"ativa"` desde que o payload passou a filtrar: as arquivadas viram a contagem
|
|
29
|
+
* `arquivadas` do `Brain`. O campo fica porque o cache local guarda memorias gravadas na
|
|
30
|
+
* propria sessao, e `acrescentaAoCache` decide por ele.
|
|
31
|
+
*/
|
|
20
32
|
status: "ativa" | "historico";
|
|
21
33
|
/**
|
|
22
34
|
* `global` = vale para todo projeto do tenant, inclusive os que ainda nao existem.
|
|
23
35
|
* Ausente em payload antigo, e ai a memoria e de projeto — que era o unico escopo.
|
|
24
36
|
*/
|
|
25
37
|
escopo?: "projeto" | "global";
|
|
26
|
-
dano: string;
|
|
27
|
-
invisibilidade: string;
|
|
28
|
-
externalidade: string;
|
|
29
38
|
ancoras: Ancora[];
|
|
30
39
|
revisar_ate: string | null;
|
|
31
40
|
/** Observacoes de deriva esperando julgamento. Ausente em payload antigo. */
|
|
@@ -48,7 +57,14 @@ export type Brain = {
|
|
|
48
57
|
slug: string;
|
|
49
58
|
definicao: string;
|
|
50
59
|
}[];
|
|
60
|
+
/** So as ativas. As arquivadas nao vem na lista — viram o numero `arquivadas`. */
|
|
51
61
|
memorias: Memoria[];
|
|
62
|
+
/**
|
|
63
|
+
* Quantas memorias arquivadas o projeto tem. Ausente em payload antigo, e ai o `check`
|
|
64
|
+
* cai para o calculo velho (lista inteira menos ativas), que dava o mesmo resultado
|
|
65
|
+
* quando a lista ainda trazia as duas.
|
|
66
|
+
*/
|
|
67
|
+
arquivadas?: number;
|
|
52
68
|
/**
|
|
53
69
|
* Memorias que excederam as tentativas de indexacao e nao serao mais tentadas. Ficam
|
|
54
70
|
* sem embedding — somem da busca semantica — e so este numero denuncia.
|
package/dist/check.js
CHANGED
|
@@ -2,6 +2,7 @@ import { pede } from "./api.js";
|
|
|
2
2
|
import { leConfigDoRepo, leToken } from "./config.js";
|
|
3
3
|
import { caminhosDoCommit, memoriasTocadas, sugereReancoragem, } from "./diff.js";
|
|
4
4
|
import { mede } from "./medir.js";
|
|
5
|
+
import { corpoComCache, leCacheDoPayload } from "./payload-cache.js";
|
|
5
6
|
/** Separado do IO para poder ser testado sem rede: dado um Brain, o que se mede. */
|
|
6
7
|
export async function medeAsAncoras(raiz, brain) {
|
|
7
8
|
const medicoes = [];
|
|
@@ -30,16 +31,27 @@ async function buscaOBrain(raiz) {
|
|
|
30
31
|
throw new Error(`sem credencial para ${config.api}. Rode \`dd-harness login --token <token>\`.`);
|
|
31
32
|
}
|
|
32
33
|
const parametros = `tenant=${encodeURIComponent(config.tenant)}&projeto=${encodeURIComponent(config.projeto)}`;
|
|
34
|
+
// Mesmo ETag do hook de sessao: `check` e `status` leem o mesmo payload, e rodar os dois
|
|
35
|
+
// em sequencia (o que a abertura de sessao faz) nao precisa baixar o acervo duas vezes.
|
|
36
|
+
const cache = await leCacheDoPayload(raiz);
|
|
33
37
|
const resposta = await pede(`${config.api}/api/v1/artefatos?${parametros}`, {
|
|
34
|
-
headers: {
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
40
|
+
...(cache ? { "If-None-Match": cache.etag } : {}),
|
|
41
|
+
},
|
|
35
42
|
});
|
|
36
43
|
if (resposta.status === 401) {
|
|
37
44
|
throw new Error("token recusado. Rode `dd-harness login --token <token>`.");
|
|
38
45
|
}
|
|
39
|
-
|
|
46
|
+
// `304` nao e `ok`, mas e o caminho feliz: o corpo vem do cache logo abaixo.
|
|
47
|
+
if (!resposta.ok && resposta.status !== 304) {
|
|
40
48
|
throw new Error(`a API respondeu ${resposta.status} ao buscar as âncoras.`);
|
|
41
49
|
}
|
|
42
|
-
|
|
50
|
+
const corpo = await corpoComCache(raiz, resposta, cache);
|
|
51
|
+
if (corpo === null) {
|
|
52
|
+
throw new Error("o cache local do payload sumiu; rode de novo.");
|
|
53
|
+
}
|
|
54
|
+
return { config, token, brain: JSON.parse(corpo) };
|
|
43
55
|
}
|
|
44
56
|
/**
|
|
45
57
|
* Somente leitura, de proposito: e o que roda na ABERTURA da sessao. Medir e reportar
|
|
@@ -56,7 +68,9 @@ export async function status(raiz) {
|
|
|
56
68
|
return {
|
|
57
69
|
acervo: {
|
|
58
70
|
ativas: ativas.length,
|
|
59
|
-
|
|
71
|
+
// O servico manda o numero pronto, porque a lista so traz ativas. O `??` cobre
|
|
72
|
+
// servico antigo, cujo payload ainda misturava as duas — ali a subtracao valia.
|
|
73
|
+
arquivadas: brain.arquivadas ?? brain.memorias.length - ativas.length,
|
|
60
74
|
porPasta: [...porPasta]
|
|
61
75
|
.map(([pasta, quantas]) => ({ pasta, quantas }))
|
|
62
76
|
.sort((a, b) => a.pasta.localeCompare(b.pasta)),
|
package/dist/curar.d.ts
CHANGED
|
@@ -20,6 +20,11 @@ export type MemoriaDoServico = {
|
|
|
20
20
|
invisibilidade: string;
|
|
21
21
|
externalidade: string;
|
|
22
22
|
revisar_ate: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* O carimbo de versão que o PATCH exige como `If-Match`. O tipo continua opcional para
|
|
25
|
+
* reconhecer uma leitura de serviço antigo e recusá-la com uma mensagem útil.
|
|
26
|
+
*/
|
|
27
|
+
atualizada_em?: string;
|
|
23
28
|
ancoras: {
|
|
24
29
|
tipo: string;
|
|
25
30
|
valor: string;
|
|
@@ -73,7 +78,7 @@ export declare function promove(raiz: string, endereco: string, global: boolean)
|
|
|
73
78
|
* a memoria dizia pode voltar a importar. Isto e para o que nunca deveria ter existido.
|
|
74
79
|
*
|
|
75
80
|
* Sem `confirmacao`, o servidor RECUSA e devolve o que a cascata levaria junto — e so
|
|
76
|
-
* entao se repete a chamada com
|
|
81
|
+
* entao se repete a chamada com a frase de confirmação devolvida. Duas etapas de proposito: DELETE nao
|
|
77
82
|
* tem desfazer, e a cascata e invisivel de fora.
|
|
78
83
|
*/
|
|
79
84
|
export declare function apaga(raiz: string, endereco: string, confirmacao?: string): Promise<{
|
package/dist/curar.js
CHANGED
|
@@ -30,6 +30,7 @@ export function comoMarkdown(m) {
|
|
|
30
30
|
`titulo: ${m.titulo}`,
|
|
31
31
|
`description: ${m.resumo}`,
|
|
32
32
|
`pasta: ${m.pasta}`,
|
|
33
|
+
...(m.atualizada_em ? [`atualizada-em: ${m.atualizada_em}`] : []),
|
|
33
34
|
...(m.revisar_ate ? [`revisar-ate: ${m.revisar_ate.slice(0, 10)}`] : []),
|
|
34
35
|
// So aparece quando ha vinculo — omitir e "so este projeto", igual a `gravar` sem
|
|
35
36
|
// `projetos:`. Formato inline (`a, b`), que e o que `interpreta` ja sabe ler.
|
|
@@ -53,9 +54,12 @@ export async function edita(raiz, caminho) {
|
|
|
53
54
|
const cru = await readFile(caminho, "utf8");
|
|
54
55
|
const memoria = interpreta(cru);
|
|
55
56
|
const endereco = `${memoria.pasta}/${memoria.slug}`;
|
|
57
|
+
if (!memoria.atualizadaEm) {
|
|
58
|
+
throw new Error("a edição precisa partir de `dd-harness ler`: falta `atualizada-em` no frontmatter.");
|
|
59
|
+
}
|
|
56
60
|
const resposta = await pede(`${config.api}/api/v1/memorias/${endereco}`, {
|
|
57
61
|
method: "PATCH",
|
|
58
|
-
headers: cabecalhos(token, true),
|
|
62
|
+
headers: { ...cabecalhos(token, true), "If-Match": memoria.atualizadaEm },
|
|
59
63
|
body: JSON.stringify({
|
|
60
64
|
tenant: config.tenant,
|
|
61
65
|
projeto: config.projeto,
|
|
@@ -121,7 +125,7 @@ export async function promove(raiz, endereco, global) {
|
|
|
121
125
|
* a memoria dizia pode voltar a importar. Isto e para o que nunca deveria ter existido.
|
|
122
126
|
*
|
|
123
127
|
* Sem `confirmacao`, o servidor RECUSA e devolve o que a cascata levaria junto — e so
|
|
124
|
-
* entao se repete a chamada com
|
|
128
|
+
* entao se repete a chamada com a frase de confirmação devolvida. Duas etapas de proposito: DELETE nao
|
|
125
129
|
* tem desfazer, e a cascata e invisivel de fora.
|
|
126
130
|
*/
|
|
127
131
|
export async function apaga(raiz, endereco, confirmacao) {
|
package/dist/escreve-config.js
CHANGED
|
@@ -140,28 +140,28 @@ export const escreveAgents = (raiz) => escrevePonteiro(raiz, "AGENTS.md");
|
|
|
140
140
|
* em producao compara para saber se precisa de atualizacao.
|
|
141
141
|
*/
|
|
142
142
|
export const VERSAO_DO_MOLDE = "v1.3.0";
|
|
143
|
-
export const SUGESTAO_AGENTS = `## Protocolo do dd-harness
|
|
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
|
-
|
|
155
|
-
Leia também o briefing com a mesma ferramenta (tipo briefing). Os dois são obrigatórios.
|
|
156
|
-
|
|
157
|
-
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
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
|
|
143
|
+
export const SUGESTAO_AGENTS = `## Protocolo do dd-harness
|
|
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
|
+
|
|
155
|
+
Leia também o briefing com a mesma ferramenta (tipo briefing). Os dois são obrigatórios.
|
|
156
|
+
|
|
157
|
+
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
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
|
|
167
167
|
e quando.`;
|
package/dist/gravar.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export type MemoriaLida = {
|
|
|
24
24
|
* vinculo transversal por omissao.
|
|
25
25
|
*/
|
|
26
26
|
tambemEmInformado: boolean;
|
|
27
|
+
atualizadaEm?: string;
|
|
27
28
|
};
|
|
28
29
|
export declare function interpreta(texto: string): MemoriaLida;
|
|
29
30
|
export declare function grava(raiz: string, caminho: string): Promise<{
|
package/dist/gravar.js
CHANGED