@orkastery/cli 0.5.0 → 0.5.3
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/adapters/claude-code/README.md +11 -2
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/onboarding.md +3 -2
- package/adapters/claude-code/commands/ork.md +9 -0
- package/adapters/codex/skills/ork/SKILL.md +18 -3
- package/adapters/hermes/README.md +1 -0
- package/adapters/hermes/bin/ork-network-status.sh +10 -0
- package/adapters/hermes/hermes.plugin.json +1 -0
- package/adapters/hermes/hitl-ingress/__init__.py +2 -2
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
- package/adapters/openclaw/README.md +35 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +47 -12
- package/adapters/openclaw/openclaw.plugin.json +5 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +2 -2
- package/adapters/openclaw/src/index.ts +50 -12
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +59 -11
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +6 -2
- package/dist/board.js +16 -14
- package/dist/branch-de-estado.js +66 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/ci.js +8 -1
- package/dist/claim-lint.js +3 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +110 -3
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +294 -37
- package/dist/entrega-pr.js +27 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +35 -9
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/fix.js +3 -3
- package/dist/forja.js +31 -7
- package/dist/gates.js +5 -1
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +33 -1
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/horario.js +27 -0
- package/dist/hosts.js +59 -13
- package/dist/impedimento.js +205 -0
- package/dist/index.js +433 -88
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +28 -5
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +267 -30
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-contract.js +71 -12
- package/dist/intelligence-graph-extract-md.js +41 -23
- package/dist/intelligence-graph-extract-ts.js +181 -11
- package/dist/intelligence-graph-extract.js +186 -9
- package/dist/intelligence-graph-index.js +205 -24
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-repo.js +10 -0
- package/dist/leases.js +680 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +12 -0
- package/dist/licoes.js +6 -4
- package/dist/liveness.js +2 -1
- package/dist/maestro-runtime.js +7 -1
- package/dist/manifest.js +44 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +36 -3
- package/dist/mcp-git.js +80 -15
- package/dist/mcp-grafo-worker.js +93 -0
- package/dist/mcp-grafo.js +279 -0
- package/dist/mcp-install.js +2 -1
- package/dist/mcp-server.js +23 -1
- package/dist/mcp-ship.js +2 -0
- package/dist/mcp-verify.js +3 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +195 -20
- package/dist/ocupacao.js +17 -5
- package/dist/onboarding.js +9 -4
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +14 -11
- package/dist/parado-no-condutor.js +1089 -0
- package/dist/phase.js +68 -15
- package/dist/policies.js +79 -3
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +414 -0
- package/dist/pulse-delivery.js +60 -7
- package/dist/pulse.js +99 -3
- package/dist/ratelimit.js +20 -4
- package/dist/recall.js +3 -1
- package/dist/rede-adesao.js +399 -0
- package/dist/rede-forja.js +289 -0
- package/dist/rede-projetos.js +239 -0
- package/dist/rede-status.js +336 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +69 -2
- package/dist/roadmap-status.js +162 -7
- package/dist/runtime-context.js +5 -1
- package/dist/runtime-profiles.js +22 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-watcher-claude.js +113 -23
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -12
- package/dist/sessoes.js +87 -3
- package/dist/ship.js +110 -20
- package/dist/thread.js +212 -14
- package/dist/util.js +71 -4
- package/dist/verify.js +2 -2
- package/dist/worktree.js +34 -8
- package/eval/casos/onboarding.json +1 -1
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/skills/README.md +1 -1
- package/skills/core/onboarding/SKILL.md +3 -2
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
- package/skills/phases/ship-release/SKILL.md +6 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.textoAceito = exports.LACUNAS_SO_CONTAGEM = exports.EXTENSOES_MD = exports.EXTENSOES_TS = exports.CONFIG_SCHEMA = exports.RELATORIO_SCHEMA = exports.VERSAO_KG2 = exports.EXTRATOR_ARQUIVOS = exports.EXTRATOR_ID = exports.EXTRATOR_MD = exports.EXTRATOR_TS = void 0;
|
|
3
|
+
exports.textoAceito = exports.UNIDADES_SCHEMA = exports.LACUNAS_SO_CONTAGEM = exports.EXTENSOES_MD = exports.EXTENSOES_TS = exports.CONFIG_SCHEMA = exports.RELATORIO_SCHEMA = exports.VERSAO_KG2 = exports.EXTRATOR_ARQUIVOS = exports.EXTRATOR_ID = exports.EXTRATOR_MD = exports.EXTRATOR_TS = void 0;
|
|
4
4
|
exports.textoCurto = textoCurto;
|
|
5
5
|
exports.extensaoDe = extensaoDe;
|
|
6
6
|
exports.idDeBlob = idDeBlob;
|
|
@@ -34,6 +34,8 @@ exports.LACUNAS_SO_CONTAGEM = new Set([
|
|
|
34
34
|
'chamada-fora-de-simbolo', 'chamada-nao-resolvida', 'chamada-alvo-fora-do-grafo', 'chamada-por-tipo', 'import-sem-simbolo',
|
|
35
35
|
'id-sem-artefato', 'link-externo',
|
|
36
36
|
]);
|
|
37
|
+
/** RM-031 KG4 (D2): as unidades por arquivo que o indice guarda para a proxima revisao reaproveitar. */
|
|
38
|
+
exports.UNIDADES_SCHEMA = 'ork.graph-extraction-units/v0';
|
|
37
39
|
function falha(codigo, onde) {
|
|
38
40
|
throw new Error(onde ? `${codigo} em ${onde}` : codigo);
|
|
39
41
|
}
|
|
@@ -136,11 +138,144 @@ const zeros = '0'.repeat(64);
|
|
|
136
138
|
function contagemVazia(chaves) {
|
|
137
139
|
return Object.fromEntries(chaves.map((k) => [k, 0]));
|
|
138
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* A mudanca e por conteudo: o hash de cada caminho contra o da base, mais os novos e os removidos
|
|
143
|
+
* (renome e os dois). No TypeScript, semente e o arquivo mudado ou novo e o nao mudado cuja sonda casa
|
|
144
|
+
* caminho novo ou removido; afetado e a semente e quem alcanca semente ou caminho mudado pelas
|
|
145
|
+
* dependencias gravadas na base. `package.json` ou arquivo global na mudanca extrai o TypeScript inteiro.
|
|
146
|
+
*/
|
|
147
|
+
function planejarReuso(base, manifesto, fontesTs, fontesMd) {
|
|
148
|
+
const porCaminho = new Map(base.arquivos.map((u) => [u.path, u]));
|
|
149
|
+
const alterados = [], novos = [], removidos = [];
|
|
150
|
+
for (const [p, m] of manifesto) {
|
|
151
|
+
const u = porCaminho.get(p);
|
|
152
|
+
if (!u)
|
|
153
|
+
novos.push(p);
|
|
154
|
+
else if (u.source_hash !== m.source_hash)
|
|
155
|
+
alterados.push(p);
|
|
156
|
+
}
|
|
157
|
+
for (const p of porCaminho.keys())
|
|
158
|
+
if (!manifesto.has(p))
|
|
159
|
+
removidos.push(p);
|
|
160
|
+
for (const l of [alterados, novos, removidos])
|
|
161
|
+
l.sort(intelligence_graph_contract_1.compararUtf8);
|
|
162
|
+
const mudados = new Set([...alterados, ...novos, ...removidos]);
|
|
163
|
+
const md = new Map();
|
|
164
|
+
for (const f of fontesMd) {
|
|
165
|
+
const u = porCaminho.get(f.path);
|
|
166
|
+
if (u?.md && !mudados.has(f.path))
|
|
167
|
+
md.set(f.path, u.md);
|
|
168
|
+
}
|
|
169
|
+
const plano = { base, porCaminho, mudanca: { alterados, novos, removidos }, md, ts: { motivo: null, sementes: new Set(), afetados: new Set() } };
|
|
170
|
+
const ordenados = [...mudados].sort(intelligence_graph_contract_1.compararUtf8), globais = new Set(base.globais_ts), ts1 = new Set(fontesTs.map((f) => f.path));
|
|
171
|
+
const pacote = ordenados.find((p) => p === 'package.json' || p.endsWith('/package.json'));
|
|
172
|
+
const global = ordenados.find((p) => globais.has(p));
|
|
173
|
+
const semUnidade = fontesTs.find((f) => !mudados.has(f.path) && !porCaminho.get(f.path)?.ts);
|
|
174
|
+
if (pacote !== undefined)
|
|
175
|
+
plano.ts.motivo = `package.json na mudanca (${pacote})`;
|
|
176
|
+
else if (global !== undefined)
|
|
177
|
+
plano.ts.motivo = `arquivo global do TypeScript na mudanca (${global})`;
|
|
178
|
+
else if (semUnidade !== undefined)
|
|
179
|
+
plano.ts.motivo = `base sem a unidade TypeScript de ${semUnidade.path}`;
|
|
180
|
+
if (plano.ts.motivo !== null)
|
|
181
|
+
return plano;
|
|
182
|
+
const existencia = [...novos, ...removidos];
|
|
183
|
+
for (const p of ts1) {
|
|
184
|
+
if (mudados.has(p))
|
|
185
|
+
plano.ts.sementes.add(p);
|
|
186
|
+
else if (existencia.length && (porCaminho.get(p)?.ts).sondas.some((b) => existencia.some((q) => (0, intelligence_graph_extract_ts_1.casaSonda)(b, q))))
|
|
187
|
+
plano.ts.sementes.add(p);
|
|
188
|
+
}
|
|
189
|
+
const dependentes = new Map();
|
|
190
|
+
for (const u of base.arquivos) {
|
|
191
|
+
for (const d of u.ts?.dependencias ?? []) {
|
|
192
|
+
const lista = dependentes.get(d);
|
|
193
|
+
if (lista)
|
|
194
|
+
lista.push(u.path);
|
|
195
|
+
else
|
|
196
|
+
dependentes.set(d, [u.path]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const vistos = new Set(), fila = [...plano.ts.sementes, ...mudados];
|
|
200
|
+
while (fila.length) {
|
|
201
|
+
const q = fila.pop();
|
|
202
|
+
if (vistos.has(q))
|
|
203
|
+
continue;
|
|
204
|
+
vistos.add(q);
|
|
205
|
+
for (const x of dependentes.get(q) ?? [])
|
|
206
|
+
if (!vistos.has(x))
|
|
207
|
+
fila.push(x);
|
|
208
|
+
}
|
|
209
|
+
// CHECK (B1): quem usa um global nao importa o arquivo dele, e o global depende do que esse arquivo
|
|
210
|
+
// importa (heranca, tipo importado, `export *` atras de UMD, aumento que estende tipo de outro modulo).
|
|
211
|
+
const globalAlcancado = [...globais].sort(intelligence_graph_contract_1.compararUtf8).find((g) => vistos.has(g));
|
|
212
|
+
if (globalAlcancado !== undefined) {
|
|
213
|
+
plano.ts.motivo = `dependencia de arquivo global na mudanca (${globalAlcancado})`;
|
|
214
|
+
return plano;
|
|
215
|
+
}
|
|
216
|
+
for (const p of vistos)
|
|
217
|
+
if (ts1.has(p))
|
|
218
|
+
plano.ts.afetados.add(p);
|
|
219
|
+
return plano;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* KG4 (D3): extrai os afetados num programa parcial: eles, os globais e o fecho direto pelas
|
|
223
|
+
* dependencias da base (a semente descobre as suas no programa, que cresce ate fechar). O resto vem
|
|
224
|
+
* da base. Afetado que passa a declarar global devolve o motivo, e o TypeScript sai inteiro.
|
|
225
|
+
*/
|
|
226
|
+
function extrairTsParcial(plano, entrada, extrair) {
|
|
227
|
+
const { afetados, sementes } = plano.ts, ts1 = new Set(entrada.fontes.map((f) => f.path));
|
|
228
|
+
const daBase = (p) => plano.porCaminho.get(p)?.ts;
|
|
229
|
+
const unidades = new Map(), globais = [...plano.base.globais_ts];
|
|
230
|
+
const raizes = new Set();
|
|
231
|
+
const incluir = (inicio) => {
|
|
232
|
+
const fila = [...inicio];
|
|
233
|
+
while (fila.length) {
|
|
234
|
+
const p = fila.pop();
|
|
235
|
+
if (raizes.has(p) || !ts1.has(p))
|
|
236
|
+
continue;
|
|
237
|
+
raizes.add(p);
|
|
238
|
+
if (!sementes.has(p))
|
|
239
|
+
for (const d of daBase(p).dependencias)
|
|
240
|
+
if (!raizes.has(d))
|
|
241
|
+
fila.push(d);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
let r = null;
|
|
245
|
+
if (afetados.size) {
|
|
246
|
+
incluir([...afetados, ...globais]);
|
|
247
|
+
for (;;) {
|
|
248
|
+
r = extrair({ ...entrada, fontes: entrada.fontes.filter((f) => raizes.has(f.path)), emitir: afetados });
|
|
249
|
+
if (!r.faltantes.length)
|
|
250
|
+
break;
|
|
251
|
+
const antes = raizes.size;
|
|
252
|
+
incluir(r.faltantes);
|
|
253
|
+
if (raizes.size === antes)
|
|
254
|
+
falha('extracao.interna.programa-parcial');
|
|
255
|
+
}
|
|
256
|
+
const daBaseGlobal = new Set(globais), doPrograma = new Set(r.globais);
|
|
257
|
+
const novo = r.globais.find((g) => !daBaseGlobal.has(g));
|
|
258
|
+
if (novo !== undefined)
|
|
259
|
+
return { motivo: `arquivo passa a declarar global no TypeScript (${novo})`, unidades, globais, programa: raizes.size };
|
|
260
|
+
const sumiu = globais.find((g) => ts1.has(g) && !doPrograma.has(g));
|
|
261
|
+
if (sumiu !== undefined)
|
|
262
|
+
return { motivo: `global da base fora do escopo global (${sumiu})`, unidades, globais, programa: raizes.size };
|
|
263
|
+
}
|
|
264
|
+
for (const f of entrada.fontes) {
|
|
265
|
+
const u = afetados.has(f.path) ? r?.unidades.get(f.path) : daBase(f.path);
|
|
266
|
+
if (!u)
|
|
267
|
+
falha('extracao.interna.unidade-ts-ausente');
|
|
268
|
+
unidades.set(f.path, u);
|
|
269
|
+
}
|
|
270
|
+
return { motivo: null, unidades, globais, programa: raizes.size };
|
|
271
|
+
}
|
|
139
272
|
/**
|
|
140
273
|
* Extrai o grafo das fontes fornecidas. Lanca `extracao.*` para entrada invalida ou teto do
|
|
141
274
|
* contrato estourado (D10), e `grafo.*` se o resultado violar o contrato (defeito do extrator).
|
|
275
|
+
* RM-031 KG4: com `base` (as unidades do indice de outra revisao, do mesmo extrator), reextrai so o
|
|
276
|
+
* que a mudanca alcanca; o resultado e o mesmo, byte a byte, da extracao sem base.
|
|
142
277
|
*/
|
|
143
|
-
function extrairGrafo(entrada, parser) {
|
|
278
|
+
function extrairGrafo(entrada, parser, base = null) {
|
|
144
279
|
const { ts, unicode, markdown, javascript } = parser;
|
|
145
280
|
if (!/^[0-9]+(\.[0-9]+)*$/.test(unicode))
|
|
146
281
|
falha('extracao.entrada.unicode-invalido');
|
|
@@ -224,18 +359,40 @@ function extrairGrafo(entrada, parser) {
|
|
|
224
359
|
// B1: a raiz virtual do compilador deriva do manifesto; um caminho do repositorio nao a nomeia.
|
|
225
360
|
const raiz = `/ork-${(0, intelligence_graph_contract_1.sha256DoCanonico)([...manifesto.values()].map((m) => [m.path, m.source_hash])).slice(0, 32)}`;
|
|
226
361
|
const aceitaFragmento = (f) => f.length >= 1 && f.length <= intelligence_graph_contract_1.GRAFO_LIMITES.fragmento && (0, exports.textoAceito)(f);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
362
|
+
const entradaTs = { fontes: fontesTs, arquivos: caminhos, texto, raiz, aceitaFragmento, sintaxe: javascript.sintaxe, extrator: exports.EXTRATOR_TS };
|
|
363
|
+
const extrairTs = (e) => semEstouro(exports.EXTRATOR_TS, () => (0, intelligence_graph_extract_ts_1.extrairTypeScript)(e, ts));
|
|
364
|
+
// KG4 (D1, D3, D4): com as unidades de uma base, so o que a mudanca alcanca e extraido de novo.
|
|
365
|
+
const plano = base ? planejarReuso(base, manifesto, fontesTs, fontesMd) : null;
|
|
366
|
+
let tsDaBase = null;
|
|
367
|
+
if (plano && plano.ts.motivo === null)
|
|
368
|
+
tsDaBase = extrairTsParcial(plano, entradaTs, extrairTs);
|
|
369
|
+
const motivoTs = plano ? plano.ts.motivo ?? tsDaBase?.motivo ?? null : null;
|
|
370
|
+
let unidadesTs, globaisTs;
|
|
371
|
+
if (tsDaBase && tsDaBase.motivo === null) {
|
|
372
|
+
unidadesTs = tsDaBase.unidades;
|
|
373
|
+
globaisTs = tsDaBase.globais;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const r = extrairTs(entradaTs);
|
|
377
|
+
unidadesTs = r.unidades;
|
|
378
|
+
globaisTs = r.globais;
|
|
379
|
+
}
|
|
380
|
+
for (const f of fontesTs) {
|
|
381
|
+
const u = unidadesTs.get(f.path);
|
|
382
|
+
if (!u)
|
|
383
|
+
falha('extracao.interna.unidade-ts-ausente');
|
|
384
|
+
juntar(u.achados);
|
|
385
|
+
}
|
|
230
386
|
// B4: chave `caminho#fragmento` como o frontmatter a escreve; duas refs na mesma chave ficam ambiguas.
|
|
231
387
|
const simbolos = new Map();
|
|
232
388
|
for (const r of achados.nos.filter((x) => x.kind === 'symbol')) {
|
|
233
389
|
const chave = `${r.path}#${r.fragment}`, antes = simbolos.get(chave);
|
|
234
390
|
simbolos.set(chave, antes === undefined || (antes && antes.path === r.path && antes.fragment === r.fragment) ? r : null);
|
|
235
391
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
392
|
+
const estruturas = semEstouro(exports.EXTRATOR_MD, () => fontesMd.map((f) => plano?.md.get(f.path)
|
|
393
|
+
?? (0, intelligence_graph_extract_md_1.estruturarMarkdown)(f, { aceitaFragmento, analisar: markdown.analisar, referencia: markdown.referencia })));
|
|
394
|
+
juntar(semEstouro(exports.EXTRATOR_MD, () => (0, intelligence_graph_extract_md_1.ligarMarkdown)({
|
|
395
|
+
estruturas, codigo: fontesTs, arquivos: caminhos, simbolos, aceitaFragmento, extratorMd: exports.EXTRATOR_MD, extratorId: exports.EXTRATOR_ID,
|
|
239
396
|
})));
|
|
240
397
|
const extratores = [
|
|
241
398
|
{ extractor_id: exports.EXTRATOR_ARQUIVOS, extractor_version: exports.VERSAO_KG2 },
|
|
@@ -365,5 +522,25 @@ function extrairGrafo(entrada, parser) {
|
|
|
365
522
|
lacunas_por_categoria: Object.fromEntries([...porCategoria.entries()].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a[0], b[0]))),
|
|
366
523
|
lacunas: [...listadas.entries()].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a[0], b[0])).map(([, l]) => l),
|
|
367
524
|
};
|
|
368
|
-
|
|
525
|
+
const estruturaDe = new Map(estruturas.map((x) => [x.path, x]));
|
|
526
|
+
const unidades = {
|
|
527
|
+
schema: exports.UNIDADES_SCHEMA, snapshot_id: grafo.snapshot.snapshot_id, graph_digest: digest, globais_ts: globaisTs,
|
|
528
|
+
arquivos: grafo.snapshot.source_manifest.map((m) => ({
|
|
529
|
+
path: m.path, source_hash: m.source_hash, ts: unidadesTs.get(m.path) ?? null, md: estruturaDe.get(m.path) ?? null,
|
|
530
|
+
})),
|
|
531
|
+
};
|
|
532
|
+
let reaproveitamento = null;
|
|
533
|
+
if (plano) {
|
|
534
|
+
const parcial = motivoTs === null, afetados = [...plano.ts.afetados].sort(intelligence_graph_contract_1.compararUtf8);
|
|
535
|
+
reaproveitamento = {
|
|
536
|
+
mudanca: { alterados: plano.mudanca.alterados.length, novos: plano.mudanca.novos.length, removidos: plano.mudanca.removidos.length },
|
|
537
|
+
ts: {
|
|
538
|
+
modo: !parcial ? 'inteiro' : afetados.length ? 'parcial' : 'reaproveitado', motivo: motivoTs,
|
|
539
|
+
reextraidos: parcial ? afetados : fontesTs.map((f) => f.path), programa: parcial ? tsDaBase?.programa ?? 0 : fontesTs.length,
|
|
540
|
+
reaproveitados: parcial ? fontesTs.length - afetados.length : 0,
|
|
541
|
+
},
|
|
542
|
+
md: { reextraidos: fontesMd.filter((f) => !plano.md.has(f.path)).map((f) => f.path), reaproveitados: plano.md.size },
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
return { grafo, digest, relatorio, unidades, reaproveitamento };
|
|
369
546
|
}
|
|
@@ -33,13 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.versoesDoParser = exports.EXCLUSOES_DA_ARVORE = exports.MODULOS_DO_EXTRATOR = exports.PRAZO_DE_SOBRA_MS = exports.NOME_DE_INDICE = exports.INDICE_SCHEMA = void 0;
|
|
36
|
+
exports.versoesDoParser = exports.EXCLUSOES_DA_ARVORE = exports.MODULOS_DO_EXTRATOR = exports.PRAZO_DE_SOBRA_MS = exports.LIMITE_DE_ANCESTRAIS = exports.NOME_DE_INDICE = exports.INDICE_SCHEMA_ANTERIOR = exports.INDICE_SCHEMA = void 0;
|
|
37
37
|
exports.impressaoDoExtrator = impressaoDoExtrator;
|
|
38
38
|
exports.perfilDoIndice = perfilDoIndice;
|
|
39
39
|
exports.chaveDoIndice = chaveDoIndice;
|
|
40
40
|
exports.concessaoLocal = concessaoLocal;
|
|
41
41
|
exports.pastaDoGrafo = pastaDoGrafo;
|
|
42
42
|
exports.lerIndice = lerIndice;
|
|
43
|
+
exports.escolherBase = escolherBase;
|
|
43
44
|
exports.construirIndice = construirIndice;
|
|
44
45
|
exports.indiceDoHead = indiceDoHead;
|
|
45
46
|
exports.estadoDosIndices = estadoDosIndices;
|
|
@@ -61,6 +62,11 @@ exports.limparIndices = limparIndices;
|
|
|
61
62
|
* publica, por pasta temporaria e `rename`; a leitura confere tamanho e digest dos bytes.
|
|
62
63
|
*
|
|
63
64
|
* O indice nao e autoridade de fato: e projecao descartavel do repositorio. Nada nele concede acesso.
|
|
65
|
+
*
|
|
66
|
+
* RM-031 KG4 (D1, D2, D5, D7): o indice guarda tambem as unidades por arquivo (`unidades.json`), e a
|
|
67
|
+
* construcao sem indice do HEAD parte do indice da revisao ancestral mais proxima com o mesmo perfil:
|
|
68
|
+
* reextrai so o que a mudanca alcanca e grava os mesmos bytes da extracao completa. Sem base que
|
|
69
|
+
* prove isso, extrai completo e diz por que.
|
|
64
70
|
*/
|
|
65
71
|
const node_crypto_1 = require("node:crypto");
|
|
66
72
|
const fs = __importStar(require("node:fs"));
|
|
@@ -69,9 +75,13 @@ const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
|
|
|
69
75
|
const intelligence_graph_extract_1 = require("./intelligence-graph-extract");
|
|
70
76
|
const intelligence_graph_parsers_1 = require("./intelligence-graph-parsers");
|
|
71
77
|
const intelligence_graph_repo_1 = require("./intelligence-graph-repo");
|
|
72
|
-
|
|
78
|
+
/** KG4 (D2): a v1 tem as unidades por arquivo; a v0 (KG3) nao serve de base e o `limpar` a remove. */
|
|
79
|
+
exports.INDICE_SCHEMA = 'ork.code-graph-index/v1';
|
|
80
|
+
exports.INDICE_SCHEMA_ANTERIOR = 'ork.code-graph-index/v0';
|
|
73
81
|
exports.NOME_DE_INDICE = /^idx-[a-f0-9]{64}$/;
|
|
74
|
-
const ARQUIVOS = { manifesto: 'indice.json', grafo: 'grafo.json', relatorio: 'relatorio.json' };
|
|
82
|
+
const ARQUIVOS = { manifesto: 'indice.json', grafo: 'grafo.json', relatorio: 'relatorio.json', unidades: 'unidades.json' };
|
|
83
|
+
/** KG4 (D1): quantas revisoes, do HEAD para tras, a escolha da base percorre. */
|
|
84
|
+
exports.LIMITE_DE_ANCESTRAIS = 512;
|
|
75
85
|
/** Temporario e lixo de construcao interrompida so saem no `limpar` depois deste prazo. */
|
|
76
86
|
exports.PRAZO_DE_SOBRA_MS = 60 * 60 * 1000;
|
|
77
87
|
/** D3: os modulos compilados da extracao e do indice. Codigo corrigido sem troca de versao muda a chave. */
|
|
@@ -189,6 +199,31 @@ function lerPrivado(arquivo) {
|
|
|
189
199
|
fs.closeSync(fd);
|
|
190
200
|
}
|
|
191
201
|
}
|
|
202
|
+
/** KG4: as mesmas regras de `lerPrivado` e o tamanho do manifesto, sem ler o conteudo (a consulta nao precisa das unidades). */
|
|
203
|
+
function conferirPrivado(arquivo, bytes) {
|
|
204
|
+
let fd;
|
|
205
|
+
try {
|
|
206
|
+
fd = fs.openSync(arquivo, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
const codigo = e.code;
|
|
210
|
+
if (codigo === 'ENOENT')
|
|
211
|
+
falha('grafo.indice.corrompido', `${path.basename(arquivo)} ausente`);
|
|
212
|
+
falha('grafo.indice.permissao-invalida', `${path.basename(arquivo)} (${codigo ?? 'erro'})`);
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const st = fs.fstatSync(fd);
|
|
216
|
+
const dono = uid();
|
|
217
|
+
if (!st.isFile() || st.nlink !== 1 || (dono !== null && st.uid !== dono) || (st.mode & 0o777) !== 0o600) {
|
|
218
|
+
falha('grafo.indice.permissao-invalida', path.basename(arquivo));
|
|
219
|
+
}
|
|
220
|
+
if (st.size !== bytes)
|
|
221
|
+
falha('grafo.indice.corrompido', `${path.basename(arquivo)} nao bate com o tamanho`);
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
fs.closeSync(fd);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
192
227
|
function gravarPrivado(arquivo, texto) {
|
|
193
228
|
const fd = fs.openSync(arquivo, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW, 0o600);
|
|
194
229
|
try {
|
|
@@ -213,7 +248,11 @@ const HEX64 = /^[a-f0-9]{64}$/;
|
|
|
213
248
|
function manifestoValido(m, chave) {
|
|
214
249
|
const o = m;
|
|
215
250
|
const inteiro = (n) => Number.isSafeInteger(n) && n >= 0;
|
|
251
|
+
if (o && typeof o === 'object' && o.schema === exports.INDICE_SCHEMA_ANTERIOR) {
|
|
252
|
+
falha('grafo.indice.formato-anterior', `${exports.INDICE_SCHEMA_ANTERIOR} (KG3), sem unidades; o ork grafo limpar o remove`);
|
|
253
|
+
}
|
|
216
254
|
if (!o || typeof o !== 'object' || o.schema !== exports.INDICE_SCHEMA || o.chave !== chave || o.graph_schema !== intelligence_graph_contract_1.GRAFO_SCHEMA
|
|
255
|
+
|| o.units_schema !== intelligence_graph_extract_1.UNIDADES_SCHEMA || !HEX64.test(o.units_digest) || !inteiro(o.units_bytes)
|
|
217
256
|
|| typeof o.revision !== 'string' || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(o.revision)
|
|
218
257
|
|| !HEX64.test(o.graph_digest) || !HEX64.test(o.report_digest) || !inteiro(o.graph_bytes) || !inteiro(o.report_bytes)
|
|
219
258
|
|| typeof o.snapshot_id !== 'string' || typeof o.repository_id !== 'string' || typeof o.tenant_id !== 'string'
|
|
@@ -259,7 +298,27 @@ function lerIndice(ctx, chave, opcoes = {}) {
|
|
|
259
298
|
}
|
|
260
299
|
}
|
|
261
300
|
const relatorio = opcoes.relatorio ? JSON.parse(bytesDoRelatorio.toString('utf8')) : null;
|
|
262
|
-
|
|
301
|
+
// KG4: as unidades so sao lidas (e o digest conferido) por quem as usa; a consulta confere so o tamanho.
|
|
302
|
+
let unidades = null;
|
|
303
|
+
if (opcoes.unidades) {
|
|
304
|
+
let u;
|
|
305
|
+
try {
|
|
306
|
+
u = JSON.parse(conferido(ARQUIVOS.unidades, manifesto.units_bytes, manifesto.units_digest).toString('utf8'));
|
|
307
|
+
}
|
|
308
|
+
catch (e) {
|
|
309
|
+
if (e instanceof SyntaxError)
|
|
310
|
+
falha('grafo.indice.corrompido', 'unidades.json');
|
|
311
|
+
throw e;
|
|
312
|
+
}
|
|
313
|
+
if (!u || u.schema !== intelligence_graph_extract_1.UNIDADES_SCHEMA || u.snapshot_id !== manifesto.snapshot_id || u.graph_digest !== manifesto.graph_digest
|
|
314
|
+
|| !Array.isArray(u.arquivos) || !Array.isArray(u.globais_ts)) {
|
|
315
|
+
falha('grafo.indice.corrompido', 'unidades.json fora do manifesto');
|
|
316
|
+
}
|
|
317
|
+
unidades = u;
|
|
318
|
+
}
|
|
319
|
+
else
|
|
320
|
+
conferirPrivado(path.join(dir, ARQUIVOS.unidades), manifesto.units_bytes);
|
|
321
|
+
return { dir, manifesto, grafo, relatorio, unidades };
|
|
263
322
|
}
|
|
264
323
|
/** Embaralhamento reproduzivel (LCG): a permutacao da verificacao nao depende de acaso. */
|
|
265
324
|
function embaralhar(itens, semente) {
|
|
@@ -296,11 +355,88 @@ function removerPasta(grafoDir, nome) {
|
|
|
296
355
|
fs.renameSync(alvo, lixo);
|
|
297
356
|
fs.rmSync(lixo, { recursive: true, force: true });
|
|
298
357
|
}
|
|
358
|
+
/** O perfil que um manifesto guarda: tudo o que entra na chave, menos a revisao. */
|
|
359
|
+
const perfilDoManifesto = (m) => ({
|
|
360
|
+
repository_id: m.repository_id, tenant_id: m.tenant_id, acl_refs: m.acl_refs, analisadores: m.analisadores, pacotes: m.pacotes, codigo: m.codigo,
|
|
361
|
+
});
|
|
362
|
+
const curta = (r) => r.slice(0, 12);
|
|
363
|
+
/**
|
|
364
|
+
* KG4 (D1, D5): a base e o indice da revisao ancestral mais proxima do HEAD (nas `LIMITE_DE_ANCESTRAIS`
|
|
365
|
+
* do `git rev-list`) com o mesmo perfil. Sem ela, o motivo diz o que havia: indice ancestral de outro
|
|
366
|
+
* extrator, indice do mesmo extrator fora da linha do HEAD (historico reescrito ou outro ramo), indice
|
|
367
|
+
* de formato anterior, ou nenhum. Base que nao passa na leitura e trocada pela proxima, com o erro.
|
|
368
|
+
*/
|
|
369
|
+
function escolherBase(ctx, perfil, head, raiz) {
|
|
370
|
+
let dir;
|
|
371
|
+
try {
|
|
372
|
+
dir = pastaDoGrafo(ctx, false);
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
if (e.message === 'grafo.indice.ausente')
|
|
376
|
+
return { base: null, motivo: 'nenhum indice guardado' };
|
|
377
|
+
throw e;
|
|
378
|
+
}
|
|
379
|
+
const posicao = new Map((0, intelligence_graph_repo_1.revisoesAncestrais)(raiz, exports.LIMITE_DE_ANCESTRAIS).map((r, i) => [r, i]));
|
|
380
|
+
const desejado = (0, intelligence_graph_contract_1.canonico)(perfil), identidade = (0, intelligence_graph_contract_1.canonico)([perfil.repository_id, perfil.tenant_id, perfil.acl_refs]);
|
|
381
|
+
const candidatos = [];
|
|
382
|
+
let outroExtrator = null, foraDaLinha = null, anterior = false;
|
|
383
|
+
for (const nome of fs.readdirSync(dir).sort(intelligence_graph_contract_1.compararUtf8)) {
|
|
384
|
+
if (!exports.NOME_DE_INDICE.test(nome))
|
|
385
|
+
continue;
|
|
386
|
+
let m;
|
|
387
|
+
try {
|
|
388
|
+
pastaPrivada(path.join(dir, nome), false);
|
|
389
|
+
m = manifestoValido(JSON.parse(lerPrivado(path.join(dir, nome, ARQUIVOS.manifesto)).toString('utf8')), nome);
|
|
390
|
+
}
|
|
391
|
+
catch (e) {
|
|
392
|
+
if (e.message.startsWith('grafo.indice.formato-anterior'))
|
|
393
|
+
anterior = true;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (m.revision === head)
|
|
397
|
+
continue;
|
|
398
|
+
const p = perfilDoManifesto(m), i = posicao.get(m.revision);
|
|
399
|
+
if ((0, intelligence_graph_contract_1.canonico)(p) === desejado) {
|
|
400
|
+
if (i === undefined)
|
|
401
|
+
foraDaLinha ??= m.revision;
|
|
402
|
+
else
|
|
403
|
+
candidatos.push({ chave: nome, revision: m.revision, posicao: i });
|
|
404
|
+
}
|
|
405
|
+
else if (i !== undefined && (0, intelligence_graph_contract_1.canonico)([p.repository_id, p.tenant_id, p.acl_refs]) === identidade && (!outroExtrator || i < outroExtrator.posicao)) {
|
|
406
|
+
const campos = ['analisadores', 'pacotes', 'codigo'].filter((k) => (0, intelligence_graph_contract_1.canonico)(p[k]) !== (0, intelligence_graph_contract_1.canonico)(perfil[k]));
|
|
407
|
+
outroExtrator = { revision: m.revision, campos, posicao: i };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const erros = [];
|
|
411
|
+
for (const c of candidatos.sort((a, b) => a.posicao - b.posicao)) {
|
|
412
|
+
try {
|
|
413
|
+
const lido = lerIndice(ctx, c.chave, { grafo: false, unidades: true });
|
|
414
|
+
return { base: { revision: c.revision, chave: c.chave, unidades: lido.unidades }, motivo: null };
|
|
415
|
+
}
|
|
416
|
+
catch (e) {
|
|
417
|
+
erros.push(`${curta(c.revision)}: ${e.message}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (erros.length)
|
|
421
|
+
return { base: null, motivo: `base ilegivel (${erros.join('; ')})` };
|
|
422
|
+
const motivos = [];
|
|
423
|
+
if (foraDaLinha) {
|
|
424
|
+
motivos.push(`nenhum indice de revisao ancestral nas ultimas ${exports.LIMITE_DE_ANCESTRAIS}; o de ${curta(foraDaLinha)} nao esta entre elas (historico reescrito, outro ramo ou revisao mais antiga)`);
|
|
425
|
+
}
|
|
426
|
+
if (outroExtrator)
|
|
427
|
+
motivos.push(`o extrator mudou desde o indice de ${curta(outroExtrator.revision)} (${outroExtrator.campos.join(', ')})`);
|
|
428
|
+
if (!motivos.length && anterior)
|
|
429
|
+
motivos.push(`so ha indice de formato anterior (${exports.INDICE_SCHEMA_ANTERIOR})`);
|
|
430
|
+
return { base: null, motivo: motivos.length ? motivos.join('; ') : 'nenhum indice de revisao ancestral com este extrator' };
|
|
431
|
+
}
|
|
432
|
+
const textoDasUnidades = (u) => JSON.stringify(u);
|
|
299
433
|
/**
|
|
300
|
-
* Constroi o indice do HEAD limpo, ou confirma o que ja existe.
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
434
|
+
* Constroi o indice do HEAD limpo, ou confirma o que ja existe. Sem o indice do HEAD, parte do indice
|
|
435
|
+
* ancestral com o mesmo perfil (KG4) e reextrai so o que a mudanca alcanca; sem base, ou se o
|
|
436
|
+
* incremental falha, extrai completo e diz por que. `--forcar` extrai completo e so troca os arquivos se
|
|
437
|
+
* o conteudo mudou; `--verificar` extrai completo, prova o determinismo com a ordem de leitura trocada,
|
|
438
|
+
* compara com o incremental quando ha base e reprova se o guardado integro difere; indice que nao passa
|
|
439
|
+
* na leitura e substituido. O incremental passa pelas mesmas validacoes da completa antes de publicar.
|
|
304
440
|
*/
|
|
305
441
|
function construirIndice(ctx, opcoes = {}) {
|
|
306
442
|
const inicio = process.hrtime.bigint();
|
|
@@ -308,10 +444,11 @@ function construirIndice(ctx, opcoes = {}) {
|
|
|
308
444
|
const arvore = (0, intelligence_graph_repo_1.revisaoDaArvore)(ctx.raiz);
|
|
309
445
|
if (arvore.motivo !== null || arvore.head === null)
|
|
310
446
|
falha('grafo.indice.arvore-nao-limpa', arvore.motivo ?? 'sem-commit');
|
|
447
|
+
const head = arvore.head;
|
|
311
448
|
const parser = opcoes.parser ?? (0, intelligence_graph_parsers_1.carregarAnalisadores)();
|
|
312
449
|
const leitura = leituraDo(ctx, opcoes.leitura);
|
|
313
450
|
const perfil = perfilDoIndice(arvore.raiz, (0, exports.versoesDoParser)(parser), leitura);
|
|
314
|
-
const chave = chaveDoIndice(
|
|
451
|
+
const chave = chaveDoIndice(head, perfil);
|
|
315
452
|
const grafoDir = pastaDoGrafo(ctx, true);
|
|
316
453
|
const final = path.join(grafoDir, chave);
|
|
317
454
|
let motivo = null;
|
|
@@ -320,55 +457,96 @@ function construirIndice(ctx, opcoes = {}) {
|
|
|
320
457
|
try {
|
|
321
458
|
const atual = lerIndice(ctx, chave, { grafo: false });
|
|
322
459
|
// `--verificar` nunca confia no guardado: extrai de novo e compara, como o `--forcar`.
|
|
323
|
-
if (!opcoes.forcar && !opcoes.verificar)
|
|
324
|
-
return {
|
|
460
|
+
if (!opcoes.forcar && !opcoes.verificar) {
|
|
461
|
+
return {
|
|
462
|
+
estado: 'existente', motivo: null, chave, dir: final, manifesto: atual.manifesto, determinismo: null, ms: ms(),
|
|
463
|
+
modo: null, base: null, motivo_completo: null, reaproveitamento: null, incremental: null,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
325
466
|
}
|
|
326
467
|
catch (e) {
|
|
327
468
|
motivo = e.message;
|
|
328
469
|
}
|
|
329
470
|
}
|
|
330
471
|
const entrada = (0, intelligence_graph_repo_1.lerRepositorio)(arvore.raiz, leitura);
|
|
331
|
-
if (entrada.revision !==
|
|
472
|
+
if (entrada.revision !== head)
|
|
332
473
|
falha('grafo.indice.arvore-nao-limpa', entrada.revision_unavailable_reason ?? 'revisao-mudou');
|
|
333
474
|
const fora = (entrada.excluidas ?? []).filter((e) => exports.EXCLUSOES_DA_ARVORE.has(e.motivo)).sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a.path, b.path));
|
|
334
475
|
if (fora.length) {
|
|
335
476
|
falha('grafo.indice.arvore-nao-limpa', `rastreado fora da leitura (${fora[0].motivo}: ${fora[0].path}${fora.length > 1 ? ` e mais ${fora.length - 1}` : ''})`);
|
|
336
477
|
}
|
|
337
|
-
|
|
478
|
+
// KG4 (D1, D5, D7): a base, salvo com `--forcar`.
|
|
479
|
+
let base = null, motivoCompleto = 'pedido com --forcar';
|
|
480
|
+
if (!opcoes.forcar)
|
|
481
|
+
({ base, motivo: motivoCompleto } = escolherBase(ctx, perfil, head, arvore.raiz));
|
|
482
|
+
let r = null, modo = 'completo';
|
|
483
|
+
if (base && !opcoes.verificar) {
|
|
484
|
+
try {
|
|
485
|
+
r = (0, intelligence_graph_extract_1.extrairGrafo)(entrada, parser, base.unidades);
|
|
486
|
+
modo = 'incremental';
|
|
487
|
+
}
|
|
488
|
+
catch (e) {
|
|
489
|
+
// O incremental nunca impede o indice: a completa decide, e o motivo fica dito.
|
|
490
|
+
motivoCompleto = `o incremental a partir de ${curta(base.revision)} falhou e a extracao foi completa (${e.message})`;
|
|
491
|
+
r = null;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (!r)
|
|
495
|
+
r = (0, intelligence_graph_extract_1.extrairGrafo)(entrada, parser);
|
|
338
496
|
const bytesDe = new Map(entrada.fontes.map((f) => [f.path, f.bytes]));
|
|
339
497
|
const fornecidas = new Map(r.grafo.snapshot.source_manifest.map((m) => {
|
|
340
498
|
const b = bytesDe.get(m.path);
|
|
341
499
|
return [m.path, { tipo: (0, intelligence_graph_extract_1.decodificarUtf8)(b) === null ? 'binario' : 'texto', bytes: b }];
|
|
342
500
|
}));
|
|
343
|
-
|
|
501
|
+
// KG4 (D6): `r.grafo` e o retorno de `validarGrafo` dentro da extracao; validar de novo so repetiria.
|
|
502
|
+
const conferencia = (0, intelligence_graph_contract_1.conferirFontesDoGrafoValidado)(r.grafo, fornecidas);
|
|
344
503
|
if (conferencia.estado !== 'verificada' || conferencia.evidenciasIndisponiveis > 0)
|
|
345
504
|
falha('grafo.indice.fontes-nao-conferidas');
|
|
346
|
-
|
|
505
|
+
const textoDoGrafo = (0, intelligence_graph_contract_1.canonico)(r.grafo), textoDoRelatorio = (0, intelligence_graph_contract_1.canonico)(r.relatorio), unidades = textoDasUnidades(r.unidades);
|
|
506
|
+
if (sha256(textoDoGrafo) !== r.digest)
|
|
507
|
+
falha('grafo.indice.digest-divergente');
|
|
508
|
+
let determinismo = null, incremental = null;
|
|
347
509
|
if (opcoes.verificar) {
|
|
348
|
-
const relatorio = (
|
|
510
|
+
const relatorio = sha256(textoDoRelatorio), dasUnidades = sha256(unidades);
|
|
349
511
|
determinismo = [['ordem invertida', [...entrada.fontes].reverse()], ['ordem embaralhada', embaralhar(entrada.fontes, 2026)]]
|
|
350
512
|
.map(([ordem, fontes]) => {
|
|
351
513
|
const outra = (0, intelligence_graph_extract_1.extrairGrafo)({ ...entrada, fontes }, parser);
|
|
352
|
-
const doOutro = (0, intelligence_graph_contract_1.sha256DoCanonico)(outra.relatorio);
|
|
353
|
-
return {
|
|
514
|
+
const doOutro = (0, intelligence_graph_contract_1.sha256DoCanonico)(outra.relatorio), unidadesDoOutro = sha256(textoDasUnidades(outra.unidades));
|
|
515
|
+
return {
|
|
516
|
+
ordem, digest: outra.digest, relatorio: doOutro, unidades: unidadesDoOutro,
|
|
517
|
+
igual: outra.digest === r.digest && doOutro === relatorio && unidadesDoOutro === dasUnidades,
|
|
518
|
+
};
|
|
354
519
|
});
|
|
355
520
|
const diferente = determinismo.find((d) => !d.igual);
|
|
356
521
|
if (diferente)
|
|
357
522
|
falha('grafo.indice.nao-deterministico', diferente.ordem);
|
|
523
|
+
if (base) {
|
|
524
|
+
// KG4 (D7): a prova no repositorio de quem usa: o incremental da base da os mesmos bytes da completa.
|
|
525
|
+
let inc;
|
|
526
|
+
try {
|
|
527
|
+
inc = (0, intelligence_graph_extract_1.extrairGrafo)(entrada, parser, base.unidades);
|
|
528
|
+
}
|
|
529
|
+
catch (e) {
|
|
530
|
+
falha('grafo.indice.incremental-divergente', `o incremental da base ${curta(base.revision)} falhou: ${e.message}`);
|
|
531
|
+
}
|
|
532
|
+
const igual = (0, intelligence_graph_contract_1.canonico)(inc.grafo) === textoDoGrafo && (0, intelligence_graph_contract_1.canonico)(inc.relatorio) === textoDoRelatorio && textoDasUnidades(inc.unidades) === unidades;
|
|
533
|
+
if (!igual)
|
|
534
|
+
falha('grafo.indice.incremental-divergente', `base ${curta(base.revision)}`);
|
|
535
|
+
incremental = { base: base.revision, igual, reaproveitamento: inc.reaproveitamento };
|
|
536
|
+
}
|
|
358
537
|
}
|
|
359
|
-
const textoDoGrafo = (0, intelligence_graph_contract_1.canonico)(r.grafo), textoDoRelatorio = (0, intelligence_graph_contract_1.canonico)(r.relatorio);
|
|
360
|
-
if (sha256(textoDoGrafo) !== r.digest)
|
|
361
|
-
falha('grafo.indice.digest-divergente');
|
|
362
538
|
const manifesto = {
|
|
363
|
-
schema: exports.INDICE_SCHEMA, chave, revision:
|
|
539
|
+
schema: exports.INDICE_SCHEMA, chave, revision: head, ...perfil, graph_schema: intelligence_graph_contract_1.GRAFO_SCHEMA, snapshot_id: r.grafo.snapshot.snapshot_id,
|
|
364
540
|
graph_digest: r.digest, graph_bytes: Buffer.byteLength(textoDoGrafo, 'utf8'),
|
|
365
541
|
report_digest: sha256(textoDoRelatorio), report_bytes: Buffer.byteLength(textoDoRelatorio, 'utf8'),
|
|
366
542
|
contagens: r.relatorio.contagens,
|
|
367
543
|
conferencia: { fontes: conferencia.fontesVerificadas.length, evidencias: conferencia.evidenciasVerificadas },
|
|
544
|
+
units_schema: intelligence_graph_extract_1.UNIDADES_SCHEMA, units_digest: sha256(unidades), units_bytes: Buffer.byteLength(unidades, 'utf8'),
|
|
368
545
|
};
|
|
369
546
|
const conteudos = {
|
|
370
|
-
[ARQUIVOS.manifesto]: (0, intelligence_graph_contract_1.canonico)(manifesto), [ARQUIVOS.grafo]: textoDoGrafo, [ARQUIVOS.relatorio]: textoDoRelatorio,
|
|
547
|
+
[ARQUIVOS.manifesto]: (0, intelligence_graph_contract_1.canonico)(manifesto), [ARQUIVOS.grafo]: textoDoGrafo, [ARQUIVOS.relatorio]: textoDoRelatorio, [ARQUIVOS.unidades]: unidades,
|
|
371
548
|
};
|
|
549
|
+
const daBase = modo === 'incremental' && base ? { revision: base.revision, chave: base.chave } : opcoes.verificar && base ? { revision: base.revision, chave: base.chave } : null;
|
|
372
550
|
const tmp = path.join(grafoDir, `.tmp-${(0, node_crypto_1.randomUUID)()}`);
|
|
373
551
|
pastaPrivada(tmp, true);
|
|
374
552
|
try {
|
|
@@ -376,7 +554,10 @@ function construirIndice(ctx, opcoes = {}) {
|
|
|
376
554
|
gravarPrivado(path.join(tmp, nome), texto);
|
|
377
555
|
sincronizarPasta(tmp);
|
|
378
556
|
opcoes.antesDePublicar?.();
|
|
379
|
-
const resultado = (estado) => ({
|
|
557
|
+
const resultado = (estado) => ({
|
|
558
|
+
estado, motivo, chave, dir: final, manifesto, determinismo, ms: ms(), modo, base: daBase,
|
|
559
|
+
motivo_completo: modo === 'incremental' ? null : motivoCompleto, reaproveitamento: r?.reaproveitamento ?? null, incremental,
|
|
560
|
+
});
|
|
380
561
|
if (!existia && fs.lstatSync(final, { throwIfNoEntry: false })) {
|
|
381
562
|
// Corrida: outra construcao publicou a mesma chave durante esta. Vale a dela, se estiver integra.
|
|
382
563
|
lerIndice(ctx, chave, { grafo: false });
|
|
@@ -46,10 +46,12 @@ exports.carregarAnalisadores = carregarAnalisadores;
|
|
|
46
46
|
* `typescript` e os pacotes do micromark so valem dentro da instalacao do `ork` que roda (o
|
|
47
47
|
* `node_modules` do pacote `@orkastery/cli` que contem este modulo), nunca do diretorio atual, do
|
|
48
48
|
* `NODE_PATH` nem de uma pasta acima, como a do projeto que instalou o `ork` como dependencia: o
|
|
49
|
-
* repositorio lido e dado, e codigo dele nunca e carregado.
|
|
50
|
-
*
|
|
51
|
-
* instalacao
|
|
52
|
-
*
|
|
49
|
+
* repositorio lido e dado, e codigo dele nunca e carregado. Desde a correcao de empacotamento da
|
|
50
|
+
* RM-031 eles sao dependencias de runtime do pacote publicado, com versao exata, e o
|
|
51
|
+
* `npm install -g` os poe dentro da instalacao; onde faltam ou estao fora dela (o `ork` instalado
|
|
52
|
+
* dentro de um projeto ou pelo `npx`, que icam as dependencias), a recusa e
|
|
53
|
+
* `grafo.parser.indisponivel: <pacote>`, e o `ork doctor` diz a correcao. `pacotesDosAnalisadores`
|
|
54
|
+
* lista o fecho de dependencias deles, com versao, para a chave do indice (CHECK rodada 1, A10).
|
|
53
55
|
*
|
|
54
56
|
* O juiz de sintaxe e o V8 do Node que roda a extracao, o mesmo que carregaria o arquivo. CommonJS
|
|
55
57
|
* compila aqui, em funcao com as variaveis do modulo, como o carregador faz. ESM compila num unico
|
|
@@ -37,6 +37,7 @@ exports.TENANT_PADRAO = void 0;
|
|
|
37
37
|
exports.identidadeDaLeitura = identidadeDaLeitura;
|
|
38
38
|
exports.revisaoDaArvore = revisaoDaArvore;
|
|
39
39
|
exports.headsDasArvores = headsDasArvores;
|
|
40
|
+
exports.revisoesAncestrais = revisoesAncestrais;
|
|
40
41
|
exports.lerRepositorio = lerRepositorio;
|
|
41
42
|
/**
|
|
42
43
|
* RM-031 KG2 (D8): leitura do repositorio Git local para o extrator. E a unica borda de E/S do
|
|
@@ -118,6 +119,15 @@ function headsDasArvores(diretorio) {
|
|
|
118
119
|
const saida = obrigatorio(diretorio, ['worktree', 'list', '--porcelain']).toString('utf8');
|
|
119
120
|
return [...new Set(saida.split('\n').filter((l) => /^HEAD [0-9a-f]{40,64}$/.test(l)).map((l) => l.slice(5)))].sort();
|
|
120
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* RM-031 KG4 (D1): o HEAD e as revisoes ancestrais dele (`git rev-list`), da mais recente para a mais
|
|
124
|
+
* antiga, ate o limite. Sem commit, ou com o Git falhando, nao ha ancestral.
|
|
125
|
+
*/
|
|
126
|
+
function revisoesAncestrais(diretorio, limite) {
|
|
127
|
+
const raiz = obrigatorio(diretorio, ['rev-parse', '--show-toplevel']).toString('utf8').trim();
|
|
128
|
+
const r = git(raiz, ['rev-list', `--max-count=${Math.max(1, Math.floor(limite))}`, 'HEAD']);
|
|
129
|
+
return r.ok ? r.saida.toString('utf8').split('\n').filter((l) => /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(l)) : [];
|
|
130
|
+
}
|
|
121
131
|
/** Le o repositorio que contem `diretorio` e devolve a entrada do extrator. */
|
|
122
132
|
function lerRepositorio(diretorio, opcoes = {}) {
|
|
123
133
|
const raiz = obrigatorio(diretorio, ['rev-parse', '--show-toplevel']).toString('utf8').trim();
|