@orkastery/cli 0.5.1 → 0.5.6
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 +158 -0
- 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/claude-code/mods/autoridade.json +56 -0
- package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
- package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
- package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
- package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
- package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
- package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
- package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
- package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
- package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
- package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
- package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
- package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
- package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
- package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
- package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
- package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
- package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
- package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
- package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
- package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
- package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
- package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
- package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
- package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
- package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
- package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
- package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
- package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
- package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
- package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
- package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
- package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
- package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
- package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -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 +7 -6
- package/adapters/openclaw/README.md +26 -5
- 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/docs-en/markdownlint-cli2.jsonc +22 -0
- package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
- package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
- package/assets/docs-en/produto/README.md +14 -0
- package/assets/docs-en/produto/_modelo-feature.md +62 -0
- package/assets/docs-en/roadmap/README.md +14 -0
- package/assets/docs-en/roadmap/_modelo-item.md +75 -0
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +116 -18
- package/dist/adapters/codex.js +14 -4
- package/dist/agents-md.js +24 -14
- package/dist/auditrun.js +22 -3
- package/dist/board.js +20 -17
- package/dist/branch-de-estado.js +88 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/catalogo.js +33 -0
- package/dist/ci.js +21 -8
- package/dist/claims-conferir.js +342 -0
- package/dist/claims.js +41 -1
- package/dist/company-brain-client.js +36 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/company-brain-journal.js +2 -1
- package/dist/company-brain-migration.js +36 -1
- package/dist/conducao-sentinela.js +388 -0
- package/dist/conducao-texto.js +12 -18
- package/dist/conducao.js +122 -30
- package/dist/conhecimento.js +490 -0
- package/dist/docs.js +70 -17
- package/dist/doctor-pulse-cron.js +349 -0
- package/dist/doctor-rede.js +150 -0
- package/dist/doctor.js +195 -111
- package/dist/entrega-pr.js +42 -29
- package/dist/escopo-escrita.js +10 -1
- package/dist/esgotamentos.js +181 -0
- package/dist/estado-thread.js +23 -1
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-batida.js +310 -0
- package/dist/fabrica-estado.js +52 -14
- package/dist/fabrica-publicar.js +9 -1
- package/dist/fechamento.js +20 -66
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +3 -2
- package/dist/forja.js +31 -7
- package/dist/gates.js +3 -24
- package/dist/handoff.js +10 -6
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-local-receipt.js +2 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +38 -3
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/hitl.js +29 -33
- package/dist/horario.js +41 -7
- package/dist/hosts.js +104 -11
- package/dist/impedimento.js +299 -0
- package/dist/index.js +961 -542
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +9 -1
- package/dist/init.js +56 -43
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +170 -16
- package/dist/intelligence-graph-contexto.js +254 -0
- package/dist/intelligence-graph-contract.js +2 -1
- package/dist/intelligence-graph-extract-md.js +56 -4
- package/dist/intelligence-graph-extract-ts.js +71 -3
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-query.js +66 -19
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +18 -1
- package/dist/licoes.js +1 -0
- package/dist/liveness.js +6 -3
- package/dist/locale-ajuda.js +761 -0
- package/dist/locale-gerados.js +160 -0
- package/dist/locale-master.js +99 -0
- package/dist/locale-onboarding.js +92 -0
- package/dist/locale-phase.js +151 -0
- package/dist/locale-pulse.js +211 -0
- package/dist/locale-retry.js +385 -0
- package/dist/locale-roadmap.js +102 -0
- package/dist/locale-ship.js +494 -0
- package/dist/locale-thread.js +277 -0
- package/dist/locale-verify.js +125 -0
- package/dist/locale.js +714 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +149 -4
- package/dist/maquina.js +23 -4
- package/dist/master-digest.js +6 -1
- package/dist/master-nota.js +18 -11
- package/dist/master.js +145 -31
- package/dist/mcp-artifacts.js +43 -3
- package/dist/mcp-git.js +42 -8
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +55 -6
- package/dist/mcp-server.js +22 -3
- package/dist/mcp-ship.js +3 -1
- package/dist/mcp-verify.js +6 -1
- package/dist/memoria.js +48 -6
- package/dist/modos.js +3 -6
- package/dist/network-roadmap.js +196 -18
- package/dist/noctum-arco.js +911 -0
- package/dist/noctum-capacidade.js +141 -0
- package/dist/noctum-envelope.js +810 -0
- package/dist/noctum-execucao.js +304 -0
- package/dist/noctum-fila.js +280 -0
- package/dist/ocupacao.js +40 -5
- package/dist/onboarding.js +40 -21
- package/dist/orkmind.js +99 -7
- package/dist/orquestracao.js +24 -21
- package/dist/parado-no-condutor.js +219 -38
- package/dist/phase.js +160 -52
- package/dist/policies.js +56 -5
- package/dist/portfolio.js +8 -3
- package/dist/postura-local.js +234 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +225 -0
- package/dist/projeto-alvo.js +132 -5
- package/dist/prompts.js +40 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +47 -4
- package/dist/pulse.js +98 -19
- package/dist/ratelimit.js +24 -6
- package/dist/recall.js +3 -1
- package/dist/redacao-saida.js +63 -0
- 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 +337 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +291 -140
- package/dist/roadmap-reservas.js +20 -3
- package/dist/roadmap-status.js +150 -34
- package/dist/runtime-context.js +181 -3
- package/dist/runtime-profiles.js +22 -1
- package/dist/runtimes.js +2 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-events.js +7 -3
- package/dist/session-watcher-claude.js +120 -24
- package/dist/session-watcher.js +185 -33
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship-publicar.js +800 -0
- package/dist/ship.js +157 -88
- package/dist/steal.js +77 -0
- package/dist/thread-close.js +3 -2
- package/dist/thread.js +299 -49
- package/dist/util.js +8 -1
- package/dist/verify.js +141 -52
- package/dist/vida-da-thread.js +254 -0
- package/dist/worktree-local.js +165 -0
- package/dist/worktree.js +25 -2
- package/dist/yaml.js +27 -8
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +2 -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
|
@@ -33,8 +33,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.CORRECAO_DO_INDICE = exports.USO_DO_GRAFO = exports.AMOSTRA_SCHEMA = exports.STATUS_SCHEMA = void 0;
|
|
36
|
+
exports.CORRECAO_DO_INDICE = exports.USO_DO_GRAFO = exports.AMOSTRA_SCHEMA = exports.REDACAO_DOS_ANALISADORES = exports.STATUS_SCHEMA = void 0;
|
|
37
|
+
exports.descreverVersoes = descreverVersoes;
|
|
38
|
+
exports.correcaoDosAnalisadores = correcaoDosAnalisadores;
|
|
39
|
+
exports.checarAnalisadoresDoGrafo = checarAnalisadoresDoGrafo;
|
|
37
40
|
exports.lerPedido = lerPedido;
|
|
41
|
+
exports.situacaoNaArvore = situacaoNaArvore;
|
|
38
42
|
exports.executarGrafo = executarGrafo;
|
|
39
43
|
/**
|
|
40
44
|
* RM-031 KG3 (D7, D8): `ork grafo`, o CLI do indice e da consulta do grafo de codigo.
|
|
@@ -56,14 +60,64 @@ const fs = __importStar(require("node:fs"));
|
|
|
56
60
|
const path = __importStar(require("node:path"));
|
|
57
61
|
const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
|
|
58
62
|
const intelligence_graph_index_1 = require("./intelligence-graph-index");
|
|
63
|
+
const intelligence_graph_parsers_1 = require("./intelligence-graph-parsers");
|
|
59
64
|
const intelligence_graph_query_1 = require("./intelligence-graph-query");
|
|
60
65
|
const intelligence_graph_repo_1 = require("./intelligence-graph-repo");
|
|
66
|
+
const intelligence_graph_contexto_1 = require("./intelligence-graph-contexto");
|
|
61
67
|
exports.STATUS_SCHEMA = 'ork.code-graph-index-status/v0';
|
|
68
|
+
/** As versoes dos analisadores como o `ork grafo status` e o `ork doctor` as mostram. */
|
|
69
|
+
function descreverVersoes(v) {
|
|
70
|
+
return Object.entries(v).map(([k, x]) => `${k} ${x}`).join(', ');
|
|
71
|
+
}
|
|
72
|
+
/** O prefixo das recusas dos analisadores (`intelligence-graph-parsers.ts`). */
|
|
73
|
+
const RECUSA_DOS_ANALISADORES = 'grafo.parser.indisponivel';
|
|
74
|
+
/**
|
|
75
|
+
* RM-031 (pacote do npm): o que fazer quando os analisadores nao carregam, dito pelo `ork doctor` e
|
|
76
|
+
* pelo `ork grafo status`. O micromark e so ESM e carrega por `require`, o que o Node so faz sem flag
|
|
77
|
+
* a partir de 20.19 e de 22.12. Nos outros casos o pacote falta ou esta fora da instalacao do `ork`,
|
|
78
|
+
* e a instalacao global do npm traz os analisadores, que sao dependencias do pacote. Mora aqui, fora
|
|
79
|
+
* de `MODULOS_DO_EXTRATOR`, para a redacao nao entrar na chave do indice; a versao vem de quem chama
|
|
80
|
+
* (o `index.ts`), porque o CLI do grafo so importa a propria familia (fronteira do KG3).
|
|
81
|
+
*/
|
|
82
|
+
function correcaoDosAnalisadores(motivo, versao, redacao = exports.REDACAO_DOS_ANALISADORES) {
|
|
83
|
+
if (/ERR_REQUIRE_ESM/.test(motivo))
|
|
84
|
+
return redacao.soEsm(process.version);
|
|
85
|
+
// Sem a versao do pacote (`0.0.0-desconhecida` quando o package.json dele nao e achado), o comando
|
|
86
|
+
// sai sem `@<versao>` e o npm instala a ultima publicada.
|
|
87
|
+
const fixada = versao && /^\d+\.\d+\.\d+/.test(versao) && !versao.startsWith('0.0.0') ? `@${versao}` : '';
|
|
88
|
+
return redacao.reinstale(fixada);
|
|
89
|
+
}
|
|
90
|
+
exports.REDACAO_DOS_ANALISADORES = {
|
|
91
|
+
recusa: (motivo) => `${motivo}: o ork grafo indexar recusa nesta instalacao, e sem o indice as consultas e as tools ork_grafo_* tambem`,
|
|
92
|
+
soEsm: (versaoDoNode) => `o micromark e so ESM, e este Node (${versaoDoNode}) nao o carrega por require: use Node 20.19, 22.12 ou mais novo, ` +
|
|
93
|
+
'sem a opcao --no-experimental-require-module (na linha de comando ou no NODE_OPTIONS)',
|
|
94
|
+
reinstale: (fixada) => `reinstale o ork global, que traz os analisadores como dependencias: npm install -g @orkastery/cli${fixada}` +
|
|
95
|
+
' (instalado dentro de um projeto ou pelo npx, o npm deixa os analisadores fora do pacote do ork, e o grafo os recusa)',
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* RM-031 (pacote do npm): o check "analisadores do grafo" do `ork doctor`. Carrega o que o
|
|
99
|
+
* `ork grafo indexar` carrega (`carregarAnalisadores`), entao diz o que o indexar faria, inclusive no
|
|
100
|
+
* Node sem `require` de ESM. A falta e `warn`, com a correcao: o grafo nao e condicao do despacho de
|
|
101
|
+
* fase. Fora da familia do grafo so o `index.ts` e o worker do MCP a abrem (fronteira do KG1), entao o
|
|
102
|
+
* `index.ts` passa este check ao doctor, que nao importa o grafo.
|
|
103
|
+
*/
|
|
104
|
+
function checarAnalisadoresDoGrafo(versao, carregar = intelligence_graph_parsers_1.carregarAnalisadores, versoes = intelligence_graph_parsers_1.versoesDosAnalisadores, redacao = exports.REDACAO_DOS_ANALISADORES) {
|
|
105
|
+
const nome = 'analisadores do grafo';
|
|
106
|
+
try {
|
|
107
|
+
carregar();
|
|
108
|
+
return { nome, nivel: 'ok', detalhe: descreverVersoes(versoes()) };
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
const motivo = e.message;
|
|
112
|
+
return { nome, nivel: 'warn', detalhe: redacao.recusa(motivo), correcao: correcaoDosAnalisadores(motivo, versao, redacao) };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
62
115
|
/** O mesmo schema da amostra do KG2: as amostras auditadas continuam validas. */
|
|
63
116
|
exports.AMOSTRA_SCHEMA = 'ork.graph-edge-audit-sample/v0';
|
|
64
117
|
exports.USO_DO_GRAFO = [
|
|
65
118
|
'uso: ork grafo indexar [--verificar] [--forcar] [--json]',
|
|
66
119
|
' ork grafo status [--json]',
|
|
120
|
+
' ork grafo contexto <thread> [--json [--teto-bytes N]]',
|
|
67
121
|
' ork grafo vizinhos <no> [--profundidade N] [--sentido entrada|saida|ambos] [--tipo T,...] [--limite N] [--json [--teto-bytes N]]',
|
|
68
122
|
' ork grafo chamadores <simbolo> [--profundidade N] [--limite N] [--json [--teto-bytes N]]',
|
|
69
123
|
' ork grafo importadores <arquivo|simbolo> [--profundidade N] [--limite N] [--json [--teto-bytes N]]',
|
|
@@ -83,6 +137,7 @@ const ESTADO_DO_INDICE = Object.freeze({
|
|
|
83
137
|
const SUBCOMANDOS = Object.freeze({
|
|
84
138
|
indexar: { posicionais: 0, bandeiras: ['verificar', 'forcar', 'json'], valores: [] },
|
|
85
139
|
status: { posicionais: 0, bandeiras: ['json'], valores: [] },
|
|
140
|
+
contexto: { posicionais: 1, bandeiras: ['json'], valores: ['teto-bytes'] },
|
|
86
141
|
vizinhos: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'sentido', 'tipo', 'limite', 'teto-bytes'] },
|
|
87
142
|
chamadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite', 'teto-bytes'] },
|
|
88
143
|
importadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite', 'teto-bytes'] },
|
|
@@ -238,9 +293,11 @@ function status(ctx, p) {
|
|
|
238
293
|
const doHead = chave ? estado.indices.find((i) => i.chave === chave) ?? null : null;
|
|
239
294
|
// Sem analisadores nao ha chave: o indice do HEAD fica indisponivel, nunca "ausente" (indexar tambem nao roda).
|
|
240
295
|
const indiceDoHeadEstado = erro ? 'indisponivel' : doHead ? (doHead.problema ? 'com-problema' : 'presente') : 'ausente';
|
|
296
|
+
// RM-031 (pacote do npm): a recusa dos analisadores vem com o que fazer, a mesma correcao do `ork doctor`.
|
|
297
|
+
const correcao = erro !== null && erro.startsWith(RECUSA_DOS_ANALISADORES) ? correcaoDosAnalisadores(erro, ctx.versao) : null;
|
|
241
298
|
const r = {
|
|
242
299
|
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,
|
|
300
|
+
indice_do_head: indiceDoHeadEstado, analisadores, erro, correcao,
|
|
244
301
|
dir: estado.dir, bytes: estado.bytes, indices: estado.indices, sobras: estado.sobras,
|
|
245
302
|
};
|
|
246
303
|
if (p.bandeiras.has('json')) {
|
|
@@ -250,8 +307,11 @@ function status(ctx, p) {
|
|
|
250
307
|
const linhas = [
|
|
251
308
|
`grafo: HEAD ${arvore.head ? arvore.head.slice(0, 12) : 'sem commit'}, arvore ${r.arvore}`,
|
|
252
309
|
` indice do HEAD ${chave ?? 'indisponivel'} ${r.indice_do_head === 'ausente' ? '(ausente: rode ork grafo indexar)'
|
|
253
|
-
: r.indice_do_head === 'indisponivel'
|
|
254
|
-
|
|
310
|
+
: r.indice_do_head === 'indisponivel'
|
|
311
|
+
? (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)')
|
|
312
|
+
: `(${r.indice_do_head})`}`,
|
|
313
|
+
` analisadores ${erro ?? descreverVersoes(analisadores)}`,
|
|
314
|
+
...(correcao ? [` correcao ${correcao}`] : []),
|
|
255
315
|
` pasta ${estado.dir ?? 'ainda nao criada'} (${estado.indices.length} indice(s), ${mb(estado.bytes)})`,
|
|
256
316
|
];
|
|
257
317
|
for (const i of estado.indices) {
|
|
@@ -309,7 +369,10 @@ function semIndiceDoHead(ctx, original) {
|
|
|
309
369
|
}
|
|
310
370
|
throw original;
|
|
311
371
|
}
|
|
312
|
-
/**
|
|
372
|
+
/**
|
|
373
|
+
* O indice do HEAD pronto para consulta, com a concessao local e o cabecalho; `grafo` ja vem filtrado por ela.
|
|
374
|
+
* KG5 fatia 5 (D3): `situacao` so le a arvore quando o cabecalho diz `modificada`; limpa, tudo vale `igual`.
|
|
375
|
+
*/
|
|
313
376
|
function consultavel(ctx) {
|
|
314
377
|
let doHead;
|
|
315
378
|
try {
|
|
@@ -328,7 +391,8 @@ function consultavel(ctx) {
|
|
|
328
391
|
arvore: arvore.motivo === null ? 'limpa' : 'modificada',
|
|
329
392
|
extratores: grafo.snapshot.extractors.map((e) => ({ extractor_id: e.extractor_id, extractor_version: e.extractor_version })),
|
|
330
393
|
};
|
|
331
|
-
|
|
394
|
+
const situacao = cabecalho.arvore === 'limpa' ? intelligence_graph_query_1.TUDO_IGUAL : situacaoNaArvore(arvore.raiz, grafo.snapshot.source_manifest);
|
|
395
|
+
return { g: (0, intelligence_graph_query_1.prepararConsulta)(grafo, concessao), cabecalho, grafo, raiz: arvore.raiz, situacao };
|
|
332
396
|
}
|
|
333
397
|
function responder(ctx, p, r) {
|
|
334
398
|
ctx.escrever(p.bandeiras.has('json') ? (0, intelligence_graph_query_1.jsonDaResposta)(r) : (0, intelligence_graph_query_1.textoDaResposta)(r));
|
|
@@ -373,21 +437,48 @@ function consultar(ctx, p) {
|
|
|
373
437
|
// As opcoes sao conferidas antes de carregar o indice: erro de uso nao custa a leitura do grafo.
|
|
374
438
|
const [a, b] = p.posicionais;
|
|
375
439
|
const profundidade = inteiro(p, 'profundidade'), limite = inteiro(p, 'limite'), s = sentido(p), t = tipos(p), teto = tetoDeBytes(p);
|
|
376
|
-
const { g, cabecalho } = consultavel(ctx);
|
|
440
|
+
const { g, cabecalho, situacao } = consultavel(ctx);
|
|
441
|
+
// A busca binaria do teto pergunta de novo com outro limite; a situacao guarda o que ja leu da arvore.
|
|
377
442
|
const perguntar = (lim) => {
|
|
378
443
|
if (p.sub === 'vizinhos')
|
|
379
|
-
return (0, intelligence_graph_query_1.vizinhos)(g, cabecalho, a, { profundidade, limite: lim, sentido: s, tipos: t });
|
|
444
|
+
return (0, intelligence_graph_query_1.vizinhos)(g, cabecalho, a, { profundidade, limite: lim, sentido: s, tipos: t }, situacao);
|
|
380
445
|
if (p.sub === 'chamadores')
|
|
381
|
-
return (0, intelligence_graph_query_1.chamadores)(g, cabecalho, a, { profundidade, limite: lim });
|
|
446
|
+
return (0, intelligence_graph_query_1.chamadores)(g, cabecalho, a, { profundidade, limite: lim }, situacao);
|
|
382
447
|
if (p.sub === 'importadores')
|
|
383
|
-
return (0, intelligence_graph_query_1.importadores)(g, cabecalho, a, { profundidade, limite: lim });
|
|
384
|
-
return (0, intelligence_graph_query_1.caminho)(g, cabecalho, a, b, { sentido: s, tipos: t });
|
|
448
|
+
return (0, intelligence_graph_query_1.importadores)(g, cabecalho, a, { profundidade, limite: lim }, situacao);
|
|
449
|
+
return (0, intelligence_graph_query_1.caminho)(g, cabecalho, a, b, { sentido: s, tipos: t }, situacao);
|
|
385
450
|
};
|
|
386
451
|
if (teto === undefined)
|
|
387
452
|
return responder(ctx, p, perguntar(limite));
|
|
388
453
|
ctx.escrever(respostaComTeto(perguntar, limite, teto));
|
|
389
454
|
return 0;
|
|
390
455
|
}
|
|
456
|
+
function contexto(ctx, p) {
|
|
457
|
+
const teto = tetoDeBytes(p);
|
|
458
|
+
if (teto !== undefined && (teto < 4096 || teto > 65536))
|
|
459
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-invalido', 'teto deve ser inteiro de 4096 a 65536 bytes');
|
|
460
|
+
if (!ctx.contextoDaThread)
|
|
461
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.indisponivel', 'borda sem leitor da thread');
|
|
462
|
+
const lido = ctx.contextoDaThread(p.posicionais[0]);
|
|
463
|
+
const { grafo, cabecalho, situacao } = consultavel({ ...ctx, raiz: lido.raiz });
|
|
464
|
+
if (lido.head !== cabecalho.revision)
|
|
465
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.revisao-mudou', 'HEAD mudou durante a leitura; repita a consulta');
|
|
466
|
+
const json = (0, intelligence_graph_contexto_1.pacoteDeContexto)(grafo, cabecalho, lido.entrada, teto, situacao);
|
|
467
|
+
if (p.bandeiras.has('json'))
|
|
468
|
+
ctx.escrever(json);
|
|
469
|
+
else {
|
|
470
|
+
const r = JSON.parse(json);
|
|
471
|
+
// KG5 fatia 5 (D9): o resumo conta as ligacoes cuja fonte mudou na arvore, como o JSON marca.
|
|
472
|
+
const mudadas = r.arestas.filter((a) => a.arvore === 'modificada').length;
|
|
473
|
+
ctx.escrever([`Contexto ${r.thread} @ ${r.indice.revision}`,
|
|
474
|
+
` ${r.sementes.length}/${r.total_sementes} sementes, ${r.arestas.length}/${r.total_ligacoes} ligacoes agregadas; ${r.medida.pacote_bytes} bytes JSON`,
|
|
475
|
+
` tamanho dos arquivos no pacote (nao descoberta): ${r.medida.leitura_crua_bytes} bytes (revisao indexada); tokens: unavailable`,
|
|
476
|
+
` diff: ${r.fontes.diff}`,
|
|
477
|
+
...(mudadas ? [` ligacoes com fonte modificada na arvore: ${mudadas}`] : []),
|
|
478
|
+
` truncado: ${r.truncado}; arvore: ${r.indice.arvore}; use --json para nos e evidencias`, json].join('\n'));
|
|
479
|
+
}
|
|
480
|
+
return 0;
|
|
481
|
+
}
|
|
391
482
|
const sha256 = (b) => (0, node_crypto_1.createHash)('sha256').update(b).digest('hex');
|
|
392
483
|
/**
|
|
393
484
|
* Bytes da arvore, conferidos arquivo a arquivo contra o manifesto do indice: o trecho da amostra e
|
|
@@ -427,6 +518,66 @@ function leitorDaArvore(raiz, grafo) {
|
|
|
427
518
|
return bytes;
|
|
428
519
|
};
|
|
429
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* KG5 fatia 5 (D3, D6): a situacao de cada fonte do indice na arvore, pelos bytes. So caminho do manifesto;
|
|
523
|
+
* sem seguir link, nem no ultimo nome nem numa pasta do caminho: o caminho real tem de ser o proprio caminho
|
|
524
|
+
* indexado dentro da raiz (CHECK rodada 1, A1). So arquivo regular; tamanho diferente do indexado e
|
|
525
|
+
* `modificada` sem ler, e o sha256 dos bytes decide o resto, lidos ate o tamanho indexado mais um. O arquivo
|
|
526
|
+
* aberto tem de ser o mesmo do `lstat` (dispositivo e inode, CHECK rodada 1, S3): troca entre a conferencia e
|
|
527
|
+
* a abertura vira `ausente`; duas trocas no intervalo ainda passam, e revelariam so se os bytes sao os
|
|
528
|
+
* indexados. Qualquer falha e `ausente`: nao ha arquivo regular legivel no caminho. Cada caminho e lido uma
|
|
529
|
+
* vez, sob demanda, e nada e escrito.
|
|
530
|
+
*/
|
|
531
|
+
function situacaoNaArvore(raiz, manifesto) {
|
|
532
|
+
const porCaminho = new Map(manifesto.map((m) => [m.path, m]));
|
|
533
|
+
const vistas = new Map();
|
|
534
|
+
let raizReal = null;
|
|
535
|
+
const ler = (p) => {
|
|
536
|
+
const m = porCaminho.get(p);
|
|
537
|
+
if (!m)
|
|
538
|
+
return 'ausente';
|
|
539
|
+
const absoluto = path.join(raiz, p);
|
|
540
|
+
try {
|
|
541
|
+
raizReal ??= fs.realpathSync(raiz);
|
|
542
|
+
const st = fs.lstatSync(absoluto, { throwIfNoEntry: false });
|
|
543
|
+
if (!st || !st.isFile())
|
|
544
|
+
return 'ausente';
|
|
545
|
+
// CHECK rodada 2 (R2-S1): caminho de manifesto adulterado com `..` coincidiria com o real fora da raiz.
|
|
546
|
+
const real = fs.realpathSync(absoluto);
|
|
547
|
+
if (real !== path.join(raizReal, p) || !real.startsWith(raizReal + path.sep))
|
|
548
|
+
return 'ausente';
|
|
549
|
+
if (st.size !== m.size_bytes)
|
|
550
|
+
return 'modificada';
|
|
551
|
+
const fd = fs.openSync(absoluto, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
552
|
+
try {
|
|
553
|
+
const aberto = fs.fstatSync(fd);
|
|
554
|
+
if (!aberto.isFile() || aberto.dev !== st.dev || aberto.ino !== st.ino)
|
|
555
|
+
return 'ausente';
|
|
556
|
+
if (aberto.size !== m.size_bytes)
|
|
557
|
+
return 'modificada';
|
|
558
|
+
const bytes = Buffer.alloc(m.size_bytes + 1);
|
|
559
|
+
let lidos = 0;
|
|
560
|
+
for (let n = 1; n > 0 && lidos < bytes.length; lidos += n)
|
|
561
|
+
n = fs.readSync(fd, bytes, lidos, bytes.length - lidos, null);
|
|
562
|
+
return lidos === m.size_bytes && sha256(bytes.subarray(0, lidos)) === m.source_hash ? 'igual' : 'modificada';
|
|
563
|
+
}
|
|
564
|
+
finally {
|
|
565
|
+
fs.closeSync(fd);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
return 'ausente';
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
return (p) => {
|
|
573
|
+
const vista = vistas.get(p);
|
|
574
|
+
if (vista !== undefined)
|
|
575
|
+
return vista;
|
|
576
|
+
const s = ler(p);
|
|
577
|
+
vistas.set(p, s);
|
|
578
|
+
return s;
|
|
579
|
+
};
|
|
580
|
+
}
|
|
430
581
|
const localizadorDe = (g) => new Map(g.nodes.map((n) => [n.node_id, { kind: n.kind, path: n.locator.path, fragment: n.locator.fragment }]));
|
|
431
582
|
const rotulo = (l) => `${l.kind}:${l.path}${l.fragment === null ? '' : `#${l.fragment}`}`;
|
|
432
583
|
const chaveDaAresta = (kind, de, para) => `${kind} ${rotulo(de)} -> ${rotulo(para)}`;
|
|
@@ -541,12 +692,12 @@ function limpar(ctx, p) {
|
|
|
541
692
|
return 0;
|
|
542
693
|
}
|
|
543
694
|
/** 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) => {
|
|
695
|
+
const erroEmJson = (ctx, e, compacto, schema = intelligence_graph_query_1.CONSULTA_SCHEMA) => {
|
|
545
696
|
const [codigo, ...detalhe] = String(e.message).split('\n')[0].split(': ');
|
|
546
697
|
const doIndice = Object.prototype.hasOwnProperty.call(ESTADO_DO_INDICE, codigo)
|
|
547
698
|
? { estado_do_indice: ESTADO_DO_INDICE[codigo], correcao: exports.CORRECAO_DO_INDICE } : {};
|
|
548
699
|
const r = {
|
|
549
|
-
schema
|
|
700
|
+
schema,
|
|
550
701
|
erro: { codigo, detalhe: detalhe.join(': ') || null, candidatos: e instanceof intelligence_graph_query_1.ErroDeConsulta ? e.candidatos : [], ...doIndice },
|
|
551
702
|
};
|
|
552
703
|
ctx.escrever(compacto ? JSON.stringify(r) : JSON.stringify(r, null, 2));
|
|
@@ -554,7 +705,8 @@ const erroEmJson = (ctx, e, compacto) => {
|
|
|
554
705
|
};
|
|
555
706
|
/** `ork grafo <subcomando> ...`: devolve o codigo de saida; sem `--json`, o erro de uso ou tipado e lancado. */
|
|
556
707
|
function executarGrafo(argv, ctx) {
|
|
557
|
-
const
|
|
708
|
+
const schema = argv[0] === 'contexto' ? intelligence_graph_contexto_1.CONTEXTO_SCHEMA : intelligence_graph_query_1.CONSULTA_SCHEMA;
|
|
709
|
+
const compacto = argv[0] === 'contexto' || argv.some((a) => a === '--teto-bytes' || a.startsWith('--teto-bytes='));
|
|
558
710
|
let p;
|
|
559
711
|
try {
|
|
560
712
|
p = lerPedido(argv);
|
|
@@ -562,7 +714,7 @@ function executarGrafo(argv, ctx) {
|
|
|
562
714
|
catch (e) {
|
|
563
715
|
// Com `--json` no argv, tambem o erro de uso sai como objeto, como os demais.
|
|
564
716
|
if (argv.includes('--json'))
|
|
565
|
-
return erroEmJson(ctx, e, compacto);
|
|
717
|
+
return erroEmJson(ctx, e, compacto, schema);
|
|
566
718
|
throw e;
|
|
567
719
|
}
|
|
568
720
|
try {
|
|
@@ -574,11 +726,13 @@ function executarGrafo(argv, ctx) {
|
|
|
574
726
|
return amostra(ctx, p);
|
|
575
727
|
if (p.sub === 'limpar')
|
|
576
728
|
return limpar(ctx, p);
|
|
729
|
+
if (p.sub === 'contexto')
|
|
730
|
+
return contexto(ctx, p);
|
|
577
731
|
return consultar(ctx, p);
|
|
578
732
|
}
|
|
579
733
|
catch (e) {
|
|
580
734
|
if (!p.bandeiras.has('json'))
|
|
581
735
|
throw e;
|
|
582
|
-
return erroEmJson(ctx, e, compacto);
|
|
736
|
+
return erroEmJson(ctx, e, compacto, schema);
|
|
583
737
|
}
|
|
584
738
|
}
|
|
@@ -0,0 +1,254 @@
|
|
|
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
|
+
/**
|
|
7
|
+
* KG5: composicao pura do contexto da thread. Sem E/S, relogio ou inferencia.
|
|
8
|
+
*
|
|
9
|
+
* KG5 fatia 5 (D5): quem chama passa a situacao das fontes na arvore (o CLI le os bytes); o grupo cuja
|
|
10
|
+
* origem ou alvo nao confere ganha `arvore: "modificada"`, e o que confere sai sem o campo. Sem a situacao,
|
|
11
|
+
* ou com a arvore limpa, o pacote e o de antes, byte a byte.
|
|
12
|
+
*/
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
|
|
15
|
+
const intelligence_graph_query_1 = require("./intelligence-graph-query");
|
|
16
|
+
exports.CONTEXTO_SCHEMA = 'ork.thread-graph-context/v2';
|
|
17
|
+
exports.CONTEXTO_TETO_PADRAO = 32768;
|
|
18
|
+
exports.CONTEXTO_POR_ALVO = 8;
|
|
19
|
+
exports.CONTEXTO_FORA_DO_INDICE = 3;
|
|
20
|
+
const LIMITE_REJEICOES_SEGUNDO_SALTO = 8;
|
|
21
|
+
const hash = (texto) => (0, node_crypto_1.createHash)('sha256').update(texto).digest('hex');
|
|
22
|
+
/** Caminho relativo do repositorio, nunca caminho de maquina, URL ou estado privado. */
|
|
23
|
+
function caminhoPublico(bruto) {
|
|
24
|
+
const p = bruto.replace(/^\.\//, '');
|
|
25
|
+
if (!p || p.startsWith('/') || p.startsWith('~') || /[:\\\u0000-\u001f\u007f]/.test(p) || p.length > 500
|
|
26
|
+
|| p.split('/').some((x) => !x || x === '..' || x === '.' || x === '.git' || x === '.orkastery'))
|
|
27
|
+
return null;
|
|
28
|
+
return p;
|
|
29
|
+
}
|
|
30
|
+
/** GOAL/PLAN citam caminhos relativos a raiz em codigo, links ou texto; nao executam instrucoes. */
|
|
31
|
+
function caminhosCitados(texto, diretorios) {
|
|
32
|
+
const r = [];
|
|
33
|
+
const semCitacoes = texto.replace(/`([^`\n]+)`|\]\(([^)\n]+)\)/g, (_m, codigo, link) => {
|
|
34
|
+
const v = codigo ?? link ?? '';
|
|
35
|
+
if (!/^(?:[a-z]+:|\/)/i.test(v) && (v.includes('/') || /\.[a-z0-9]+(?:#.*|:\d+(?::\d+)?)?$/i.test(v)
|
|
36
|
+
|| /^(?:Dockerfile|Makefile|LICENSE)$/.test(v)))
|
|
37
|
+
r.push(v.replace(/#.*$/, '').replace(/:\d+(?::\d+)?$/, ''));
|
|
38
|
+
return ' ';
|
|
39
|
+
});
|
|
40
|
+
// Em prosa, exigir diretorio ou extensao de fonte conhecida evita versoes, Node.js e dominios.
|
|
41
|
+
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))
|
|
42
|
+
if (!/^Node\.js\.?$/i.test(m[1]))
|
|
43
|
+
r.push(m[1].replace(/\.$/, ''));
|
|
44
|
+
return r.filter((bruto) => {
|
|
45
|
+
const p = caminhoPublico(bruto);
|
|
46
|
+
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)
|
|
47
|
+
|| /(?:^|\/)(?:Dockerfile|Makefile|LICENSE)$/.test(p)
|
|
48
|
+
|| (p.includes('/') && diretorios.has(p.split('/')[0])));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function sementesDaThread(entrada, caminhosDoRepositorio = []) {
|
|
52
|
+
const diretorios = new Set(caminhosDoRepositorio.filter((p) => p.includes('/')).map((p) => p.split('/')[0]));
|
|
53
|
+
const mapa = new Map();
|
|
54
|
+
const adicionar = (bruto, origem) => {
|
|
55
|
+
const p = caminhoPublico(bruto);
|
|
56
|
+
if (!p)
|
|
57
|
+
return;
|
|
58
|
+
const origens = mapa.get(p) ?? new Set();
|
|
59
|
+
origens.add(origem);
|
|
60
|
+
mapa.set(p, origens);
|
|
61
|
+
};
|
|
62
|
+
if (entrada.diffEstado !== 'ignorado-sem-worktree')
|
|
63
|
+
for (const p of entrada.diff)
|
|
64
|
+
adicionar(p, 'diff');
|
|
65
|
+
for (const tipo of ['goal', 'plan'])
|
|
66
|
+
for (const p of caminhosCitados(entrada[tipo] ?? '', diretorios))
|
|
67
|
+
adicionar(p, tipo);
|
|
68
|
+
for (const c of entrada.claims)
|
|
69
|
+
adicionar(c.arquivo, `claim:${c.id}`);
|
|
70
|
+
return [...mapa].sort(([a], [b]) => (0, intelligence_graph_contract_1.compararUtf8)(a, b))
|
|
71
|
+
.map(([arquivo, origens]) => ({ arquivo, origens: [...origens].sort(intelligence_graph_contract_1.compararUtf8) }));
|
|
72
|
+
}
|
|
73
|
+
const compararTipo = (a, b) => Number(a === 'cites') - Number(b === 'cites') || (0, intelligence_graph_contract_1.compararUtf8)(a, b);
|
|
74
|
+
/** O grafo recebido ja deve estar filtrado pela concessao de quem consulta. */
|
|
75
|
+
function pacoteDeContexto(grafo, indice, entrada, tetoBytes = exports.CONTEXTO_TETO_PADRAO, situacao = intelligence_graph_query_1.TUDO_IGUAL) {
|
|
76
|
+
if (!Number.isInteger(tetoBytes) || tetoBytes < 4096 || tetoBytes > 65536)
|
|
77
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-invalido', 'teto deve ser inteiro de 4096 a 65536 bytes');
|
|
78
|
+
const porId = new Map(grafo.nodes.map((n) => [n.node_id, n]));
|
|
79
|
+
const arquivos = new Set(grafo.nodes.filter((n) => n.kind === 'file').map((n) => n.locator.path));
|
|
80
|
+
const sementes = sementesDaThread(entrada, [...arquivos]).map((s) => ({ ...s, estado: arquivos.has(s.arquivo) ? 'indexado' : 'fora-do-indice' }));
|
|
81
|
+
const indexadas = sementes.filter((s) => s.estado === 'indexado'), ausentes = sementes.filter((s) => s.estado !== 'indexado');
|
|
82
|
+
const alvos = new Set(indexadas.map((s) => s.arquivo));
|
|
83
|
+
const diff = entrada.diffEstado === 'ignorado-sem-worktree' ? [] : [...new Set(entrada.diff)].sort(intelligence_graph_contract_1.compararUtf8);
|
|
84
|
+
// Distancia em arquivos, em ambos os sentidos, sem depender da ordem das arestas.
|
|
85
|
+
const adj = new Map();
|
|
86
|
+
for (const a of grafo.edges) {
|
|
87
|
+
const de = porId.get(a.from).locator.path, para = porId.get(a.to).locator.path;
|
|
88
|
+
if (de === para)
|
|
89
|
+
continue;
|
|
90
|
+
if (!adj.has(de))
|
|
91
|
+
adj.set(de, new Set());
|
|
92
|
+
if (!adj.has(para))
|
|
93
|
+
adj.set(para, new Set());
|
|
94
|
+
adj.get(de).add(para);
|
|
95
|
+
adj.get(para).add(de);
|
|
96
|
+
}
|
|
97
|
+
const vizinhos = new Set([...alvos].flatMap((p) => [...(adj.get(p) ?? [])]));
|
|
98
|
+
const dist = new Map(diff.filter((p) => arquivos.has(p)).map((p) => [p, 0]));
|
|
99
|
+
const fila = [...dist.keys()];
|
|
100
|
+
for (let i = 0; i < fila.length; i++)
|
|
101
|
+
for (const p of adj.get(fila[i]) ?? []) {
|
|
102
|
+
if (!dist.has(p)) {
|
|
103
|
+
dist.set(p, dist.get(fila[i]) + 1);
|
|
104
|
+
fila.push(p);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
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)));
|
|
108
|
+
const extratorIds = new Map(extratores.map((e, i) => [(0, intelligence_graph_contract_1.canonico)(e), i]));
|
|
109
|
+
const grupos = new Map();
|
|
110
|
+
let totalArestas = 0, arestasDiretas = 0, estruturais = 0, evidenciasAuxiliares = 0, auxiliaresDiretas = 0;
|
|
111
|
+
for (const a of grafo.edges) {
|
|
112
|
+
const de = porId.get(a.from), para = porId.get(a.to);
|
|
113
|
+
const direto = alvos.has(de.locator.path) || alvos.has(para.locator.path);
|
|
114
|
+
if (!direto && (de.locator.path === para.locator.path
|
|
115
|
+
|| (!vizinhos.has(de.locator.path) && !vizinhos.has(para.locator.path))))
|
|
116
|
+
continue;
|
|
117
|
+
totalArestas++;
|
|
118
|
+
if (direto)
|
|
119
|
+
arestasDiretas++;
|
|
120
|
+
if ((a.kind === 'declares' || a.kind === 'contains') && de.locator.path === para.locator.path && alvos.has(de.locator.path)) {
|
|
121
|
+
estruturais++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const proprias = a.evidence.filter((e) => e.path === de.locator.path);
|
|
125
|
+
evidenciasAuxiliares += a.evidence.length - proprias.length;
|
|
126
|
+
if (direto)
|
|
127
|
+
auxiliaresDiretas += a.evidence.length - proprias.length;
|
|
128
|
+
// Sem evidencia no arquivo de origem, a aresta fica em omitidos.arestas.
|
|
129
|
+
if (!proprias.length)
|
|
130
|
+
continue;
|
|
131
|
+
const origem = `file ${de.locator.path}`, destino = (0, intelligence_graph_query_1.rotuloDoNo)(para);
|
|
132
|
+
const chave = (0, intelligence_graph_contract_1.canonico)([a.kind, destino, de.locator.path]);
|
|
133
|
+
const grupo = grupos.get(chave) ?? { kind: a.kind, origem, destino, alvo: para.node_id, quantidade: 0,
|
|
134
|
+
evidencias: new Map(), entreArquivos: de.locator.path !== para.locator.path,
|
|
135
|
+
salto: direto ? 1 : 2,
|
|
136
|
+
distancia: Math.min(dist.get(de.locator.path) ?? Infinity, dist.get(para.locator.path) ?? Infinity) };
|
|
137
|
+
grupo.quantidade++;
|
|
138
|
+
for (const e of proprias) {
|
|
139
|
+
const x = extratorIds.get((0, intelligence_graph_contract_1.canonico)({ extractor_id: e.extractor_id, extractor_version: e.extractor_version }));
|
|
140
|
+
if (x === undefined)
|
|
141
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.extrator-ausente', 'extrator da evidencia ausente no cabecalho');
|
|
142
|
+
const s = e.span;
|
|
143
|
+
const tupla = [x, e.extraction_method,
|
|
144
|
+
s.type === 'text' ? [s.line_start, s.line_end] : ['pdf', s.page, s.extracted_text_hash], [s.byte_start, s.byte_end]];
|
|
145
|
+
grupo.evidencias.set((0, intelligence_graph_contract_1.canonico)(tupla), tupla);
|
|
146
|
+
}
|
|
147
|
+
grupos.set(chave, grupo);
|
|
148
|
+
}
|
|
149
|
+
// Entre arquivos > perto do diff > tipo > rotulos; empates independem da ordem do indice.
|
|
150
|
+
const ordenados = [...grupos.values()].sort((a, b) => a.salto - b.salto || Number(b.entreArquivos) - Number(a.entreArquivos)
|
|
151
|
+
|| (a.distancia === b.distancia ? 0 : a.distancia < b.distancia ? -1 : 1)
|
|
152
|
+
|| compararTipo(a.kind, b.kind) || (0, intelligence_graph_contract_1.compararUtf8)(a.destino, b.destino) || (0, intelligence_graph_contract_1.compararUtf8)(a.origem, b.origem));
|
|
153
|
+
// Dentro da mesma prioridade, intercalar tipos impede calls de expulsar imports/references.
|
|
154
|
+
const rodadas = new Map();
|
|
155
|
+
const justos = ordenados.map((g) => {
|
|
156
|
+
const chave = JSON.stringify([g.salto, g.alvo, g.entreArquivos, g.distancia, g.kind]);
|
|
157
|
+
const rodada = rodadas.get(chave) ?? 0;
|
|
158
|
+
rodadas.set(chave, rodada + 1);
|
|
159
|
+
return { g, rodada };
|
|
160
|
+
}).sort((a, b) => a.g.salto - b.g.salto || Number(b.g.entreArquivos) - Number(a.g.entreArquivos)
|
|
161
|
+
|| (a.g.distancia === b.g.distancia ? 0 : a.g.distancia < b.g.distancia ? -1 : 1)
|
|
162
|
+
|| a.rodada - b.rodada || compararTipo(a.g.kind, b.g.kind)
|
|
163
|
+
|| (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);
|
|
164
|
+
const normalizada = { ...entrada, diff, diffEstado: entrada.diffEstado ?? 'coletado-na-worktree',
|
|
165
|
+
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))) };
|
|
166
|
+
const fixo = { schema: exports.CONTEXTO_SCHEMA, thread: entrada.thread, base: entrada.base, entrada_sha256: hash((0, intelligence_graph_contract_1.canonico)(normalizada)),
|
|
167
|
+
indice: { ...indice, extratores },
|
|
168
|
+
fontes: { goal: entrada.goal === null ? 'ausente' : hash(entrada.goal), plan: entrada.plan === null ? 'ausente' : hash(entrada.plan),
|
|
169
|
+
diff: normalizada.diffEstado },
|
|
170
|
+
consulta: { profundidade: 2, sentido: 'ambos', por_alvo: exports.CONTEXTO_POR_ALVO, fora_do_indice: exports.CONTEXTO_FORA_DO_INDICE },
|
|
171
|
+
total_sementes: sementes.length, sementes_fora_do_indice: ausentes.length, total_arestas: totalArestas,
|
|
172
|
+
total_ligacoes: ordenados.length, resumidas: { estruturais }, parcial: intelligence_graph_query_1.AVISO_DE_PARCIALIDADE };
|
|
173
|
+
const selecionadas = [], ligacoes = [];
|
|
174
|
+
// D4 e D5: as evidencias do grupo estao no arquivo da origem; o alvo pesa como nas consultas por no.
|
|
175
|
+
const modificado = (a) => (a.modificada ??= situacao(a.origem.slice(5)) !== 'igual' || situacao(porId.get(a.alvo).locator.path) !== 'igual');
|
|
176
|
+
const totalDiretas = ordenados.filter((a) => a.salto === 1).length;
|
|
177
|
+
const totalSegundoSalto = ordenados.length - totalDiretas;
|
|
178
|
+
const montar = () => {
|
|
179
|
+
const caminhos = new Set(selecionadas.filter((s) => s.estado === 'indexado').map((s) => s.arquivo));
|
|
180
|
+
const rotulos = new Set([...caminhos].map((p) => `file ${p}`));
|
|
181
|
+
for (const a of ligacoes) {
|
|
182
|
+
rotulos.add(a.origem);
|
|
183
|
+
rotulos.add(a.destino);
|
|
184
|
+
caminhos.add(porId.get(a.alvo).locator.path);
|
|
185
|
+
caminhos.add(a.origem.slice(5));
|
|
186
|
+
}
|
|
187
|
+
const refs = new Map([...rotulos].sort(intelligence_graph_contract_1.compararUtf8).map((r, i) => [r, `n${i + 1}`]));
|
|
188
|
+
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));
|
|
189
|
+
const diretas = ligacoes.filter((a) => a.salto === 1);
|
|
190
|
+
const omitidos = { sementes: sementes.length - selecionadas.length, ligacoes: totalDiretas - diretas.length,
|
|
191
|
+
segundo_salto: totalSegundoSalto - (ligacoes.length - diretas.length),
|
|
192
|
+
arestas: totalArestas - estruturais - ligacoes.reduce((s, a) => s + a.quantidade, 0), evidencias_auxiliares: evidenciasAuxiliares };
|
|
193
|
+
const diretasOmitidas = arestasDiretas - estruturais - diretas.reduce((s, a) => s + a.quantidade, 0);
|
|
194
|
+
const cortado = omitidos.sementes > 0 || omitidos.ligacoes > 0 || diretasOmitidas > 0 || auxiliaresDiretas > 0;
|
|
195
|
+
const r = { ...fixo, sementes: selecionadas, nos: Object.fromEntries([...refs].map(([r, ref]) => [ref, r])),
|
|
196
|
+
arestas: ligacoes.map((a) => ({ kind: a.kind, from: refs.get(a.origem), to: refs.get(a.destino), quantidade: a.quantidade,
|
|
197
|
+
...(a.salto === 2 ? { salto: 2 } : {}), ...(modificado(a) ? { arvore: 'modificada' } : {}),
|
|
198
|
+
evidencias: [...a.evidencias].sort(([a], [b]) => (0, intelligence_graph_contract_1.compararUtf8)(a, b)).map(([, e]) => e) })),
|
|
199
|
+
truncado: cortado, omitidos, teto: { bytes: tetoBytes, cortado },
|
|
200
|
+
medida: { pacote_bytes: 0, leitura_crua_bytes: fontes.reduce((s, f) => s + f.size_bytes, 0),
|
|
201
|
+
arquivos: fontes.map((f) => ({ path: f.path, bytes: f.size_bytes })),
|
|
202
|
+
origem: 'source_manifest; tamanho dos arquivos, nao custo de descoberta', tokens: 'unavailable' } };
|
|
203
|
+
let texto = (0, intelligence_graph_contract_1.canonico)(r);
|
|
204
|
+
while (r.medida.pacote_bytes !== Buffer.byteLength(texto)) {
|
|
205
|
+
r.medida.pacote_bytes = Buffer.byteLength(texto);
|
|
206
|
+
texto = (0, intelligence_graph_contract_1.canonico)(r);
|
|
207
|
+
}
|
|
208
|
+
return texto;
|
|
209
|
+
};
|
|
210
|
+
let melhor = montar();
|
|
211
|
+
if (Buffer.byteLength(melhor) > tetoBytes)
|
|
212
|
+
throw new intelligence_graph_query_1.ErroDeConsulta('grafo.contexto.teto-excedido', 'cabecalho nao cabe no teto');
|
|
213
|
+
const tentarSemente = (s) => {
|
|
214
|
+
selecionadas.push(s);
|
|
215
|
+
const texto = montar();
|
|
216
|
+
if (Buffer.byteLength(texto) <= tetoBytes)
|
|
217
|
+
melhor = texto;
|
|
218
|
+
else
|
|
219
|
+
selecionadas.pop();
|
|
220
|
+
};
|
|
221
|
+
for (const s of indexadas)
|
|
222
|
+
tentarSemente(s);
|
|
223
|
+
const porAlvo = new Map();
|
|
224
|
+
const tentarLigacao = (a) => {
|
|
225
|
+
if ((porAlvo.get(a.alvo) ?? 0) >= exports.CONTEXTO_POR_ALVO)
|
|
226
|
+
return 'por-alvo';
|
|
227
|
+
ligacoes.push(a);
|
|
228
|
+
const texto = montar();
|
|
229
|
+
if (Buffer.byteLength(texto) <= tetoBytes) {
|
|
230
|
+
melhor = texto;
|
|
231
|
+
porAlvo.set(a.alvo, (porAlvo.get(a.alvo) ?? 0) + 1);
|
|
232
|
+
return 'incluida';
|
|
233
|
+
}
|
|
234
|
+
ligacoes.pop(); // Um hub grande nao impede uma ligacao menor e relevante de entrar.
|
|
235
|
+
return 'sem-espaco';
|
|
236
|
+
};
|
|
237
|
+
for (const a of justos)
|
|
238
|
+
if (a.salto === 1)
|
|
239
|
+
tentarLigacao(a);
|
|
240
|
+
for (const s of ausentes.slice(0, exports.CONTEXTO_FORA_DO_INDICE))
|
|
241
|
+
tentarSemente(s);
|
|
242
|
+
// Expande somente pontes que sobreviveram ao corte direto; a fronteira fica fixa nesta rodada.
|
|
243
|
+
const pontes = new Set(ligacoes.flatMap((a) => [a.origem.slice(5), porId.get(a.alvo).locator.path]));
|
|
244
|
+
let rejeicoes = 0;
|
|
245
|
+
for (const a of justos)
|
|
246
|
+
if (a.salto === 2 && (pontes.has(a.origem.slice(5)) || pontes.has(porId.get(a.alvo).locator.path))) {
|
|
247
|
+
const resultado = tentarLigacao(a);
|
|
248
|
+
if (resultado === 'incluida')
|
|
249
|
+
rejeicoes = 0;
|
|
250
|
+
else if (resultado === 'sem-espaco' && ++rejeicoes >= LIMITE_REJEICOES_SEGUNDO_SALTO)
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
return melhor;
|
|
254
|
+
}
|
|
@@ -29,7 +29,7 @@ exports.GRAFO_LIMITES = Object.freeze({
|
|
|
29
29
|
extratores: 32, diagnosticos: 100_000, caminho: 1024, fragmento: 512, paginas: 100_000,
|
|
30
30
|
});
|
|
31
31
|
exports.TIPOS_DE_NO = ['file', 'symbol', 'section', 'artifact'];
|
|
32
|
-
exports.TIPOS_DE_ARESTA = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from'];
|
|
32
|
+
exports.TIPOS_DE_ARESTA = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from', 'cites'];
|
|
33
33
|
/** D4: so metodo deterministico sustenta aresta. Embedding, similaridade e inferencia ficam fora. */
|
|
34
34
|
exports.METODOS_DE_EXTRACAO = ['ast', 'structured', 'explicit-link', 'text-location'];
|
|
35
35
|
exports.CLASSE_DE_CONFIANCA = 'EXTRACTED';
|
|
@@ -45,6 +45,7 @@ exports.MATRIZ_DE_ARESTAS = Object.freeze({
|
|
|
45
45
|
imports: { file: ['file', 'symbol'], symbol: ['file', 'symbol'], section: nenhum, artifact: nenhum },
|
|
46
46
|
calls: { file: nenhum, symbol: ['symbol'], section: nenhum, artifact: nenhum },
|
|
47
47
|
references: { file: exports.TIPOS_DE_NO, symbol: exports.TIPOS_DE_NO, section: exports.TIPOS_DE_NO, artifact: exports.TIPOS_DE_NO },
|
|
48
|
+
cites: { file: ['file'], symbol: nenhum, section: ['file'], artifact: nenhum },
|
|
48
49
|
derived_from: { file: nenhum, symbol: nenhum, section: nenhum, artifact: ['file', 'section', 'artifact'] },
|
|
49
50
|
});
|
|
50
51
|
const inteiro = zod_1.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|