@semacode/cli 2.3.1 → 3.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 (281) hide show
  1. package/README.md +265 -217
  2. package/dist/agentContextPack.js +14 -10
  3. package/dist/agentEntryPoints.d.ts +5 -0
  4. package/dist/agentEntryPoints.js +592 -568
  5. package/dist/angular-consumer-standalone.js +1 -1
  6. package/dist/bin.d.ts +6 -0
  7. package/dist/bin.js +130 -0
  8. package/dist/cliArgs.js +4 -4
  9. package/dist/cliControlError.d.ts +12 -0
  10. package/dist/cliControlError.js +47 -0
  11. package/dist/cliGrammar.d.ts +11 -0
  12. package/dist/cliGrammar.js +551 -0
  13. package/dist/cliHelp.d.ts +13 -0
  14. package/dist/cliHelp.js +19 -0
  15. package/dist/cliHelpTexto.d.ts +3 -0
  16. package/dist/cliHelpTexto.js +168 -0
  17. package/dist/cliRuntime.d.ts +2 -0
  18. package/dist/cliRuntime.js +31 -0
  19. package/dist/comandos.js +9 -22
  20. package/dist/contexto.js +5 -5
  21. package/dist/dev/index.d.ts +1 -0
  22. package/dist/dev/index.js +51 -9
  23. package/dist/discovery/catalog.js +3 -3
  24. package/dist/distribuicao/filesystemGlobal.d.ts +63 -0
  25. package/dist/distribuicao/filesystemGlobal.js +701 -0
  26. package/dist/distribuicao/index.d.ts +7 -0
  27. package/dist/distribuicao/index.js +227 -0
  28. package/dist/distribuicao/launcherGlobal.d.ts +53 -0
  29. package/dist/distribuicao/launcherGlobal.js +643 -0
  30. package/dist/distribuicao/launcherWindows.d.ts +28 -0
  31. package/dist/distribuicao/launcherWindows.js +326 -0
  32. package/dist/distribuicao/lockContextGlobal.d.ts +10 -0
  33. package/dist/distribuicao/lockContextGlobal.js +17 -0
  34. package/dist/distribuicao/lockGlobal.d.ts +6 -0
  35. package/dist/distribuicao/lockGlobal.js +520 -0
  36. package/dist/distribuicao/skillGlobal.d.ts +48 -0
  37. package/dist/distribuicao/skillGlobal.js +652 -0
  38. package/dist/distribuicao/skillIntentPolicy.d.ts +21 -0
  39. package/dist/distribuicao/skillIntentPolicy.js +115 -0
  40. package/dist/distribuicao/tipos.d.ts +50 -0
  41. package/dist/distribuicao/tipos.js +10 -0
  42. package/dist/distribuicao/versaoSemantica.d.ts +3 -0
  43. package/dist/distribuicao/versaoSemantica.js +62 -0
  44. package/dist/docs.part01.d.ts +4 -1
  45. package/dist/docs.part01.js +8 -0
  46. package/dist/docs.part02.js +9 -1
  47. package/dist/drift.part01.d.ts +33 -25
  48. package/dist/drift.part01.js +2 -1
  49. package/dist/drift.part04.d.ts +26 -5
  50. package/dist/drift.part04.js +123 -19
  51. package/dist/drift.part05.d.ts +2 -2
  52. package/dist/drift.part05.js +8 -6
  53. package/dist/drift.part06.d.ts +2 -2
  54. package/dist/drift.part06.js +113 -26
  55. package/dist/drift.part07.d.ts +11 -11
  56. package/dist/drift.part07.js +261 -265
  57. package/dist/drift.part08.d.ts +2 -2
  58. package/dist/drift.part08.js +35 -26
  59. package/dist/drift.part09.d.ts +2 -2
  60. package/dist/drift.part09.js +10 -3
  61. package/dist/drift.part11.js +261 -58
  62. package/dist/drift.part12.d.ts +1 -1
  63. package/dist/drift.part12.js +193 -21
  64. package/dist/drift.part13.d.ts +20 -39
  65. package/dist/drift.part13.js +601 -647
  66. package/dist/drift.part14.js +23 -7
  67. package/dist/driftCacheCas.d.ts +43 -0
  68. package/dist/driftCacheCas.js +351 -0
  69. package/dist/driftCacheFilesystem.d.ts +64 -0
  70. package/dist/driftCacheFilesystem.js +313 -0
  71. package/dist/driftCacheModes.d.ts +38 -0
  72. package/dist/driftCacheModes.js +147 -0
  73. package/dist/driftCacheStore.d.ts +80 -0
  74. package/dist/driftCacheStore.js +603 -0
  75. package/dist/driftCatalogo.d.ts +2 -28
  76. package/dist/driftCatalogo.js +143 -284
  77. package/dist/driftEscopo.d.ts +1 -3
  78. package/dist/driftEscopo.js +235 -151
  79. package/dist/driftEscopoReferencias.d.ts +5 -1
  80. package/dist/driftEscopoReferencias.js +375 -28
  81. package/dist/driftOrcamento.d.ts +0 -6
  82. package/dist/driftOrcamento.js +2 -1
  83. package/dist/execucoesExternas.js +19 -5
  84. package/dist/exemplosOficiais.d.ts +2 -1
  85. package/dist/exemplosOficiais.js +9 -3
  86. package/dist/geracaoCore.d.ts +1 -0
  87. package/dist/geracaoCore.js +6 -6
  88. package/dist/iaPrompts.d.ts +3 -3
  89. package/dist/iaPrompts.js +312 -313
  90. package/dist/importador.part01.d.ts +1 -1
  91. package/dist/importador.part06.d.ts +2 -0
  92. package/dist/importador.part06.js +87 -1
  93. package/dist/importador.part09.js +7 -1
  94. package/dist/index.d.ts +4 -1
  95. package/dist/index.js +6 -25
  96. package/dist/index.part01.d.ts +20 -28
  97. package/dist/index.part01.js +16 -237
  98. package/dist/index.part02.js +36 -22
  99. package/dist/index.part03.d.ts +24 -2
  100. package/dist/index.part03.js +83 -19
  101. package/dist/index.part04.d.ts +10 -2
  102. package/dist/index.part04.js +152 -123
  103. package/dist/index.part05.js +80 -78
  104. package/dist/index.part06.js +34 -17
  105. package/dist/index.part07.d.ts +8 -2
  106. package/dist/index.part07.js +153 -7
  107. package/dist/index.part08.d.ts +1 -1
  108. package/dist/index.part08.js +25 -30
  109. package/dist/initCommand.d.ts +1 -0
  110. package/dist/initCommand.js +20 -4
  111. package/dist/initTemplatesBase.js +6 -4
  112. package/dist/pipelineConteudo/command.d.ts +1 -0
  113. package/dist/pipelineConteudo/command.js +9 -2
  114. package/dist/pipelineConteudo/help.d.ts +2 -0
  115. package/dist/pipelineConteudo/help.js +33 -0
  116. package/dist/profileAuthorCommand.js +3 -7
  117. package/dist/profileCommand.js +3 -7
  118. package/dist/projetoCarregar.js +35 -17
  119. package/dist/projetoCatalogo.d.ts +1 -0
  120. package/dist/projetoCatalogo.js +64 -25
  121. package/dist/projetoConfig.js +2 -0
  122. package/dist/projetoLegado.js +18 -0
  123. package/dist/projetoOrigens.d.ts +2 -0
  124. package/dist/projetoOrigens.js +65 -9
  125. package/dist/projetoTipos.d.ts +1 -0
  126. package/dist/resultadoCli.d.ts +20 -0
  127. package/dist/resultadoCli.js +57 -0
  128. package/dist/saidaCli.d.ts +35 -0
  129. package/dist/saidaCli.js +118 -0
  130. package/dist/sistemasInterativos/acceptanceEvidence.d.ts +22 -0
  131. package/dist/sistemasInterativos/acceptanceEvidence.js +345 -0
  132. package/dist/sistemasInterativos/engineObservation.d.ts +12 -0
  133. package/dist/sistemasInterativos/engineObservation.js +438 -0
  134. package/dist/sistemasInterativos/jobOrchestration.d.ts +2 -0
  135. package/dist/sistemasInterativos/jobOrchestration.js +204 -0
  136. package/dist/sistemasInterativos/operationPrimitives.d.ts +21 -0
  137. package/dist/sistemasInterativos/operationPrimitives.js +194 -0
  138. package/dist/sistemasInterativos/operations.d.ts +4 -39
  139. package/dist/sistemasInterativos/operations.js +5 -1164
  140. package/dist/skillCommand.d.ts +5 -0
  141. package/dist/skillCommand.js +88 -0
  142. package/dist/tipos.d.ts +1 -1
  143. package/dist/typescript-http-modelos.d.ts +1 -1
  144. package/dist/typescript-http-rotas.d.ts +1 -0
  145. package/dist/typescript-http-rotas.js +93 -0
  146. package/dist/typescript-http.d.ts +1 -1
  147. package/dist/typescript-http.js +1 -1
  148. package/dist/verificacaoCache.d.ts +25 -0
  149. package/dist/verificacaoCache.js +80 -0
  150. package/docs/README.md +34 -30
  151. package/docs/ai-integration.md +25 -12
  152. package/docs/ai-onboarding.md +37 -18
  153. package/docs/ai-workflow.md +9 -7
  154. package/docs/cli.md +125 -7
  155. package/docs/commands.md +41 -20
  156. package/docs/deploy.md +21 -8
  157. package/docs/descoberta-capacidades.md +106 -106
  158. package/docs/documentation.md +49 -39
  159. package/docs/drift-cache.md +108 -0
  160. package/docs/getting-started.md +43 -18
  161. package/docs/pipeline-conteudo.md +246 -246
  162. package/docs/profiles.md +54 -54
  163. package/docs/repositories.md +19 -2
  164. package/docs/rollback.md +15 -8
  165. package/docs/security.md +25 -3
  166. package/docs/sistemas-interativos.md +379 -374
  167. package/docs/syntax.md +14 -0
  168. package/docs/testing.md +139 -40
  169. package/exemplos/express_crud.sema +139 -0
  170. package/exemplos/fastify_crud.sema +146 -0
  171. package/exemplos/pipeline-conteudo/README.md +44 -44
  172. package/exemplos/pipeline-conteudo/alvos.json +23 -23
  173. package/exemplos/pipeline-conteudo/definicao.json +136 -136
  174. package/exemplos/profile_simulation.sema +211 -211
  175. package/exemplos/sistemas-interativos/README.md +100 -100
  176. package/exemplos/sistemas-interativos/advanced/acceptance-context-evaluate-valid.json +5 -5
  177. package/exemplos/sistemas-interativos/advanced/acceptance-lock-valid.json +16 -16
  178. package/exemplos/sistemas-interativos/advanced/asset-provenance-valid.json +32 -32
  179. package/exemplos/sistemas-interativos/advanced/autonomy-repair-valid.json +93 -93
  180. package/exemplos/sistemas-interativos/advanced/control-run-definition-valid.json +78 -78
  181. package/exemplos/sistemas-interativos/advanced/control-run-valid.json +27 -27
  182. package/exemplos/sistemas-interativos/advanced/distributed-workers-valid.json +79 -79
  183. package/exemplos/sistemas-interativos/advanced/editor-state-valid.json +42 -42
  184. package/exemplos/sistemas-interativos/advanced/engine-snapshot-after-valid.json +32 -32
  185. package/exemplos/sistemas-interativos/advanced/engine-snapshot-before-valid.json +23 -23
  186. package/exemplos/sistemas-interativos/advanced/job-orchestration-valid.json +39 -39
  187. package/exemplos/sistemas-interativos/advanced/multimodal-evidence-valid.json +46 -46
  188. package/exemplos/sistemas-interativos/advanced/multiplayer-authority-valid.json +39 -39
  189. package/exemplos/sistemas-interativos/advanced/playtest-fuzz-valid.json +37 -37
  190. package/exemplos/sistemas-interativos/advanced/portability-valid.json +104 -104
  191. package/exemplos/sistemas-interativos/advanced/temporal-evidence-valid.json +27 -27
  192. package/exemplos/sistemas-interativos/advanced/temporal-valid.json +118 -118
  193. package/exemplos/sistemas-interativos/experience-ir-valid.json +459 -459
  194. package/exemplos/sistemas-interativos/game-2d.json +83 -83
  195. package/exemplos/sistemas-interativos/game-3d-human.json +81 -81
  196. package/exemplos/sistemas-interativos/game-pixel-16-bit.json +97 -97
  197. package/exemplos/sistemas-interativos/game-pixel-8-bit.json +94 -94
  198. package/exemplos/sistemas-interativos/game-xr-human.json +80 -80
  199. package/exemplos/sistemas-interativos/hybrid-2-5d.json +108 -108
  200. package/exemplos/sistemas-interativos/protocol-mutating-rollback-valid.json +75 -75
  201. package/exemplos/sistemas-interativos/protocol-read-only-valid.json +58 -58
  202. package/exemplos/sistemas-interativos/simulation-2d-controlled.json +97 -97
  203. package/exemplos/sistemas-interativos/simulation-3d-calibrated-autonomous.json +141 -141
  204. package/exemplos/sistemas-interativos/simulation-headless-autonomous-batch.json +112 -112
  205. package/exemplos/sistemas-interativos/simulation-pixel-16-bit.json +103 -103
  206. package/exemplos/sistemas-interativos/simulation-text-controlled.json +95 -95
  207. package/node_modules/@sema/gerador-cpp/package.json +1 -1
  208. package/node_modules/@sema/gerador-dotnet/package.json +1 -1
  209. package/node_modules/@sema/gerador-lua/dist/index.js +51 -51
  210. package/node_modules/@sema/gerador-php/dist/index.js +113 -113
  211. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js +37 -38
  212. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +1 -0
  213. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +1 -0
  214. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +1 -0
  215. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.d.ts +7 -0
  216. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js +33 -10
  217. package/package.json +9 -4
  218. package/scripts/postinstall.mjs +148 -0
  219. package/skills/sema/SKILL.md +199 -0
  220. package/skills/sema/agents/openai.yaml +4 -0
  221. package/dist/driftCache.d.ts +0 -49
  222. package/dist/driftCache.js +0 -311
  223. package/dist/driftCacheIncremental.d.ts +0 -98
  224. package/dist/driftCacheIncremental.js +0 -596
  225. package/dist/driftCatalogoPersistente.d.ts +0 -8
  226. package/dist/driftCatalogoPersistente.js +0 -77
  227. package/node_modules/@sema/gerador-cpp/dist/index.js.map +0 -1
  228. package/node_modules/@sema/gerador-css/dist/index.js.map +0 -1
  229. package/node_modules/@sema/gerador-css/dist/index.part01.js.map +0 -1
  230. package/node_modules/@sema/gerador-css/dist/index.part02.js.map +0 -1
  231. package/node_modules/@sema/gerador-dart/dist/index.js.map +0 -1
  232. package/node_modules/@sema/gerador-dotnet/dist/index.js.map +0 -1
  233. package/node_modules/@sema/gerador-html/dist/index.js.map +0 -1
  234. package/node_modules/@sema/gerador-javascript/dist/index.js.map +0 -1
  235. package/node_modules/@sema/gerador-lua/dist/index.js.map +0 -1
  236. package/node_modules/@sema/gerador-php/dist/index.js.map +0 -1
  237. package/node_modules/@sema/gerador-python/dist/index.js.map +0 -1
  238. package/node_modules/@sema/gerador-python/dist/index.part01.js.map +0 -1
  239. package/node_modules/@sema/gerador-python/dist/index.part02.js.map +0 -1
  240. package/node_modules/@sema/gerador-typescript/dist/index.js.map +0 -1
  241. package/node_modules/@sema/gerador-typescript/dist/index.part01.js.map +0 -1
  242. package/node_modules/@sema/gerador-typescript/dist/index.part02.js.map +0 -1
  243. package/node_modules/@sema/gerador-typescript/dist/index.part03.js.map +0 -1
  244. package/node_modules/@sema/nucleo/dist/ast/tipos.js.map +0 -1
  245. package/node_modules/@sema/nucleo/dist/diagnosticos/index.js.map +0 -1
  246. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +0 -1
  247. package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.js.map +0 -1
  248. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +0 -1
  249. package/node_modules/@sema/nucleo/dist/formatador/index.part01.js.map +0 -1
  250. package/node_modules/@sema/nucleo/dist/formatador/index.part02.js.map +0 -1
  251. package/node_modules/@sema/nucleo/dist/index.js.map +0 -1
  252. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +0 -1
  253. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js.map +0 -1
  254. package/node_modules/@sema/nucleo/dist/ir/conversor.part02.js.map +0 -1
  255. package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js.map +0 -1
  256. package/node_modules/@sema/nucleo/dist/ir/modelos.js.map +0 -1
  257. package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +0 -1
  258. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +0 -1
  259. package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js.map +0 -1
  260. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +0 -1
  261. package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js.map +0 -1
  262. package/node_modules/@sema/nucleo/dist/parser/parser.part01.js.map +0 -1
  263. package/node_modules/@sema/nucleo/dist/parser/parser.part02.js.map +0 -1
  264. package/node_modules/@sema/nucleo/dist/parser/parser.part03.js.map +0 -1
  265. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +0 -1
  266. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +0 -1
  267. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js.map +0 -1
  268. package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.js.map +0 -1
  269. package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.js.map +0 -1
  270. package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.js.map +0 -1
  271. package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.js.map +0 -1
  272. package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.js.map +0 -1
  273. package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.js.map +0 -1
  274. package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js.map +0 -1
  275. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +0 -1
  276. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.js.map +0 -1
  277. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.js.map +0 -1
  278. package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.js.map +0 -1
  279. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js.map +0 -1
  280. package/node_modules/@sema/nucleo/dist/util/arquivos.js.map +0 -1
  281. package/node_modules/@sema/padroes/dist/index.js.map +0 -1
