@orkastery/cli 0.4.3 → 0.5.1

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 (146) 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/README.md +11 -2
  4. package/adapters/claude-code/agents/ork-check.md +1 -1
  5. package/adapters/claude-code/agents/ork-go.md +2 -2
  6. package/adapters/claude-code/agents/ork-goal.md +1 -1
  7. package/adapters/claude-code/agents/ork-master.md +1 -1
  8. package/adapters/claude-code/agents/ork-plan.md +1 -1
  9. package/adapters/claude-code/agents/ork-ship.md +1 -1
  10. package/adapters/claude-code/commands/master.md +11 -8
  11. package/adapters/claude-code/commands/onboarding.md +3 -2
  12. package/adapters/claude-code/commands/ork.md +8 -0
  13. package/adapters/claude-code/commands/ship.md +2 -2
  14. package/adapters/codex/skills/ork/SKILL.md +12 -1
  15. package/adapters/hermes/README.md +3 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
  17. package/adapters/hermes/bin/ork-brain.sh +3 -0
  18. package/adapters/hermes/bin/ork-maestro.sh +4 -1
  19. package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
  20. package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
  21. package/adapters/hermes/hermes.plugin.json +2 -0
  22. package/adapters/hermes/hitl-ingress/__init__.py +36 -3
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
  24. package/adapters/openclaw/README.md +45 -2
  25. package/adapters/openclaw/dist/hitl-ingress.js +37 -3
  26. package/adapters/openclaw/dist/index.js +93 -21
  27. package/adapters/openclaw/openclaw.plugin.json +10 -1
  28. package/adapters/openclaw/package.json +2 -2
  29. package/adapters/openclaw/src/hitl-ingress.ts +32 -3
  30. package/adapters/openclaw/src/index.ts +109 -21
  31. package/assets/docs/padroes/documentacao-de-produto.md +2 -2
  32. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  33. package/assets/docs/produto/_modelo-feature.md +2 -0
  34. package/assets/orkmind_bridge.py +214 -1
  35. package/dist/adapters/claude-bg.js +24 -7
  36. package/dist/auditrun.js +1 -1
  37. package/dist/board.js +74 -0
  38. package/dist/branch-de-estado.js +5 -4
  39. package/dist/busca-semantica.js +161 -0
  40. package/dist/ci.js +141 -10
  41. package/dist/claim-lint.js +3 -1
  42. package/dist/company-brain-cli.js +27 -2
  43. package/dist/company-brain-context.js +132 -0
  44. package/dist/company-brain-dossie.js +376 -0
  45. package/dist/company-brain-mcp.js +4 -1
  46. package/dist/conducao.js +71 -18
  47. package/dist/decisao-autonoma.js +42 -0
  48. package/dist/docs.js +135 -25
  49. package/dist/doctor.js +242 -32
  50. package/dist/entrega-pr.js +116 -5
  51. package/dist/experiencia-instalacao.js +256 -0
  52. package/dist/experiencia.js +72 -0
  53. package/dist/fabrica-estado.js +63 -12
  54. package/dist/fechamento.js +105 -0
  55. package/dist/fix.js +3 -3
  56. package/dist/forja.js +435 -0
  57. package/dist/gates.js +9 -1
  58. package/dist/hitl-classificacao.js +11 -1
  59. package/dist/hitl-contract.js +50 -7
  60. package/dist/hitl-curto.js +158 -0
  61. package/dist/hitl-gates.js +67 -1
  62. package/dist/hitl-lote.js +30 -15
  63. package/dist/hitl-presentation.js +10 -7
  64. package/dist/hitl-resumo.js +57 -13
  65. package/dist/hitl-texto-livre.js +150 -0
  66. package/dist/hosts.js +92 -3
  67. package/dist/index.js +637 -45
  68. package/dist/indice-vetorial.js +317 -0
  69. package/dist/init.js +24 -5
  70. package/dist/integracoes-locais.js +3 -1
  71. package/dist/intelligence-benchmark-contract.js +570 -0
  72. package/dist/intelligence-graph-cli.js +584 -0
  73. package/dist/intelligence-graph-contract.js +636 -0
  74. package/dist/intelligence-graph-extract-md.js +487 -0
  75. package/dist/intelligence-graph-extract-ts.js +980 -0
  76. package/dist/intelligence-graph-extract.js +546 -0
  77. package/dist/intelligence-graph-index.js +693 -0
  78. package/dist/intelligence-graph-parsers.js +327 -0
  79. package/dist/intelligence-graph-query.js +344 -0
  80. package/dist/intelligence-graph-repo.js +197 -0
  81. package/dist/leases.js +100 -0
  82. package/dist/ledger.js +23 -0
  83. package/dist/licoes.js +5 -4
  84. package/dist/liveness.js +2 -1
  85. package/dist/maestro-cli.js +10 -1
  86. package/dist/maestro-contract.js +5 -1
  87. package/dist/maestro-discovery.js +16 -2
  88. package/dist/maestro-runtime.js +3 -0
  89. package/dist/maestro-snapshot.js +6 -2
  90. package/dist/manifest.js +166 -5
  91. package/dist/master-batch.js +3 -2
  92. package/dist/master-digest.js +2 -2
  93. package/dist/master-nota.js +203 -0
  94. package/dist/master.js +4 -0
  95. package/dist/mcp-artifacts.js +2 -0
  96. package/dist/mcp-experiencia.js +164 -0
  97. package/dist/mcp-git.js +64 -12
  98. package/dist/mcp-grafo-worker.js +91 -0
  99. package/dist/mcp-grafo.js +233 -0
  100. package/dist/mcp-install.js +5 -2
  101. package/dist/mcp-maestro.js +3 -2
  102. package/dist/mcp-server.js +93 -5
  103. package/dist/mcp-ship.js +2 -0
  104. package/dist/mcp-verify.js +3 -1
  105. package/dist/memoria.js +147 -1
  106. package/dist/network-roadmap.js +907 -0
  107. package/dist/ocupacao.js +43 -3
  108. package/dist/onboarding.js +122 -11
  109. package/dist/orkmind.js +165 -9
  110. package/dist/orquestracao.js +2 -1
  111. package/dist/parado-no-condutor.js +933 -0
  112. package/dist/phase.js +166 -13
  113. package/dist/policies.js +29 -2
  114. package/dist/projeto-alvo.js +551 -0
  115. package/dist/prompts.js +1 -1
  116. package/dist/prova-ativacao.js +345 -0
  117. package/dist/pulse-consentimento.js +4 -2
  118. package/dist/pulse-delivery.js +32 -6
  119. package/dist/pulse-resposta.js +674 -49
  120. package/dist/pulse.js +74 -3
  121. package/dist/retry.js +51 -8
  122. package/dist/roadmap-reservas.js +262 -20
  123. package/dist/roadmap-status.js +348 -0
  124. package/dist/runtime-context.js +5 -1
  125. package/dist/sessoes-inventario.js +7 -1
  126. package/dist/sessoes.js +4 -1
  127. package/dist/ship.js +25 -1
  128. package/dist/thread-close.js +3 -0
  129. package/dist/thread.js +21 -2
  130. package/dist/util.js +71 -4
  131. package/dist/verify.js +6 -5
  132. package/dist/worktree.js +29 -6
  133. package/eval/casos/onboarding.json +1 -1
  134. package/eval/casos/orchestration-experience-pt-br.json +48 -0
  135. package/eval/casos/orchestration-experience.json +48 -0
  136. package/package.json +1 -1
  137. package/schemas/code-artifact-graph.v1.schema.json +581 -0
  138. package/schemas/graph-benchmark.v1.schema.json +2240 -0
  139. package/schemas/maestro-snapshot.schema.json +23 -0
  140. package/skills/README.md +7 -5
  141. package/skills/core/onboarding/SKILL.md +10 -2
  142. package/skills/core/orchestration-experience/SKILL.md +113 -0
  143. package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
  144. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  145. package/skills/phases/go-implementation/SKILL.md +2 -0
  146. package/skills/phases/ship-release/SKILL.md +6 -3
