@orkastery/cli 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/adapters/README.md +11 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +3 -1
  3. package/adapters/claude-code/agents/ork-check.md +1 -1
  4. package/adapters/claude-code/agents/ork-go.md +2 -2
  5. package/adapters/claude-code/agents/ork-goal.md +1 -1
  6. package/adapters/claude-code/agents/ork-master.md +1 -1
  7. package/adapters/claude-code/agents/ork-plan.md +1 -1
  8. package/adapters/claude-code/agents/ork-ship.md +1 -1
  9. package/adapters/claude-code/commands/master.md +11 -8
  10. package/adapters/claude-code/commands/ork.md +8 -0
  11. package/adapters/claude-code/commands/ship.md +2 -2
  12. package/adapters/codex/skills/ork/SKILL.md +12 -1
  13. package/adapters/hermes/README.md +3 -0
  14. package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
  15. package/adapters/hermes/bin/ork-brain.sh +3 -0
  16. package/adapters/hermes/bin/ork-maestro.sh +4 -1
  17. package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
  18. package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
  19. package/adapters/hermes/hermes.plugin.json +2 -0
  20. package/adapters/hermes/hitl-ingress/__init__.py +36 -3
  21. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
  22. package/adapters/openclaw/README.md +34 -2
  23. package/adapters/openclaw/dist/hitl-ingress.js +37 -3
  24. package/adapters/openclaw/dist/index.js +92 -20
  25. package/adapters/openclaw/openclaw.plugin.json +10 -1
  26. package/adapters/openclaw/package.json +2 -2
  27. package/adapters/openclaw/src/hitl-ingress.ts +32 -3
  28. package/adapters/openclaw/src/index.ts +108 -20
  29. package/assets/docs/padroes/documentacao-de-produto.md +2 -2
  30. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  31. package/assets/docs/produto/_modelo-feature.md +2 -0
  32. package/assets/orkmind_bridge.py +214 -1
  33. package/dist/adapters/claude-bg.js +6 -3
  34. package/dist/board.js +74 -0
  35. package/dist/branch-de-estado.js +5 -4
  36. package/dist/busca-semantica.js +161 -0
  37. package/dist/ci.js +141 -10
  38. package/dist/company-brain-cli.js +27 -2
  39. package/dist/company-brain-context.js +132 -0
  40. package/dist/company-brain-dossie.js +376 -0
  41. package/dist/company-brain-mcp.js +4 -1
  42. package/dist/conducao.js +71 -18
  43. package/dist/decisao-autonoma.js +42 -0
  44. package/dist/docs.js +64 -22
  45. package/dist/doctor.js +33 -0
  46. package/dist/entrega-pr.js +109 -5
  47. package/dist/experiencia-instalacao.js +256 -0
  48. package/dist/experiencia.js +72 -0
  49. package/dist/fabrica-estado.js +43 -10
  50. package/dist/fechamento.js +105 -0
  51. package/dist/forja.js +435 -0
  52. package/dist/gates.js +9 -1
  53. package/dist/hitl-classificacao.js +11 -1
  54. package/dist/hitl-contract.js +50 -7
  55. package/dist/hitl-curto.js +158 -0
  56. package/dist/hitl-gates.js +67 -1
  57. package/dist/hitl-lote.js +30 -15
  58. package/dist/hitl-presentation.js +10 -7
  59. package/dist/hitl-resumo.js +33 -12
  60. package/dist/hitl-texto-livre.js +150 -0
  61. package/dist/hosts.js +86 -1
  62. package/dist/index.js +602 -38
  63. package/dist/indice-vetorial.js +317 -0
  64. package/dist/init.js +13 -0
  65. package/dist/integracoes-locais.js +1 -1
  66. package/dist/intelligence-benchmark-contract.js +570 -0
  67. package/dist/intelligence-graph-cli.js +430 -0
  68. package/dist/intelligence-graph-contract.js +577 -0
  69. package/dist/intelligence-graph-extract-md.js +469 -0
  70. package/dist/intelligence-graph-extract-ts.js +810 -0
  71. package/dist/intelligence-graph-extract.js +369 -0
  72. package/dist/intelligence-graph-index.js +512 -0
  73. package/dist/intelligence-graph-parsers.js +327 -0
  74. package/dist/intelligence-graph-query.js +344 -0
  75. package/dist/intelligence-graph-repo.js +187 -0
  76. package/dist/leases.js +84 -0
  77. package/dist/ledger.js +14 -0
  78. package/dist/maestro-cli.js +10 -1
  79. package/dist/maestro-contract.js +5 -1
  80. package/dist/maestro-discovery.js +16 -2
  81. package/dist/maestro-snapshot.js +6 -2
  82. package/dist/manifest.js +142 -5
  83. package/dist/master-batch.js +3 -2
  84. package/dist/master-digest.js +2 -2
  85. package/dist/master-nota.js +203 -0
  86. package/dist/master.js +4 -0
  87. package/dist/mcp-experiencia.js +164 -0
  88. package/dist/mcp-git.js +4 -0
  89. package/dist/mcp-install.js +3 -1
  90. package/dist/mcp-maestro.js +3 -2
  91. package/dist/mcp-server.js +84 -5
  92. package/dist/memoria.js +147 -1
  93. package/dist/network-roadmap.js +907 -0
  94. package/dist/ocupacao.js +38 -2
  95. package/dist/onboarding.js +113 -7
  96. package/dist/orkmind.js +165 -9
  97. package/dist/phase.js +166 -13
  98. package/dist/policies.js +2 -0
  99. package/dist/projeto-alvo.js +551 -0
  100. package/dist/prompts.js +1 -1
  101. package/dist/pulse-consentimento.js +4 -2
  102. package/dist/pulse-delivery.js +5 -0
  103. package/dist/pulse-resposta.js +674 -49
  104. package/dist/pulse.js +21 -0
  105. package/dist/retry.js +51 -8
  106. package/dist/roadmap-reservas.js +262 -20
  107. package/dist/roadmap-status.js +213 -0
  108. package/dist/thread-close.js +3 -0
  109. package/dist/verify.js +4 -3
  110. package/eval/casos/orchestration-experience-pt-br.json +48 -0
  111. package/eval/casos/orchestration-experience.json +48 -0
  112. package/package.json +1 -1
  113. package/schemas/code-artifact-graph.v1.schema.json +581 -0
  114. package/schemas/graph-benchmark.v1.schema.json +2240 -0
  115. package/schemas/maestro-snapshot.schema.json +23 -0
  116. package/skills/README.md +7 -5
  117. package/skills/core/onboarding/SKILL.md +7 -0
  118. package/skills/core/orchestration-experience/SKILL.md +113 -0
  119. package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
  120. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  121. package/skills/phases/go-implementation/SKILL.md +2 -0