@@ -1,9 +1,8 @@
1
- // SEMA-GOVERNED: sema.produto.governanca_ia.drift
2
- // Descrição: cataloga somente o plano explícito do drift e compartilha leituras e fingerprints de conteúdo.
1
+ // SEMA-GOVERNED: sema.produto.governanca_ia.drift, sema.produto.governanca_ia.drift.cache.store
2
+ // Descrição: cataloga somente o plano físico do drift e compartilha uma leitura estável por arquivo.
3
3
  import { createHash } from "node:crypto";
4
4
  import { lstat, open, readdir, realpath } from "node:fs/promises";
5
5
  import path from "node:path";
6
- export const SCHEMA_SNAPSHOT_CATALOGO_DRIFT = "sema.drift-catalog/v1";
7
6
  const CONCORRENCIA_PADRAO = 8;
8
7
  const CONCORRENCIA_MAXIMA = 64;
9
8
  function emitirEvento(observador, evento) {
@@ -35,7 +34,7 @@ function chaveCaminho(caminho) {
35
34
  return process.platform === "win32" ? normalizado.toLowerCase() : normalizado;
36
35
  }
37
36
  function caminhoEstaDentro(raiz, alvo) {
38
- const relativo = path.relative(raiz, alvo);
37
+ const relativo = path.relative(path.resolve(raiz), path.resolve(alvo));
39
38
  return relativo === "" || (relativo !== ".."
40
39
  && !relativo.startsWith(`..${path.sep}`)
41
40
  && !path.isAbsolute(relativo));
@@ -45,10 +44,10 @@ function erroEhAusencia(erro) {
45
44
  }
46
45
  function assinaturaDiretorio(info) {
47
46
  return {
48
- mtimeNs: info.mtimeNs.toString(),
49
- ctimeNs: info.ctimeNs.toString(),
50
- dev: info.dev.toString(),
51
- ino: info.ino.toString(),
47
+ mtimeNs: info.mtimeNs,
48
+ ctimeNs: info.ctimeNs,
49
+ dev: info.dev,
50
+ ino: info.ino,
52
51
  };
53
52
  }
54
53
  function assinaturasDiretorioIguais(a, b) {
@@ -62,31 +61,49 @@ function identidadeArquivoEstavel(a, b) {
62
61
  && b.isFile()
63
62
  && !a.isSymbolicLink()
64
63
  && !b.isSymbolicLink()
64
+ && a.nlink === 1n
65
+ && b.nlink === 1n
65
66
  && a.dev === b.dev
66
67
  && a.ino === b.ino
67
68
  && a.size === b.size
68
69
  && a.mtimeNs === b.mtimeNs
69
70
  && a.ctimeNs === b.ctimeNs;
70
71
  }
71
- function registroObjeto(valor) {
72
- return typeof valor === "object" && valor !== null && !Array.isArray(valor);
72
+ function criarIdentidadeArquivoCatalogado(caminhoReal, informacao) {
73
+ return {
74
+ caminhoReal: path.resolve(caminhoReal),
75
+ dev: informacao.dev,
76
+ ino: informacao.ino,
77
+ nlink: informacao.nlink,
78
+ size: informacao.size,
79
+ mtimeNs: informacao.mtimeNs,
80
+ ctimeNs: informacao.ctimeNs,
81
+ };
73
82
  }
74
- function caminhoRelativoSeguro(valor) {
75
- return typeof valor === "string"
76
- && valor.length > 0
77
- && valor !== "."
78
- && valor !== ".."
79
- && !valor.startsWith("../")
80
- && !valor.includes("\\")
81
- && !path.posix.isAbsolute(valor);
83
+ function identidadeCatalogadaCorresponde(identidade, caminhoReal, informacao) {
84
+ return chaveCaminho(identidade.caminhoReal) === chaveCaminho(caminhoReal)
85
+ && informacao.isFile()
86
+ && !informacao.isSymbolicLink()
87
+ && identidade.nlink === 1n
88
+ && informacao.nlink === 1n
89
+ && identidade.dev === informacao.dev
90
+ && identidade.ino === informacao.ino
91
+ && identidade.size === informacao.size
92
+ && identidade.mtimeNs === informacao.mtimeNs
93
+ && identidade.ctimeNs === informacao.ctimeNs;
82
94
  }
83
- function diretorioRelativoSeguro(valor) {
84
- return valor === "." || caminhoRelativoSeguro(valor);
95
+ function chavesFisicasArquivo(identidade) {
96
+ const chaves = [`real:${chaveCaminho(identidade.caminhoReal)}`];
97
+ if (identidade.dev !== 0n || identidade.ino !== 0n) {
98
+ chaves.push(`id:${identidade.dev.toString()}:${identidade.ino.toString()}`);
99
+ }
100
+ return chaves;
85
101
  }
86
- function assinaturaDiretorioValida(valor) {
87
- return registroObjeto(valor)
88
- && ["mtimeNs", "ctimeNs", "dev", "ino"]
89
- .every((campo) => typeof valor[campo] === "string" && /^\d+$/u.test(valor[campo]));
102
+ function mesmoObjetoFisico(a, b) {
103
+ const possuiIdentidadeInode = (a.dev !== 0n || a.ino !== 0n) && (b.dev !== 0n || b.ino !== 0n);
104
+ return possuiIdentidadeInode
105
+ ? a.dev === b.dev && a.ino === b.ino
106
+ : chaveCaminho(a.caminhoReal) === chaveCaminho(b.caminhoReal);
90
107
  }
91
108
  async function mapearComLimite(itens, limite, executar) {
92
109
  if (itens.length === 0) {
@@ -111,14 +128,12 @@ class CatalogoDriftImplementacao {
111
128
  baseDiretorio;
112
129
  raizes;
113
130
  registros = new Map();
131
+ registrosFisicos = new Map();
114
132
  conteudos = new Map();
115
133
  extensoesPermitidas;
116
134
  concorrencia;
117
135
  observador;
118
136
  baseDiretorioReal;
119
- extensoesSnapshot;
120
- diretoriosVisitados = new Map();
121
- diretoriosIgnoradosSnapshot = [];
122
137
  contadores = {
123
138
  diretoriosVisitados: 0,
124
139
  arquivosCatalogados: 0,
@@ -126,13 +141,13 @@ class CatalogoDriftImplementacao {
126
141
  bytesLidos: 0,
127
142
  acertosMemoriaConteudo: 0,
128
143
  origem: "plano_explicito",
129
- diretoriosValidadosCache: 0,
130
144
  };
131
145
  constructor(opcoes) {
132
146
  this.baseDiretorio = path.resolve(opcoes.baseDiretorio ?? process.cwd());
133
147
  this.baseDiretorioReal = realpath(this.baseDiretorio);
134
148
  this.raizes = [...new Map((opcoes.raizes ?? [])
135
149
  .map((raiz) => path.resolve(this.baseDiretorio, raiz))
150
+ .filter((raiz) => caminhoEstaDentro(this.baseDiretorio, raiz))
136
151
  .map((raiz) => [chaveCaminho(raiz), raiz])).values()].sort((a, b) => a.localeCompare(b, "pt-BR"));
137
152
  const extensoes = opcoes.extensoes
138
153
  ?.map(normalizarExtensao)
@@ -140,21 +155,13 @@ class CatalogoDriftImplementacao {
140
155
  this.extensoesPermitidas = extensoes?.length
141
156
  ? new Set(extensoes)
142
157
  : undefined;
143
- this.extensoesSnapshot = this.extensoesPermitidas
144
- ? [...this.extensoesPermitidas].sort((a, b) => a.localeCompare(b, "en"))
145
- : null;
146
158
  this.concorrencia = normalizarConcorrencia(opcoes.concorrencia);
147
159
  this.observador = opcoes.observador;
148
160
  }
149
- async construir(arquivosExplicitos, diretoriosIgnorados, snapshot) {
161
+ async construir(arquivosExplicitos, diretoriosIgnorados) {
150
162
  await this.baseDiretorioReal;
151
- this.diretoriosIgnoradosSnapshot = [...diretoriosIgnorados]
152
- .sort((a, b) => a.localeCompare(b, "en"));
153
- const restaurado = snapshot
154
- ? await this.restaurarSnapshot(snapshot, diretoriosIgnorados, arquivosExplicitos)
155
- : false;
156
- if (!restaurado) {
157
- this.contadores.origem = this.raizes.length > 0 ? "caminhada" : "plano_explicito";
163
+ if (this.raizes.length > 0) {
164
+ this.contadores.origem = "caminhada";
158
165
  await this.caminharRaizes(diretoriosIgnorados);
159
166
  }
160
167
  await this.incluir(arquivosExplicitos);
@@ -163,25 +170,12 @@ class CatalogoDriftImplementacao {
163
170
  const explicitos = [...new Map(arquivosExplicitos
164
171
  .map((arquivo) => path.resolve(this.baseDiretorio, arquivo))
165
172
  .map((arquivo) => [chaveCaminho(arquivo), arquivo])).values()].sort((a, b) => a.localeCompare(b, "pt-BR"));
166
- await mapearComLimite(explicitos, this.concorrencia, async (arquivo) => {
167
- if (!await this.caminhoPermaneceNoWorkspace(arquivo)) {
168
- return;
169
- }
170
- let informacao;
171
- try {
172
- informacao = await lstat(arquivo);
173
- }
174
- catch (erro) {
175
- if (erroEhAusencia(erro)) {
176
- return;
177
- }
178
- throw erro;
179
- }
180
- if (!informacao.isFile() || informacao.isSymbolicLink()) {
181
- return;
182
- }
183
- this.adicionarArquivo(arquivo, true);
184
- });
173
+ const sondagens = await mapearComLimite(explicitos, this.concorrencia, async (arquivo) => this.sondarArquivoSeguro(arquivo));
174
+ for (const sondagem of sondagens
175
+ .filter((item) => Boolean(item))
176
+ .sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR"))) {
177
+ this.adicionarArquivo(sondagem, true);
178
+ }
185
179
  }
186
180
  listar(extensoesOuFiltro = [], raizes) {
187
181
  if (ehFiltroCatalogoDrift(extensoesOuFiltro)) {
@@ -192,9 +186,7 @@ class CatalogoDriftImplementacao {
192
186
  return this.listarEntradas({ extensoes }).map((arquivo) => arquivo.caminho);
193
187
  }
194
188
  const raizesAbsolutas = raizes.map((raiz) => path.resolve(this.baseDiretorio, raiz));
195
- return this.listarEntradas({ extensoes })
196
- .filter((arquivo) => raizesAbsolutas.some((raiz) => caminhoEstaDentro(raiz, arquivo.caminho)))
197
- .map((arquivo) => arquivo.caminho);
189
+ return [...new Map(raizesAbsolutas.flatMap((raiz) => this.listarEntradas({ extensoes, raiz }).map((arquivo) => [chaveCaminho(arquivo.caminho), arquivo.caminho]))).values()].sort((a, b) => a.localeCompare(b, "pt-BR"));
198
190
  }
199
191
  listarEntradas(filtro = {}) {
200
192
  const extensoes = filtro.extensoes
@@ -203,9 +195,9 @@ class CatalogoDriftImplementacao {
203
195
  const raiz = filtro.raiz
204
196
  ? path.resolve(this.baseDiretorio, filtro.raiz)
205
197
  : undefined;
206
- return [...this.registros.values()]
198
+ return [...new Set(this.registros.values())]
207
199
  .filter((registro) => !extensoes || extensoes.has(registro.extensao))
208
- .filter((registro) => !raiz || caminhoEstaDentro(raiz, registro.caminho))
200
+ .filter((registro) => !raiz || [...registro.aliases].some((alias) => caminhoEstaDentro(raiz, alias)))
209
201
  .map((registro) => ({
210
202
  caminho: registro.caminho,
211
203
  extensao: registro.extensao,
@@ -231,18 +223,21 @@ class CatalogoDriftImplementacao {
231
223
  const chave = chaveCaminho(absoluto);
232
224
  const registro = this.registros.get(chave);
233
225
  if (!registro) {
234
- return Promise.reject(new Error(`Arquivo fora do plano explicito do drift: ${absoluto}`));
226
+ const descricao = caminhoEstaDentro(this.baseDiretorio, absoluto)
227
+ ? absoluto
228
+ : `[fora_do_workspace]/${path.basename(absoluto)}`;
229
+ return Promise.reject(new Error(`Arquivo fora do plano explicito do drift: ${descricao}`));
235
230
  }
236
- const existente = this.conteudos.get(chave);
231
+ const existente = this.conteudos.get(registro);
237
232
  if (existente) {
238
233
  this.contadores.acertosMemoriaConteudo += 1;
239
234
  return existente;
240
235
  }
241
- const leitura = this.lerFisicamente(registro.caminho);
242
- this.conteudos.set(chave, leitura);
236
+ const leitura = this.lerFisicamente(registro);
237
+ this.conteudos.set(registro, leitura);
243
238
  void leitura.catch(() => {
244
- if (this.conteudos.get(chave) === leitura) {
245
- this.conteudos.delete(chave);
239
+ if (this.conteudos.get(registro) === leitura) {
240
+ this.conteudos.delete(registro);
246
241
  }
247
242
  });
248
243
  return leitura;
@@ -253,23 +248,6 @@ class CatalogoDriftImplementacao {
253
248
  async digest(caminho) {
254
249
  return (await this.ler(caminho)).digest;
255
250
  }
256
- async fingerprint(caminhos) {
257
- const selecionados = caminhos
258
- ? [...new Map(caminhos.map((caminho) => {
259
- const absoluto = path.resolve(this.baseDiretorio, caminho);
260
- return [chaveCaminho(absoluto), absoluto];
261
- })).values()]
262
- : this.arquivosCatalogados();
263
- selecionados.sort((a, b) => chaveCaminho(a).localeCompare(chaveCaminho(b), "en"));
264
- const itens = await mapearComLimite(selecionados, this.concorrencia, async (arquivo) => ({
265
- caminho: chaveCaminho(arquivo).replace(/\\/g, "/"),
266
- digest: await this.digest(arquivo),
267
- }));
268
- return `sha256:${createHash("sha256").update(JSON.stringify(itens)).digest("hex")}`;
269
- }
270
- obterFingerprint(caminhos) {
271
- return this.fingerprint(caminhos);
272
- }
273
251
  emitir(tipo, arquivo) {
274
252
  emitirEvento(this.observador, {
275
253
  tipo,
@@ -279,26 +257,6 @@ class CatalogoDriftImplementacao {
279
257
  metricas() {
280
258
  return { ...this.contadores };
281
259
  }
282
- snapshot() {
283
- return {
284
- schema: SCHEMA_SNAPSHOT_CATALOGO_DRIFT,
285
- raizes: this.raizes.map((raiz) => this.relativoSeguro(raiz, true)),
286
- extensoes: this.extensoesSnapshot ? [...this.extensoesSnapshot] : null,
287
- diretoriosIgnorados: [...this.diretoriosIgnoradosSnapshot],
288
- diretorios: [...this.diretoriosVisitados.entries()]
289
- .map(([caminho, assinatura]) => ({
290
- caminho: this.relativoSeguro(caminho, true),
291
- assinatura: { ...assinatura },
292
- }))
293
- .sort((a, b) => a.caminho.localeCompare(b.caminho, "en")),
294
- arquivos: [...this.registros.values()]
295
- .map((registro) => ({
296
- caminho: this.relativoSeguro(registro.caminho),
297
- explicito: registro.explicito,
298
- }))
299
- .sort((a, b) => a.caminho.localeCompare(b.caminho, "en")),
300
- };
301
- }
302
260
  async caminharRaizes(diretoriosIgnorados) {
303
261
  let nivel = [...this.raizes];
304
262
  const visitados = new Set();
@@ -335,22 +293,16 @@ class CatalogoDriftImplementacao {
335
293
  return [];
336
294
  }
337
295
  if (informacao.isFile()) {
338
- this.adicionarArquivo(diretorio, false);
296
+ const sondagem = await this.sondarArquivoSeguro(diretorio);
297
+ if (sondagem) {
298
+ this.adicionarArquivo(sondagem, false);
299
+ }
339
300
  return [];
340
301
  }
341
302
  if (!informacao.isDirectory()) {
342
303
  return [];
343
304
  }
344
- let entradas;
345
- try {
346
- entradas = await readdir(diretorio, { withFileTypes: true });
347
- }
348
- catch (erro) {
349
- if (erroEhAusencia(erro)) {
350
- return [];
351
- }
352
- throw erro;
353
- }
305
+ const entradas = await readdir(diretorio, { withFileTypes: true });
354
306
  const informacaoDepois = await lstat(diretorio, { bigint: true });
355
307
  if (!informacaoDepois.isDirectory()
356
308
  || informacaoDepois.isSymbolicLink()
@@ -358,13 +310,13 @@ class CatalogoDriftImplementacao {
358
310
  throw new Error(`catalogo_diretorio_instavel:${diretorio}`);
359
311
  }
360
312
  this.contadores.diretoriosVisitados += 1;
361
- this.diretoriosVisitados.set(path.resolve(diretorio), assinaturaDiretorio(informacaoDepois));
362
313
  emitirEvento(this.observador, {
363
314
  tipo: "catalog.visit",
364
315
  caminho: diretorio,
365
316
  categoria: "diretorio",
366
317
  });
367
318
  const proximos = [];
319
+ const arquivos = [];
368
320
  for (const entrada of entradas.sort((a, b) => a.name.localeCompare(b.name, "pt-BR"))) {
369
321
  if (entrada.isSymbolicLink()) {
370
322
  continue;
@@ -374,205 +326,111 @@ class CatalogoDriftImplementacao {
374
326
  if (!diretoriosIgnorados.has(entrada.name.toLowerCase())) {
375
327
  proximos.push(caminhoAtual);
376
328
  }
377
- continue;
378
329
  }
379
- if (entrada.isFile()) {
380
- this.adicionarArquivo(caminhoAtual, false);
330
+ else if (entrada.isFile()) {
331
+ arquivos.push(caminhoAtual);
381
332
  }
382
333
  }
334
+ const sondagens = await mapearComLimite(arquivos, this.concorrencia, async (arquivo) => this.sondarArquivoSeguro(arquivo));
335
+ for (const sondagem of sondagens
336
+ .filter((item) => Boolean(item))
337
+ .sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR"))) {
338
+ this.adicionarArquivo(sondagem, false);
339
+ }
383
340
  return proximos;
384
341
  }
385
- adicionarArquivo(caminho, explicito, emitirVisita = true) {
386
- const absoluto = path.resolve(caminho);
342
+ adicionarArquivo(sondagem, explicito) {
343
+ const absoluto = path.resolve(sondagem.caminho);
387
344
  const extensao = path.extname(absoluto).toLowerCase();
388
- if (this.extensoesPermitidas && !this.extensoesPermitidas.has(extensao)) {
345
+ if (!explicito && this.extensoesPermitidas && !this.extensoesPermitidas.has(extensao)) {
389
346
  return;
390
347
  }
391
348
  const chave = chaveCaminho(absoluto);
392
- const existente = this.registros.get(chave);
349
+ const chavesFisicas = chavesFisicasArquivo(sondagem.identidade);
350
+ const existentePorCaminho = this.registros.get(chave);
351
+ if (existentePorCaminho && !mesmoObjetoFisico(existentePorCaminho.identidade, sondagem.identidade)) {
352
+ throw new Error(`Arquivo catalogado mudou de identidade fisica: ${absoluto}`);
353
+ }
354
+ const existente = existentePorCaminho
355
+ ?? chavesFisicas.map((chaveFisica) => this.registrosFisicos.get(chaveFisica)).find(Boolean);
393
356
  const raizes = this.raizes.filter((raiz) => caminhoEstaDentro(raiz, absoluto));
394
357
  if (existente) {
395
358
  existente.explicito = existente.explicito || explicito;
359
+ existente.aliases.add(absoluto);
360
+ this.registros.set(chave, existente);
396
361
  for (const raiz of raizes) {
397
362
  existente.raizes.add(raiz);
398
363
  }
364
+ for (const chaveFisica of chavesFisicas) {
365
+ this.registrosFisicos.set(chaveFisica, existente);
366
+ }
367
+ if (absoluto.localeCompare(existente.caminho, "pt-BR") < 0) {
368
+ existente.caminho = absoluto;
369
+ existente.extensao = extensao;
370
+ existente.identidade = sondagem.identidade;
371
+ }
399
372
  return;
400
373
  }
401
- this.registros.set(chave, {
374
+ const registro = {
402
375
  caminho: absoluto,
403
376
  extensao,
404
377
  explicito,
405
378
  raizes: new Set(raizes),
406
- });
407
- this.contadores.arquivosCatalogados += 1;
408
- if (emitirVisita) {
409
- emitirEvento(this.observador, {
410
- tipo: "catalog.visit",
411
- caminho: absoluto,
412
- categoria: "arquivo",
413
- });
379
+ aliases: new Set([absoluto]),
380
+ identidade: sondagem.identidade,
381
+ };
382
+ this.registros.set(chave, registro);
383
+ for (const chaveFisica of chavesFisicas) {
384
+ this.registrosFisicos.set(chaveFisica, registro);
414
385
  }
386
+ this.contadores.arquivosCatalogados += 1;
387
+ emitirEvento(this.observador, {
388
+ tipo: "catalog.visit",
389
+ caminho: absoluto,
390
+ categoria: "arquivo",
391
+ });
415
392
  }
416
- async restaurarSnapshot(snapshot, diretoriosIgnorados, arquivosExplicitos) {
417
- if (!registroObjeto(snapshot)
418
- || snapshot.schema !== SCHEMA_SNAPSHOT_CATALOGO_DRIFT
419
- || !Array.isArray(snapshot.raizes)
420
- || !snapshot.raizes.every(diretorioRelativoSeguro)
421
- || !Array.isArray(snapshot.diretoriosIgnorados)
422
- || !snapshot.diretoriosIgnorados.every((item) => typeof item === "string")
423
- || !(snapshot.extensoes === null
424
- || (Array.isArray(snapshot.extensoes) && snapshot.extensoes.every((item) => typeof item === "string")))
425
- || !Array.isArray(snapshot.diretorios)
426
- || !Array.isArray(snapshot.arquivos)) {
427
- return false;
428
- }
429
- const raizesAtuais = this.raizes.map((raiz) => this.relativoSeguro(raiz, true));
430
- const ignoradosAtuais = [...diretoriosIgnorados].sort((a, b) => a.localeCompare(b, "en"));
431
- if (JSON.stringify(snapshot.raizes) !== JSON.stringify(raizesAtuais)
432
- || JSON.stringify(snapshot.extensoes) !== JSON.stringify(this.extensoesSnapshot)
433
- || JSON.stringify(snapshot.diretoriosIgnorados) !== JSON.stringify(ignoradosAtuais)) {
434
- return false;
393
+ async sondarArquivoSeguro(caminho) {
394
+ const absoluto = path.resolve(caminho);
395
+ if (!caminhoEstaDentro(this.baseDiretorio, absoluto)) {
396
+ return undefined;
435
397
  }
436
- const diretorios = snapshot.diretorios.map((entrada) => {
437
- if (!registroObjeto(entrada)
438
- || !diretorioRelativoSeguro(entrada.caminho)
439
- || !assinaturaDiretorioValida(entrada.assinatura)) {
398
+ try {
399
+ const informacaoAntes = await lstat(absoluto, { bigint: true });
400
+ if (!informacaoAntes.isFile() || informacaoAntes.isSymbolicLink() || informacaoAntes.nlink !== 1n) {
440
401
  return undefined;
441
402
  }
442
- return {
443
- caminho: path.resolve(this.baseDiretorio, entrada.caminho),
444
- assinatura: entrada.assinatura,
445
- };
446
- });
447
- if (diretorios.some((entrada) => !entrada)) {
448
- return false;
449
- }
450
- if (diretorios.some((entrada) => entrada
451
- && !this.caminhoPertenceRaizCatalogavel(entrada.caminho, diretoriosIgnorados, true))) {
452
- return false;
453
- }
454
- const estadosDiretorios = await mapearComLimite(diretorios, this.concorrencia, async (entrada) => {
455
- if (!await this.caminhoPermaneceNoWorkspace(entrada.caminho)) {
456
- return false;
457
- }
458
- try {
459
- const info = await lstat(entrada.caminho, { bigint: true });
460
- this.contadores.diretoriosValidadosCache += 1;
461
- return info.isDirectory()
462
- && !info.isSymbolicLink()
463
- && assinaturasDiretorioIguais(entrada.assinatura, assinaturaDiretorio(info));
464
- }
465
- catch {
466
- return false;
467
- }
468
- });
469
- if (estadosDiretorios.some((valido) => !valido)) {
470
- this.contadores.diretoriosValidadosCache = 0;
471
- return false;
472
- }
473
- const arquivos = snapshot.arquivos.map((entrada) => {
474
- if (!registroObjeto(entrada)
475
- || !caminhoRelativoSeguro(entrada.caminho)
476
- || typeof entrada.explicito !== "boolean") {
403
+ const [baseReal, caminhoReal] = await Promise.all([
404
+ this.baseDiretorioReal,
405
+ realpath(absoluto),
406
+ ]);
407
+ const informacaoDepois = await lstat(absoluto, { bigint: true });
408
+ if (!caminhoEstaDentro(baseReal, caminhoReal)
409
+ || !identidadeArquivoEstavel(informacaoAntes, informacaoDepois)) {
477
410
  return undefined;
478
411
  }
479
412
  return {
480
- caminho: path.resolve(this.baseDiretorio, entrada.caminho),
481
- explicito: entrada.explicito,
413
+ caminho: absoluto,
414
+ identidade: criarIdentidadeArquivoCatalogado(caminhoReal, informacaoDepois),
482
415
  };
483
- });
484
- if (arquivos.some((entrada) => !entrada)) {
485
- return false;
486
- }
487
- const arquivosTipados = arquivos;
488
- const explicitosPermitidos = new Set(arquivosExplicitos.map((arquivo) => chaveCaminho(path.resolve(this.baseDiretorio, arquivo))));
489
- if (arquivosTipados.some((entrada) => entrada.explicito
490
- ? !explicitosPermitidos.has(chaveCaminho(entrada.caminho))
491
- : !this.caminhoPertenceRaizCatalogavel(entrada.caminho, diretoriosIgnorados))) {
492
- return false;
493
- }
494
- const caminhosRepresentados = new Set([
495
- ...diretorios
496
- .filter((entrada) => Boolean(entrada))
497
- .map((entrada) => chaveCaminho(entrada.caminho)),
498
- ...arquivosTipados.map((entrada) => chaveCaminho(entrada.caminho)),
499
- ]);
500
- if (this.raizes.some((raiz) => !caminhosRepresentados.has(chaveCaminho(raiz)))) {
501
- // Uma raiz ausente nao pode produzir um snapshot eterno: a criacao
502
- // posterior dessa raiz precisa forcar uma nova caminhada.
503
- return false;
504
- }
505
- const estadosArquivos = await mapearComLimite(arquivosTipados, this.concorrencia, async (entrada) => {
506
- if (!caminhoEstaDentro(this.baseDiretorio, entrada.caminho)
507
- || !await this.caminhoPermaneceNoWorkspace(entrada.caminho)) {
508
- return false;
509
- }
510
- try {
511
- const info = await lstat(entrada.caminho);
512
- return info.isFile()
513
- && !info.isSymbolicLink()
514
- && (!this.extensoesPermitidas
515
- || this.extensoesPermitidas.has(path.extname(entrada.caminho).toLowerCase()));
516
- }
517
- catch {
518
- return false;
519
- }
520
- });
521
- if (estadosArquivos.some((valido) => !valido)) {
522
- return false;
523
416
  }
524
- const diretoriosTipados = diretorios;
525
- const diretoriosAindaEstaveis = await mapearComLimite(diretoriosTipados, this.concorrencia, async (entrada) => {
526
- try {
527
- const info = await lstat(entrada.caminho, { bigint: true });
528
- return info.isDirectory()
529
- && !info.isSymbolicLink()
530
- && assinaturasDiretorioIguais(entrada.assinatura, assinaturaDiretorio(info));
531
- }
532
- catch {
533
- return false;
417
+ catch (erro) {
418
+ if (erroEhAusencia(erro)) {
419
+ return undefined;
534
420
  }
535
- });
536
- if (diretoriosAindaEstaveis.some((valido) => !valido)) {
537
- return false;
538
- }
539
- for (const entrada of arquivosTipados) {
540
- this.adicionarArquivo(entrada.caminho, entrada.explicito, false);
541
- }
542
- for (const entrada of diretoriosTipados) {
543
- this.diretoriosVisitados.set(entrada.caminho, { ...entrada.assinatura });
544
- }
545
- this.contadores.origem = "snapshot";
546
- return true;
547
- }
548
- relativoSeguro(caminho, permitirBase = false) {
549
- const relativo = path.relative(this.baseDiretorio, path.resolve(caminho)).replace(/\\/g, "/");
550
- if (!(permitirBase ? diretorioRelativoSeguro(relativo || ".") : caminhoRelativoSeguro(relativo))) {
551
- throw new Error(`caminho_snapshot_catalogo_invalido:${caminho}`);
421
+ throw erro;
552
422
  }
553
- return relativo || ".";
554
423
  }
555
- caminhoPertenceRaizCatalogavel(caminho, diretoriosIgnorados, incluirUltimoSegmento = false) {
556
- return this.raizes.some((raiz) => {
557
- if (!caminhoEstaDentro(raiz, caminho)) {
558
- return false;
559
- }
560
- const segmentos = path.relative(raiz, caminho)
561
- .split(path.sep)
562
- .filter(Boolean);
563
- if (!incluirUltimoSegmento) {
564
- segmentos.pop();
565
- }
566
- return segmentos.every((segmento) => !diretoriosIgnorados.has(segmento.toLowerCase()));
567
- });
568
- }
569
- async lerFisicamente(caminho) {
570
- if (!await this.caminhoPermaneceNoWorkspace(caminho)) {
571
- throw new Error(`Arquivo catalogado saiu do workspace real: ${caminho}`);
572
- }
424
+ async lerFisicamente(registro) {
425
+ const caminho = registro.caminho;
573
426
  const informacaoAntes = await lstat(caminho, { bigint: true });
574
- if (!informacaoAntes.isFile() || informacaoAntes.isSymbolicLink()) {
575
- throw new Error(`Arquivo catalogado deixou de ser arquivo regular: ${caminho}`);
427
+ const [baseReal, caminhoRealAntes] = await Promise.all([
428
+ this.baseDiretorioReal,
429
+ realpath(caminho),
430
+ ]);
431
+ if (!caminhoEstaDentro(baseReal, caminhoRealAntes)
432
+ || !identidadeCatalogadaCorresponde(registro.identidade, caminhoRealAntes, informacaoAntes)) {
433
+ throw new Error(`Arquivo catalogado mudou entre catalogacao e primeira leitura: ${caminho}`);
576
434
  }
577
435
  const handle = await open(caminho, "r");
578
436
  let bytes;
@@ -587,8 +445,8 @@ class CatalogoDriftImplementacao {
587
445
  lstat(caminho, { bigint: true }),
588
446
  realpath(caminho),
589
447
  ]);
590
- const baseReal = await this.baseDiretorioReal;
591
448
  if (!caminhoEstaDentro(baseReal, caminhoRealAberto)
449
+ || !identidadeCatalogadaCorresponde(registro.identidade, caminhoRealAberto, informacaoCaminhoAberto)
592
450
  || !identidadeArquivoEstavel(informacaoAntes, informacaoHandleAntes)
593
451
  || !identidadeArquivoEstavel(informacaoHandleAntes, informacaoCaminhoAberto)) {
594
452
  throw new Error(`Arquivo catalogado mudou durante abertura segura: ${caminho}`);
@@ -600,6 +458,7 @@ class CatalogoDriftImplementacao {
600
458
  realpath(caminho),
601
459
  ]);
602
460
  if (!caminhoEstaDentro(baseReal, caminhoRealDepois)
461
+ || !identidadeCatalogadaCorresponde(registro.identidade, caminhoRealDepois, informacaoCaminhoDepois)
603
462
  || !identidadeArquivoEstavel(informacaoHandleAntes, informacaoHandleDepois)
604
463
  || !identidadeArquivoEstavel(informacaoHandleDepois, informacaoCaminhoDepois)) {
605
464
  throw new Error(`Arquivo catalogado mudou durante leitura segura: ${caminho}`);
@@ -651,7 +510,7 @@ export async function criarCatalogoDrift(opcoes) {
651
510
  .map((diretorio) => diretorio.trim().toLowerCase())
652
511
  .filter(Boolean));
653
512
  const catalogo = new CatalogoDriftImplementacao(opcoes);
654
- await catalogo.construir(opcoes.arquivos ?? [], ignorados, opcoes.snapshot);
513
+ await catalogo.construir(opcoes.arquivos ?? [], ignorados);
655
514
  return catalogo;
656
515
  }
657
516
  //# sourceMappingURL=driftCatalogo.js.map
@@ -1,7 +1,6 @@
1
1
  import type { ContextoProjetoCarregado } from "./projeto.js";
2
2
  import type { ConfiguracaoEscopoDriftAplicada, EscopoDriftReal } from "./drift.part01.js";
3
3
  import type { CatalogoDrift } from "./driftCatalogo.js";
4
- import type { CacheIncrementalDrift } from "./driftCacheIncremental.js";
5
4
  export { extrairReferenciasLocaisDrift } from "./driftEscopoReferencias.js";
6
5
  export type EstrategiaEscopoDrift = "arquivos_vinculados" | "projeto";
7
6
  export type CoberturaEscopoDrift = "completa" | "parcial";
@@ -19,5 +18,4 @@ export interface PlanoEscopoDrift {
19
18
  dependencias: Record<string, string[]>;
20
19
  }
21
20
  export declare function planejarEscopoDrift(contexto: ContextoProjetoCarregado, configuracao: ConfiguracaoEscopoDriftAplicada): Promise<PlanoEscopoDrift>;
22
- export declare function expandirDependenciasPlanoDrift(contexto: ContextoProjetoCarregado, plano: PlanoEscopoDrift, catalogo: CatalogoDrift, cache?: CacheIncrementalDrift): Promise<PlanoEscopoDrift>;
23
- export declare function mapearDependenciasCatalogadasDrift(contexto: ContextoProjetoCarregado, catalogo: CatalogoDrift, cache: CacheIncrementalDrift, arquivos?: readonly string[]): Promise<Record<string, string[]>>;
21
+ export declare function expandirDependenciasPlanoDrift(contexto: ContextoProjetoCarregado, plano: PlanoEscopoDrift, catalogo: CatalogoDrift): Promise<PlanoEscopoDrift>;