@semacode/cli 2.3.0 → 2.3.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 (177) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +251 -228
  3. package/dist/agentEntryPoints.js +551 -550
  4. package/dist/angular-consumer-standalone.d.ts +3 -1
  5. package/dist/angular-consumer-standalone.js +12 -8
  6. package/dist/drift.part01.d.ts +32 -2
  7. package/dist/drift.part01.js +2 -0
  8. package/dist/drift.part04.d.ts +3 -2
  9. package/dist/drift.part04.js +6 -3
  10. package/dist/drift.part05.d.ts +2 -1
  11. package/dist/drift.part05.js +4 -3
  12. package/dist/drift.part06.d.ts +2 -1
  13. package/dist/drift.part06.js +9 -5
  14. package/dist/drift.part07.d.ts +11 -10
  15. package/dist/drift.part07.js +40 -30
  16. package/dist/drift.part08.d.ts +2 -1
  17. package/dist/drift.part08.js +4 -3
  18. package/dist/drift.part11.js +71 -6
  19. package/dist/drift.part12.js +14 -1
  20. package/dist/drift.part13.d.ts +42 -7
  21. package/dist/drift.part13.js +660 -36
  22. package/dist/driftCache.d.ts +49 -0
  23. package/dist/driftCache.js +311 -0
  24. package/dist/driftCacheIncremental.d.ts +98 -0
  25. package/dist/driftCacheIncremental.js +596 -0
  26. package/dist/driftCatalogo.d.ts +91 -0
  27. package/dist/driftCatalogo.js +657 -0
  28. package/dist/driftCatalogoPersistente.d.ts +8 -0
  29. package/dist/driftCatalogoPersistente.js +77 -0
  30. package/dist/driftEscopo.d.ts +23 -0
  31. package/dist/driftEscopo.js +563 -0
  32. package/dist/driftEscopoReferencias.d.ts +4 -0
  33. package/dist/driftEscopoReferencias.js +265 -0
  34. package/dist/driftOrcamento.d.ts +12 -0
  35. package/dist/driftOrcamento.js +19 -3
  36. package/dist/execucoesExternas.js +5 -19
  37. package/dist/iaPrompts.js +310 -310
  38. package/dist/index.part01.d.ts +16 -1
  39. package/dist/index.part01.js +80 -4
  40. package/dist/index.part02.js +21 -21
  41. package/dist/index.part03.d.ts +2 -2
  42. package/dist/index.part03.js +14 -3
  43. package/dist/index.part04.d.ts +2 -2
  44. package/dist/index.part04.js +113 -101
  45. package/dist/index.part05.d.ts +1 -1
  46. package/dist/index.part05.js +99 -22
  47. package/dist/index.part06.js +3 -2
  48. package/dist/index.part07.js +24 -24
  49. package/dist/index.part08.js +1 -1
  50. package/dist/init/templates.part01.js +393 -393
  51. package/dist/init/templates.part02.js +189 -189
  52. package/dist/initTemplatesBackend.js +73 -73
  53. package/dist/initTemplatesBase.js +81 -81
  54. package/dist/initTemplatesFlutter.js +137 -137
  55. package/dist/initTemplatesRuntime.js +350 -350
  56. package/dist/initTemplatesWeb.js +309 -309
  57. package/dist/pipelineConteudo/command.js +1 -36
  58. package/dist/projeto.d.ts +1 -1
  59. package/dist/projetoCarregar.d.ts +2 -2
  60. package/dist/projetoCarregar.js +47 -24
  61. package/dist/projetoCatalogo.d.ts +7 -0
  62. package/dist/projetoCatalogo.js +125 -0
  63. package/dist/projetoTipos.d.ts +14 -5
  64. package/dist/sync/index.js +35 -35
  65. package/docs/README.md +34 -34
  66. package/docs/ai-integration.md +1 -7
  67. package/docs/ai-onboarding.md +62 -62
  68. package/docs/ai-workflow.md +4 -0
  69. package/docs/auth.md +26 -26
  70. package/docs/cli.md +79 -79
  71. package/docs/commands.md +16 -13
  72. package/docs/database.md +15 -15
  73. package/docs/deploy.md +41 -41
  74. package/docs/descoberta-capacidades.md +106 -106
  75. package/docs/documentation.md +37 -46
  76. package/docs/env.md +16 -16
  77. package/docs/frontend.md +41 -41
  78. package/docs/getting-started.md +57 -57
  79. package/docs/i18n.md +15 -15
  80. package/docs/pipeline-conteudo.md +246 -246
  81. package/docs/profiles.md +54 -54
  82. package/docs/repositories.md +43 -43
  83. package/docs/rollback.md +31 -31
  84. package/docs/security.md +32 -32
  85. package/docs/sistemas-interativos.md +373 -378
  86. package/docs/support.md +8 -8
  87. package/docs/testing.md +51 -44
  88. package/docs/vocabulary.md +29 -29
  89. package/exemplos/agendamento.sema +1 -1
  90. package/exemplos/assinatura.sema +1 -1
  91. package/exemplos/auditoria.sema +1 -1
  92. package/exemplos/autenticacao.sema +1 -1
  93. package/exemplos/author_obra_comum.sema +1 -1
  94. package/exemplos/author_tema_sensivel.sema +1 -1
  95. package/exemplos/automacao.sema +1 -1
  96. package/exemplos/cadastro_usuario.sema +1 -1
  97. package/exemplos/calculadora.sema +1 -1
  98. package/exemplos/crud_simples.sema +1 -1
  99. package/exemplos/estoque.sema +1 -1
  100. package/exemplos/exportacao.sema +1 -1
  101. package/exemplos/fila.sema +1 -1
  102. package/exemplos/integracao_externa.sema +1 -1
  103. package/exemplos/multi_tenant.sema +1 -1
  104. package/exemplos/notificacao.sema +1 -1
  105. package/exemplos/operacao_estrategia.sema +132 -132
  106. package/exemplos/operacao_estrategia_discovery.sema +220 -220
  107. package/exemplos/operacao_estrategia_fluxo.sema +114 -114
  108. package/exemplos/operacao_estrategia_gates.sema +106 -106
  109. package/exemplos/operacao_estrategia_quarentena.sema +133 -133
  110. package/exemplos/operacao_estrategia_rollout.sema +124 -124
  111. package/exemplos/pagamento.sema +1 -1
  112. package/exemplos/pagamento_dominio.sema +1 -1
  113. package/exemplos/pedido.sema +1 -1
  114. package/exemplos/permissao.sema +1 -1
  115. package/exemplos/persistencia_vendor_first.sema +1 -1
  116. package/exemplos/pipeline-conteudo/README.md +44 -44
  117. package/exemplos/pipeline-conteudo/alvos.json +23 -23
  118. package/exemplos/pipeline-conteudo/definicao.json +136 -136
  119. package/exemplos/profile_conversas.sema +165 -165
  120. package/exemplos/profile_game.sema +1 -1
  121. package/exemplos/profile_legal.sema +1 -1
  122. package/exemplos/profile_ops.sema +1 -1
  123. package/exemplos/profile_research.sema +1 -1
  124. package/exemplos/profile_simulation.sema +211 -211
  125. package/exemplos/profile_software.sema +1 -1
  126. package/exemplos/profile_workflow_n8n.sema +1 -1
  127. package/exemplos/relatorio.sema +1 -1
  128. package/exemplos/replica_analitica_erp.sema +1 -1
  129. package/exemplos/sistemas-interativos/README.md +100 -100
  130. package/exemplos/sistemas-interativos/advanced/acceptance-context-evaluate-valid.json +5 -5
  131. package/exemplos/sistemas-interativos/advanced/acceptance-lock-valid.json +16 -16
  132. package/exemplos/sistemas-interativos/advanced/asset-provenance-valid.json +32 -32
  133. package/exemplos/sistemas-interativos/advanced/autonomy-repair-valid.json +93 -93
  134. package/exemplos/sistemas-interativos/advanced/control-run-definition-valid.json +78 -78
  135. package/exemplos/sistemas-interativos/advanced/control-run-valid.json +27 -27
  136. package/exemplos/sistemas-interativos/advanced/distributed-workers-valid.json +79 -79
  137. package/exemplos/sistemas-interativos/advanced/editor-state-valid.json +42 -42
  138. package/exemplos/sistemas-interativos/advanced/engine-snapshot-after-valid.json +32 -32
  139. package/exemplos/sistemas-interativos/advanced/engine-snapshot-before-valid.json +23 -23
  140. package/exemplos/sistemas-interativos/advanced/job-orchestration-valid.json +39 -39
  141. package/exemplos/sistemas-interativos/advanced/multimodal-evidence-valid.json +46 -46
  142. package/exemplos/sistemas-interativos/advanced/multiplayer-authority-valid.json +39 -39
  143. package/exemplos/sistemas-interativos/advanced/playtest-fuzz-valid.json +37 -37
  144. package/exemplos/sistemas-interativos/advanced/portability-valid.json +104 -104
  145. package/exemplos/sistemas-interativos/advanced/temporal-evidence-valid.json +27 -27
  146. package/exemplos/sistemas-interativos/advanced/temporal-valid.json +118 -118
  147. package/exemplos/sistemas-interativos/experience-ir-valid.json +459 -459
  148. package/exemplos/sistemas-interativos/game-2d.json +83 -83
  149. package/exemplos/sistemas-interativos/game-3d-human.json +81 -81
  150. package/exemplos/sistemas-interativos/game-pixel-16-bit.json +97 -97
  151. package/exemplos/sistemas-interativos/game-pixel-8-bit.json +94 -94
  152. package/exemplos/sistemas-interativos/game-xr-human.json +80 -80
  153. package/exemplos/sistemas-interativos/hybrid-2-5d.json +108 -108
  154. package/exemplos/sistemas-interativos/protocol-mutating-rollback-valid.json +75 -75
  155. package/exemplos/sistemas-interativos/protocol-read-only-valid.json +58 -58
  156. package/exemplos/sistemas-interativos/simulation-2d-controlled.json +97 -97
  157. package/exemplos/sistemas-interativos/simulation-3d-calibrated-autonomous.json +141 -141
  158. package/exemplos/sistemas-interativos/simulation-headless-autonomous-batch.json +112 -112
  159. package/exemplos/sistemas-interativos/simulation-pixel-16-bit.json +103 -103
  160. package/exemplos/sistemas-interativos/simulation-text-controlled.json +95 -95
  161. package/exemplos/testes_embutidos.sema +1 -1
  162. package/exemplos/tratamento_erro.sema +1 -1
  163. package/exemplos/upload_arquivo.sema +1 -1
  164. package/exemplos/webhook.sema +1 -1
  165. package/node_modules/@sema/gerador-cpp/dist/index.js +176 -176
  166. package/node_modules/@sema/gerador-cpp/package.json +1 -1
  167. package/node_modules/@sema/gerador-css/dist/index.part01.js +10 -10
  168. package/node_modules/@sema/gerador-css/dist/index.part02.js +460 -460
  169. package/node_modules/@sema/gerador-dotnet/dist/index.js +169 -169
  170. package/node_modules/@sema/gerador-dotnet/package.json +1 -1
  171. package/node_modules/@sema/gerador-html/dist/index.js +17 -17
  172. package/node_modules/@sema/gerador-lua/dist/index.js +51 -51
  173. package/node_modules/@sema/gerador-php/dist/index.js +113 -113
  174. package/node_modules/@sema/gerador-python/dist/index.part02.js +3 -3
  175. package/node_modules/@sema/gerador-typescript/dist/index.part02.js +11 -11
  176. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +42 -42
  177. package/package.json +3 -3