@@ -0,0 +1,546 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.textoAceito = exports.UNIDADES_SCHEMA = exports.LACUNAS_SO_CONTAGEM = exports.EXTENSOES_MD = exports.EXTENSOES_TS = exports.CONFIG_SCHEMA = exports.RELATORIO_SCHEMA = exports.VERSAO_KG2 = exports.EXTRATOR_ARQUIVOS = exports.EXTRATOR_ID = exports.EXTRATOR_MD = exports.EXTRATOR_TS = void 0;
4
+ exports.textoCurto = textoCurto;
5
+ exports.extensaoDe = extensaoDe;
6
+ exports.idDeBlob = idDeBlob;
7
+ exports.decodificarUtf8 = decodificarUtf8;
8
+ exports.extrairGrafo = extrairGrafo;
9
+ /**
10
+ * RM-031 KG2 (D1, D7 a D10): extracao deterministica do grafo `ork.code-artifact-graph/v1`.
11
+ *
12
+ * Modulo puro: recebe os bytes das fontes e o compilador TypeScript por parametro (D1), sem abrir
13
+ * arquivo, rede ou processo. As fontes sao ordenadas antes de tudo e os IDs saem do contrato
14
+ * (`derivarIds`), entao a ordem de leitura nao muda o grafo nem o relatorio. O que nenhum extrator
15
+ * prova vira diagnostico do contrato ou lacuna do relatorio (D7), nunca aresta nem no fabricado.
16
+ */
17
+ const node_crypto_1 = require("node:crypto");
18
+ const intelligence_graph_contract_1 = require("./intelligence-graph-contract");
19
+ const intelligence_graph_extract_md_1 = require("./intelligence-graph-extract-md");
20
+ const intelligence_graph_extract_ts_1 = require("./intelligence-graph-extract-ts");
21
+ exports.EXTRATOR_TS = 'ork.ts-ast';
22
+ exports.EXTRATOR_MD = 'ork.md-structure';
23
+ exports.EXTRATOR_ID = 'ork.id-mention';
24
+ /** D9: declara o arquivo do manifesto que nenhum extrator leu. */
25
+ exports.EXTRATOR_ARQUIVOS = 'ork.repo-files';
26
+ /** Versao da regra de extracao; a do compilador entra no `extractor_version` do `ork.ts-ast`. */
27
+ exports.VERSAO_KG2 = '1.0.0';
28
+ exports.RELATORIO_SCHEMA = 'ork.graph-extraction-report/v0';
29
+ exports.CONFIG_SCHEMA = 'ork.graph-extraction-config/v0';
30
+ exports.EXTENSOES_TS = ['.cjs', '.cts', '.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx'];
31
+ exports.EXTENSOES_MD = ['.markdown', '.md'];
32
+ /** D7: categorias de lacuna volumosas saem so na contagem; as demais saem tambem listadas. */
33
+ exports.LACUNAS_SO_CONTAGEM = new Set([
34
+ 'chamada-fora-de-simbolo', 'chamada-nao-resolvida', 'chamada-alvo-fora-do-grafo', 'chamada-por-tipo', 'import-sem-simbolo',
35
+ 'id-sem-artefato', 'link-externo',
36
+ ]);
37
+ /** RM-031 KG4 (D2): as unidades por arquivo que o indice guarda para a proxima revisao reaproveitar. */
38
+ exports.UNIDADES_SCHEMA = 'ork.graph-extraction-units/v0';
39
+ function falha(codigo, onde) {
40
+ throw new Error(onde ? `${codigo} em ${onde}` : codigo);
41
+ }
42
+ /**
43
+ * Aninhamento extremo estoura a pilha do compilador ou do analisador (o binder do TypeScript e
44
+ * recursivo): a extracao falha inteira com erro tipado, nunca com grafo parcial (D10).
45
+ */
46
+ function semEstouro(extrator, f) {
47
+ try {
48
+ return f();
49
+ }
50
+ catch (e) {
51
+ if (e instanceof RangeError && /call stack/i.test(e.message))
52
+ falha('extracao.limite.pilha', extrator);
53
+ throw e;
54
+ }
55
+ }
56
+ /**
57
+ * Replica da regra de texto do contrato (controles, marcas invisiveis, surrogate isolado), para o
58
+ * produtor descartar referencia que o contrato recusaria. O corpus do KG1 e a autoridade.
59
+ */
60
+ const CONTROLE = /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u180e\u200b\u200e\u200f\u2028\u2029\u202a-\u202e\u2060-\u206f\ufeff\ufff9-\ufffb]/;
61
+ const SURROGATE_ISOLADO = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
62
+ const textoAceito = (t) => !CONTROLE.test(t) && !SURROGATE_ISOLADO.test(t);
63
+ exports.textoAceito = textoAceito;
64
+ /** Texto curto que cabe em `reference` ou `fragment`; fora disso, `null` (nunca truncado). */
65
+ function textoCurto(t) {
66
+ const limpo = t.trim();
67
+ return limpo.length >= 1 && limpo.length <= intelligence_graph_contract_1.GRAFO_LIMITES.fragmento && (0, exports.textoAceito)(limpo) ? limpo : null;
68
+ }
69
+ /** Extensao do nome do arquivo em minusculas (`.ts`); arquivo oculto sem ponto no meio nao tem. */
70
+ function extensaoDe(caminho) {
71
+ const nome = caminho.slice(caminho.lastIndexOf('/') + 1), i = nome.lastIndexOf('.');
72
+ return i <= 0 ? '' : nome.slice(i).toLowerCase();
73
+ }
74
+ /** D8: id de blob do Git, calculado dos bytes; igual ao `git hash-object --no-filters` do arquivo. */
75
+ function idDeBlob(bytes) {
76
+ return (0, node_crypto_1.createHash)('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex');
77
+ }
78
+ const sha256 = (b) => (0, node_crypto_1.createHash)('sha256').update(b).digest('hex');
79
+ /** UTF-8 estrito, com o BOM preservado para os offsets baterem com os bytes. */
80
+ function decodificarUtf8(bytes) {
81
+ try {
82
+ return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ /** Converte offset UTF-16 do texto em offset de byte UTF-8 e em linha (1-based). */
89
+ class MapaDoTexto {
90
+ texto;
91
+ tamanho;
92
+ bytes = null;
93
+ quebras = null;
94
+ constructor(texto, tamanho) {
95
+ this.texto = texto;
96
+ this.tamanho = tamanho;
97
+ }
98
+ byte(i) {
99
+ if (this.tamanho === this.texto.length)
100
+ return i;
101
+ if (!this.bytes) {
102
+ const t = this.texto, acc = new Uint32Array(t.length + 1);
103
+ for (let j = 0; j < t.length; j++) {
104
+ const c = t.charCodeAt(j);
105
+ // Par de surrogates e um code point de 4 bytes; o texto veio de UTF-8 valido, sem surrogate isolado.
106
+ if (c >= 0xd800 && c <= 0xdbff && j + 1 < t.length) {
107
+ acc[j + 1] = acc[j] + 4;
108
+ acc[j + 2] = acc[j + 1];
109
+ j++;
110
+ continue;
111
+ }
112
+ acc[j + 1] = acc[j] + (c < 0x80 ? 1 : c < 0x800 ? 2 : 3);
113
+ }
114
+ this.bytes = acc;
115
+ }
116
+ return this.bytes[i];
117
+ }
118
+ linha(i) {
119
+ if (!this.quebras) {
120
+ const q = [];
121
+ for (let j = this.texto.indexOf('\n'); j >= 0; j = this.texto.indexOf('\n', j + 1))
122
+ q.push(j);
123
+ this.quebras = q;
124
+ }
125
+ let baixo = 0, alto = this.quebras.length;
126
+ while (baixo < alto) {
127
+ const meio = (baixo + alto) >> 1;
128
+ if (this.quebras[meio] < i)
129
+ baixo = meio + 1;
130
+ else
131
+ alto = meio;
132
+ }
133
+ return baixo + 1;
134
+ }
135
+ }
136
+ const chaveDoNo = (r) => (0, intelligence_graph_contract_1.canonico)([r.kind, r.path, r.fragment]);
137
+ const zeros = '0'.repeat(64);
138
+ function contagemVazia(chaves) {
139
+ return Object.fromEntries(chaves.map((k) => [k, 0]));
140
+ }
141
+ /**
142
+ * A mudanca e por conteudo: o hash de cada caminho contra o da base, mais os novos e os removidos
143
+ * (renome e os dois). No TypeScript, semente e o arquivo mudado ou novo e o nao mudado cuja sonda casa
144
+ * caminho novo ou removido; afetado e a semente e quem alcanca semente ou caminho mudado pelas
145
+ * dependencias gravadas na base. `package.json` ou arquivo global na mudanca extrai o TypeScript inteiro.
146
+ */
147
+ function planejarReuso(base, manifesto, fontesTs, fontesMd) {
148
+ const porCaminho = new Map(base.arquivos.map((u) => [u.path, u]));
149
+ const alterados = [], novos = [], removidos = [];
150
+ for (const [p, m] of manifesto) {
151
+ const u = porCaminho.get(p);
152
+ if (!u)
153
+ novos.push(p);
154
+ else if (u.source_hash !== m.source_hash)
155
+ alterados.push(p);
156
+ }
157
+ for (const p of porCaminho.keys())
158
+ if (!manifesto.has(p))
159
+ removidos.push(p);
160
+ for (const l of [alterados, novos, removidos])
161
+ l.sort(intelligence_graph_contract_1.compararUtf8);
162
+ const mudados = new Set([...alterados, ...novos, ...removidos]);
163
+ const md = new Map();
164
+ for (const f of fontesMd) {
165
+ const u = porCaminho.get(f.path);
166
+ if (u?.md && !mudados.has(f.path))
167
+ md.set(f.path, u.md);
168
+ }
169
+ const plano = { base, porCaminho, mudanca: { alterados, novos, removidos }, md, ts: { motivo: null, sementes: new Set(), afetados: new Set() } };
170
+ const ordenados = [...mudados].sort(intelligence_graph_contract_1.compararUtf8), globais = new Set(base.globais_ts), ts1 = new Set(fontesTs.map((f) => f.path));
171
+ const pacote = ordenados.find((p) => p === 'package.json' || p.endsWith('/package.json'));
172
+ const global = ordenados.find((p) => globais.has(p));
173
+ const semUnidade = fontesTs.find((f) => !mudados.has(f.path) && !porCaminho.get(f.path)?.ts);
174
+ if (pacote !== undefined)
175
+ plano.ts.motivo = `package.json na mudanca (${pacote})`;
176
+ else if (global !== undefined)
177
+ plano.ts.motivo = `arquivo global do TypeScript na mudanca (${global})`;
178
+ else if (semUnidade !== undefined)
179
+ plano.ts.motivo = `base sem a unidade TypeScript de ${semUnidade.path}`;
180
+ if (plano.ts.motivo !== null)
181
+ return plano;
182
+ const existencia = [...novos, ...removidos];
183
+ for (const p of ts1) {
184
+ if (mudados.has(p))
185
+ plano.ts.sementes.add(p);
186
+ else if (existencia.length && (porCaminho.get(p)?.ts).sondas.some((b) => existencia.some((q) => (0, intelligence_graph_extract_ts_1.casaSonda)(b, q))))
187
+ plano.ts.sementes.add(p);
188
+ }
189
+ const dependentes = new Map();
190
+ for (const u of base.arquivos) {
191
+ for (const d of u.ts?.dependencias ?? []) {
192
+ const lista = dependentes.get(d);
193
+ if (lista)
194
+ lista.push(u.path);
195
+ else
196
+ dependentes.set(d, [u.path]);
197
+ }
198
+ }
199
+ const vistos = new Set(), fila = [...plano.ts.sementes, ...mudados];
200
+ while (fila.length) {
201
+ const q = fila.pop();
202
+ if (vistos.has(q))
203
+ continue;
204
+ vistos.add(q);
205
+ for (const x of dependentes.get(q) ?? [])
206
+ if (!vistos.has(x))
207
+ fila.push(x);
208
+ }
209
+ // CHECK (B1): quem usa um global nao importa o arquivo dele, e o global depende do que esse arquivo
210
+ // importa (heranca, tipo importado, `export *` atras de UMD, aumento que estende tipo de outro modulo).
211
+ const globalAlcancado = [...globais].sort(intelligence_graph_contract_1.compararUtf8).find((g) => vistos.has(g));
212
+ if (globalAlcancado !== undefined) {
213
+ plano.ts.motivo = `dependencia de arquivo global na mudanca (${globalAlcancado})`;
214
+ return plano;
215
+ }
216
+ for (const p of vistos)
217
+ if (ts1.has(p))
218
+ plano.ts.afetados.add(p);
219
+ return plano;
220
+ }
221
+ /**
222
+ * KG4 (D3): extrai os afetados num programa parcial: eles, os globais e o fecho direto pelas
223
+ * dependencias da base (a semente descobre as suas no programa, que cresce ate fechar). O resto vem
224
+ * da base. Afetado que passa a declarar global devolve o motivo, e o TypeScript sai inteiro.
225
+ */
226
+ function extrairTsParcial(plano, entrada, extrair) {
227
+ const { afetados, sementes } = plano.ts, ts1 = new Set(entrada.fontes.map((f) => f.path));
228
+ const daBase = (p) => plano.porCaminho.get(p)?.ts;
229
+ const unidades = new Map(), globais = [...plano.base.globais_ts];
230
+ const raizes = new Set();
231
+ const incluir = (inicio) => {
232
+ const fila = [...inicio];
233
+ while (fila.length) {
234
+ const p = fila.pop();
235
+ if (raizes.has(p) || !ts1.has(p))
236
+ continue;
237
+ raizes.add(p);
238
+ if (!sementes.has(p))
239
+ for (const d of daBase(p).dependencias)
240
+ if (!raizes.has(d))
241
+ fila.push(d);
242
+ }
243
+ };
244
+ let r = null;
245
+ if (afetados.size) {
246
+ incluir([...afetados, ...globais]);
247
+ for (;;) {
248
+ r = extrair({ ...entrada, fontes: entrada.fontes.filter((f) => raizes.has(f.path)), emitir: afetados });
249
+ if (!r.faltantes.length)
250
+ break;
251
+ const antes = raizes.size;
252
+ incluir(r.faltantes);
253
+ if (raizes.size === antes)
254
+ falha('extracao.interna.programa-parcial');
255
+ }
256
+ const daBaseGlobal = new Set(globais), doPrograma = new Set(r.globais);
257
+ const novo = r.globais.find((g) => !daBaseGlobal.has(g));
258
+ if (novo !== undefined)
259
+ return { motivo: `arquivo passa a declarar global no TypeScript (${novo})`, unidades, globais, programa: raizes.size };
260
+ const sumiu = globais.find((g) => ts1.has(g) && !doPrograma.has(g));
261
+ if (sumiu !== undefined)
262
+ return { motivo: `global da base fora do escopo global (${sumiu})`, unidades, globais, programa: raizes.size };
263
+ }
264
+ for (const f of entrada.fontes) {
265
+ const u = afetados.has(f.path) ? r?.unidades.get(f.path) : daBase(f.path);
266
+ if (!u)
267
+ falha('extracao.interna.unidade-ts-ausente');
268
+ unidades.set(f.path, u);
269
+ }
270
+ return { motivo: null, unidades, globais, programa: raizes.size };
271
+ }
272
+ /**
273
+ * Extrai o grafo das fontes fornecidas. Lanca `extracao.*` para entrada invalida ou teto do
274
+ * contrato estourado (D10), e `grafo.*` se o resultado violar o contrato (defeito do extrator).
275
+ * RM-031 KG4: com `base` (as unidades do indice de outra revisao, do mesmo extrator), reextrai so o
276
+ * que a mudanca alcanca; o resultado e o mesmo, byte a byte, da extracao sem base.
277
+ */
278
+ function extrairGrafo(entrada, parser, base = null) {
279
+ const { ts, unicode, markdown, javascript } = parser;
280
+ if (!/^[0-9]+(\.[0-9]+)*$/.test(unicode))
281
+ falha('extracao.entrada.unicode-invalido');
282
+ if (!/^[0-9A-Za-z][0-9A-Za-z.-]{0,40}$/.test(markdown.versao) || typeof markdown.analisar !== 'function'
283
+ || typeof markdown.referencia !== 'function')
284
+ falha('extracao.entrada.markdown-invalido');
285
+ if (!javascript || !/^node\.[0-9]+(\.[0-9]+)*$/.test(javascript.versao) || typeof javascript.sintaxe !== 'function') {
286
+ falha('extracao.entrada.javascript-invalido');
287
+ }
288
+ const acl = [...new Set(entrada.acl_refs)].sort(intelligence_graph_contract_1.compararUtf8);
289
+ const access = { tenant_id: entrada.tenant_id, acl_refs: acl };
290
+ const authority = `git:${entrada.repository_id}`;
291
+ const fontes = [...entrada.fontes].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a.path, b.path));
292
+ for (let i = 1; i < fontes.length; i++)
293
+ if (fontes[i - 1].path === fontes[i].path)
294
+ falha('extracao.entrada.fonte-duplicada');
295
+ // O contrato recusa o grafo inteiro por um caminho ruim; aqui o caminho sai e fica declarado.
296
+ const excluidas = (entrada.excluidas ?? []).map((e) => ({ path: e.path, motivo: e.motivo }));
297
+ const validas = fontes.filter((f) => {
298
+ const ok = f.path.length <= intelligence_graph_contract_1.GRAFO_LIMITES.caminho && (0, intelligence_graph_contract_1.caminhoValido)(f.path);
299
+ if (!ok)
300
+ excluidas.push({ path: f.path, motivo: 'caminho-recusado' });
301
+ return ok;
302
+ });
303
+ const porNfc = new Map();
304
+ for (const f of validas)
305
+ porNfc.set(f.path.normalize('NFC'), (porNfc.get(f.path.normalize('NFC')) ?? 0) + 1);
306
+ const aceitas = validas.filter((f) => {
307
+ const ok = porNfc.get(f.path.normalize('NFC')) === 1;
308
+ if (!ok)
309
+ excluidas.push({ path: f.path, motivo: 'caminho-ambiguo' });
310
+ return ok;
311
+ });
312
+ if (aceitas.length === 0)
313
+ falha('extracao.entrada.sem-fontes');
314
+ if (aceitas.length > intelligence_graph_contract_1.GRAFO_LIMITES.manifesto)
315
+ falha('extracao.limite.manifesto');
316
+ const manifesto = new Map();
317
+ for (const f of aceitas) {
318
+ manifesto.set(f.path, {
319
+ path: f.path, authority, source_hash: sha256(f.bytes), source_version: idDeBlob(f.bytes), size_bytes: f.bytes.length, access,
320
+ });
321
+ }
322
+ const bytesDe = new Map(aceitas.map((f) => [f.path, f.bytes]));
323
+ const textos = new Map();
324
+ const texto = (p) => {
325
+ if (!textos.has(p)) {
326
+ const b = bytesDe.get(p);
327
+ textos.set(p, b ? decodificarUtf8(b) : null);
328
+ }
329
+ return textos.get(p) ?? undefined;
330
+ };
331
+ const achados = { nos: [], arestas: [], diagnosticos: [], lacunas: [] };
332
+ // Laco, nao `push(...lista)`: lista grande estouraria a pilha antes do teto tipado do contrato.
333
+ const juntar = (a) => {
334
+ for (const x of a.nos)
335
+ achados.nos.push(x);
336
+ for (const x of a.arestas)
337
+ achados.arestas.push(x);
338
+ for (const x of a.diagnosticos)
339
+ achados.diagnosticos.push(x);
340
+ for (const x of a.lacunas)
341
+ achados.lacunas.push(x);
342
+ };
343
+ const caminhos = aceitas.map((f) => f.path);
344
+ const fontesTs = [], fontesMd = [];
345
+ for (const p of caminhos) {
346
+ const ext = extensaoDe(p), ehTs = exports.EXTENSOES_TS.includes(ext), ehMd = exports.EXTENSOES_MD.includes(ext);
347
+ if (!ehTs && !ehMd) {
348
+ // D9: o arquivo vira no, e o diagnostico diz que o conteudo dele nao foi lido.
349
+ achados.diagnosticos.push({ kind: 'unsupported-language', path: p, reference: ext || null, extrator: exports.EXTRATOR_ARQUIVOS });
350
+ continue;
351
+ }
352
+ const t = texto(p);
353
+ if (t === undefined)
354
+ achados.lacunas.push({ categoria: 'utf8-invalido', path: p, inicio: null, detalhe: null });
355
+ else
356
+ (ehTs ? fontesTs : fontesMd).push({ path: p, texto: t });
357
+ }
358
+ const versaoTs = `${exports.VERSAO_KG2}+typescript.${ts.version}+${javascript.versao}`;
359
+ // B1: a raiz virtual do compilador deriva do manifesto; um caminho do repositorio nao a nomeia.
360
+ const raiz = `/ork-${(0, intelligence_graph_contract_1.sha256DoCanonico)([...manifesto.values()].map((m) => [m.path, m.source_hash])).slice(0, 32)}`;
361
+ const aceitaFragmento = (f) => f.length >= 1 && f.length <= intelligence_graph_contract_1.GRAFO_LIMITES.fragmento && (0, exports.textoAceito)(f);
362
+ const entradaTs = { fontes: fontesTs, arquivos: caminhos, texto, raiz, aceitaFragmento, sintaxe: javascript.sintaxe, extrator: exports.EXTRATOR_TS };
363
+ const extrairTs = (e) => semEstouro(exports.EXTRATOR_TS, () => (0, intelligence_graph_extract_ts_1.extrairTypeScript)(e, ts));
364
+ // KG4 (D1, D3, D4): com as unidades de uma base, so o que a mudanca alcanca e extraido de novo.
365
+ const plano = base ? planejarReuso(base, manifesto, fontesTs, fontesMd) : null;
366
+ let tsDaBase = null;
367
+ if (plano && plano.ts.motivo === null)
368
+ tsDaBase = extrairTsParcial(plano, entradaTs, extrairTs);
369
+ const motivoTs = plano ? plano.ts.motivo ?? tsDaBase?.motivo ?? null : null;
370
+ let unidadesTs, globaisTs;
371
+ if (tsDaBase && tsDaBase.motivo === null) {
372
+ unidadesTs = tsDaBase.unidades;
373
+ globaisTs = tsDaBase.globais;
374
+ }
375
+ else {
376
+ const r = extrairTs(entradaTs);
377
+ unidadesTs = r.unidades;
378
+ globaisTs = r.globais;
379
+ }
380
+ for (const f of fontesTs) {
381
+ const u = unidadesTs.get(f.path);
382
+ if (!u)
383
+ falha('extracao.interna.unidade-ts-ausente');
384
+ juntar(u.achados);
385
+ }
386
+ // B4: chave `caminho#fragmento` como o frontmatter a escreve; duas refs na mesma chave ficam ambiguas.
387
+ const simbolos = new Map();
388
+ for (const r of achados.nos.filter((x) => x.kind === 'symbol')) {
389
+ const chave = `${r.path}#${r.fragment}`, antes = simbolos.get(chave);
390
+ simbolos.set(chave, antes === undefined || (antes && antes.path === r.path && antes.fragment === r.fragment) ? r : null);
391
+ }
392
+ const estruturas = semEstouro(exports.EXTRATOR_MD, () => fontesMd.map((f) => plano?.md.get(f.path)
393
+ ?? (0, intelligence_graph_extract_md_1.estruturarMarkdown)(f, { aceitaFragmento, analisar: markdown.analisar, referencia: markdown.referencia })));
394
+ juntar(semEstouro(exports.EXTRATOR_MD, () => (0, intelligence_graph_extract_md_1.ligarMarkdown)({
395
+ estruturas, codigo: fontesTs, arquivos: caminhos, simbolos, aceitaFragmento, extratorMd: exports.EXTRATOR_MD, extratorId: exports.EXTRATOR_ID,
396
+ })));
397
+ const extratores = [
398
+ { extractor_id: exports.EXTRATOR_ARQUIVOS, extractor_version: exports.VERSAO_KG2 },
399
+ { extractor_id: exports.EXTRATOR_ID, extractor_version: exports.VERSAO_KG2 },
400
+ { extractor_id: exports.EXTRATOR_MD, extractor_version: `${exports.VERSAO_KG2}+${markdown.versao}+unicode.${unicode}` },
401
+ { extractor_id: exports.EXTRATOR_TS, extractor_version: versaoTs },
402
+ ];
403
+ const versoes = new Map(extratores.map((e) => [e.extractor_id, e.extractor_version]));
404
+ const versaoDe = (id) => versoes.get(id) ?? falha('extracao.interna.extrator-desconhecido');
405
+ // Nos: todo arquivo do manifesto e os nos que os extratores provaram.
406
+ const nos = new Map();
407
+ for (const p of caminhos)
408
+ nos.set(chaveDoNo({ kind: 'file', path: p, fragment: null }), { kind: 'file', path: p, fragment: null });
409
+ for (const r of achados.nos) {
410
+ if (!manifesto.has(r.path))
411
+ falha('extracao.interna.no-sem-fonte');
412
+ if (r.fragment === null || !(0, exports.textoAceito)(r.fragment) || r.fragment.length > intelligence_graph_contract_1.GRAFO_LIMITES.fragmento)
413
+ falha('extracao.interna.fragmento');
414
+ nos.set(chaveDoNo(r), r);
415
+ }
416
+ if (nos.size > intelligence_graph_contract_1.GRAFO_LIMITES.nos)
417
+ falha('extracao.limite.nos');
418
+ const mapas = new Map();
419
+ const mapaDe = (p) => {
420
+ let m = mapas.get(p);
421
+ if (!m) {
422
+ const t = texto(p);
423
+ if (t === undefined)
424
+ falha('extracao.interna.trecho-sem-texto');
425
+ m = new MapaDoTexto(t, bytesDe.get(p).length);
426
+ mapas.set(p, m);
427
+ }
428
+ return m;
429
+ };
430
+ // D10: uma aresta por (tipo, origem, destino), com as evidencias ordenadas por posicao.
431
+ const arestas = new Map();
432
+ for (const a of achados.arestas) {
433
+ const kf = chaveDoNo(a.from), kt = chaveDoNo(a.to);
434
+ if (!nos.has(kf) || !nos.has(kt))
435
+ falha('extracao.interna.extremidade-ausente');
436
+ if (a.trecho.path !== a.from.path)
437
+ falha('extracao.interna.evidencia-fora-da-origem');
438
+ if (!(a.trecho.inicio < a.trecho.fim))
439
+ falha('extracao.interna.trecho-vazio');
440
+ const m = mapaDe(a.trecho.path), fonte = manifesto.get(a.trecho.path);
441
+ const e = {
442
+ snapshot_id: `snap-${zeros}`, path: fonte.path, source_hash: fonte.source_hash, source_version: fonte.source_version, authority,
443
+ extractor_id: a.extrator, extractor_version: versaoDe(a.extrator), extraction_method: a.metodo, confidence_class: intelligence_graph_contract_1.CLASSE_DE_CONFIANCA,
444
+ span: { type: 'text', byte_start: m.byte(a.trecho.inicio), byte_end: m.byte(a.trecho.fim), line_start: m.linha(a.trecho.inicio), line_end: m.linha(a.trecho.fim - 1) },
445
+ access,
446
+ };
447
+ const chave = `${a.kind}\u0000${kf}\u0000${kt}`;
448
+ let atual = arestas.get(chave);
449
+ if (!atual)
450
+ arestas.set(chave, (atual = { kind: a.kind, from: a.from, to: a.to, evidencias: new Map() }));
451
+ atual.evidencias.set((0, intelligence_graph_contract_1.canonico)(e), e);
452
+ }
453
+ if (arestas.size > intelligence_graph_contract_1.GRAFO_LIMITES.arestas)
454
+ falha('extracao.limite.arestas');
455
+ const idProvisorio = (r) => `node-${(0, intelligence_graph_contract_1.sha256DoCanonico)([r.kind, r.path, r.fragment])}`;
456
+ let excedentes = 0;
457
+ const edges = [...arestas.values()].map((a) => {
458
+ const evidencias = [...a.evidencias.values()].sort((x, y) => (x.span.byte_start - y.span.byte_start) || (x.span.byte_end - y.span.byte_end)
459
+ || (0, intelligence_graph_contract_1.compararUtf8)(x.extractor_id, y.extractor_id) || (0, intelligence_graph_contract_1.compararUtf8)(x.extraction_method, y.extraction_method));
460
+ excedentes += Math.max(0, evidencias.length - intelligence_graph_contract_1.GRAFO_LIMITES.evidenciasPorAresta);
461
+ return {
462
+ edge_id: `edge-${zeros}`, kind: a.kind, snapshot_id: `snap-${zeros}`, from: idProvisorio(a.from), to: idProvisorio(a.to),
463
+ evidence: evidencias.slice(0, intelligence_graph_contract_1.GRAFO_LIMITES.evidenciasPorAresta), access,
464
+ };
465
+ });
466
+ const diagnosticos = new Map();
467
+ for (const d of achados.diagnosticos) {
468
+ if (!manifesto.has(d.path))
469
+ falha('extracao.interna.diagnostico-sem-fonte');
470
+ const reference = d.reference === null ? null : textoCurto(d.reference);
471
+ const diag = { kind: d.kind, path: d.path, reference, extractor_id: d.extrator, extractor_version: versaoDe(d.extrator), access };
472
+ diagnosticos.set((0, intelligence_graph_contract_1.canonico)(diag), diag);
473
+ }
474
+ if (diagnosticos.size > intelligence_graph_contract_1.GRAFO_LIMITES.diagnosticos)
475
+ falha('extracao.limite.diagnosticos');
476
+ const config = {
477
+ schema: exports.CONFIG_SCHEMA, authority, acl_refs: acl, evidencias_por_aresta: intelligence_graph_contract_1.GRAFO_LIMITES.evidenciasPorAresta,
478
+ typescript: { extensoes: exports.EXTENSOES_TS, opcoes: intelligence_graph_extract_ts_1.OPCOES_TS_DESCRITAS },
479
+ markdown: {
480
+ extensoes: exports.EXTENSOES_MD, ancora: 'github-slug', artefato: intelligence_graph_extract_md_1.PADRAO_DE_ID.source, frontmatter: intelligence_graph_extract_md_1.CHAVES_DO_FRONTMATTER, sem_mencao: intelligence_graph_extract_md_1.TOKENS_SEM_MENCAO,
481
+ },
482
+ };
483
+ const rascunho = {
484
+ schema: intelligence_graph_contract_1.GRAFO_SCHEMA, tenant_id: entrada.tenant_id, repository_id: entrada.repository_id,
485
+ snapshot: {
486
+ snapshot_id: `snap-${zeros}`, revision: entrada.revision, revision_unavailable_reason: entrada.revision_unavailable_reason,
487
+ source_manifest: [...manifesto.values()], config_hash: (0, intelligence_graph_contract_1.sha256DoCanonico)(config), extractors: extratores, extractors_digest: zeros,
488
+ },
489
+ nodes: [...nos.values()].map((r) => ({
490
+ node_id: idProvisorio(r), kind: r.kind, snapshot_id: `snap-${zeros}`, locator: { path: r.path, fragment: r.fragment },
491
+ source_hash: manifesto.get(r.path).source_hash, access,
492
+ })),
493
+ edges,
494
+ diagnostics: [...diagnosticos.values()],
495
+ };
496
+ const grafo = (0, intelligence_graph_contract_1.validarGrafo)((0, intelligence_graph_contract_1.derivarIds)(rascunho));
497
+ const digest = (0, intelligence_graph_contract_1.sha256DoCanonico)(grafo);
498
+ const contagens = {
499
+ fontes: grafo.snapshot.source_manifest.length, nos: contagemVazia(intelligence_graph_contract_1.TIPOS_DE_NO), arestas: contagemVazia(intelligence_graph_contract_1.TIPOS_DE_ARESTA),
500
+ diagnosticos: contagemVazia(intelligence_graph_contract_1.TIPOS_DE_DIAGNOSTICO), evidencias: 0,
501
+ };
502
+ for (const n of grafo.nodes)
503
+ contagens.nos[n.kind]++;
504
+ for (const a of grafo.edges) {
505
+ contagens.arestas[a.kind]++;
506
+ contagens.evidencias += a.evidence.length;
507
+ }
508
+ for (const d of grafo.diagnostics)
509
+ contagens.diagnosticos[d.kind]++;
510
+ const porCategoria = new Map(), listadas = new Map();
511
+ for (const l of achados.lacunas) {
512
+ porCategoria.set(l.categoria, (porCategoria.get(l.categoria) ?? 0) + 1);
513
+ if (exports.LACUNAS_SO_CONTAGEM.has(l.categoria))
514
+ continue;
515
+ const linha = l.inicio === null || texto(l.path) === undefined ? null : mapaDe(l.path).linha(l.inicio);
516
+ const item = { categoria: l.categoria, path: l.path, linha, detalhe: l.detalhe };
517
+ listadas.set((0, intelligence_graph_contract_1.canonico)(item), item);
518
+ }
519
+ const relatorio = {
520
+ schema: exports.RELATORIO_SCHEMA, snapshot_id: grafo.snapshot.snapshot_id, graph_digest: digest, contagens, evidencias_excedentes: excedentes,
521
+ excluidas: [...new Map(excluidas.map((e) => [(0, intelligence_graph_contract_1.canonico)(e), e])).entries()].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a[0], b[0])).map(([, e]) => e),
522
+ lacunas_por_categoria: Object.fromEntries([...porCategoria.entries()].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a[0], b[0]))),
523
+ lacunas: [...listadas.entries()].sort((a, b) => (0, intelligence_graph_contract_1.compararUtf8)(a[0], b[0])).map(([, l]) => l),
524
+ };
525
+ const estruturaDe = new Map(estruturas.map((x) => [x.path, x]));
526
+ const unidades = {
527
+ schema: exports.UNIDADES_SCHEMA, snapshot_id: grafo.snapshot.snapshot_id, graph_digest: digest, globais_ts: globaisTs,
528
+ arquivos: grafo.snapshot.source_manifest.map((m) => ({
529
+ path: m.path, source_hash: m.source_hash, ts: unidadesTs.get(m.path) ?? null, md: estruturaDe.get(m.path) ?? null,
530
+ })),
531
+ };
532
+ let reaproveitamento = null;
533
+ if (plano) {
534
+ const parcial = motivoTs === null, afetados = [...plano.ts.afetados].sort(intelligence_graph_contract_1.compararUtf8);
535
+ reaproveitamento = {
536
+ mudanca: { alterados: plano.mudanca.alterados.length, novos: plano.mudanca.novos.length, removidos: plano.mudanca.removidos.length },
537
+ ts: {
538
+ modo: !parcial ? 'inteiro' : afetados.length ? 'parcial' : 'reaproveitado', motivo: motivoTs,
539
+ reextraidos: parcial ? afetados : fontesTs.map((f) => f.path), programa: parcial ? tsDaBase?.programa ?? 0 : fontesTs.length,
540
+ reaproveitados: parcial ? fontesTs.length - afetados.length : 0,
541
+ },
542
+ md: { reextraidos: fontesMd.filter((f) => !plano.md.has(f.path)).map((f) => f.path), reaproveitados: plano.md.size },
543
+ };
544
+ }
545
+ return { grafo, digest, relatorio, unidades, reaproveitamento };
546
+ }