dd-harness 0.30.0 → 0.32.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 -64
- package/dist/api.d.ts +2 -0
- package/dist/api.js +29 -25
- package/dist/artefato.js +6 -2
- package/dist/cinto.d.ts +2 -0
- package/dist/cinto.js +29 -10
- package/dist/config.d.ts +4 -0
- package/dist/config.js +35 -6
- package/dist/curar.js +9 -4
- package/dist/diagnostico.d.ts +5 -0
- package/dist/diagnostico.js +92 -0
- package/dist/edicoes.d.ts +15 -0
- package/dist/edicoes.js +52 -0
- package/dist/escreve-config.d.ts +1 -0
- package/dist/escreve-config.js +9 -3
- package/dist/estado-local.d.ts +7 -0
- package/dist/estado-local.js +33 -0
- package/dist/gravar.js +5 -15
- package/dist/hosts.d.ts +6 -0
- package/dist/hosts.js +129 -0
- package/dist/index.js +69 -96
- package/dist/pasta.js +2 -2
- package/dist/politica.js +4 -2
- package/dist/projeto.js +2 -2
- package/dist/regras-de-commit.d.ts +3 -0
- package/dist/regras-de-commit.js +15 -0
- package/dist/roadmap.js +3 -3
- package/dist/sessao.d.ts +5 -0
- package/dist/sessao.js +125 -0
- package/dist/skill.d.ts +7 -9
- package/dist/skill.js +101 -30
- package/dist/versao.d.ts +1 -0
- package/dist/versao.js +18 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +21 -10
- package/package.json +3 -3
package/dist/edicoes.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
const texto = (v) => typeof v === "string" ? v : undefined;
|
|
3
|
+
export function normalizaEntrada(host, entrada) {
|
|
4
|
+
if (host === "antigravity") {
|
|
5
|
+
const roots = entrada.workspacePaths;
|
|
6
|
+
if (!Array.isArray(roots) || roots.length !== 1 || typeof roots[0] !== "string") {
|
|
7
|
+
throw new Error("dd-harness exige um workspace inequívoco por sessão; selecione um projeto.");
|
|
8
|
+
}
|
|
9
|
+
const chamada = entrada.toolCall;
|
|
10
|
+
return { raiz: roots[0], sessao: texto(entrada.conversationId) ?? "", ferramenta: chamada?.name ?? "",
|
|
11
|
+
args: chamada?.args ?? {} };
|
|
12
|
+
}
|
|
13
|
+
return { raiz: texto(entrada.cwd) ?? process.cwd(), sessao: texto(entrada.session_id) ?? "",
|
|
14
|
+
ferramenta: texto(entrada.tool_name) ?? "", args: (entrada.tool_input ?? {}) };
|
|
15
|
+
}
|
|
16
|
+
export function edicoesDaChamada(c) {
|
|
17
|
+
const a = c.args;
|
|
18
|
+
if (c.ferramenta === "apply_patch") {
|
|
19
|
+
const patch = texto(a.command) ?? texto(a.patch) ?? "";
|
|
20
|
+
const edicoes = [];
|
|
21
|
+
let atual;
|
|
22
|
+
for (const linha of patch.split(/\r?\n/)) {
|
|
23
|
+
const inicio = /^\*\*\* (Update|Add|Delete) File: (.+)$/.exec(linha);
|
|
24
|
+
if (inicio) {
|
|
25
|
+
atual = { arquivo: resolve(c.raiz, inicio[2]), antes: inicio[1] === "Delete" ? undefined : "", depois: "" };
|
|
26
|
+
edicoes.push(atual);
|
|
27
|
+
}
|
|
28
|
+
else if (atual && linha.startsWith("*** Move to: ")) {
|
|
29
|
+
// Renomear afeta o arquivo inteiro, inclusive trechos fora dos hunks.
|
|
30
|
+
atual.antes = undefined;
|
|
31
|
+
edicoes.push({ arquivo: resolve(c.raiz, linha.slice(13)), origem: atual.arquivo });
|
|
32
|
+
}
|
|
33
|
+
else if (atual && !linha.startsWith("***")) {
|
|
34
|
+
if (atual.antes !== undefined && (linha.startsWith("-") || linha.startsWith(" ")))
|
|
35
|
+
atual.antes += linha.slice(1) + "\n";
|
|
36
|
+
if (linha.startsWith("+") || linha.startsWith(" "))
|
|
37
|
+
atual.depois += linha.slice(1) + "\n";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return edicoes;
|
|
41
|
+
}
|
|
42
|
+
const arquivo = texto(a.file_path) ?? texto(a.TargetFile) ?? texto(a.Path);
|
|
43
|
+
if (!arquivo)
|
|
44
|
+
return [];
|
|
45
|
+
const chunks = a.ReplacementChunks ?? a.edits;
|
|
46
|
+
if (Array.isArray(chunks))
|
|
47
|
+
return chunks.map(chunk => ({ arquivo: resolve(c.raiz, arquivo),
|
|
48
|
+
antes: texto(chunk.TargetContent ?? chunk.old_string), depois: texto(chunk.ReplacementContent ?? chunk.new_string) }));
|
|
49
|
+
return [{ arquivo: resolve(c.raiz, arquivo),
|
|
50
|
+
antes: texto(a.old_string) ?? texto(a.TargetContent),
|
|
51
|
+
depois: texto(a.new_string) ?? texto(a.content) ?? texto(a.ReplacementContent) ?? texto(a.CodeContent) }];
|
|
52
|
+
}
|
package/dist/escreve-config.d.ts
CHANGED
|
@@ -50,3 +50,4 @@ export declare function escrevePonteiro(raiz: string, arquivo: "AGENTS.md" | "CL
|
|
|
50
50
|
export declare const escreveAgents: (raiz: string) => Promise<{
|
|
51
51
|
estado: "criado" | "ja-tinha" | "acrescentado";
|
|
52
52
|
}>;
|
|
53
|
+
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
|
@@ -112,7 +112,7 @@ export async function escrevePonteiro(raiz, arquivo) {
|
|
|
112
112
|
}
|
|
113
113
|
/** Compatibilidade: `init` ainda chama pelo nome antigo. */
|
|
114
114
|
export const escreveAgents = (raiz) => escrevePonteiro(raiz, "AGENTS.md");
|
|
115
|
-
const SUGESTAO_AGENTS = `## Protocolo do dd-harness
|
|
115
|
+
export const SUGESTAO_AGENTS = `## Protocolo do dd-harness
|
|
116
116
|
|
|
117
117
|
Este projeto tem um protocolo de trabalho que **não está neste arquivo**.
|
|
118
118
|
|
|
@@ -124,10 +124,16 @@ de ler código, responder ou planejar.
|
|
|
124
124
|
avise o usuário e **não modifique nada** até ele resolver.
|
|
125
125
|
- Se ela devolver vazio, este projeto nunca foi briefado — diga isso ao usuário.
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Leia também o briefing com a mesma ferramenta (tipo briefing). Os dois são obrigatórios.
|
|
128
|
+
|
|
129
|
+
Depois, \`ler_roadmap\`: se houver uma fase **Agora**, é dela que saem os passos
|
|
128
130
|
desta sessão. Lista vazia significa que este projeto não usa roadmap, e isso é
|
|
129
131
|
válido — não crie fase sem o usuário pedir.
|
|
130
132
|
|
|
131
133
|
E \`listar_skills\`: são os procedimentos deste projeto. **Invoque a que couber
|
|
132
134
|
ANTES de fazer o trabalho, não depois** — skill lida no fim vira revisão do que
|
|
133
|
-
já saiu errado
|
|
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
|
|
139
|
+
e quando.`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Override explícito para testes e instalações isoladas; nunca troca HOME do processo. */
|
|
2
|
+
export declare const diretorioDoUsuario: () => string;
|
|
3
|
+
export declare function estadoDoRepo(raiz: string): string;
|
|
4
|
+
export declare function revisaoDoContexto(raiz: string): Promise<string>;
|
|
5
|
+
export declare function invalidaContexto(raiz: string): Promise<void>;
|
|
6
|
+
/** Leitores veem o JSON anterior ou o novo, nunca um arquivo parcialmente escrito. */
|
|
7
|
+
export declare function escreveAtomico(caminho: string, conteudo: string): Promise<void>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, rename, writeFile, rm, readFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
/** Override explícito para testes e instalações isoladas; nunca troca HOME do processo. */
|
|
6
|
+
export const diretorioDoUsuario = () => process.env.DD_HARNESS_HOME ?? join(homedir(), ".dd-harness");
|
|
7
|
+
export function estadoDoRepo(raiz) {
|
|
8
|
+
const caminho = resolve(raiz);
|
|
9
|
+
const chave = createHash("sha256").update(process.platform === "win32" ? caminho.toLowerCase() : caminho).digest("hex");
|
|
10
|
+
return join(diretorioDoUsuario(), "repos", chave);
|
|
11
|
+
}
|
|
12
|
+
export async function revisaoDoContexto(raiz) {
|
|
13
|
+
return readFile(join(estadoDoRepo(raiz), "contexto-revisao"), "utf8").catch((e) => {
|
|
14
|
+
if (e.code === "ENOENT")
|
|
15
|
+
return "";
|
|
16
|
+
throw e;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export async function invalidaContexto(raiz) {
|
|
20
|
+
await escreveAtomico(join(estadoDoRepo(raiz), "contexto-revisao"), randomUUID());
|
|
21
|
+
}
|
|
22
|
+
/** Leitores veem o JSON anterior ou o novo, nunca um arquivo parcialmente escrito. */
|
|
23
|
+
export async function escreveAtomico(caminho, conteudo) {
|
|
24
|
+
await mkdir(dirname(caminho), { recursive: true });
|
|
25
|
+
const temporario = `${caminho}.${randomUUID()}.tmp`;
|
|
26
|
+
try {
|
|
27
|
+
await writeFile(temporario, conteudo, { encoding: "utf8", mode: 0o600 });
|
|
28
|
+
await rename(temporario, caminho);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
await rm(temporario, { force: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/gravar.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { invalidaCache } from "./cinto.js";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { recusaPorAcentuacao } from "./acentuacao.js";
|
|
3
|
-
import { cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
4
|
-
import { acrescentaAoCache } from "./cinto.js";
|
|
4
|
+
import { jsonDaEscrita, cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
5
5
|
const OBRIGATORIOS = ["name", "titulo", "description", "pasta"];
|
|
6
6
|
/**
|
|
7
7
|
* Frontmatter simples: `chave: valor` por linha. Sem lib de YAML — nao ha aninhamento.
|
|
@@ -188,19 +188,9 @@ export async function grava(raiz, caminho) {
|
|
|
188
188
|
});
|
|
189
189
|
if (!resposta.ok)
|
|
190
190
|
await recusa(resposta);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
//
|
|
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
|
+
await invalidaCache(raiz);
|
|
192
|
+
const { endereco } = (await jsonDaEscrita(resposta));
|
|
193
|
+
// A próxima edição atualiza o cache inteiro, incluindo outras memórias e globais.
|
|
204
194
|
return {
|
|
205
195
|
endereco,
|
|
206
196
|
ancoras: memoria.ancoras.length,
|
package/dist/hosts.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Host } from "./edicoes.js";
|
|
2
|
+
export declare const HOSTS: Host[];
|
|
3
|
+
export declare function selecionaHosts(valor?: string): Host[];
|
|
4
|
+
export declare function hostsInstalados(raiz: string): Promise<Host[]>;
|
|
5
|
+
/** Cada host usa seu formato. Configuração alheia não é inferida como gerenciada. */
|
|
6
|
+
export declare function instalaHosts(raiz: string, hosts: Host[]): Promise<string[]>;
|
package/dist/hosts.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { readFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { escreveAtomico, estadoDoRepo } from "./estado-local.js";
|
|
4
|
+
import { escrevePonteiro, SUGESTAO_AGENTS } from "./escreve-config.js";
|
|
5
|
+
export const HOSTS = ["claude", "codex", "antigravity"];
|
|
6
|
+
export function selecionaHosts(valor = "claude") {
|
|
7
|
+
const nomes = valor === "todos" ? HOSTS : valor.split(",");
|
|
8
|
+
if (nomes.some(n => !HOSTS.includes(n)))
|
|
9
|
+
throw new Error("host: use claude, codex, antigravity ou todos");
|
|
10
|
+
return [...new Set(nomes)];
|
|
11
|
+
}
|
|
12
|
+
export async function hostsInstalados(raiz) {
|
|
13
|
+
try {
|
|
14
|
+
return selecionaHosts(JSON.parse(await readFile(join(estadoDoRepo(raiz), "hosts.json"), "utf8")).join(","));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function objeto(v) {
|
|
21
|
+
if (v === undefined)
|
|
22
|
+
return {};
|
|
23
|
+
if (!v || typeof v !== "object" || Array.isArray(v))
|
|
24
|
+
throw new Error("estrutura de configuração inválida");
|
|
25
|
+
return v;
|
|
26
|
+
}
|
|
27
|
+
async function json(caminho, altera) {
|
|
28
|
+
const atual = await readFile(caminho, "utf8").catch((e) => {
|
|
29
|
+
if (e.code === "ENOENT")
|
|
30
|
+
return "{}";
|
|
31
|
+
throw e;
|
|
32
|
+
});
|
|
33
|
+
const doc = objeto(JSON.parse(atual));
|
|
34
|
+
altera(doc);
|
|
35
|
+
const novo = JSON.stringify(doc, null, 2) + "\n";
|
|
36
|
+
if (atual !== novo)
|
|
37
|
+
await escreveAtomico(caminho, novo);
|
|
38
|
+
}
|
|
39
|
+
function grupo(doc, evento, command, antigos = []) {
|
|
40
|
+
const grupos = doc[evento] ?? [];
|
|
41
|
+
if (!Array.isArray(grupos))
|
|
42
|
+
throw new Error(`hooks.${evento} precisa ser lista`);
|
|
43
|
+
const preservados = grupos.map(g => {
|
|
44
|
+
if (!g || typeof g !== "object" || !Array.isArray(g.hooks))
|
|
45
|
+
throw new Error(`hook ${evento} inválido`);
|
|
46
|
+
return { ...g, hooks: g.hooks.filter((h) => ![command, ...antigos].includes(h.command ?? "")) };
|
|
47
|
+
}).filter(g => g.hooks.length);
|
|
48
|
+
preservados.push({ hooks: [{ type: "command", command, timeout: 60 }] });
|
|
49
|
+
doc[evento] = preservados;
|
|
50
|
+
}
|
|
51
|
+
/** Cada host usa seu formato. Configuração alheia não é inferida como gerenciada. */
|
|
52
|
+
export async function instalaHosts(raiz, hosts) {
|
|
53
|
+
raiz = resolve(raiz);
|
|
54
|
+
const avisos = [];
|
|
55
|
+
const mcp = { command: "npx", args: ["-y", "dd-harness-mcp@latest"], env: { DD_HARNESS_ROOT: raiz } };
|
|
56
|
+
for (const host of hosts) {
|
|
57
|
+
if (host === "codex") {
|
|
58
|
+
const caminho = join(raiz, ".codex", "config.toml");
|
|
59
|
+
const atual = await readFile(caminho, "utf8").catch((e) => {
|
|
60
|
+
if (e.code === "ENOENT")
|
|
61
|
+
return "";
|
|
62
|
+
throw e;
|
|
63
|
+
});
|
|
64
|
+
if (atual.includes("dd-harness")) {
|
|
65
|
+
avisos.push("Codex: servidor já configurado; preservado. Confira command e DD_HARNESS_ROOT com diagnostico.");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
await escreveAtomico(caminho, atual + `\n[mcp_servers.dd-harness]\ncommand = "npx"\nargs = ["-y", "dd-harness-mcp@latest"]\nstartup_timeout_sec = 60\n[mcp_servers.dd-harness.env]\nDD_HARNESS_ROOT = ${JSON.stringify(raiz)}\n`);
|
|
69
|
+
}
|
|
70
|
+
await json(join(raiz, ".codex", "hooks.json"), doc => {
|
|
71
|
+
const h = objeto(doc.hooks);
|
|
72
|
+
doc.hooks = h;
|
|
73
|
+
grupo(h, "SessionStart", "dd-harness sessao --host codex");
|
|
74
|
+
grupo(h, "PreToolUse", "dd-harness guarda --host codex");
|
|
75
|
+
});
|
|
76
|
+
avisos.push("Codex: abra /hooks e confira a confiança dos hooks; arquivos instalados não comprovam ativação.");
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
await json(join(raiz, host === "claude" ? ".mcp.json" : ".agents/mcp_config.json"), doc => {
|
|
80
|
+
const servidores = objeto(doc.mcpServers);
|
|
81
|
+
doc.mcpServers = servidores;
|
|
82
|
+
if (servidores["dd-harness"])
|
|
83
|
+
avisos.push(`${host}: MCP existente preservado; confira a raiz no diagnóstico.`);
|
|
84
|
+
else
|
|
85
|
+
servidores["dd-harness"] = mcp;
|
|
86
|
+
});
|
|
87
|
+
if (host === "claude") {
|
|
88
|
+
await json(join(raiz, ".claude/settings.json"), doc => {
|
|
89
|
+
const h = objeto(doc.hooks);
|
|
90
|
+
doc.hooks = h;
|
|
91
|
+
grupo(h, "SessionStart", "dd-harness sessao --host claude", ["dd-harness politica --hook"]);
|
|
92
|
+
grupo(h, "PreToolUse", "dd-harness guarda --host claude", ["dd-harness cinto"]);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
await json(join(raiz, ".agents/hooks.json"), doc => {
|
|
97
|
+
const bloco = objeto(doc["dd-harness"]);
|
|
98
|
+
const handlers = bloco.PreInvocation ?? [];
|
|
99
|
+
if (!Array.isArray(handlers))
|
|
100
|
+
throw new Error("PreInvocation precisa ser lista; configuração preservada");
|
|
101
|
+
const comando = "dd-harness sessao --host antigravity";
|
|
102
|
+
if (doc["dd-harness"] && !handlers.some(h => h?.command === comando)) {
|
|
103
|
+
throw new Error("hook dd-harness já existe com conteúdo alheio; preservado");
|
|
104
|
+
}
|
|
105
|
+
bloco.PreInvocation = [...handlers.filter(h => h?.command !== comando), { type: "command", command: comando, timeout: 60 }];
|
|
106
|
+
grupo(bloco, "PreToolUse", "dd-harness guarda --host antigravity");
|
|
107
|
+
doc["dd-harness"] = bloco;
|
|
108
|
+
});
|
|
109
|
+
const regra = join(raiz, ".agents/rules/dd-harness.md");
|
|
110
|
+
const atual = await readFile(regra, "utf8").catch((e) => {
|
|
111
|
+
if (e.code === "ENOENT")
|
|
112
|
+
return null;
|
|
113
|
+
throw e;
|
|
114
|
+
});
|
|
115
|
+
const conteudo = "---\ntrigger: always_on\n---\n\n" + SUGESTAO_AGENTS;
|
|
116
|
+
if (atual === null)
|
|
117
|
+
await escreveAtomico(regra, conteudo);
|
|
118
|
+
else if (atual !== conteudo)
|
|
119
|
+
avisos.push("Antigravity: regra local existente preservada; revise a entrada de protocolo.");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
await mkdir(dirname(join(raiz, "AGENTS.md")), { recursive: true });
|
|
124
|
+
await escrevePonteiro(raiz, "AGENTS.md");
|
|
125
|
+
if (hosts.includes("claude"))
|
|
126
|
+
await escrevePonteiro(raiz, "CLAUDE.md");
|
|
127
|
+
await escreveAtomico(join(estadoDoRepo(raiz), "hosts.json"), JSON.stringify([...new Set([...await hostsInstalados(raiz), ...hosts])]));
|
|
128
|
+
return avisos;
|
|
129
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { diagnostico } from "./diagnostico.js";
|
|
3
|
+
import { instalaHosts, selecionaHosts } from "./hosts.js";
|
|
4
|
+
import { achaRaiz } from "./config.js";
|
|
5
|
+
import { abreSessao, guardaSessao, saidaDaGuarda, saidaDoBoot } from "./sessao.js";
|
|
2
6
|
import { spawn } from "node:child_process";
|
|
3
7
|
import { access, readFile } from "node:fs/promises";
|
|
4
|
-
import { join } from "node:path";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
const DIRETORIO_DA_INVOCACAO = process.cwd();
|
|
5
10
|
// DEP0190: Node imprime esse warning direto no stderr no instante em que
|
|
6
11
|
// `spawn(..., { shell: true })` recebe um array de args — de forma sincrona, ANTES de
|
|
7
12
|
// qualquer listener rodar, entao filtrar dentro de um `process.on("warning")` normal nao
|
|
@@ -14,10 +19,9 @@ process.removeAllListeners("warning");
|
|
|
14
19
|
import { termosDaConsulta } from "./argv.js";
|
|
15
20
|
import { check, status } from "./check.js";
|
|
16
21
|
import { CAMINHO_CONFIG, guardaConfigDaMaquina, guardaToken, leConfigDaMaquina, leConfigDoRepo, leToken, } from "./config.js";
|
|
17
|
-
import { escreveHook, escreveMcp, escrevePonteiro } from "./escreve-config.js";
|
|
18
22
|
import { escreveGanchoDeCommit, iniciaRepositorio } from "./git.js";
|
|
19
23
|
import { grava } from "./gravar.js";
|
|
20
|
-
import { init
|
|
24
|
+
import { init } from "./init.js";
|
|
21
25
|
import { pergunta, escolha, fechaPerguntas } from "./pergunta.js";
|
|
22
26
|
import { buscaPolitica } from "./politica.js";
|
|
23
27
|
import { avisoDeOrdem, blocoDeSessao, criaFase, editaFase, formataChangelog, formataRoadmap, leFases, } from "./roadmap.js";
|
|
@@ -30,8 +34,9 @@ import { criaPasta } from "./pasta.js";
|
|
|
30
34
|
import { criaProjeto, listaTenants } from "./projeto.js";
|
|
31
35
|
import { reancora } from "./reancorar.js";
|
|
32
36
|
import { subiuOWorker } from "./worker.js";
|
|
37
|
+
import { REGRA_DE_COMMITS } from "./regras-de-commit.js";
|
|
33
38
|
/**
|
|
34
|
-
* `dd-harness` — o cliente
|
|
39
|
+
* `dd-harness` — o cliente de política, memória e integrações de hosts.
|
|
35
40
|
*
|
|
36
41
|
* Sem dependencia de proposito: `fetch`, `crypto` e `fs` sao do Node, e o molde original
|
|
37
42
|
* ja seguia a regra de validador determinístico sem dependencia. Um CLI que vive pinado
|
|
@@ -40,14 +45,18 @@ import { subiuOWorker } from "./worker.js";
|
|
|
40
45
|
*/
|
|
41
46
|
const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
|
|
42
47
|
|
|
43
|
-
dd-harness
|
|
48
|
+
dd-harness diagnostico [--mcp] confere projeto, contexto e conexão MCP
|
|
49
|
+
dd-harness integrar --host todos instala MCP/regras/hooks em projeto existente
|
|
50
|
+
dd-harness sessao --host <host> hook de boot (stdin JSON)
|
|
51
|
+
dd-harness guarda --host <host> hook antes de ferramentas (stdin JSON)
|
|
52
|
+
dd-harness start [--host <host>] numa pasta vazia: conduz tudo (login,
|
|
44
53
|
espaço, projeto, config) numa tacada
|
|
45
54
|
dd-harness login --token <token> [--api <url>]
|
|
46
55
|
guarda a credencial desta máquina
|
|
47
56
|
dd-harness projeto <slug> --nome "<nome>" [--tenant <t>] [--api <url>]
|
|
48
57
|
cria o projeto no serviço (antes do init)
|
|
49
58
|
dd-harness init --tenant <t> --projeto <p> [--api <url>]
|
|
50
|
-
|
|
59
|
+
escreve .dd-harness.json; depois rode integrar
|
|
51
60
|
dd-harness pasta <slug> --definicao "o que entra e o que não entra"
|
|
52
61
|
cria a pasta que o gravar exige
|
|
53
62
|
dd-harness gravar <arquivo.md> registra uma memória a partir de um markdown
|
|
@@ -94,8 +103,9 @@ const AJUDA = `dd-harness — a política e o Brain do projeto, no serviço
|
|
|
94
103
|
dd-harness --help
|
|
95
104
|
dd-harness --version qual binário está instalado nesta máquina
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
Política e briefing chegam do serviço. O disco guarda configuração, ponteiros
|
|
107
|
+
para skills e estado descartável em ~/.dd-harness. Hosts: claude, codex,
|
|
108
|
+
antigravity, lista separada por vírgulas ou todos.
|
|
99
109
|
`;
|
|
100
110
|
/**
|
|
101
111
|
* Os ganchos sao IMPRESSOS, nunca instalados. `.git/hooks` nao e versionado e nao e
|
|
@@ -111,8 +121,7 @@ Opcional — o gancho que devolve a memória ao code review:
|
|
|
111
121
|
|
|
112
122
|
Termina em sucesso mesmo com deriva: avisa, não bloqueia.
|
|
113
123
|
|
|
114
|
-
|
|
115
|
-
opcional — \`dd-harness init\` imprime a linha para o \`.claude/settings.json\`.`;
|
|
124
|
+
Instale os hooks de sessão e guarda com \`dd-harness integrar --host <host>\`.`;
|
|
116
125
|
function argumento(argv, nome) {
|
|
117
126
|
const i = argv.indexOf(`--${nome}`);
|
|
118
127
|
return i >= 0 ? argv[i + 1] : undefined;
|
|
@@ -173,7 +182,7 @@ function statusDoArgv(argv) {
|
|
|
173
182
|
/** `--conteudo` aponta para um .md, como `gravar` e `editar` — markdown de verdade nao cabe em flag. */
|
|
174
183
|
async function conteudoDoArgv(argv) {
|
|
175
184
|
const caminho = argumento(argv, "conteudo");
|
|
176
|
-
return caminho === undefined ? undefined : readFile(caminho, "utf8");
|
|
185
|
+
return caminho === undefined ? undefined : readFile(resolve(DIRETORIO_DA_INVOCACAO, caminho), "utf8");
|
|
177
186
|
}
|
|
178
187
|
/**
|
|
179
188
|
* `fase criar` e `fase editar`. Concluir uma fase e `fase editar <slug> --status concluida`
|
|
@@ -338,7 +347,8 @@ function mascara(token) {
|
|
|
338
347
|
* tomada de proposito aqui, ao contrario de `init`, que continua so sugerindo. O preco e
|
|
339
348
|
* o merge cuidadoso em `escreve-config.ts`: nunca perder o que a pessoa ja tinha.
|
|
340
349
|
*/
|
|
341
|
-
async function comandoStart() {
|
|
350
|
+
async function comandoStart(argv) {
|
|
351
|
+
const hosts = selecionaHosts(argumento(argv, "host"));
|
|
342
352
|
const caminhoConfig = join(process.cwd(), CAMINHO_CONFIG);
|
|
343
353
|
try {
|
|
344
354
|
await access(caminhoConfig);
|
|
@@ -452,54 +462,13 @@ async function comandoStart() {
|
|
|
452
462
|
// 4. Config do repositorio — o unico arquivo que `init` tambem escreveria.
|
|
453
463
|
const r = await init(process.cwd(), { tenant, projeto: resultadoProjeto.projeto, api: API_PADRAO });
|
|
454
464
|
console.log(r.config === "criada" ? `criado ${CAMINHO_CONFIG}` : `mantido ${CAMINHO_CONFIG}`);
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
console.log(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
else {
|
|
463
|
-
console.log({ criado: "criado .claude/settings.json (hook adicionado)",
|
|
464
|
-
"ja-tinha": "mantido .claude/settings.json — hook já estava lá",
|
|
465
|
-
acrescentado: "atualizado .claude/settings.json (hook adicionado ao que já existia)",
|
|
466
|
-
}[hook.estado]);
|
|
467
|
-
}
|
|
468
|
-
const mcp = await escreveMcp(process.cwd());
|
|
469
|
-
if (!mcp.ok) {
|
|
470
|
-
console.log(`\nAVISO: ${mcp.caminho} não é um JSON válido — não toquei nele. ` +
|
|
471
|
-
"Acrescente manualmente:\n");
|
|
472
|
-
console.log(SUGESTAO_MCP);
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
475
|
-
console.log({ criado: "criado .mcp.json (servidor dd-harness adicionado)",
|
|
476
|
-
"ja-tinha": "mantido .mcp.json — servidor já estava declarado",
|
|
477
|
-
acrescentado: "atualizado .mcp.json (servidor adicionado ao que já existia)",
|
|
478
|
-
}[mcp.estado]);
|
|
479
|
-
}
|
|
480
|
-
if (mcp.ok) {
|
|
481
|
-
console.log("\nInstalando a versão mais recente do servidor dd-harness-mcp " +
|
|
482
|
-
"(a primeira vez pode demorar um pouco)...");
|
|
483
|
-
const { ok: instalou, erro: erroInstalacao } = await instalaMcp();
|
|
484
|
-
console.log(instalou
|
|
485
|
-
? "dd-harness-mcp instalado — a próxima sessão do Claude Code conecta na hora."
|
|
486
|
-
: `AVISO: não consegui pré-instalar dd-harness-mcp (${erroInstalacao}). A primeira ` +
|
|
487
|
-
"conexão do Claude Code pode demorar ou falhar; se falhar, abra uma nova sessão " +
|
|
488
|
-
"e tente de novo.");
|
|
489
|
-
}
|
|
490
|
-
// 6. CLAUDE.md e AGENTS.md — os dois SEMPRE, sem perguntar. Sao espelhos: o mesmo
|
|
491
|
-
// apontamento para o servico, cada um na porta que uma familia de ferramenta le. A
|
|
492
|
-
// pergunta "usa outra ferramenta?" saiu porque a resposta nao muda nada que valha a
|
|
493
|
-
// pena — quem responde "nao" hoje abre o repositorio no Cursor semana que vem e nao
|
|
494
|
-
// encontra protocolo nenhum, e o custo de ja ter o arquivo e um ponteiro de 8 linhas.
|
|
495
|
-
console.log("");
|
|
496
|
-
for (const arquivo of ["CLAUDE.md", "AGENTS.md"]) {
|
|
497
|
-
const r = await escrevePonteiro(process.cwd(), arquivo);
|
|
498
|
-
console.log({ criado: `criado ${arquivo}`,
|
|
499
|
-
"ja-tinha": `mantido ${arquivo} — já apontava para a política`,
|
|
500
|
-
acrescentado: `atualizado ${arquivo} (apontamento acrescentado ao que já existia)`,
|
|
501
|
-
}[r.estado]);
|
|
502
|
-
}
|
|
465
|
+
const avisos = await instalaHosts(process.cwd(), hosts);
|
|
466
|
+
console.log('Integrações instaladas: ' + hosts.join(', '));
|
|
467
|
+
for (const aviso of avisos)
|
|
468
|
+
console.log('AVISO: ' + aviso);
|
|
469
|
+
const instalacao = await instalaMcp();
|
|
470
|
+
if (!instalacao.ok)
|
|
471
|
+
console.log('AVISO: MCP não pré-instalado; execute diagnostico antes de usar.');
|
|
503
472
|
// 6.5. Os ponteiros das skills do projeto.
|
|
504
473
|
//
|
|
505
474
|
// O Claude Code descobre skill lendo `.claude/skills/*/SKILL.md` na ABERTURA da sessao,
|
|
@@ -518,7 +487,9 @@ async function comandoStart() {
|
|
|
518
487
|
}
|
|
519
488
|
const skills = await leSkills(process.cwd());
|
|
520
489
|
if (skills.length > 0) {
|
|
521
|
-
const { escritos } = await escrevePonteirosDeSkills(process.cwd(), skills);
|
|
490
|
+
const { escritos, conflitos } = await escrevePonteirosDeSkills(process.cwd(), skills, hosts.map(h => h === "claude" ? ".claude" : ".agents"));
|
|
491
|
+
if (conflitos.length)
|
|
492
|
+
console.log("Ponteiros preservados por conflito: " + conflitos.join(", "));
|
|
522
493
|
console.log(escritos > 0
|
|
523
494
|
? `escritos ${escritos} ponteiro(s) de skill em .claude/skills/`
|
|
524
495
|
: `${skills.length} skill(s) — ponteiros já estavam em dia`);
|
|
@@ -558,38 +529,7 @@ async function comandoInit(argv) {
|
|
|
558
529
|
});
|
|
559
530
|
console.log(r.config === "criada" ? "criado .dd-harness.json" : "mantido .dd-harness.json");
|
|
560
531
|
console.log("\nAgora: dd-harness login --token <token>");
|
|
561
|
-
|
|
562
|
-
// falha que este projeto existe para combater. O MCP e conveniencia; este, nao.
|
|
563
|
-
if (r.hook === "ja-declarado") {
|
|
564
|
-
console.log("\nmantido .claude/settings.json — o hook da política já está declarado");
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
console.log("\nOBRIGATÓRIO: o hook que carrega a política no início de cada sessão." +
|
|
568
|
-
"\nSem ele a sessão abre sem protocolo, e nada avisa. Acrescente ao" +
|
|
569
|
-
"\n`.claude/settings.json` (não escrevo nele: o arquivo é seu e pode já" +
|
|
570
|
-
"\nter hooks e permissões):\n");
|
|
571
|
-
console.log(SUGESTAO_HOOK);
|
|
572
|
-
}
|
|
573
|
-
if (r.mcp === "ja-declarado") {
|
|
574
|
-
console.log("\nmantido .mcp.json — o servidor dd-harness já está declarado");
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
console.log("\nOpcional: as memórias como ferramenta, para o agente buscar e gravar sem" +
|
|
578
|
-
"\nescrever arquivo. Acrescente ao `.mcp.json` da raiz (não escrevo nele: o" +
|
|
579
|
-
"\narquivo é seu e pode declarar outros servidores):\n");
|
|
580
|
-
console.log(SUGESTAO_MCP);
|
|
581
|
-
}
|
|
582
|
-
// Fora do Claude Code o hook nao roda, e ai o MCP deixa de ser conveniencia: e o unico
|
|
583
|
-
// caminho da politica. Mas ferramenta disponivel nao e ferramenta chamada — sem esta
|
|
584
|
-
// instrucao, o agente pode nunca perguntar.
|
|
585
|
-
if (r.agents === "ja-aponta") {
|
|
586
|
-
console.log("\nmantido AGENTS.md — já manda buscar a política pelo MCP");
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
console.log("\nUsa Codex, Cursor, Gemini CLI ou Windsurf? Eles NÃO rodam o hook do" +
|
|
590
|
-
"\nClaude Code, e sem isto a sessão abre sem política. Crie um `AGENTS.md`" +
|
|
591
|
-
"\nna raiz (ou acrescente ao seu) com:\n");
|
|
592
|
-
console.log(SUGESTAO_AGENTS);
|
|
532
|
+
console.log("\nConfigure MCP, hooks e ponteiros: dd-harness integrar --host claude,codex,antigravity");
|
|
593
533
|
}
|
|
594
534
|
/**
|
|
595
535
|
* Nao exige `.dd-harness.json`, e isso importa: sem projeto no servico o `init` nao tem o
|
|
@@ -612,7 +552,7 @@ async function comandoEditar(argv) {
|
|
|
612
552
|
if (!caminho || caminho.startsWith("-")) {
|
|
613
553
|
throw new Error("uso: dd-harness editar <arquivo.md>");
|
|
614
554
|
}
|
|
615
|
-
const r = await edita(process.cwd(), caminho);
|
|
555
|
+
const r = await edita(process.cwd(), resolve(DIRETORIO_DA_INVOCACAO, caminho));
|
|
616
556
|
console.log(`editado ${r.endereco}`);
|
|
617
557
|
console.log(` ${r.ancoras} âncora(s).`);
|
|
618
558
|
}
|
|
@@ -993,6 +933,7 @@ function contextoDaSessao(r, worker) {
|
|
|
993
933
|
"`reset --hard`, reescrever história publicada. Ficam fora por padrão.\n" +
|
|
994
934
|
" Escreva cada resposta como regra. \"Ele sabe o que pode\" não sobrevive à " +
|
|
995
935
|
"próxima sessão, que começa sem memória disto.\n" +
|
|
936
|
+
" Inclua também esta convenção nos commits:\n" + REGRA_DE_COMMITS + "\n\n" +
|
|
996
937
|
"4. Mostre o rascunho da política e do briefing e espere a confirmação " +
|
|
997
938
|
"explícita do usuário antes de escrever.\n" +
|
|
998
939
|
"5. Escreva os dois com a ferramenta MCP `escrever_artefato` " +
|
|
@@ -1164,7 +1105,7 @@ async function comandoGravar(argv) {
|
|
|
1164
1105
|
if (!caminho || caminho.startsWith("-")) {
|
|
1165
1106
|
throw new Error("uso: dd-harness gravar <arquivo.md>");
|
|
1166
1107
|
}
|
|
1167
|
-
const r = await grava(process.cwd(), caminho);
|
|
1108
|
+
const r = await grava(process.cwd(), resolve(DIRETORIO_DA_INVOCACAO, caminho));
|
|
1168
1109
|
console.log(`gravado ${r.endereco}`);
|
|
1169
1110
|
console.log(` ${r.ancoras} âncora(s), valendo para ${r.projetos} projeto(s).`);
|
|
1170
1111
|
}
|
|
@@ -1199,9 +1140,12 @@ async function principal() {
|
|
|
1199
1140
|
console.log(AJUDA);
|
|
1200
1141
|
return;
|
|
1201
1142
|
}
|
|
1143
|
+
if (comando && !["start", "init", "login", "projeto", "sessao", "guarda", "--help", "-h", "--version", "-V", "version"].includes(comando)) {
|
|
1144
|
+
process.chdir(await achaRaiz());
|
|
1145
|
+
}
|
|
1202
1146
|
switch (comando) {
|
|
1203
1147
|
case "start":
|
|
1204
|
-
return comandoStart();
|
|
1148
|
+
return comandoStart(resto);
|
|
1205
1149
|
case "init":
|
|
1206
1150
|
return comandoInit(resto);
|
|
1207
1151
|
case "login":
|
|
@@ -1232,6 +1176,35 @@ async function principal() {
|
|
|
1232
1176
|
return comandoCheck(resto);
|
|
1233
1177
|
case "status":
|
|
1234
1178
|
return comandoStatus();
|
|
1179
|
+
case "diagnostico":
|
|
1180
|
+
console.log((await diagnostico(process.cwd(), resto.includes("--mcp"))).join("\n"));
|
|
1181
|
+
break;
|
|
1182
|
+
case "integrar": {
|
|
1183
|
+
const hosts = selecionaHosts(argumento(resto, "host") ?? "todos");
|
|
1184
|
+
for (const aviso of await instalaHosts(process.cwd(), hosts))
|
|
1185
|
+
console.log(aviso);
|
|
1186
|
+
console.log("Integrações configuradas: " + hosts.join(", "));
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
case "sessao":
|
|
1190
|
+
case "guarda": {
|
|
1191
|
+
const host = selecionaHosts(argumento(resto, "host"))[0];
|
|
1192
|
+
try {
|
|
1193
|
+
let cru = "";
|
|
1194
|
+
for await (const chunk of process.stdin) {
|
|
1195
|
+
cru += chunk;
|
|
1196
|
+
if (cru.length > 2000000)
|
|
1197
|
+
throw new Error("Entrada de hook grande demais");
|
|
1198
|
+
}
|
|
1199
|
+
const entrada = JSON.parse(cru);
|
|
1200
|
+
console.log(JSON.stringify(comando === "sessao" ? await abreSessao(host, entrada) : await guardaSessao(host, entrada)));
|
|
1201
|
+
}
|
|
1202
|
+
catch (e) {
|
|
1203
|
+
const motivo = e instanceof Error ? e.message : String(e);
|
|
1204
|
+
console.log(JSON.stringify(comando === "guarda" ? saidaDaGuarda(host, motivo) : saidaDoBoot(host, motivo, false)));
|
|
1205
|
+
}
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1235
1208
|
case "politica":
|
|
1236
1209
|
return comandoPolitica(resto);
|
|
1237
1210
|
case "cinto":
|
package/dist/pasta.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
1
|
+
import { jsonDaEscrita, cabecalhos, credencial, pede, recusa } from "./api.js";
|
|
2
2
|
/**
|
|
3
3
|
* `dd-harness pasta <slug> --definicao "..."` — cria a pasta sem sair da sessao.
|
|
4
4
|
*
|
|
@@ -25,6 +25,6 @@ export async function criaPasta(raiz, slug, definicao) {
|
|
|
25
25
|
return { pasta: slug, jaExistia: true };
|
|
26
26
|
if (!resposta.ok)
|
|
27
27
|
await recusa(resposta);
|
|
28
|
-
const { pasta } = (await resposta
|
|
28
|
+
const { pasta } = (await jsonDaEscrita(resposta));
|
|
29
29
|
return { pasta, jaExistia: false };
|
|
30
30
|
}
|
package/dist/politica.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cabecalhos, credencial, pede } from "./api.js";
|
|
2
|
+
import { politicaParaSessao } from "./regras-de-commit.js";
|
|
2
3
|
export async function buscaPolitica(raiz) {
|
|
3
4
|
let config;
|
|
4
5
|
try {
|
|
@@ -29,10 +30,11 @@ export async function buscaPolitica(raiz) {
|
|
|
29
30
|
// obrigatorios. So checar `politica` vazia deixava passar o caso de politica
|
|
30
31
|
// existir sem briefing — a sessao seguia como "ok" com metade do briefing faltando,
|
|
31
32
|
// e nada acionava o fluxo que devia completa-lo.
|
|
32
|
-
if (!conteudo || payload.briefado === false) {
|
|
33
|
+
if (!conteudo || payload.briefado === false || !payload.briefing?.trim()) {
|
|
33
34
|
return { estado: "sem-politica", esperandoIndexacao, memorias: payload.memorias };
|
|
34
35
|
}
|
|
35
|
-
return { estado: "ok", conteudo
|
|
36
|
+
return { estado: "ok", conteudo: politicaParaSessao(conteudo) + "\n\n# Briefing do projeto\n\n" + payload.briefing,
|
|
37
|
+
esperandoIndexacao, roadmap, memorias: payload.memorias };
|
|
36
38
|
}
|
|
37
39
|
catch (erro) {
|
|
38
40
|
return { estado: "inalcancavel", motivo: mensagem(erro) };
|
package/dist/projeto.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cabecalhos, pede, recusa } from "./api.js";
|
|
1
|
+
import { jsonDaEscrita, cabecalhos, pede, recusa } from "./api.js";
|
|
2
2
|
import { leConfigDoRepo, leToken } from "./config.js";
|
|
3
3
|
/**
|
|
4
4
|
* `dd-harness projeto <slug> --nome "..."` — cria o projeto sem sair da sessao.
|
|
@@ -34,7 +34,7 @@ export async function criaProjeto(raiz, slug, nome, explicito = {}) {
|
|
|
34
34
|
return { projeto: slug, jaExistia: true };
|
|
35
35
|
if (!resposta.ok)
|
|
36
36
|
await recusa(resposta);
|
|
37
|
-
const { projeto } = (await resposta
|
|
37
|
+
const { projeto } = (await jsonDaEscrita(resposta));
|
|
38
38
|
return { projeto, jaExistia: false };
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Regra do produto, entregue junto da política sem reescrever o artefato no serviço. */
|
|
2
|
+
export declare const REGRA_DE_COMMITS = "## Identifica\u00E7\u00E3o do agente nos commits\n\nTodo commit feito por agente come\u00E7a com [IDENTIFICA\u00C7\u00C3O] - tipo: descri\u00E7\u00E3o.\nExemplos: [CODEX] - feat: nova funcionalidade; [CLAUDE] - fix: corrige a busca;\n[GEMINI] - docs: atualiza o guia. Outro agente usa seu nome em mai\u00FAsculas entre colchetes.\nIdentifique o agente/modelo que efetivamente realizou o commit, n\u00E3o apenas o editor:\nClaude no Antigravity continua [CLAUDE]; Gemini usa [GEMINI]; Codex usa [CODEX].\nN\u00E3o invente a identidade. A regra n\u00E3o concede autoriza\u00E7\u00E3o para commitar, n\u00E3o altera\no autor do Git e n\u00E3o pede reescrita de commits antigos.";
|
|
3
|
+
export declare function politicaParaSessao(conteudo: string): string;
|