@@ -0,0 +1,596 @@
1
+ // SEMA-GOVERNED: sema.produto.governanca_ia.drift
2
+ // Descricao: cache persistente incremental por arquivo e por grupo semantico, com validacao runtime e fast path por metadados.
3
+ import { createHash } from "node:crypto";
4
+ import { lstat, readFile, realpath } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { digestJsonCanonicoCacheDrift, serializarJsonCanonicoCacheDrift, } from "./driftCache.js";
7
+ import { escreverArquivoWorkspaceSeguro, validarDestinosEscritaWorkspace, } from "./workspaceWrite.js";
8
+ export const FILE_INDEX_SCHEMA = 2;
9
+ export const SCHEMA_MANIFESTO_ARQUIVOS_DRIFT = "sema.drift-file-cache/v2";
10
+ export const SCHEMA_GRUPO_INDICE_DRIFT = "sema.drift-index-group-cache/v2";
11
+ export const DIRETORIO_CACHE_INCREMENTAL_DRIFT = path.join(".tmp", "sema-cache", "drift-index", "v2");
12
+ export const DIRETORIO_IDENTIDADES_CACHE_INCREMENTAL_DRIFT = path.join(DIRETORIO_CACHE_INCREMENTAL_DRIFT, "identities");
13
+ const LIMITE_BYTES_CACHE = 64 * 1024 * 1024;
14
+ const PADRAO_DIGEST = /^sha256:[a-f0-9]{64}$/u;
15
+ function sufixoSeguroIdentidade(identidadeDigest) {
16
+ if (!PADRAO_DIGEST.test(identidadeDigest)) {
17
+ throw new TypeError(`identidade_digest_cache_drift_invalida:${identidadeDigest}`);
18
+ }
19
+ return identidadeDigest.slice("sha256:".length);
20
+ }
21
+ export function caminhoManifestoArquivosDrift(identidadeDigest) {
22
+ return path.join(DIRETORIO_IDENTIDADES_CACHE_INCREMENTAL_DRIFT, sufixoSeguroIdentidade(identidadeDigest), "files.json");
23
+ }
24
+ export function caminhoManifestoGruposDrift(identidadeDigest) {
25
+ return path.join(DIRETORIO_IDENTIDADES_CACHE_INCREMENTAL_DRIFT, sufixoSeguroIdentidade(identidadeDigest), "groups.json");
26
+ }
27
+ function registroObjeto(valor) {
28
+ return typeof valor === "object" && valor !== null && !Array.isArray(valor);
29
+ }
30
+ function emitirEvento(observador, evento) {
31
+ try {
32
+ observador?.(evento);
33
+ }
34
+ catch {
35
+ // Observabilidade nao altera o resultado funcional do drift.
36
+ }
37
+ }
38
+ function paraJson(valor) {
39
+ return JSON.parse(JSON.stringify(valor));
40
+ }
41
+ function assinaturasIguais(a, b) {
42
+ return a.size === b.size
43
+ && a.mtimeNs === b.mtimeNs
44
+ && a.ctimeNs === b.ctimeNs
45
+ && a.dev === b.dev
46
+ && a.ino === b.ino;
47
+ }
48
+ function assinaturaValida(valor) {
49
+ if (!registroObjeto(valor)) {
50
+ return false;
51
+ }
52
+ return ["size", "mtimeNs", "ctimeNs", "dev", "ino"]
53
+ .every((campo) => typeof valor[campo] === "string" && /^\d+$/u.test(valor[campo]));
54
+ }
55
+ function caminhoRelativoSeguro(baseProjeto, arquivo) {
56
+ const relativo = path.relative(baseProjeto, path.resolve(arquivo)).replace(/\\/g, "/");
57
+ if (!relativo || relativo === "." || relativo === ".." || relativo.startsWith("../") || path.isAbsolute(relativo)) {
58
+ throw new Error(`arquivo_cache_drift_fora_workspace:${arquivo}`);
59
+ }
60
+ return relativo;
61
+ }
62
+ function caminhoRelativoValido(caminho) {
63
+ return typeof caminho === "string"
64
+ && caminho.length > 0
65
+ && caminho !== "."
66
+ && caminho !== ".."
67
+ && !caminho.startsWith("../")
68
+ && !caminho.includes("\\")
69
+ && !path.posix.isAbsolute(caminho);
70
+ }
71
+ function chaveEstavel(valor) {
72
+ return createHash("sha256")
73
+ .update(serializarJsonCanonicoCacheDrift(valor))
74
+ .digest("hex");
75
+ }
76
+ function analiseValida(valor) {
77
+ return registroObjeto(valor)
78
+ && typeof valor.payloadDigest === "string"
79
+ && PADRAO_DIGEST.test(valor.payloadDigest)
80
+ && digestJsonCanonicoCacheDrift(valor.payload) === valor.payloadDigest;
81
+ }
82
+ function entradaArquivoValida(chave, valor) {
83
+ if (!registroObjeto(valor)
84
+ || valor.caminho !== chave
85
+ || !caminhoRelativoValido(valor.caminho)
86
+ || !assinaturaValida(valor.assinatura)
87
+ || typeof valor.contentHash !== "string"
88
+ || !PADRAO_DIGEST.test(valor.contentHash)
89
+ || !registroObjeto(valor.analises)) {
90
+ return false;
91
+ }
92
+ return Object.values(valor.analises).every(analiseValida);
93
+ }
94
+ function manifestoValido(valor, identidadeDigest) {
95
+ if (!registroObjeto(valor)
96
+ || valor.identidadeDigest !== identidadeDigest
97
+ || !registroObjeto(valor.arquivos)) {
98
+ return false;
99
+ }
100
+ return Object.entries(valor.arquivos).every(([chave, entrada]) => entradaArquivoValida(chave, entrada));
101
+ }
102
+ function membrosGrupoValidos(valor) {
103
+ return Array.isArray(valor)
104
+ && valor.every((item) => registroObjeto(item)
105
+ && caminhoRelativoValido(item.caminho)
106
+ && typeof item.contentHash === "string"
107
+ && PADRAO_DIGEST.test(item.contentHash));
108
+ }
109
+ function membrosIguais(a, b) {
110
+ return a.length === b.length
111
+ && a.every((item, indice) => (item.caminho === b[indice]?.caminho
112
+ && item.contentHash === b[indice]?.contentHash));
113
+ }
114
+ function entradaGrupoValida(valor, identidadeDigest) {
115
+ return registroObjeto(valor)
116
+ && valor.identidadeDigest === identidadeDigest
117
+ && membrosGrupoValidos(valor.membros)
118
+ && typeof valor.resumoDigest === "string"
119
+ && PADRAO_DIGEST.test(valor.resumoDigest)
120
+ && digestJsonCanonicoCacheDrift(valor.resumo) === valor.resumoDigest;
121
+ }
122
+ function manifestoGruposValido(valor, identidadeDigest) {
123
+ return registroObjeto(valor)
124
+ && valor.identidadeDigest === identidadeDigest
125
+ && registroObjeto(valor.grupos)
126
+ && Object.entries(valor.grupos).every(([chave, entrada]) => (/^[a-f0-9]{64}$/u.test(chave)
127
+ && entradaGrupoValida(entrada, identidadeDigest)));
128
+ }
129
+ function erroEhAusencia(erro) {
130
+ return ["ENOENT", "ENOTDIR"].includes(erro.code ?? "");
131
+ }
132
+ async function lerEnvelope(baseProjeto, caminhoRelativo, schema, key) {
133
+ try {
134
+ const [destino] = await validarDestinosEscritaWorkspace(baseProjeto, [caminhoRelativo]);
135
+ if (!destino.existe) {
136
+ return { estado: "miss", motivo: "arquivo_ausente" };
137
+ }
138
+ const info = await lstat(destino.caminhoAbsoluto);
139
+ if (!info.isFile() || info.isSymbolicLink() || info.size > LIMITE_BYTES_CACHE) {
140
+ return { estado: "corrupt", motivo: "arquivo_cache_invalido" };
141
+ }
142
+ const bytes = await readFile(destino.caminhoAbsoluto);
143
+ if (bytes.byteLength > LIMITE_BYTES_CACHE) {
144
+ return { estado: "corrupt", motivo: "limite_bytes_excedido" };
145
+ }
146
+ let bruto;
147
+ try {
148
+ bruto = JSON.parse(bytes.toString("utf8"));
149
+ }
150
+ catch {
151
+ return { estado: "corrupt", motivo: "json_invalido" };
152
+ }
153
+ if (!registroObjeto(bruto)
154
+ || bruto.schema !== schema
155
+ || bruto.key !== key
156
+ || typeof bruto.payloadDigest !== "string"
157
+ || !PADRAO_DIGEST.test(bruto.payloadDigest)) {
158
+ return { estado: "corrupt", motivo: "envelope_invalido" };
159
+ }
160
+ let digest;
161
+ try {
162
+ digest = digestJsonCanonicoCacheDrift(bruto.payload);
163
+ }
164
+ catch {
165
+ return { estado: "corrupt", motivo: "payload_nao_canonico" };
166
+ }
167
+ if (digest !== bruto.payloadDigest) {
168
+ return { estado: "corrupt", motivo: "payload_digest_divergente" };
169
+ }
170
+ return { estado: "hit", payload: bruto.payload };
171
+ }
172
+ catch (erro) {
173
+ return {
174
+ estado: "miss",
175
+ motivo: erroEhAusencia(erro) ? "arquivo_ausente" : "cache_indisponivel",
176
+ };
177
+ }
178
+ }
179
+ async function escreverEnvelope(baseProjeto, caminhoRelativo, schema, key, payload) {
180
+ const envelope = {
181
+ schema,
182
+ key,
183
+ payload,
184
+ payloadDigest: digestJsonCanonicoCacheDrift(payload),
185
+ };
186
+ const conteudo = JSON.stringify(envelope);
187
+ if (Buffer.byteLength(conteudo, "utf8") > LIMITE_BYTES_CACHE) {
188
+ throw new Error("limite_bytes_cache_incremental_excedido");
189
+ }
190
+ await escreverArquivoWorkspaceSeguro(baseProjeto, caminhoRelativo, conteudo, { sobrescrever: true });
191
+ }
192
+ export async function obterAssinaturaArquivoDrift(arquivo) {
193
+ const info = await lstat(arquivo, { bigint: true });
194
+ if (!info.isFile() || info.isSymbolicLink()) {
195
+ throw new Error(`arquivo_cache_drift_nao_regular:${arquivo}`);
196
+ }
197
+ return {
198
+ size: info.size.toString(),
199
+ mtimeNs: info.mtimeNs.toString(),
200
+ ctimeNs: info.ctimeNs.toString(),
201
+ dev: info.dev.toString(),
202
+ ino: info.ino.toString(),
203
+ };
204
+ }
205
+ export class CacheIncrementalDrift {
206
+ identidadeDigest;
207
+ politica;
208
+ baseProjeto;
209
+ baseProjetoReal;
210
+ observador;
211
+ caminhoManifestoArquivos;
212
+ caminhoManifestoGrupos;
213
+ manifesto;
214
+ manifestoEmVoo;
215
+ manifestoSujo = false;
216
+ arquivosSujos = new Set();
217
+ manifestoGrupos;
218
+ manifestoGruposEmVoo;
219
+ manifestoGruposSujo = false;
220
+ gruposSujos = new Set();
221
+ arquivosEmVoo = new Map();
222
+ metricasAtuais = {
223
+ metadataHits: 0,
224
+ contentHits: 0,
225
+ fileMisses: 0,
226
+ groupHits: 0,
227
+ groupMisses: 0,
228
+ corruptos: 0,
229
+ extracoesArquivo: 0,
230
+ extracoesGrupo: 0,
231
+ gravacoes: 0,
232
+ errosGravacao: 0,
233
+ };
234
+ constructor(opcoes) {
235
+ this.baseProjeto = path.resolve(opcoes.baseProjeto);
236
+ this.baseProjetoReal = realpath(this.baseProjeto);
237
+ this.politica = opcoes.politica;
238
+ this.identidadeDigest = digestJsonCanonicoCacheDrift(opcoes.identidade);
239
+ this.caminhoManifestoArquivos = caminhoManifestoArquivosDrift(this.identidadeDigest);
240
+ this.caminhoManifestoGrupos = caminhoManifestoGruposDrift(this.identidadeDigest);
241
+ this.observador = opcoes.observador;
242
+ }
243
+ metricas() {
244
+ return { ...this.metricasAtuais };
245
+ }
246
+ async resolverArquivo(opcoes) {
247
+ const chaveExecucao = `${process.platform === "win32" ? path.resolve(opcoes.arquivo).toLowerCase() : path.resolve(opcoes.arquivo)}\0${opcoes.analise}`;
248
+ const existenteEmVoo = this.arquivosEmVoo.get(chaveExecucao);
249
+ if (existenteEmVoo) {
250
+ return existenteEmVoo;
251
+ }
252
+ const execucao = this.resolverArquivoInterno(opcoes);
253
+ this.arquivosEmVoo.set(chaveExecucao, execucao);
254
+ void execucao.catch(() => {
255
+ if (this.arquivosEmVoo.get(chaveExecucao) === execucao) {
256
+ this.arquivosEmVoo.delete(chaveExecucao);
257
+ }
258
+ });
259
+ return execucao;
260
+ }
261
+ async resolverArquivoInterno(opcoes) {
262
+ await this.validarArquivoNoWorkspace(opcoes.arquivo);
263
+ const caminho = caminhoRelativoSeguro(this.baseProjeto, opcoes.arquivo);
264
+ const assinar = opcoes.assinar ?? (() => obterAssinaturaArquivoDrift(opcoes.arquivo));
265
+ const assinaturaAntes = await assinar();
266
+ const manifesto = await this.obterManifesto();
267
+ const existente = manifesto.arquivos[caminho];
268
+ const analiseExistente = existente?.analises[opcoes.analise];
269
+ const payloadExistente = analiseExistente?.payload;
270
+ const payloadValido = analiseExistente !== undefined && opcoes.validar(payloadExistente);
271
+ if (analiseExistente && !payloadValido) {
272
+ this.registrarCorrupto(opcoes.arquivo, "payload_schema_invalido");
273
+ }
274
+ if (this.politica === "auto"
275
+ && existente
276
+ && payloadValido
277
+ && assinaturasIguais(existente.assinatura, assinaturaAntes)) {
278
+ this.metricasAtuais.metadataHits += 1;
279
+ emitirEvento(this.observador, {
280
+ tipo: "cache.hit",
281
+ caminho: path.resolve(opcoes.arquivo),
282
+ motivo: "metadata_hit",
283
+ });
284
+ return {
285
+ caminho,
286
+ contentHash: existente.contentHash,
287
+ valor: payloadExistente,
288
+ origem: "metadata_hit",
289
+ };
290
+ }
291
+ this.metricasAtuais.fileMisses += 1;
292
+ emitirEvento(this.observador, {
293
+ tipo: "cache.miss",
294
+ caminho: path.resolve(opcoes.arquivo),
295
+ motivo: this.politica === "refresh" ? "politica_refresh" : this.politica === "off" ? "politica_off" : "metadata_miss",
296
+ });
297
+ const conteudo = await opcoes.ler();
298
+ if (this.politica === "auto"
299
+ && existente
300
+ && payloadValido
301
+ && existente.contentHash === conteudo.digest) {
302
+ const assinaturaDepois = await assinar();
303
+ if (assinaturasIguais(assinaturaAntes, assinaturaDepois)) {
304
+ existente.assinatura = assinaturaDepois;
305
+ this.manifestoSujo = true;
306
+ this.arquivosSujos.add(caminho);
307
+ }
308
+ this.metricasAtuais.contentHits += 1;
309
+ emitirEvento(this.observador, {
310
+ tipo: "cache.hit",
311
+ caminho: path.resolve(opcoes.arquivo),
312
+ motivo: "content_hit",
313
+ });
314
+ return {
315
+ caminho,
316
+ contentHash: conteudo.digest,
317
+ valor: payloadExistente,
318
+ origem: "content_hit",
319
+ };
320
+ }
321
+ this.metricasAtuais.extracoesArquivo += 1;
322
+ emitirEvento(this.observador, {
323
+ tipo: "extractor.run",
324
+ caminho: path.resolve(opcoes.arquivo),
325
+ motivo: `arquivo:${opcoes.analise}`,
326
+ });
327
+ const valor = paraJson(await opcoes.extrair(conteudo));
328
+ if (!opcoes.validar(valor)) {
329
+ throw new Error(`extrator_cache_drift_payload_invalido:${opcoes.analise}:${caminho}`);
330
+ }
331
+ if (this.politica !== "off") {
332
+ const assinaturaDepois = await assinar();
333
+ if (assinaturasIguais(assinaturaAntes, assinaturaDepois)) {
334
+ const analises = existente?.contentHash === conteudo.digest
335
+ ? { ...existente.analises }
336
+ : {};
337
+ analises[opcoes.analise] = {
338
+ payload: valor,
339
+ payloadDigest: digestJsonCanonicoCacheDrift(valor),
340
+ };
341
+ manifesto.arquivos[caminho] = {
342
+ caminho,
343
+ assinatura: assinaturaDepois,
344
+ contentHash: conteudo.digest,
345
+ analises,
346
+ };
347
+ this.manifestoSujo = true;
348
+ this.arquivosSujos.add(caminho);
349
+ }
350
+ }
351
+ return {
352
+ caminho,
353
+ contentHash: conteudo.digest,
354
+ valor,
355
+ origem: "calculado",
356
+ };
357
+ }
358
+ async resolverGrupo(opcoes) {
359
+ const membros = opcoes.membros
360
+ .map((membro) => ({
361
+ caminho: caminhoRelativoSeguro(this.baseProjeto, membro.caminho),
362
+ contentHash: membro.contentHash,
363
+ }))
364
+ .sort((a, b) => a.caminho.localeCompare(b.caminho, "en"));
365
+ // A chave e ancorada no primeiro arquivo, nao no conteudo nem na composicao
366
+ // atual do grupo. Mudancas sobrescrevem a mesma entrada e evitam crescimento
367
+ // infinito do cache; a lista completa de membros continua validada no envelope.
368
+ const chave = chaveEstavel({ ancora: membros[0]?.caminho ?? "grupo-vazio" });
369
+ const caminhoRelativo = this.caminhoManifestoGrupos;
370
+ if (this.politica === "auto") {
371
+ const manifesto = await this.obterManifestoGrupos();
372
+ const payload = manifesto.grupos[chave];
373
+ if (payload) {
374
+ const identidadeAtual = payload.identidadeDigest === this.identidadeDigest;
375
+ const membrosAtuais = membrosIguais(payload.membros, membros);
376
+ if (identidadeAtual && membrosAtuais) {
377
+ if (opcoes.validar(payload.resumo)) {
378
+ this.metricasAtuais.groupHits += 1;
379
+ emitirEvento(this.observador, {
380
+ tipo: "cache.hit",
381
+ chave,
382
+ caminho: path.resolve(this.baseProjeto, caminhoRelativo),
383
+ motivo: "group_content_hit",
384
+ });
385
+ return { chave, valor: payload.resumo, origem: "cache" };
386
+ }
387
+ this.registrarCorrupto(path.resolve(this.baseProjeto, caminhoRelativo), "payload_schema_invalido");
388
+ }
389
+ }
390
+ }
391
+ this.metricasAtuais.groupMisses += 1;
392
+ emitirEvento(this.observador, {
393
+ tipo: "cache.miss",
394
+ chave,
395
+ caminho: path.resolve(this.baseProjeto, caminhoRelativo),
396
+ motivo: this.politica === "refresh" ? "politica_refresh" : this.politica === "off" ? "politica_off" : "group_miss",
397
+ });
398
+ this.metricasAtuais.extracoesGrupo += 1;
399
+ emitirEvento(this.observador, {
400
+ tipo: "extractor.run",
401
+ chave,
402
+ caminho: opcoes.membros[0]?.caminho,
403
+ motivo: `grupo:${membros.length}`,
404
+ });
405
+ const valor = paraJson(await opcoes.calcular());
406
+ if (!opcoes.validar(valor)) {
407
+ throw new Error(`extrator_grupo_cache_drift_payload_invalido:${chave}`);
408
+ }
409
+ if (this.politica !== "off") {
410
+ const payload = {
411
+ identidadeDigest: this.identidadeDigest,
412
+ membros,
413
+ resumo: valor,
414
+ resumoDigest: digestJsonCanonicoCacheDrift(valor),
415
+ };
416
+ const manifesto = await this.obterManifestoGrupos();
417
+ manifesto.grupos[chave] = payload;
418
+ this.manifestoGruposSujo = true;
419
+ this.gruposSujos.add(chave);
420
+ }
421
+ return { chave, valor, origem: "calculado" };
422
+ }
423
+ async finalizar() {
424
+ if (this.politica === "off") {
425
+ return;
426
+ }
427
+ if (this.manifestoSujo && this.manifesto) {
428
+ try {
429
+ this.manifesto = await this.gravarManifestoArquivosComMerge(this.manifesto);
430
+ this.metricasAtuais.gravacoes += 1;
431
+ this.manifestoSujo = false;
432
+ this.arquivosSujos.clear();
433
+ }
434
+ catch {
435
+ this.metricasAtuais.errosGravacao += 1;
436
+ }
437
+ }
438
+ if (this.manifestoGruposSujo && this.manifestoGrupos) {
439
+ try {
440
+ this.manifestoGrupos = await this.gravarManifestoGruposComMerge(this.manifestoGrupos);
441
+ this.metricasAtuais.gravacoes += 1;
442
+ this.manifestoGruposSujo = false;
443
+ this.gruposSujos.clear();
444
+ }
445
+ catch {
446
+ this.metricasAtuais.errosGravacao += 1;
447
+ }
448
+ }
449
+ }
450
+ chaveEnvelope(tipo) {
451
+ return `${tipo}:${this.identidadeDigest}`;
452
+ }
453
+ async lerManifestoArquivosAtual() {
454
+ const leitura = await lerEnvelope(this.baseProjeto, this.caminhoManifestoArquivos, SCHEMA_MANIFESTO_ARQUIVOS_DRIFT, this.chaveEnvelope("files"));
455
+ return leitura.estado === "hit" && manifestoValido(leitura.payload, this.identidadeDigest)
456
+ ? leitura.payload
457
+ : undefined;
458
+ }
459
+ async lerManifestoGruposAtual() {
460
+ const leitura = await lerEnvelope(this.baseProjeto, this.caminhoManifestoGrupos, SCHEMA_GRUPO_INDICE_DRIFT, this.chaveEnvelope("groups"));
461
+ return leitura.estado === "hit" && manifestoGruposValido(leitura.payload, this.identidadeDigest)
462
+ ? leitura.payload
463
+ : undefined;
464
+ }
465
+ async gravarManifestoArquivosComMerge(local) {
466
+ let ultimoErro;
467
+ for (let tentativa = 0; tentativa < 2; tentativa += 1) {
468
+ const publicado = await this.lerManifestoArquivosAtual();
469
+ const mesclado = {
470
+ identidadeDigest: this.identidadeDigest,
471
+ arquivos: publicado ? { ...publicado.arquivos } : {},
472
+ };
473
+ for (const caminho of this.arquivosSujos) {
474
+ const entrada = local.arquivos[caminho];
475
+ if (entrada) {
476
+ mesclado.arquivos[caminho] = entrada;
477
+ }
478
+ }
479
+ try {
480
+ await escreverEnvelope(this.baseProjeto, this.caminhoManifestoArquivos, SCHEMA_MANIFESTO_ARQUIVOS_DRIFT, this.chaveEnvelope("files"), mesclado);
481
+ return mesclado;
482
+ }
483
+ catch (erro) {
484
+ ultimoErro = erro;
485
+ }
486
+ }
487
+ throw ultimoErro;
488
+ }
489
+ async gravarManifestoGruposComMerge(local) {
490
+ let ultimoErro;
491
+ for (let tentativa = 0; tentativa < 2; tentativa += 1) {
492
+ const publicado = await this.lerManifestoGruposAtual();
493
+ const mesclado = {
494
+ identidadeDigest: this.identidadeDigest,
495
+ grupos: publicado ? { ...publicado.grupos } : {},
496
+ };
497
+ for (const chave of this.gruposSujos) {
498
+ const entrada = local.grupos[chave];
499
+ if (entrada) {
500
+ mesclado.grupos[chave] = entrada;
501
+ }
502
+ }
503
+ try {
504
+ await escreverEnvelope(this.baseProjeto, this.caminhoManifestoGrupos, SCHEMA_GRUPO_INDICE_DRIFT, this.chaveEnvelope("groups"), mesclado);
505
+ return mesclado;
506
+ }
507
+ catch (erro) {
508
+ ultimoErro = erro;
509
+ }
510
+ }
511
+ throw ultimoErro;
512
+ }
513
+ async obterManifesto() {
514
+ if (this.manifesto) {
515
+ return this.manifesto;
516
+ }
517
+ if (this.manifestoEmVoo) {
518
+ return this.manifestoEmVoo;
519
+ }
520
+ this.manifestoEmVoo = this.carregarManifesto();
521
+ try {
522
+ return await this.manifestoEmVoo;
523
+ }
524
+ finally {
525
+ this.manifestoEmVoo = undefined;
526
+ }
527
+ }
528
+ async carregarManifesto() {
529
+ if (this.politica === "auto") {
530
+ const leitura = await lerEnvelope(this.baseProjeto, this.caminhoManifestoArquivos, SCHEMA_MANIFESTO_ARQUIVOS_DRIFT, this.chaveEnvelope("files"));
531
+ if (leitura.estado === "hit" && manifestoValido(leitura.payload, this.identidadeDigest)) {
532
+ this.manifesto = leitura.payload;
533
+ return this.manifesto;
534
+ }
535
+ if (leitura.estado === "corrupt" || leitura.estado === "hit") {
536
+ this.registrarCorrupto(path.resolve(this.baseProjeto, this.caminhoManifestoArquivos), leitura.estado === "hit" ? "payload_schema_invalido" : leitura.motivo);
537
+ }
538
+ }
539
+ this.manifesto = {
540
+ identidadeDigest: this.identidadeDigest,
541
+ arquivos: {},
542
+ };
543
+ return this.manifesto;
544
+ }
545
+ async obterManifestoGrupos() {
546
+ if (this.manifestoGrupos) {
547
+ return this.manifestoGrupos;
548
+ }
549
+ if (this.manifestoGruposEmVoo) {
550
+ return this.manifestoGruposEmVoo;
551
+ }
552
+ this.manifestoGruposEmVoo = this.carregarManifestoGrupos();
553
+ try {
554
+ return await this.manifestoGruposEmVoo;
555
+ }
556
+ finally {
557
+ this.manifestoGruposEmVoo = undefined;
558
+ }
559
+ }
560
+ async carregarManifestoGrupos() {
561
+ if (this.politica === "auto") {
562
+ const leitura = await lerEnvelope(this.baseProjeto, this.caminhoManifestoGrupos, SCHEMA_GRUPO_INDICE_DRIFT, this.chaveEnvelope("groups"));
563
+ if (leitura.estado === "hit" && manifestoGruposValido(leitura.payload, this.identidadeDigest)) {
564
+ this.manifestoGrupos = leitura.payload;
565
+ return this.manifestoGrupos;
566
+ }
567
+ if (leitura.estado === "corrupt" || leitura.estado === "hit") {
568
+ this.registrarCorrupto(path.resolve(this.baseProjeto, this.caminhoManifestoGrupos), leitura.estado === "hit" ? "payload_schema_invalido" : leitura.motivo);
569
+ }
570
+ }
571
+ this.manifestoGrupos = {
572
+ identidadeDigest: this.identidadeDigest,
573
+ grupos: {},
574
+ };
575
+ return this.manifestoGrupos;
576
+ }
577
+ registrarCorrupto(caminho, motivo) {
578
+ this.metricasAtuais.corruptos += 1;
579
+ emitirEvento(this.observador, {
580
+ tipo: "cache.corrupt",
581
+ caminho,
582
+ motivo,
583
+ });
584
+ }
585
+ async validarArquivoNoWorkspace(arquivo) {
586
+ const [baseReal, arquivoReal] = await Promise.all([
587
+ this.baseProjetoReal,
588
+ realpath(arquivo),
589
+ ]);
590
+ const relativo = path.relative(baseReal, arquivoReal);
591
+ if (relativo === ".." || relativo.startsWith(`..${path.sep}`) || path.isAbsolute(relativo)) {
592
+ throw new Error(`arquivo_cache_drift_fora_workspace_real:${arquivo}`);
593
+ }
594
+ }
595
+ }
596
+ //# sourceMappingURL=driftCacheIncremental.js.map
@@ -0,0 +1,91 @@
1
+ export declare const SCHEMA_SNAPSHOT_CATALOGO_DRIFT: "sema.drift-catalog/v1";
2
+ export type TipoEventoOperacaoDrift = "catalog.visit" | "content.open" | "content.read" | "ast.create" | "extractor.run" | "cache.hit" | "cache.miss" | "cache.corrupt";
3
+ export interface EventoOperacaoDrift {
4
+ tipo: TipoEventoOperacaoDrift;
5
+ caminho?: string;
6
+ raiz?: string;
7
+ chave?: string;
8
+ categoria?: "arquivo" | "diretorio";
9
+ bytes?: number;
10
+ digest?: string;
11
+ motivo?: string;
12
+ }
13
+ export type ObservadorOperacaoDrift = (evento: EventoOperacaoDrift) => void;
14
+ export type ObservadorDrift = ObservadorOperacaoDrift;
15
+ export interface ArquivoCatalogadoDrift {
16
+ caminho: string;
17
+ extensao: string;
18
+ explicito: boolean;
19
+ raizes: string[];
20
+ }
21
+ export interface ConteudoArquivoDrift {
22
+ caminho: string;
23
+ bytes: Buffer;
24
+ texto: string;
25
+ digest: string;
26
+ }
27
+ export interface MetricasCatalogoDrift {
28
+ diretoriosVisitados: number;
29
+ arquivosCatalogados: number;
30
+ leiturasConteudo: number;
31
+ bytesLidos: number;
32
+ acertosMemoriaConteudo: number;
33
+ origem: "plano_explicito" | "caminhada" | "snapshot";
34
+ diretoriosValidadosCache: number;
35
+ }
36
+ export interface AssinaturaDiretorioCatalogoDrift {
37
+ mtimeNs: string;
38
+ ctimeNs: string;
39
+ dev: string;
40
+ ino: string;
41
+ }
42
+ export interface SnapshotCatalogoDrift {
43
+ schema: typeof SCHEMA_SNAPSHOT_CATALOGO_DRIFT;
44
+ raizes: string[];
45
+ extensoes: string[] | null;
46
+ diretoriosIgnorados: string[];
47
+ diretorios: Array<{
48
+ caminho: string;
49
+ assinatura: AssinaturaDiretorioCatalogoDrift;
50
+ }>;
51
+ arquivos: Array<{
52
+ caminho: string;
53
+ explicito: boolean;
54
+ }>;
55
+ }
56
+ export interface FiltroCatalogoDrift {
57
+ extensoes?: readonly string[];
58
+ raiz?: string;
59
+ }
60
+ export interface OpcoesCatalogoDrift {
61
+ baseDiretorio?: string;
62
+ arquivos?: readonly string[];
63
+ raizes?: readonly string[];
64
+ extensoes?: readonly string[];
65
+ diretoriosIgnorados?: ReadonlySet<string> | readonly string[];
66
+ concorrencia?: number;
67
+ observador?: ObservadorOperacaoDrift;
68
+ snapshot?: SnapshotCatalogoDrift;
69
+ }
70
+ export interface CatalogoDrift {
71
+ readonly baseDiretorio: string;
72
+ readonly raizes: readonly string[];
73
+ listar(filtro?: FiltroCatalogoDrift): string[];
74
+ listar(extensoes?: readonly string[], raizes?: readonly string[]): string[];
75
+ listarEntradas(filtro?: FiltroCatalogoDrift): ArquivoCatalogadoDrift[];
76
+ listarPorExtensoes(extensoes: readonly string[], raiz?: string): string[];
77
+ listarPorRaiz(raiz: string, extensoes?: readonly string[]): string[];
78
+ arquivosCatalogados(): string[];
79
+ incluir(arquivos: readonly string[]): Promise<void>;
80
+ contem(caminho: string): boolean;
81
+ ler(caminho: string): Promise<ConteudoArquivoDrift>;
82
+ lerTexto(caminho: string): Promise<string>;
83
+ digest(caminho: string): Promise<string>;
84
+ fingerprint(caminhos?: readonly string[]): Promise<string>;
85
+ obterFingerprint(caminhos?: readonly string[]): Promise<string>;
86
+ emitir(tipo: TipoEventoOperacaoDrift, arquivo?: string): void;
87
+ metricas(): MetricasCatalogoDrift;
88
+ snapshot(): SnapshotCatalogoDrift;
89
+ }
90
+ export type CatalogoArquivosDrift = CatalogoDrift;
91
+ export declare function criarCatalogoDrift(opcoes: OpcoesCatalogoDrift): Promise<CatalogoDrift>;