@orkastery/cli 0.5.1 → 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/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- 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 +24 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +46 -11
- 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 +49 -11
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +39 -5
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +5 -1
- 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/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +48 -9
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +89 -9
- package/dist/entrega-pr.js +20 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +14 -6
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- 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 +9 -0
- 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 +52 -10
- package/dist/impedimento.js +205 -0
- package/dist/index.js +391 -74
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +17 -0
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +91 -8
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +3 -0
- package/dist/licoes.js +1 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +20 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +34 -3
- package/dist/mcp-git.js +20 -3
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +50 -4
- package/dist/mcp-server.js +14 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +191 -16
- package/dist/ocupacao.js +11 -3
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +12 -10
- package/dist/parado-no-condutor.js +188 -32
- package/dist/phase.js +68 -15
- package/dist/policies.js +52 -1
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +34 -2
- package/dist/pulse.js +49 -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 +23 -3
- 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 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship.js +85 -19
- package/dist/thread.js +192 -13
- package/dist/worktree.js +5 -2
- 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/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
package/dist/indice-vetorial.js
CHANGED
|
@@ -56,13 +56,19 @@ exports.decodificarVetor = decodificarVetor;
|
|
|
56
56
|
exports.lerIndice = lerIndice;
|
|
57
57
|
exports.serializarIndice = serializarIndice;
|
|
58
58
|
exports.gravarIndice = gravarIndice;
|
|
59
|
-
exports.
|
|
59
|
+
exports.conferirUniverso = conferirUniverso;
|
|
60
|
+
exports.universoDaBusca = universoDaBusca;
|
|
61
|
+
exports.codigoDaFalha = codigoDaFalha;
|
|
60
62
|
exports.conteudoRecusado = conteudoRecusado;
|
|
63
|
+
exports.indexavel = indexavel;
|
|
61
64
|
exports.tokensEstimados = tokensEstimados;
|
|
62
65
|
exports.dimDoModeloLocal = dimDoModeloLocal;
|
|
63
66
|
exports.codigoDeEmbedding = codigoDeEmbedding;
|
|
64
67
|
exports.espacoDoAlvo = espacoDoAlvo;
|
|
65
68
|
exports.indexar = indexar;
|
|
69
|
+
exports.avisoDeCobertura = avisoDeCobertura;
|
|
70
|
+
exports.textoForaDaBusca = textoForaDaBusca;
|
|
71
|
+
exports.textoDoIndice = textoDoIndice;
|
|
66
72
|
exports.vetoresCoerentes = vetoresCoerentes;
|
|
67
73
|
const fs = __importStar(require("node:fs"));
|
|
68
74
|
const os = __importStar(require("node:os"));
|
|
@@ -170,18 +176,48 @@ function gravarIndice(arquivo, indice) {
|
|
|
170
176
|
return true;
|
|
171
177
|
}
|
|
172
178
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
179
|
+
* RM-038 (D6): a fronteira do universo no `ork`, num lugar so. Entrada de outro tenant, de colecao
|
|
180
|
+
* fora do ork ou com id repetido e violacao tipada, nunca descarte silencioso: nada disso vai ao embed.
|
|
175
181
|
*/
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
function conferirUniverso(entradas, tenant, lidoEm = Date.now()) {
|
|
183
|
+
const vistos = new Set();
|
|
184
|
+
for (const e of entradas) {
|
|
185
|
+
if (!(0, orkmind_1.pertenceAoUniverso)(e, tenant, lidoEm) || vistos.has(e.id))
|
|
186
|
+
throw new Error('memory.query.scope-violation');
|
|
187
|
+
vistos.add(e.id);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* RM-038 (D4): o universo da busca e do indice, o domicilio unico. A fonte le uma vez (a ponte
|
|
192
|
+
* filtra o tenant na origem e aplica a governanca da biblioteca); aqui a fronteira e conferida de
|
|
193
|
+
* novo, a ordem fica estavel e a contagem por colecao sai pronta para o status e o index.
|
|
194
|
+
*/
|
|
195
|
+
function universoDaBusca(fonte, tenant) {
|
|
196
|
+
const lidoEm = Date.now();
|
|
197
|
+
const lido = fonte.universo(tenant);
|
|
198
|
+
conferirUniverso(lido.entradas, tenant, lidoEm);
|
|
199
|
+
const entradas = [...lido.entradas].sort((a, b) => a.collection.localeCompare(b.collection) || a.id.localeCompare(b.id));
|
|
200
|
+
const porColecao = Object.fromEntries(orkmind_1.COLECOES_DO_ORK.map(c => [c, 0]));
|
|
201
|
+
for (const e of entradas)
|
|
202
|
+
porColecao[e.collection] += 1;
|
|
203
|
+
return { tenant, lidoEm, entradas, porColecao, foraDaBusca: lido.foraDaBusca,
|
|
204
|
+
...(lido.latenciaMs === undefined ? {} : { latenciaMs: lido.latenciaMs }) };
|
|
205
|
+
}
|
|
206
|
+
/** Codigo tipado de uma falha (`memory.query.window-saturated`), ou o padrao quando nao ha. */
|
|
207
|
+
function codigoDaFalha(erro, padrao = 'memory.universo.indisponivel') {
|
|
208
|
+
return /^[a-z]+(?:\.[a-z-]+)+/.exec(erro instanceof Error ? erro.message : '')?.[0] ?? padrao;
|
|
180
209
|
}
|
|
181
210
|
/** Conteudo que nunca vai ao provider: padrao de segredo da policy ou URL com credencial. */
|
|
182
211
|
function conteudoRecusado(conteudo) {
|
|
183
212
|
return (0, policies_1.procurarSegredos)(conteudo).length > 0 || URL_COM_CREDENCIAL.test(conteudo);
|
|
184
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* RM-038: o indice embeda a entrada? Nao embeda texto vazio, acima do limite nem com padrao de
|
|
216
|
+
* segredo. Domicilio unico para o `indexar` e para o aviso de cobertura do status.
|
|
217
|
+
*/
|
|
218
|
+
function indexavel(e) {
|
|
219
|
+
return e.content.trim() !== '' && e.content.length <= orkmind_1.EMBED_MAX_CARACTERES && !conteudoRecusado(e.content);
|
|
220
|
+
}
|
|
185
221
|
function tokensEstimados(conteudo) {
|
|
186
222
|
return Math.ceil(conteudo.length / exports.CARACTERES_POR_TOKEN);
|
|
187
223
|
}
|
|
@@ -236,13 +272,20 @@ function espacoDoAlvo(config, alvo, env = process.env) {
|
|
|
236
272
|
* que ja voltaram, porque cada vetor gravado e coerente por si.
|
|
237
273
|
*/
|
|
238
274
|
function indexar(o) {
|
|
275
|
+
// RM-038 (D6): conferir de novo antes de qualquer coisa; nada de outro tenant vai ao embed, nem de
|
|
276
|
+
// um chamador que montou o universo a mao. Violacao falha alto, nunca vira descarte silencioso.
|
|
277
|
+
if (o.universo.tenant !== o.tenant)
|
|
278
|
+
throw new Error('memory.query.scope-violation');
|
|
279
|
+
conferirUniverso(o.universo.entradas, o.tenant, o.universo.lidoEm);
|
|
239
280
|
const espaco = espacoDoAlvo(o.config, o.alvo, o.env);
|
|
240
|
-
const universo = o.universo.
|
|
281
|
+
const universo = o.universo.entradas;
|
|
241
282
|
const foraDoLimite = universo.filter(e => e.content.length > orkmind_1.EMBED_MAX_CARACTERES);
|
|
242
283
|
const recusados = universo.filter(e => e.content.length <= orkmind_1.EMBED_MAX_CARACTERES && conteudoRecusado(e.content));
|
|
243
|
-
const indexaveis = universo.filter(
|
|
284
|
+
const indexaveis = universo.filter(indexavel);
|
|
244
285
|
const base = { alvo: o.alvo, modelo: null, dim: null, arquivo: null, dryRun: o.dryRun,
|
|
245
|
-
universo: universo.length,
|
|
286
|
+
universo: universo.length, porColecao: { ...o.universo.porColecao }, foraDaBusca: o.universo.foraDaBusca,
|
|
287
|
+
latenciaUniversoMs: o.universo.latenciaMs ?? null,
|
|
288
|
+
coerentes: 0, embedados: 0, reescritos: 0, removidos: 0, recusados: recusados.length,
|
|
246
289
|
foraDoLimite: foraDoLimite.length, truncados: 0, tokensEstimados: 0, custoEstimadoUsd: 0, chamadasAoProvider: 0, motivo: null, detalhe: '' };
|
|
247
290
|
if ('motivo' in espaco) {
|
|
248
291
|
const tokens = indexaveis.reduce((t, e) => t + tokensEstimados(e.content), 0);
|
|
@@ -302,6 +345,40 @@ function indexar(o) {
|
|
|
302
345
|
return { ...r, motivo, detalhe: `indexacao interrompida depois de ${r.embedados} vetor(es); os lotes concluidos ficaram gravados` };
|
|
303
346
|
return r;
|
|
304
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* RM-038 (D7): o aviso de cobertura, o mesmo no status e na busca. Reindexar so e sugerido quando
|
|
350
|
+
* resolve; o que o indice nunca embeda (vazio, acima do limite, padrao de segredo) e dito a parte.
|
|
351
|
+
*/
|
|
352
|
+
function avisoDeCobertura(coerentes, entradas, alvo, onde = '') {
|
|
353
|
+
if (coerentes >= entradas.length)
|
|
354
|
+
return null;
|
|
355
|
+
const foraPorDesenho = entradas.filter(e => !indexavel(e)).length;
|
|
356
|
+
const base = `o indice cobre ${coerentes} de ${entradas.length} entrada(s) que a busca enxerga${onde}`;
|
|
357
|
+
if (coerentes < entradas.length - foraPorDesenho)
|
|
358
|
+
return `${base}: rode ork memory index${alvo === 'fallback' ? ' --modelo fallback' : ''}`;
|
|
359
|
+
return `${base}; ${foraPorDesenho} fica(m) fora do indice por desenho (vazia, acima de ${orkmind_1.EMBED_MAX_CARACTERES} caracteres ou com padrao de segredo)`;
|
|
360
|
+
}
|
|
361
|
+
/** RM-038: a linha do que fica fora da busca, a mesma no `ork memory index` e no `ork memory status`. */
|
|
362
|
+
function textoForaDaBusca(f) {
|
|
363
|
+
return f ? `${f.injecao} com injection_risk e ${f.expiradas} expirada(s) (governanca da biblioteca), ` +
|
|
364
|
+
`${f.outrasColecoes} em outras colecoes (fora da busca do ork); nada disso vai ao embed` : 'nao medido nesta base';
|
|
365
|
+
}
|
|
366
|
+
/** Texto de `ork memory index`: de que universo, o que foi (ou seria) embedado e quanto custa estimado. */
|
|
367
|
+
function textoDoIndice(r) {
|
|
368
|
+
const custo = r.custoEstimadoUsd === null ? 'nao estimado' : `US$ ${r.custoEstimadoUsd.toFixed(8)}`;
|
|
369
|
+
const colecoes = Object.entries(r.porColecao).map(([c, n]) => `${c} ${n}`).join(', ');
|
|
370
|
+
return [
|
|
371
|
+
`Indice vetorial (${r.alvo}${r.dryRun ? ', --dry-run' : ''}): ${r.modelo ?? '(sem modelo)'}${r.dim ? ` / ${r.dim} dim` : ''}`,
|
|
372
|
+
` universo da busca ${r.universo} entrada(s): ${colecoes}; coerentes ${r.coerentes}`,
|
|
373
|
+
` fora da busca ${textoForaDaBusca(r.foraDaBusca)}`,
|
|
374
|
+
` embedados ${r.embedados} (reescritos ${r.reescritos}); removidos ${r.removidos}`,
|
|
375
|
+
` fora do indice ${r.recusados} recusada(s) por padrao de segredo, ${r.foraDoLimite} acima do limite`,
|
|
376
|
+
...(r.truncados ? [` truncados ${r.truncados} acima do contexto do modelo local, embedados pelo comeco`] : []),
|
|
377
|
+
` estimativa ${r.tokensEstimados} token(s), ${custo}; chamadas ao provider ${r.chamadasAoProvider}`,
|
|
378
|
+
...(r.arquivo ? [` arquivo ${r.arquivo}`] : []),
|
|
379
|
+
...(r.motivo ? [` motivo ${r.motivo}: ${r.detalhe}`] : r.detalhe ? [` ${r.detalhe}`] : []),
|
|
380
|
+
].join('\n');
|
|
381
|
+
}
|
|
305
382
|
/** Vetores coerentes de um indice para o universo informado: a base da busca e da cobertura. */
|
|
306
383
|
function vetoresCoerentes(indice, universo) {
|
|
307
384
|
const saida = new Map();
|
package/dist/indice.js
CHANGED
|
@@ -63,7 +63,9 @@ function calcularIndice(eventos) {
|
|
|
63
63
|
const parcelas = [];
|
|
64
64
|
let valor = exports.INDICE_BASE;
|
|
65
65
|
for (const insumo of exports.INSUMOS_DO_INDICE) {
|
|
66
|
-
|
|
66
|
+
// Ensaio de 03/10/2026 (RM-049): o `ork ship --dry-run` barrado grava `ship_blocked` com `dryRun: true`;
|
|
67
|
+
// ensaio nao e tropeco da entrega, como ja nao e pausa no board (fatia 2 do ensaio da 0.5.0, P2).
|
|
68
|
+
const ocorrencias = eventos.filter((e) => e.tipo === insumo.evento && e.dryRun !== true).length;
|
|
67
69
|
if (ocorrencias === 0)
|
|
68
70
|
continue;
|
|
69
71
|
const bruto = insumo.peso * ocorrencias;
|
package/dist/init.js
CHANGED
|
@@ -46,6 +46,7 @@ exports.baseBranchDetectada = baseBranchDetectada;
|
|
|
46
46
|
exports.verifyDetectado = verifyDetectado;
|
|
47
47
|
exports.detectar = detectar;
|
|
48
48
|
exports.manifestoYaml = manifestoYaml;
|
|
49
|
+
exports.exigirRepositorioParaInit = exigirRepositorioParaInit;
|
|
49
50
|
exports.init = init;
|
|
50
51
|
const fs = __importStar(require("node:fs"));
|
|
51
52
|
const path = __importStar(require("node:path"));
|
|
@@ -192,6 +193,8 @@ conduction:
|
|
|
192
193
|
worktree:
|
|
193
194
|
base_branch: "${d.baseBranch}"
|
|
194
195
|
dir: ".claude/worktrees"
|
|
196
|
+
# true: o ork thread new cria a worktree e a branch da thread sem flag (--sem-worktree cria sem);
|
|
197
|
+
# false ou ausente: só com --worktree auto
|
|
195
198
|
por_thread: true
|
|
196
199
|
|
|
197
200
|
verify:
|
|
@@ -259,6 +262,20 @@ policies:
|
|
|
259
262
|
push_direto_na_base: block
|
|
260
263
|
`;
|
|
261
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Ensaio de 03/10/2026 (RM-049): o `ork init` rodado por engano fora de um repositorio (no HOME, por
|
|
267
|
+
* exemplo) gravava manifesto, `AGENTS.md` e `.orkastery/` ali e saia 0; um repositorio criado depois
|
|
268
|
+
* dentro dessa pasta herdava o manifesto de fora, com outro nome e outra abbrev, e o doctor dizia PRONTO.
|
|
269
|
+
* A CLI recusa antes de gravar qualquer coisa. A funcao `init` segue aceitando qualquer pasta (demo e
|
|
270
|
+
* canarios montam o projeto por ela).
|
|
271
|
+
*/
|
|
272
|
+
function exigirRepositorioParaInit(dir) {
|
|
273
|
+
const r = (0, util_1.exec)('git', ['rev-parse', '--is-inside-work-tree'], dir);
|
|
274
|
+
if (r.ok && r.stdout.trim() === 'true')
|
|
275
|
+
return;
|
|
276
|
+
throw new Error(`init.fora-do-repositorio: ${path.resolve(dir)} não está num repositório git; nada foi criado. ` +
|
|
277
|
+
'Entre no repositório do projeto (ou crie um com git init e o primeiro commit) e rode ork init de novo.');
|
|
278
|
+
}
|
|
262
279
|
/** Gera o manifesto e o esqueleto de `.orkastery/`. Nao sobrescreve sem `force`. */
|
|
263
280
|
function init(dirInicial, opcoes = {}) {
|
|
264
281
|
const deteccao = detectar(dirInicial, opcoes.nome, opcoes.abbrev);
|
|
@@ -16,4 +16,6 @@ exports.TESTES_DE_INTEGRACAO_LOCAL = new Set([
|
|
|
16
16
|
'memory-publication-profile.test.js', 'native-fixture.test.js', 'orkmind-transport.test.js', 'verify-sandbox.test.js',
|
|
17
17
|
// RM-037 (fatia 3): o worker do ork_git_commit e o sandbox do verify de verdade, como no mcp-git.test.js.
|
|
18
18
|
'rm037-fatia3-hard-link-mcp-git.test.js', 'rm037-fatia3-lease-mcp-git.test.js',
|
|
19
|
+
// RM-038 (fatia de correcao): a ponte com o GovernedStore real da biblioteca instalada.
|
|
20
|
+
'rm038-universo-ponte.test.js',
|
|
19
21
|
]);
|
|
@@ -34,6 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.CORRECAO_DO_INDICE = exports.USO_DO_GRAFO = exports.AMOSTRA_SCHEMA = exports.STATUS_SCHEMA = void 0;
|
|
37
|
+
exports.descreverVersoes = descreverVersoes;
|
|
38
|
+
exports.correcaoDosAnalisadores = correcaoDosAnalisadores;
|
|
39
|
+
exports.checarAnalisadoresDoGrafo = checarAnalisadoresDoGrafo;
|
|
37
40
|
exports.lerPedido = lerPedido;
|
|
38
41
|
exports.executarGrafo = executarGrafo;
|
|
39
42
|
/**
|
|
@@ -56,14 +59,62 @@ const fs = __importStar(require("node:fs"));
|
|
|
56
59
|
const path = __importStar(require("node:path"));
|
|
57
60
|
const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
|
|
58
61
|
const intelligence_graph_index_1 = require("./intelligence-graph-index");
|
|
62
|
+
const intelligence_graph_parsers_1 = require("./intelligence-graph-parsers");
|
|
59
63
|
const intelligence_graph_query_1 = require("./intelligence-graph-query");
|
|
60
64
|
const intelligence_graph_repo_1 = require("./intelligence-graph-repo");
|
|
65
|
+
const intelligence_graph_contexto_1 = require("./intelligence-graph-contexto");
|
|
61
66
|
exports.STATUS_SCHEMA = 'ork.code-graph-index-status/v0';
|
|
67
|
+
/** As versoes dos analisadores como o `ork grafo status` e o `ork doctor` as mostram. */
|
|
68
|
+
function descreverVersoes(v) {
|
|
69
|
+
return Object.entries(v).map(([k, x]) => `${k} ${x}`).join(', ');
|
|
70
|
+
}
|
|
71
|
+
/** O prefixo das recusas dos analisadores (`intelligence-graph-parsers.ts`). */
|
|
72
|
+
const RECUSA_DOS_ANALISADORES = 'grafo.parser.indisponivel';
|
|
73
|
+
/**
|
|
74
|
+
* RM-031 (pacote do npm): o que fazer quando os analisadores nao carregam, dito pelo `ork doctor` e
|
|
75
|
+
* pelo `ork grafo status`. O micromark e so ESM e carrega por `require`, o que o Node so faz sem flag
|
|
76
|
+
* a partir de 20.19 e de 22.12. Nos outros casos o pacote falta ou esta fora da instalacao do `ork`,
|
|
77
|
+
* e a instalacao global do npm traz os analisadores, que sao dependencias do pacote. Mora aqui, fora
|
|
78
|
+
* de `MODULOS_DO_EXTRATOR`, para a redacao nao entrar na chave do indice; a versao vem de quem chama
|
|
79
|
+
* (o `index.ts`), porque o CLI do grafo so importa a propria familia (fronteira do KG3).
|
|
80
|
+
*/
|
|
81
|
+
function correcaoDosAnalisadores(motivo, versao) {
|
|
82
|
+
if (/ERR_REQUIRE_ESM/.test(motivo)) {
|
|
83
|
+
return `o micromark e so ESM, e este Node (${process.version}) nao o carrega por require: use Node 20.19, 22.12 ou mais novo, ` +
|
|
84
|
+
'sem a opcao --no-experimental-require-module (na linha de comando ou no NODE_OPTIONS)';
|
|
85
|
+
}
|
|
86
|
+
// Sem a versao do pacote (`0.0.0-desconhecida` quando o package.json dele nao e achado), o comando
|
|
87
|
+
// sai sem `@<versao>` e o npm instala a ultima publicada.
|
|
88
|
+
const fixada = versao && /^\d+\.\d+\.\d+/.test(versao) && !versao.startsWith('0.0.0') ? `@${versao}` : '';
|
|
89
|
+
return `reinstale o ork global, que traz os analisadores como dependencias: npm install -g @orkastery/cli${fixada}` +
|
|
90
|
+
' (instalado dentro de um projeto ou pelo npx, o npm deixa os analisadores fora do pacote do ork, e o grafo os recusa)';
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* RM-031 (pacote do npm): o check "analisadores do grafo" do `ork doctor`. Carrega o que o
|
|
94
|
+
* `ork grafo indexar` carrega (`carregarAnalisadores`), entao diz o que o indexar faria, inclusive no
|
|
95
|
+
* Node sem `require` de ESM. A falta e `warn`, com a correcao: o grafo nao e condicao do despacho de
|
|
96
|
+
* fase. Fora da familia do grafo so o `index.ts` e o worker do MCP a abrem (fronteira do KG1), entao o
|
|
97
|
+
* `index.ts` passa este check ao doctor, que nao importa o grafo.
|
|
98
|
+
*/
|
|
99
|
+
function checarAnalisadoresDoGrafo(versao, carregar = intelligence_graph_parsers_1.carregarAnalisadores, versoes = intelligence_graph_parsers_1.versoesDosAnalisadores) {
|
|
100
|
+
const nome = 'analisadores do grafo';
|
|
101
|
+
try {
|
|
102
|
+
carregar();
|
|
103
|
+
return { nome, nivel: 'ok', detalhe: descreverVersoes(versoes()) };
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
const motivo = e.message;
|
|
107
|
+
return { nome, nivel: 'warn',
|
|
108
|
+
detalhe: `${motivo}: o ork grafo indexar recusa nesta instalacao, e sem o indice as consultas e as tools ork_grafo_* tambem`,
|
|
109
|
+
correcao: correcaoDosAnalisadores(motivo, versao) };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
62
112
|
/** O mesmo schema da amostra do KG2: as amostras auditadas continuam validas. */
|
|
63
113
|
exports.AMOSTRA_SCHEMA = 'ork.graph-edge-audit-sample/v0';
|
|
64
114
|
exports.USO_DO_GRAFO = [
|
|
65
115
|
'uso: ork grafo indexar [--verificar] [--forcar] [--json]',
|
|
66
116
|
' ork grafo status [--json]',
|
|
117
|
+
' ork grafo contexto <thread> [--json [--teto-bytes N]]',
|
|
67
118
|
' ork grafo vizinhos <no> [--profundidade N] [--sentido entrada|saida|ambos] [--tipo T,...] [--limite N] [--json [--teto-bytes N]]',
|
|
68
119
|
' ork grafo chamadores <simbolo> [--profundidade N] [--limite N] [--json [--teto-bytes N]]',
|
|
69
120
|
' ork grafo importadores <arquivo|simbolo> [--profundidade N] [--limite N] [--json [--teto-bytes N]]',
|
|
@@ -83,6 +134,7 @@ const ESTADO_DO_INDICE = Object.freeze({
|
|
|
83
134
|
const SUBCOMANDOS = Object.freeze({
|
|
84
135
|
indexar: { posicionais: 0, bandeiras: ['verificar', 'forcar', 'json'], valores: [] },
|
|
85
136
|
status: { posicionais: 0, bandeiras: ['json'], valores: [] },
|
|
137
|
+
contexto: { posicionais: 1, bandeiras: ['json'], valores: ['teto-bytes'] },
|
|
86
138
|
vizinhos: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'sentido', 'tipo', 'limite', 'teto-bytes'] },
|
|
87
139
|
chamadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite', 'teto-bytes'] },
|
|
88
140
|
importadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite', 'teto-bytes'] },
|
|
@@ -238,9 +290,11 @@ function status(ctx, p) {
|
|
|
238
290
|
const doHead = chave ? estado.indices.find((i) => i.chave === chave) ?? null : null;
|
|
239
291
|
// Sem analisadores nao ha chave: o indice do HEAD fica indisponivel, nunca "ausente" (indexar tambem nao roda).
|
|
240
292
|
const indiceDoHeadEstado = erro ? 'indisponivel' : doHead ? (doHead.problema ? 'com-problema' : 'presente') : 'ausente';
|
|
293
|
+
// RM-031 (pacote do npm): a recusa dos analisadores vem com o que fazer, a mesma correcao do `ork doctor`.
|
|
294
|
+
const correcao = erro !== null && erro.startsWith(RECUSA_DOS_ANALISADORES) ? correcaoDosAnalisadores(erro, ctx.versao) : null;
|
|
241
295
|
const r = {
|
|
242
296
|
schema: exports.STATUS_SCHEMA, head: arvore.head, arvore: arvore.motivo === null ? 'limpa' : arvore.motivo, chave_do_head: chave,
|
|
243
|
-
indice_do_head: indiceDoHeadEstado, analisadores, erro,
|
|
297
|
+
indice_do_head: indiceDoHeadEstado, analisadores, erro, correcao,
|
|
244
298
|
dir: estado.dir, bytes: estado.bytes, indices: estado.indices, sobras: estado.sobras,
|
|
245
299
|
};
|
|
246
300
|
if (p.bandeiras.has('json')) {
|
|
@@ -250,8 +304,11 @@ function status(ctx, p) {
|
|
|
250
304
|
const linhas = [
|
|
251
305
|
`grafo: HEAD ${arvore.head ? arvore.head.slice(0, 12) : 'sem commit'}, arvore ${r.arvore}`,
|
|
252
306
|
` indice do HEAD ${chave ?? 'indisponivel'} ${r.indice_do_head === 'ausente' ? '(ausente: rode ork grafo indexar)'
|
|
253
|
-
: r.indice_do_head === 'indisponivel'
|
|
254
|
-
|
|
307
|
+
: r.indice_do_head === 'indisponivel'
|
|
308
|
+
? (correcao ? '(sem os analisadores nesta instalacao, nem a consulta nem o indexar rodam)' : '(sem a chave do indice: o erro esta na linha de baixo)')
|
|
309
|
+
: `(${r.indice_do_head})`}`,
|
|
310
|
+
` analisadores ${erro ?? descreverVersoes(analisadores)}`,
|
|
311
|
+
...(correcao ? [` correcao ${correcao}`] : []),
|
|
255
312
|
` pasta ${estado.dir ?? 'ainda nao criada'} (${estado.indices.length} indice(s), ${mb(estado.bytes)})`,
|
|
256
313
|
];
|
|
257
314
|
for (const i of estado.indices) {
|
|
@@ -388,6 +445,29 @@ function consultar(ctx, p) {
|
|
|
388
445
|
ctx.escrever(respostaComTeto(perguntar, limite, teto));
|
|
389
446
|
return 0;
|
|
390
447
|
}
|
|
448
|
+
function contexto(ctx, p) {
|
|
449
|
+
const teto = tetoDeBytes(p);
|
|
450
|
+
if (teto !== undefined && (teto < 4096 || teto > 65536))
|
|
451
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-invalido', 'teto deve ser inteiro de 4096 a 65536 bytes');
|
|
452
|
+
if (!ctx.contextoDaThread)
|
|
453
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.indisponivel', 'borda sem leitor da thread');
|
|
454
|
+
const lido = ctx.contextoDaThread(p.posicionais[0]);
|
|
455
|
+
const { grafo, cabecalho } = consultavel({ ...ctx, raiz: lido.raiz });
|
|
456
|
+
if (lido.head !== cabecalho.revision)
|
|
457
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.revisao-mudou', 'HEAD mudou durante a leitura; repita a consulta');
|
|
458
|
+
const json = (0, intelligence_graph_contexto_1.pacoteDeContexto)(grafo, cabecalho, lido.entrada, teto);
|
|
459
|
+
if (p.bandeiras.has('json'))
|
|
460
|
+
ctx.escrever(json);
|
|
461
|
+
else {
|
|
462
|
+
const r = JSON.parse(json);
|
|
463
|
+
ctx.escrever([`Contexto ${r.thread} @ ${r.indice.revision}`,
|
|
464
|
+
` ${r.sementes.length}/${r.total_sementes} sementes, ${r.arestas.length}/${r.total_ligacoes} ligacoes agregadas; ${r.medida.pacote_bytes} bytes JSON`,
|
|
465
|
+
` tamanho dos arquivos no pacote (nao descoberta): ${r.medida.leitura_crua_bytes} bytes (revisao indexada); tokens: unavailable`,
|
|
466
|
+
` diff: ${r.fontes.diff}`,
|
|
467
|
+
` truncado: ${r.truncado}; arvore: ${r.indice.arvore}; use --json para nos e evidencias`, json].join('\n'));
|
|
468
|
+
}
|
|
469
|
+
return 0;
|
|
470
|
+
}
|
|
391
471
|
const sha256 = (b) => (0, node_crypto_1.createHash)('sha256').update(b).digest('hex');
|
|
392
472
|
/**
|
|
393
473
|
* Bytes da arvore, conferidos arquivo a arquivo contra o manifesto do indice: o trecho da amostra e
|
|
@@ -541,12 +621,12 @@ function limpar(ctx, p) {
|
|
|
541
621
|
return 0;
|
|
542
622
|
}
|
|
543
623
|
/** KG5 (D4, D5): com `--teto-bytes` o erro tambem sai compacto; recusa de indice traz o estado e a correcao. */
|
|
544
|
-
const erroEmJson = (ctx, e, compacto) => {
|
|
624
|
+
const erroEmJson = (ctx, e, compacto, schema = intelligence_graph_query_1.CONSULTA_SCHEMA) => {
|
|
545
625
|
const [codigo, ...detalhe] = String(e.message).split('\n')[0].split(': ');
|
|
546
626
|
const doIndice = Object.prototype.hasOwnProperty.call(ESTADO_DO_INDICE, codigo)
|
|
547
627
|
? { estado_do_indice: ESTADO_DO_INDICE[codigo], correcao: exports.CORRECAO_DO_INDICE } : {};
|
|
548
628
|
const r = {
|
|
549
|
-
schema
|
|
629
|
+
schema,
|
|
550
630
|
erro: { codigo, detalhe: detalhe.join(': ') || null, candidatos: e instanceof intelligence_graph_query_1.ErroDeConsulta ? e.candidatos : [], ...doIndice },
|
|
551
631
|
};
|
|
552
632
|
ctx.escrever(compacto ? JSON.stringify(r) : JSON.stringify(r, null, 2));
|
|
@@ -554,7 +634,8 @@ const erroEmJson = (ctx, e, compacto) => {
|
|
|
554
634
|
};
|
|
555
635
|
/** `ork grafo <subcomando> ...`: devolve o codigo de saida; sem `--json`, o erro de uso ou tipado e lancado. */
|
|
556
636
|
function executarGrafo(argv, ctx) {
|
|
557
|
-
const
|
|
637
|
+
const schema = argv[0] === 'contexto' ? intelligence_graph_contexto_1.CONTEXTO_SCHEMA : intelligence_graph_query_1.CONSULTA_SCHEMA;
|
|
638
|
+
const compacto = argv[0] === 'contexto' || argv.some((a) => a === '--teto-bytes' || a.startsWith('--teto-bytes='));
|
|
558
639
|
let p;
|
|
559
640
|
try {
|
|
560
641
|
p = lerPedido(argv);
|
|
@@ -562,7 +643,7 @@ function executarGrafo(argv, ctx) {
|
|
|
562
643
|
catch (e) {
|
|
563
644
|
// Com `--json` no argv, tambem o erro de uso sai como objeto, como os demais.
|
|
564
645
|
if (argv.includes('--json'))
|
|
565
|
-
return erroEmJson(ctx, e, compacto);
|
|
646
|
+
return erroEmJson(ctx, e, compacto, schema);
|
|
566
647
|
throw e;
|
|
567
648
|
}
|
|
568
649
|
try {
|
|
@@ -574,11 +655,13 @@ function executarGrafo(argv, ctx) {
|
|
|
574
655
|
return amostra(ctx, p);
|
|
575
656
|
if (p.sub === 'limpar')
|
|
576
657
|
return limpar(ctx, p);
|
|
658
|
+
if (p.sub === 'contexto')
|
|
659
|
+
return contexto(ctx, p);
|
|
577
660
|
return consultar(ctx, p);
|
|
578
661
|
}
|
|
579
662
|
catch (e) {
|
|
580
663
|
if (!p.bandeiras.has('json'))
|
|
581
664
|
throw e;
|
|
582
|
-
return erroEmJson(ctx, e, compacto);
|
|
665
|
+
return erroEmJson(ctx, e, compacto, schema);
|
|
583
666
|
}
|
|
584
667
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CONTEXTO_FORA_DO_INDICE = exports.CONTEXTO_POR_ALVO = exports.CONTEXTO_TETO_PADRAO = exports.CONTEXTO_SCHEMA = void 0;
|
|
4
|
+
exports.sementesDaThread = sementesDaThread;
|
|
5
|
+
exports.pacoteDeContexto = pacoteDeContexto;
|
|
6
|
+
/** KG5 fatia 3: composicao pura do contexto da thread. Sem E/S, relogio ou inferencia. */
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
|
|
9
|
+
const intelligence_graph_query_1 = require("./intelligence-graph-query");
|
|
10
|
+
exports.CONTEXTO_SCHEMA = 'ork.thread-graph-context/v2';
|
|
11
|
+
exports.CONTEXTO_TETO_PADRAO = 32768;
|
|
12
|
+
exports.CONTEXTO_POR_ALVO = 8;
|
|
13
|
+
exports.CONTEXTO_FORA_DO_INDICE = 3;
|
|
14
|
+
const hash = (texto) => (0, node_crypto_1.createHash)('sha256').update(texto).digest('hex');
|
|
15
|
+
/** Caminho relativo do repositorio, nunca caminho de maquina, URL ou estado privado. */
|
|
16
|
+
function caminhoPublico(bruto) {
|
|
17
|
+
const p = bruto.replace(/^\.\//, '');
|
|
18
|
+
if (!p || p.startsWith('/') || p.startsWith('~') || /[:\\\u0000-\u001f\u007f]/.test(p) || p.length > 500
|
|
19
|
+
|| p.split('/').some((x) => !x || x === '..' || x === '.' || x === '.git' || x === '.orkastery'))
|
|
20
|
+
return null;
|
|
21
|
+
return p;
|
|
22
|
+
}
|
|
23
|
+
/** GOAL/PLAN citam caminhos relativos a raiz em codigo, links ou texto; nao executam instrucoes. */
|
|
24
|
+
function caminhosCitados(texto, diretorios) {
|
|
25
|
+
const r = [];
|
|
26
|
+
const semCitacoes = texto.replace(/`([^`\n]+)`|\]\(([^)\n]+)\)/g, (_m, codigo, link) => {
|
|
27
|
+
const v = codigo ?? link ?? '';
|
|
28
|
+
if (!/^(?:[a-z]+:|\/)/i.test(v) && (v.includes('/') || /\.[a-z0-9]+(?:#.*|:\d+(?::\d+)?)?$/i.test(v)
|
|
29
|
+
|| /^(?:Dockerfile|Makefile|LICENSE)$/.test(v)))
|
|
30
|
+
r.push(v.replace(/#.*$/, '').replace(/:\d+(?::\d+)?$/, ''));
|
|
31
|
+
return ' ';
|
|
32
|
+
});
|
|
33
|
+
// Em prosa, exigir diretorio ou extensao de fonte conhecida evita versoes, Node.js e dominios.
|
|
34
|
+
for (const m of semCitacoes.matchAll(/(?:^|[\s(\["'])((?:[\p{L}\p{N}_@.-]+\/)+[\p{L}\p{N}_@.-]+|[\p{L}\p{N}_@-]+\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|json|md|markdown|yaml|yml|toml|py|rs|go|c|h|css|html))(?=\.(?:\s|$)|[:#\s),;\]"']|$)/gu))
|
|
35
|
+
if (!/^Node\.js\.?$/i.test(m[1]))
|
|
36
|
+
r.push(m[1].replace(/\.$/, ''));
|
|
37
|
+
return r.filter((bruto) => {
|
|
38
|
+
const p = caminhoPublico(bruto);
|
|
39
|
+
return p !== null && !/^Node\.js$/i.test(p) && (/\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|json|md|markdown|yaml|yml|toml|py|rs|go|c|h|css|html)$/i.test(p)
|
|
40
|
+
|| /(?:^|\/)(?:Dockerfile|Makefile|LICENSE)$/.test(p)
|
|
41
|
+
|| (p.includes('/') && diretorios.has(p.split('/')[0])));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function sementesDaThread(entrada, caminhosDoRepositorio = []) {
|
|
45
|
+
const diretorios = new Set(caminhosDoRepositorio.filter((p) => p.includes('/')).map((p) => p.split('/')[0]));
|
|
46
|
+
const mapa = new Map();
|
|
47
|
+
const adicionar = (bruto, origem) => {
|
|
48
|
+
const p = caminhoPublico(bruto);
|
|
49
|
+
if (!p)
|
|
50
|
+
return;
|
|
51
|
+
const origens = mapa.get(p) ?? new Set();
|
|
52
|
+
origens.add(origem);
|
|
53
|
+
mapa.set(p, origens);
|
|
54
|
+
};
|
|
55
|
+
if (entrada.diffEstado !== 'ignorado-sem-worktree')
|
|
56
|
+
for (const p of entrada.diff)
|
|
57
|
+
adicionar(p, 'diff');
|
|
58
|
+
for (const tipo of ['goal', 'plan'])
|
|
59
|
+
for (const p of caminhosCitados(entrada[tipo] ?? '', diretorios))
|
|
60
|
+
adicionar(p, tipo);
|
|
61
|
+
for (const c of entrada.claims)
|
|
62
|
+
adicionar(c.arquivo, `claim:${c.id}`);
|
|
63
|
+
return [...mapa].sort(([a], [b]) => (0, intelligence_graph_contract_1.compararUtf8)(a, b))
|
|
64
|
+
.map(([arquivo, origens]) => ({ arquivo, origens: [...origens].sort(intelligence_graph_contract_1.compararUtf8) }));
|
|
65
|
+
}
|
|
66
|
+
/** O grafo recebido ja deve estar filtrado pela concessao de quem consulta. */
|
|
67
|
+
function pacoteDeContexto(grafo, indice, entrada, tetoBytes = exports.CONTEXTO_TETO_PADRAO) {
|
|
68
|
+
if (!Number.isInteger(tetoBytes) || tetoBytes < 4096 || tetoBytes > 65536)
|
|
69
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-invalido', 'teto deve ser inteiro de 4096 a 65536 bytes');
|
|
70
|
+
const porId = new Map(grafo.nodes.map((n) => [n.node_id, n]));
|
|
71
|
+
const arquivos = new Set(grafo.nodes.filter((n) => n.kind === 'file').map((n) => n.locator.path));
|
|
72
|
+
const sementes = sementesDaThread(entrada, [...arquivos]).map((s) => ({ ...s, estado: arquivos.has(s.arquivo) ? 'indexado' : 'fora-do-indice' }));
|
|
73
|
+
const indexadas = sementes.filter((s) => s.estado === 'indexado'), ausentes = sementes.filter((s) => s.estado !== 'indexado');
|
|
74
|
+
const alvos = new Set(indexadas.map((s) => s.arquivo));
|
|
75
|
+
const diff = entrada.diffEstado === 'ignorado-sem-worktree' ? [] : [...new Set(entrada.diff)].sort(intelligence_graph_contract_1.compararUtf8);
|
|
76
|
+
// Distancia em arquivos, em ambos os sentidos, sem depender da ordem das arestas.
|
|
77
|
+
const adj = new Map();
|
|
78
|
+
for (const a of grafo.edges) {
|
|
79
|
+
const de = porId.get(a.from).locator.path, para = porId.get(a.to).locator.path;
|
|
80
|
+
if (de === para)
|
|
81
|
+
continue;
|
|
82
|
+
if (!adj.has(de))
|
|
83
|
+
adj.set(de, new Set());
|
|
84
|
+
if (!adj.has(para))
|
|
85
|
+
adj.set(para, new Set());
|
|
86
|
+
adj.get(de).add(para);
|
|
87
|
+
adj.get(para).add(de);
|
|
88
|
+
}
|
|
89
|
+
const dist = new Map(diff.filter((p) => arquivos.has(p)).map((p) => [p, 0]));
|
|
90
|
+
const fila = [...dist.keys()];
|
|
91
|
+
for (let i = 0; i < fila.length; i++)
|
|
92
|
+
for (const p of adj.get(fila[i]) ?? []) {
|
|
93
|
+
if (!dist.has(p)) {
|
|
94
|
+
dist.set(p, dist.get(fila[i]) + 1);
|
|
95
|
+
fila.push(p);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const extratores = [...indice.extratores].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)((0, intelligence_graph_contract_1.canonico)(a), (0, intelligence_graph_contract_1.canonico)(b)));
|
|
99
|
+
const extratorIds = new Map(extratores.map((e, i) => [(0, intelligence_graph_contract_1.canonico)(e), i]));
|
|
100
|
+
const grupos = new Map();
|
|
101
|
+
let totalArestas = 0, estruturais = 0, evidenciasAuxiliares = 0;
|
|
102
|
+
for (const a of grafo.edges) {
|
|
103
|
+
const de = porId.get(a.from), para = porId.get(a.to);
|
|
104
|
+
if (!alvos.has(de.locator.path) && !alvos.has(para.locator.path))
|
|
105
|
+
continue;
|
|
106
|
+
totalArestas++;
|
|
107
|
+
if ((a.kind === 'declares' || a.kind === 'contains') && de.locator.path === para.locator.path && alvos.has(de.locator.path)) {
|
|
108
|
+
estruturais++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const proprias = a.evidence.filter((e) => e.path === de.locator.path);
|
|
112
|
+
evidenciasAuxiliares += a.evidence.length - proprias.length;
|
|
113
|
+
// Sem evidencia no arquivo de origem, a aresta fica em omitidos.arestas.
|
|
114
|
+
if (!proprias.length)
|
|
115
|
+
continue;
|
|
116
|
+
const origem = `file ${de.locator.path}`, destino = (0, intelligence_graph_query_1.rotuloDoNo)(para);
|
|
117
|
+
const chave = (0, intelligence_graph_contract_1.canonico)([a.kind, destino, de.locator.path]);
|
|
118
|
+
const grupo = grupos.get(chave) ?? { kind: a.kind, origem, destino, alvo: para.node_id, quantidade: 0,
|
|
119
|
+
evidencias: new Map(), entreArquivos: de.locator.path !== para.locator.path,
|
|
120
|
+
distancia: Math.min(dist.get(de.locator.path) ?? Infinity, dist.get(para.locator.path) ?? Infinity) };
|
|
121
|
+
grupo.quantidade++;
|
|
122
|
+
for (const e of proprias) {
|
|
123
|
+
const x = extratorIds.get((0, intelligence_graph_contract_1.canonico)({ extractor_id: e.extractor_id, extractor_version: e.extractor_version }));
|
|
124
|
+
if (x === undefined)
|
|
125
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.extrator-ausente', 'extrator da evidencia ausente no cabecalho');
|
|
126
|
+
const s = e.span;
|
|
127
|
+
const tupla = [x, e.extraction_method,
|
|
128
|
+
s.type === 'text' ? [s.line_start, s.line_end] : ['pdf', s.page, s.extracted_text_hash], [s.byte_start, s.byte_end]];
|
|
129
|
+
grupo.evidencias.set((0, intelligence_graph_contract_1.canonico)(tupla), tupla);
|
|
130
|
+
}
|
|
131
|
+
grupos.set(chave, grupo);
|
|
132
|
+
}
|
|
133
|
+
// Entre arquivos > perto do diff > tipo > rotulos; empates independem da ordem do indice.
|
|
134
|
+
const ordenados = [...grupos.values()].sort((a, b) => Number(b.entreArquivos) - Number(a.entreArquivos)
|
|
135
|
+
|| (a.distancia === b.distancia ? 0 : a.distancia < b.distancia ? -1 : 1)
|
|
136
|
+
|| (0, intelligence_graph_contract_1.compararUtf8)(a.kind, b.kind) || (0, intelligence_graph_contract_1.compararUtf8)(a.destino, b.destino) || (0, intelligence_graph_contract_1.compararUtf8)(a.origem, b.origem));
|
|
137
|
+
// Dentro da mesma prioridade, intercalar tipos impede calls de expulsar imports/references.
|
|
138
|
+
const rodadas = new Map();
|
|
139
|
+
const justos = ordenados.map((g) => {
|
|
140
|
+
const chave = JSON.stringify([g.alvo, g.entreArquivos, g.distancia, g.kind]);
|
|
141
|
+
const rodada = rodadas.get(chave) ?? 0;
|
|
142
|
+
rodadas.set(chave, rodada + 1);
|
|
143
|
+
return { g, rodada };
|
|
144
|
+
}).sort((a, b) => Number(b.g.entreArquivos) - Number(a.g.entreArquivos)
|
|
145
|
+
|| (a.g.distancia === b.g.distancia ? 0 : a.g.distancia < b.g.distancia ? -1 : 1)
|
|
146
|
+
|| a.rodada - b.rodada || (0, intelligence_graph_contract_1.compararUtf8)(a.g.kind, b.g.kind)
|
|
147
|
+
|| (0, intelligence_graph_contract_1.compararUtf8)(a.g.destino, b.g.destino) || (0, intelligence_graph_contract_1.compararUtf8)(a.g.origem, b.g.origem)).map(({ g }) => g);
|
|
148
|
+
const normalizada = { ...entrada, diff, diffEstado: entrada.diffEstado ?? 'coletado-na-worktree',
|
|
149
|
+
claims: [...entrada.claims].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)((0, intelligence_graph_contract_1.canonico)(a), (0, intelligence_graph_contract_1.canonico)(b))) };
|
|
150
|
+
const fixo = { schema: exports.CONTEXTO_SCHEMA, thread: entrada.thread, base: entrada.base, entrada_sha256: hash((0, intelligence_graph_contract_1.canonico)(normalizada)),
|
|
151
|
+
indice: { ...indice, extratores },
|
|
152
|
+
fontes: { goal: entrada.goal === null ? 'ausente' : hash(entrada.goal), plan: entrada.plan === null ? 'ausente' : hash(entrada.plan),
|
|
153
|
+
diff: normalizada.diffEstado },
|
|
154
|
+
consulta: { profundidade: 1, sentido: 'ambos', por_alvo: exports.CONTEXTO_POR_ALVO, fora_do_indice: exports.CONTEXTO_FORA_DO_INDICE },
|
|
155
|
+
total_sementes: sementes.length, sementes_fora_do_indice: ausentes.length, total_arestas: totalArestas,
|
|
156
|
+
total_ligacoes: ordenados.length, resumidas: { estruturais }, parcial: intelligence_graph_query_1.AVISO_DE_PARCIALIDADE };
|
|
157
|
+
const selecionadas = [], ligacoes = [];
|
|
158
|
+
const montar = () => {
|
|
159
|
+
const caminhos = new Set(selecionadas.filter((s) => s.estado === 'indexado').map((s) => s.arquivo));
|
|
160
|
+
const rotulos = new Set([...caminhos].map((p) => `file ${p}`));
|
|
161
|
+
for (const a of ligacoes) {
|
|
162
|
+
rotulos.add(a.origem);
|
|
163
|
+
rotulos.add(a.destino);
|
|
164
|
+
caminhos.add(porId.get(a.alvo).locator.path);
|
|
165
|
+
caminhos.add(a.origem.slice(5));
|
|
166
|
+
}
|
|
167
|
+
const refs = new Map([...rotulos].sort(intelligence_graph_contract_1.compararUtf8).map((r, i) => [r, `n${i + 1}`]));
|
|
168
|
+
const fontes = grafo.snapshot.source_manifest.filter((m) => caminhos.has(m.path)).sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a.path, b.path));
|
|
169
|
+
const omitidos = { sementes: sementes.length - selecionadas.length, ligacoes: ordenados.length - ligacoes.length,
|
|
170
|
+
arestas: totalArestas - estruturais - ligacoes.reduce((s, a) => s + a.quantidade, 0), evidencias_auxiliares: evidenciasAuxiliares };
|
|
171
|
+
const cortado = omitidos.sementes > 0 || omitidos.ligacoes > 0 || omitidos.arestas > 0 || evidenciasAuxiliares > 0;
|
|
172
|
+
const r = { ...fixo, sementes: selecionadas, nos: Object.fromEntries([...refs].map(([r, ref]) => [ref, r])),
|
|
173
|
+
arestas: ligacoes.map((a) => ({ kind: a.kind, from: refs.get(a.origem), to: refs.get(a.destino), quantidade: a.quantidade,
|
|
174
|
+
evidencias: [...a.evidencias].sort(([a], [b]) => (0, intelligence_graph_contract_1.compararUtf8)(a, b)).map(([, e]) => e) })),
|
|
175
|
+
truncado: cortado, omitidos, teto: { bytes: tetoBytes, cortado },
|
|
176
|
+
medida: { pacote_bytes: 0, leitura_crua_bytes: fontes.reduce((s, f) => s + f.size_bytes, 0),
|
|
177
|
+
arquivos: fontes.map((f) => ({ path: f.path, bytes: f.size_bytes })),
|
|
178
|
+
origem: 'source_manifest; tamanho dos arquivos, nao custo de descoberta', tokens: 'unavailable' } };
|
|
179
|
+
let texto = (0, intelligence_graph_contract_1.canonico)(r);
|
|
180
|
+
while (r.medida.pacote_bytes !== Buffer.byteLength(texto)) {
|
|
181
|
+
r.medida.pacote_bytes = Buffer.byteLength(texto);
|
|
182
|
+
texto = (0, intelligence_graph_contract_1.canonico)(r);
|
|
183
|
+
}
|
|
184
|
+
return texto;
|
|
185
|
+
};
|
|
186
|
+
let melhor = montar();
|
|
187
|
+
if (Buffer.byteLength(melhor) > tetoBytes)
|
|
188
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-excedido', 'cabecalho nao cabe no teto');
|
|
189
|
+
const tentarSemente = (s) => {
|
|
190
|
+
selecionadas.push(s);
|
|
191
|
+
const texto = montar();
|
|
192
|
+
if (Buffer.byteLength(texto) <= tetoBytes)
|
|
193
|
+
melhor = texto;
|
|
194
|
+
else
|
|
195
|
+
selecionadas.pop();
|
|
196
|
+
};
|
|
197
|
+
for (const s of indexadas)
|
|
198
|
+
tentarSemente(s);
|
|
199
|
+
const porAlvo = new Map();
|
|
200
|
+
for (const a of justos) {
|
|
201
|
+
if ((porAlvo.get(a.alvo) ?? 0) >= exports.CONTEXTO_POR_ALVO)
|
|
202
|
+
continue;
|
|
203
|
+
ligacoes.push(a);
|
|
204
|
+
const texto = montar();
|
|
205
|
+
if (Buffer.byteLength(texto) <= tetoBytes) {
|
|
206
|
+
melhor = texto;
|
|
207
|
+
porAlvo.set(a.alvo, (porAlvo.get(a.alvo) ?? 0) + 1);
|
|
208
|
+
}
|
|
209
|
+
else
|
|
210
|
+
ligacoes.pop(); // Um hub grande nao impede uma ligacao menor e relevante de entrar.
|
|
211
|
+
}
|
|
212
|
+
for (const s of ausentes.slice(0, exports.CONTEXTO_FORA_DO_INDICE))
|
|
213
|
+
tentarSemente(s);
|
|
214
|
+
return melhor;
|
|
215
|
+
}
|
|
@@ -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
|