@@ -0,0 +1,430 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.USO_DO_GRAFO = exports.AMOSTRA_SCHEMA = exports.STATUS_SCHEMA = void 0;
37
+ exports.lerPedido = lerPedido;
38
+ exports.executarGrafo = executarGrafo;
39
+ /**
40
+ * RM-031 KG3 (D7, D8): `ork grafo`, o CLI do indice e da consulta do grafo de codigo.
41
+ *
42
+ * Substitui o comando provisorio do KG2: `indexar --verificar` prova a extracao (contrato, bytes e
43
+ * determinismo com a ordem de leitura trocada), e `amostra` gera e confere a amostra auditada de
44
+ * arestas. As consultas leem o indice do HEAD e respondem em texto ou `--json`.
45
+ *
46
+ * O argv chega cru e o parser e estrito: subcomando conhecido, opcao conhecida uma vez so, valor
47
+ * onde a opcao pede valor e bandeira sem valor, numero exato de posicionais. Resposta sai 0, mesmo
48
+ * vazia; erro tipado sai 1 e, com `--json`, vem como objeto.
49
+ */
50
+ const node_crypto_1 = require("node:crypto");
51
+ const fs = __importStar(require("node:fs"));
52
+ const path = __importStar(require("node:path"));
53
+ const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
54
+ const intelligence_graph_index_1 = require("./intelligence-graph-index");
55
+ const intelligence_graph_query_1 = require("./intelligence-graph-query");
56
+ const intelligence_graph_repo_1 = require("./intelligence-graph-repo");
57
+ exports.STATUS_SCHEMA = 'ork.code-graph-index-status/v0';
58
+ /** O mesmo schema da amostra do KG2: as amostras auditadas continuam validas. */
59
+ exports.AMOSTRA_SCHEMA = 'ork.graph-edge-audit-sample/v0';
60
+ exports.USO_DO_GRAFO = [
61
+ 'uso: ork grafo indexar [--verificar] [--forcar] [--json]',
62
+ ' ork grafo status [--json]',
63
+ ' ork grafo vizinhos <no> [--profundidade N] [--sentido entrada|saida|ambos] [--tipo T,...] [--limite N] [--json]',
64
+ ' ork grafo chamadores <simbolo> [--profundidade N] [--limite N] [--json]',
65
+ ' ork grafo importadores <arquivo|simbolo> [--profundidade N] [--limite N] [--json]',
66
+ ' ork grafo caminho <de> <para> [--sentido saida|entrada|ambos] [--tipo T,...] [--json]',
67
+ ' ork grafo amostra [--por-estrato N] | ork grafo amostra --conferir ARQ [--json]',
68
+ ' ork grafo limpar [--tudo] [--json]',
69
+ ].join('\n');
70
+ const SUBCOMANDOS = Object.freeze({
71
+ indexar: { posicionais: 0, bandeiras: ['verificar', 'forcar', 'json'], valores: [] },
72
+ status: { posicionais: 0, bandeiras: ['json'], valores: [] },
73
+ vizinhos: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'sentido', 'tipo', 'limite'] },
74
+ chamadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite'] },
75
+ importadores: { posicionais: 1, bandeiras: ['json'], valores: ['profundidade', 'limite'] },
76
+ caminho: { posicionais: 2, bandeiras: ['json'], valores: ['sentido', 'tipo'] },
77
+ amostra: { posicionais: 0, bandeiras: ['json'], valores: ['por-estrato', 'conferir'] },
78
+ limpar: { posicionais: 0, bandeiras: ['tudo', 'json'], valores: [] },
79
+ });
80
+ function uso(motivo) {
81
+ throw new Error(`grafo.uso: ${motivo}\n${exports.USO_DO_GRAFO}`);
82
+ }
83
+ function lerPedido(argv) {
84
+ const [sub, ...resto] = argv;
85
+ if (!sub)
86
+ uso('falta o subcomando');
87
+ const esp = SUBCOMANDOS[sub];
88
+ if (!Object.prototype.hasOwnProperty.call(SUBCOMANDOS, sub) || !esp)
89
+ uso(`subcomando desconhecido: ${sub}`);
90
+ const posicionais = [], bandeiras = new Set(), valores = new Map();
91
+ for (let i = 0; i < resto.length; i++) {
92
+ const a = resto[i];
93
+ if (!a.startsWith('--')) {
94
+ posicionais.push(a);
95
+ continue;
96
+ }
97
+ const igual = a.indexOf('=');
98
+ const nome = igual > 0 ? a.slice(2, igual) : a.slice(2);
99
+ if (bandeiras.has(nome) || valores.has(nome))
100
+ uso(`--${nome} repetida`);
101
+ if (esp.bandeiras.includes(nome)) {
102
+ if (igual > 0)
103
+ uso(`--${nome} nao leva valor`);
104
+ bandeiras.add(nome);
105
+ }
106
+ else if (esp.valores.includes(nome)) {
107
+ const valor = igual > 0 ? a.slice(igual + 1) : resto[++i];
108
+ if (valor === undefined || valor === '' || (igual < 0 && valor.startsWith('--')))
109
+ uso(`--${nome} exige valor`);
110
+ valores.set(nome, valor);
111
+ }
112
+ else {
113
+ uso(`opcao desconhecida para ${sub}: ${a}`);
114
+ }
115
+ }
116
+ if (posicionais.length !== esp.posicionais)
117
+ uso(`${sub} pede ${esp.posicionais} argumento(s), veio ${posicionais.length}`);
118
+ return { sub, posicionais, bandeiras, valores };
119
+ }
120
+ function inteiro(p, nome) {
121
+ const v = p.valores.get(nome);
122
+ if (v === undefined)
123
+ return undefined;
124
+ if (!/^[0-9]{1,6}$/.test(v))
125
+ uso(`--${nome} precisa ser inteiro`);
126
+ return Number(v);
127
+ }
128
+ function tipos(p) {
129
+ const v = p.valores.get('tipo');
130
+ if (v === undefined)
131
+ return undefined;
132
+ const lista = v.split(',');
133
+ for (const t of lista)
134
+ if (!intelligence_graph_contract_1.TIPOS_DE_ARESTA.includes(t))
135
+ uso(`--tipo desconhecido: ${t} (use ${intelligence_graph_contract_1.TIPOS_DE_ARESTA.join(',')})`);
136
+ return lista;
137
+ }
138
+ function sentido(p) {
139
+ const v = p.valores.get('sentido');
140
+ if (v !== undefined && !['entrada', 'saida', 'ambos'].includes(v))
141
+ uso(`--sentido desconhecido: ${v}`);
142
+ return v;
143
+ }
144
+ const mb = (bytes) => `${(bytes / 1024 / 1024).toFixed(1)} MB`;
145
+ const contagem = (o) => Object.entries(o).map(([k, v]) => `${k}=${v}`).join(' ');
146
+ function indexar(ctx, p) {
147
+ const r = (0, intelligence_graph_index_1.construirIndice)(ctx, { verificar: p.bandeiras.has('verificar'), forcar: p.bandeiras.has('forcar') });
148
+ if (p.bandeiras.has('json')) {
149
+ ctx.escrever(JSON.stringify(r, null, 2));
150
+ return 0;
151
+ }
152
+ const m = r.manifesto;
153
+ const linhas = [
154
+ `indice do grafo de ${m.repository_id}: ${r.estado}`,
155
+ ` revisao ${m.revision}`,
156
+ ` chave ${r.chave}`,
157
+ ` snapshot ${m.snapshot_id}`,
158
+ ` digest ${m.graph_digest}`,
159
+ ` conferencia conferirFontes verificada: ${m.conferencia.fontes} fontes e ${m.conferencia.evidencias} evidencias contra os bytes`,
160
+ ` nos ${contagem(m.contagens.nos)}`,
161
+ ` arestas ${contagem(m.contagens.arestas)}`,
162
+ ` lugar ${r.dir} (${mb(m.graph_bytes + m.report_bytes)})`,
163
+ ];
164
+ if (r.motivo)
165
+ linhas.push(` motivo ${r.motivo}`);
166
+ for (const d of r.determinismo ?? [])
167
+ linhas.push(` determinismo ${d.ordem}: digest ${d.digest.slice(0, 16)}, relatorio ${d.relatorio.slice(0, 16)}, ${d.igual ? 'igual' : 'DIFERENTE'}`);
168
+ linhas.push(` tempo ${r.ms} ms`);
169
+ if (r.determinismo)
170
+ linhas.push('aprovado');
171
+ ctx.escrever(linhas.join('\n'));
172
+ return 0;
173
+ }
174
+ function status(ctx, p) {
175
+ const arvore = (0, intelligence_graph_repo_1.revisaoDaArvore)(ctx.raiz);
176
+ let chave = null, analisadores = null, erro = null;
177
+ try {
178
+ const perfil = (0, intelligence_graph_index_1.perfilDoIndice)(arvore.raiz, undefined, ctx.repositorio ? { repository_id: ctx.repositorio } : {});
179
+ analisadores = perfil.analisadores;
180
+ if (arvore.head)
181
+ chave = (0, intelligence_graph_index_1.chaveDoIndice)(arvore.head, perfil);
182
+ }
183
+ catch (e) {
184
+ erro = e.message;
185
+ }
186
+ const estado = (0, intelligence_graph_index_1.estadoDosIndices)(ctx);
187
+ const doHead = chave ? estado.indices.find((i) => i.chave === chave) ?? null : null;
188
+ // Sem analisadores nao ha chave: o indice do HEAD fica indisponivel, nunca "ausente" (indexar tambem nao roda).
189
+ const indiceDoHeadEstado = erro ? 'indisponivel' : doHead ? (doHead.problema ? 'com-problema' : 'presente') : 'ausente';
190
+ const r = {
191
+ schema: exports.STATUS_SCHEMA, head: arvore.head, arvore: arvore.motivo === null ? 'limpa' : arvore.motivo, chave_do_head: chave,
192
+ indice_do_head: indiceDoHeadEstado, analisadores, erro,
193
+ dir: estado.dir, bytes: estado.bytes, indices: estado.indices, sobras: estado.sobras,
194
+ };
195
+ if (p.bandeiras.has('json')) {
196
+ ctx.escrever(JSON.stringify(r, null, 2));
197
+ return 0;
198
+ }
199
+ const linhas = [
200
+ `grafo: HEAD ${arvore.head ? arvore.head.slice(0, 12) : 'sem commit'}, arvore ${r.arvore}`,
201
+ ` indice do HEAD ${chave ?? 'indisponivel'} ${r.indice_do_head === 'ausente' ? '(ausente: rode ork grafo indexar)'
202
+ : r.indice_do_head === 'indisponivel' ? '(sem os analisadores nesta instalacao, nem a consulta nem o indexar rodam)' : `(${r.indice_do_head})`}`,
203
+ ` analisadores ${erro ?? Object.entries(analisadores).map(([k, v]) => `${k} ${v}`).join(', ')}`,
204
+ ` pasta ${estado.dir ?? 'ainda nao criada'} (${estado.indices.length} indice(s), ${mb(estado.bytes)})`,
205
+ ];
206
+ for (const i of estado.indices) {
207
+ linhas.push(` ${i.chave.slice(0, 20)} ${i.revision ? i.revision.slice(0, 12) : '?'} ${i.repository_id ?? '?'} ${mb(i.bytes)} ${i.problema ?? 'ok'}`);
208
+ }
209
+ if (estado.sobras.length)
210
+ linhas.push(` sobras ${estado.sobras.join(', ')}`);
211
+ ctx.escrever(linhas.join('\n'));
212
+ return 0;
213
+ }
214
+ /** O indice do HEAD pronto para consulta, com a concessao local e o cabecalho; `grafo` ja vem filtrado por ela. */
215
+ function consultavel(ctx) {
216
+ const { arvore, perfil, chave, indice } = (0, intelligence_graph_index_1.indiceDoHead)(ctx);
217
+ const concessao = (0, intelligence_graph_index_1.concessaoLocal)(arvore.raiz, perfil);
218
+ const grafo = (0, intelligence_graph_query_1.filtrarGrafo)(indice.grafo, concessao), m = indice.manifesto;
219
+ const cabecalho = {
220
+ repository_id: m.repository_id, revision: m.revision, chave, snapshot_id: m.snapshot_id, graph_digest: m.graph_digest,
221
+ arvore: arvore.motivo === null ? 'limpa' : 'modificada',
222
+ extratores: grafo.snapshot.extractors.map((e) => ({ extractor_id: e.extractor_id, extractor_version: e.extractor_version })),
223
+ };
224
+ return { g: (0, intelligence_graph_query_1.prepararConsulta)(grafo, concessao), cabecalho, grafo, raiz: arvore.raiz };
225
+ }
226
+ function responder(ctx, p, r) {
227
+ ctx.escrever(p.bandeiras.has('json') ? (0, intelligence_graph_query_1.jsonDaResposta)(r) : (0, intelligence_graph_query_1.textoDaResposta)(r));
228
+ return 0;
229
+ }
230
+ function consultar(ctx, p) {
231
+ // As opcoes sao conferidas antes de carregar o indice: erro de uso nao custa a leitura do grafo.
232
+ const [a, b] = p.posicionais;
233
+ const profundidade = inteiro(p, 'profundidade'), limite = inteiro(p, 'limite'), s = sentido(p), t = tipos(p);
234
+ const { g, cabecalho } = consultavel(ctx);
235
+ if (p.sub === 'vizinhos')
236
+ return responder(ctx, p, (0, intelligence_graph_query_1.vizinhos)(g, cabecalho, a, { profundidade, limite, sentido: s, tipos: t }));
237
+ if (p.sub === 'chamadores')
238
+ return responder(ctx, p, (0, intelligence_graph_query_1.chamadores)(g, cabecalho, a, { profundidade, limite }));
239
+ if (p.sub === 'importadores')
240
+ return responder(ctx, p, (0, intelligence_graph_query_1.importadores)(g, cabecalho, a, { profundidade, limite }));
241
+ return responder(ctx, p, (0, intelligence_graph_query_1.caminho)(g, cabecalho, a, b, { sentido: s, tipos: t }));
242
+ }
243
+ const sha256 = (b) => (0, node_crypto_1.createHash)('sha256').update(b).digest('hex');
244
+ /**
245
+ * Bytes da arvore, conferidos arquivo a arquivo contra o manifesto do indice: o trecho da amostra e
246
+ * sempre o do HEAD, mesmo com outro arquivo modificado. So le os arquivos pedidos, e so caminhos do
247
+ * manifesto; arquivo que mudou recusa a amostra.
248
+ */
249
+ function leitorDaArvore(raiz, grafo) {
250
+ const hashes = new Map(grafo.snapshot.source_manifest.map((m) => [m.path, m.source_hash]));
251
+ const lidos = new Map();
252
+ return (p) => {
253
+ const guardado = lidos.get(p);
254
+ if (guardado)
255
+ return guardado;
256
+ const esperado = hashes.get(p);
257
+ if (!esperado)
258
+ throw new Error(`grafo.amostra.fonte-desconhecida: ${p}`);
259
+ // Sem seguir link e so arquivo regular: FIFO ou dispositivo no lugar da fonte nao trava a leitura.
260
+ let fd;
261
+ try {
262
+ fd = fs.openSync(path.join(raiz, p), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
263
+ }
264
+ catch {
265
+ throw new Error(`grafo.amostra.fonte-mudou: ${p}`);
266
+ }
267
+ let bytes;
268
+ try {
269
+ if (!fs.fstatSync(fd).isFile())
270
+ throw new Error(`grafo.amostra.fonte-mudou: ${p}`);
271
+ bytes = fs.readFileSync(fd);
272
+ }
273
+ finally {
274
+ fs.closeSync(fd);
275
+ }
276
+ if (sha256(bytes) !== esperado)
277
+ throw new Error(`grafo.amostra.fonte-mudou: ${p}`);
278
+ lidos.set(p, bytes);
279
+ return bytes;
280
+ };
281
+ }
282
+ const localizadorDe = (g) => new Map(g.nodes.map((n) => [n.node_id, { kind: n.kind, path: n.locator.path, fragment: n.locator.fragment }]));
283
+ const rotulo = (l) => `${l.kind}:${l.path}${l.fragment === null ? '' : `#${l.fragment}`}`;
284
+ const chaveDaAresta = (kind, de, para) => `${kind} ${rotulo(de)} -> ${rotulo(para)}`;
285
+ const trecho = (ler, e) => ler(e.path).subarray(e.span.byte_start, e.span.byte_end);
286
+ /** KG2 D12: estrato por tipo de aresta e metodos; passo fixo sobre os `edge_id` ordenados. */
287
+ function amostrar(grafo, ler, porEstrato, digest) {
288
+ const nos = localizadorDe(grafo), estratos = new Map();
289
+ for (const a of grafo.edges) {
290
+ const chave = `${a.kind}/${[...new Set(a.evidence.map((e) => e.extraction_method))].sort().join('+')}`;
291
+ if (!estratos.has(chave))
292
+ estratos.set(chave, []);
293
+ estratos.get(chave).push(a);
294
+ }
295
+ const arestas = [], universo = {};
296
+ for (const chave of [...estratos.keys()].sort()) {
297
+ const lista = estratos.get(chave).sort((x, y) => (x.edge_id < y.edge_id ? -1 : 1));
298
+ universo[chave] = lista.length;
299
+ const k = Math.min(porEstrato, lista.length);
300
+ for (let i = 0; i < k; i++) {
301
+ const a = lista[Math.floor((i * lista.length) / k)];
302
+ const e = [...a.evidence].sort((x, y) => (x.path === y.path ? x.span.byte_start - y.span.byte_start : x.path < y.path ? -1 : 1))[0];
303
+ const t = trecho(ler, e);
304
+ const span = e.span;
305
+ arestas.push({
306
+ estrato: chave, kind: a.kind, from: nos.get(a.from), to: nos.get(a.to),
307
+ evidencia: {
308
+ path: e.path, extractor_id: e.extractor_id, extraction_method: e.extraction_method, line_start: span.line_start, line_end: span.line_end,
309
+ trecho_sha256: sha256(t), trecho_inicio: t.toString('utf8').split('\n')[0].slice(0, 200),
310
+ },
311
+ veredito: null, nota: null,
312
+ });
313
+ }
314
+ }
315
+ return {
316
+ schema: exports.AMOSTRA_SCHEMA, graph_schema: grafo.schema, repository_id: grafo.repository_id,
317
+ revision: grafo.snapshot.revision, revision_unavailable_reason: grafo.snapshot.revision_unavailable_reason,
318
+ snapshot_id: grafo.snapshot.snapshot_id, graph_digest: digest, por_estrato: porEstrato, universo, arestas,
319
+ };
320
+ }
321
+ /** Confere a amostra auditada contra o indice do HEAD: aresta, trecho pelo hash, veredito com nota. */
322
+ function conferirAmostra(grafo, ler, arquivo) {
323
+ const amostra = JSON.parse(fs.readFileSync(arquivo, 'utf8'));
324
+ if (amostra.schema !== exports.AMOSTRA_SCHEMA || !Array.isArray(amostra.arestas))
325
+ return { linhas: [], falhas: [`schema da amostra: ${amostra.schema}`] };
326
+ if (!amostra.arestas.length)
327
+ return { linhas: [], falhas: ['amostra vazia: nada para conferir'] };
328
+ const nos = localizadorDe(grafo);
329
+ const indice = new Map(grafo.edges.map((a) => [chaveDaAresta(a.kind, nos.get(a.from), nos.get(a.to)), a]));
330
+ const falhas = [], estratos = new Set(), vereditos = {};
331
+ for (const item of amostra.arestas) {
332
+ const chave = chaveDaAresta(item.kind, item.from, item.to);
333
+ vereditos[String(item.veredito)] = (vereditos[String(item.veredito)] ?? 0) + 1;
334
+ estratos.add(item.estrato);
335
+ if (item.veredito !== 'supported' || typeof item.nota !== 'string' || !item.nota.trim()) {
336
+ falhas.push(`${chave}: veredito ${item.veredito ?? 'ausente'}${item.nota ? '' : ', sem nota'}`);
337
+ continue;
338
+ }
339
+ const achada = indice.get(chave);
340
+ if (!achada) {
341
+ falhas.push(`${chave}: aresta ausente no indice do HEAD`);
342
+ continue;
343
+ }
344
+ const ev = item.evidencia;
345
+ const bate = achada.evidence.some((e) => e.path === ev.path && e.extractor_id === ev.extractor_id
346
+ && e.extraction_method === ev.extraction_method && sha256(trecho(ler, e)) === ev.trecho_sha256);
347
+ if (!bate)
348
+ falhas.push(`${chave}: nenhuma evidencia com o trecho auditado`);
349
+ }
350
+ const linhas = [
351
+ `amostra: ${amostra.arestas.length} arestas em ${estratos.size} estratos, auditada na revisao ${amostra.revision ?? amostra.revision_unavailable_reason}`,
352
+ ` vereditos ${Object.entries(vereditos).sort(([x], [y]) => (0, intelligence_graph_contract_1.compararUtf8)(x, y)).map(([k, v]) => `${k}=${v}`).join(' ')}`,
353
+ ` conferidas contra o indice do HEAD: ${amostra.arestas.length - falhas.length} de ${amostra.arestas.length}`,
354
+ ];
355
+ return { linhas, falhas };
356
+ }
357
+ function amostra(ctx, p) {
358
+ if (p.valores.has('conferir') && p.valores.has('por-estrato'))
359
+ uso('--conferir e --por-estrato nao combinam');
360
+ const { grafo, raiz, cabecalho } = consultavel(ctx);
361
+ const ler = leitorDaArvore(raiz, grafo);
362
+ const arquivo = p.valores.get('conferir');
363
+ if (arquivo === undefined) {
364
+ const n = inteiro(p, 'por-estrato') ?? 3;
365
+ if (n < 1)
366
+ uso('--por-estrato precisa ser ao menos 1');
367
+ ctx.escrever(JSON.stringify(amostrar(grafo, ler, n, cabecalho.graph_digest), null, 2));
368
+ return 0;
369
+ }
370
+ const { linhas, falhas } = conferirAmostra(grafo, ler, arquivo);
371
+ if (p.bandeiras.has('json')) {
372
+ ctx.escrever(JSON.stringify({ schema: exports.AMOSTRA_SCHEMA, conferencia: linhas, falhas, aprovado: falhas.length === 0 }, null, 2));
373
+ }
374
+ else {
375
+ ctx.escrever([...linhas, ...falhas.map((f) => `FALHA ${f}`), falhas.length ? `reprovado: ${falhas.length} falha(s)` : 'aprovado'].join('\n'));
376
+ }
377
+ return falhas.length ? 1 : 0;
378
+ }
379
+ /** Sem `--tudo`, fica o indice de todo HEAD das arvores do repositorio: o estado e compartilhado entre elas. */
380
+ function limpar(ctx, p) {
381
+ let manter = [], manterRevisoes = [];
382
+ if (!p.bandeiras.has('tudo')) {
383
+ const arvore = (0, intelligence_graph_repo_1.revisaoDaArvore)(ctx.raiz);
384
+ manterRevisoes = (0, intelligence_graph_repo_1.headsDasArvores)(arvore.raiz);
385
+ if (arvore.head)
386
+ manter = [(0, intelligence_graph_index_1.chaveDoIndice)(arvore.head, (0, intelligence_graph_index_1.perfilDoIndice)(arvore.raiz, undefined, ctx.repositorio ? { repository_id: ctx.repositorio } : {}))];
387
+ }
388
+ const r = (0, intelligence_graph_index_1.limparIndices)(ctx, { manter, manterRevisoes, tudo: p.bandeiras.has('tudo') });
389
+ if (p.bandeiras.has('json'))
390
+ ctx.escrever(JSON.stringify({ schema: exports.STATUS_SCHEMA, manter, manter_revisoes: manterRevisoes, ...r }, null, 2));
391
+ else
392
+ ctx.escrever([`grafo limpar: ${r.removidos.length} removido(s), ${mb(r.bytes)}`, ...r.removidos.map((x) => ` ${x.nome} ${mb(x.bytes)}`)].join('\n'));
393
+ return 0;
394
+ }
395
+ const erroEmJson = (ctx, e) => {
396
+ const [codigo, ...detalhe] = String(e.message).split('\n')[0].split(': ');
397
+ ctx.escrever(JSON.stringify({
398
+ schema: intelligence_graph_query_1.CONSULTA_SCHEMA, erro: { codigo, detalhe: detalhe.join(': ') || null, candidatos: e instanceof intelligence_graph_query_1.ErroDeConsulta ? e.candidatos : [] },
399
+ }, null, 2));
400
+ return 1;
401
+ };
402
+ /** `ork grafo <subcomando> ...`: devolve o codigo de saida; sem `--json`, o erro de uso ou tipado e lancado. */
403
+ function executarGrafo(argv, ctx) {
404
+ let p;
405
+ try {
406
+ p = lerPedido(argv);
407
+ }
408
+ catch (e) {
409
+ // Com `--json` no argv, tambem o erro de uso sai como objeto, como os demais.
410
+ if (argv.includes('--json'))
411
+ return erroEmJson(ctx, e);
412
+ throw e;
413
+ }
414
+ try {
415
+ if (p.sub === 'indexar')
416
+ return indexar(ctx, p);
417
+ if (p.sub === 'status')
418
+ return status(ctx, p);
419
+ if (p.sub === 'amostra')
420
+ return amostra(ctx, p);
421
+ if (p.sub === 'limpar')
422
+ return limpar(ctx, p);
423
+ return consultar(ctx, p);
424
+ }
425
+ catch (e) {
426
+ if (!p.bandeiras.has('json'))
427
+ throw e;
428
+ return erroEmJson(ctx, e);
429
+ }
430
+ }