@semacode/cli 2.3.0 → 3.0.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 (267) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +112 -41
  3. package/dist/agentContextPack.js +14 -10
  4. package/dist/agentEntryPoints.d.ts +5 -0
  5. package/dist/agentEntryPoints.js +102 -91
  6. package/dist/angular-consumer-standalone.d.ts +3 -1
  7. package/dist/angular-consumer-standalone.js +12 -8
  8. package/dist/bin.d.ts +6 -0
  9. package/dist/bin.js +130 -0
  10. package/dist/cliArgs.js +4 -4
  11. package/dist/cliControlError.d.ts +12 -0
  12. package/dist/cliControlError.js +47 -0
  13. package/dist/cliGrammar.d.ts +11 -0
  14. package/dist/cliGrammar.js +551 -0
  15. package/dist/cliHelp.d.ts +13 -0
  16. package/dist/cliHelp.js +19 -0
  17. package/dist/cliHelpTexto.d.ts +3 -0
  18. package/dist/cliHelpTexto.js +168 -0
  19. package/dist/cliRuntime.d.ts +2 -0
  20. package/dist/cliRuntime.js +31 -0
  21. package/dist/comandos.js +9 -22
  22. package/dist/contexto.js +5 -5
  23. package/dist/dev/index.d.ts +1 -0
  24. package/dist/dev/index.js +51 -9
  25. package/dist/discovery/catalog.js +3 -3
  26. package/dist/distribuicao/filesystemGlobal.d.ts +63 -0
  27. package/dist/distribuicao/filesystemGlobal.js +701 -0
  28. package/dist/distribuicao/index.d.ts +7 -0
  29. package/dist/distribuicao/index.js +227 -0
  30. package/dist/distribuicao/launcherGlobal.d.ts +53 -0
  31. package/dist/distribuicao/launcherGlobal.js +643 -0
  32. package/dist/distribuicao/launcherWindows.d.ts +28 -0
  33. package/dist/distribuicao/launcherWindows.js +326 -0
  34. package/dist/distribuicao/lockContextGlobal.d.ts +10 -0
  35. package/dist/distribuicao/lockContextGlobal.js +17 -0
  36. package/dist/distribuicao/lockGlobal.d.ts +6 -0
  37. package/dist/distribuicao/lockGlobal.js +520 -0
  38. package/dist/distribuicao/skillGlobal.d.ts +48 -0
  39. package/dist/distribuicao/skillGlobal.js +652 -0
  40. package/dist/distribuicao/skillIntentPolicy.d.ts +21 -0
  41. package/dist/distribuicao/skillIntentPolicy.js +115 -0
  42. package/dist/distribuicao/tipos.d.ts +50 -0
  43. package/dist/distribuicao/tipos.js +10 -0
  44. package/dist/distribuicao/versaoSemantica.d.ts +3 -0
  45. package/dist/distribuicao/versaoSemantica.js +62 -0
  46. package/dist/drift.part01.d.ts +34 -2
  47. package/dist/drift.part01.js +3 -0
  48. package/dist/drift.part04.d.ts +12 -2
  49. package/dist/drift.part04.js +89 -15
  50. package/dist/drift.part05.d.ts +2 -1
  51. package/dist/drift.part05.js +9 -6
  52. package/dist/drift.part06.d.ts +2 -1
  53. package/dist/drift.part06.js +115 -24
  54. package/dist/drift.part07.d.ts +11 -10
  55. package/dist/drift.part07.js +261 -255
  56. package/dist/drift.part08.d.ts +2 -1
  57. package/dist/drift.part08.js +35 -25
  58. package/dist/drift.part11.js +279 -32
  59. package/dist/drift.part12.d.ts +1 -1
  60. package/dist/drift.part12.js +196 -11
  61. package/dist/drift.part13.d.ts +18 -2
  62. package/dist/drift.part13.js +654 -76
  63. package/dist/drift.part14.js +21 -7
  64. package/dist/driftCacheCas.d.ts +43 -0
  65. package/dist/driftCacheCas.js +351 -0
  66. package/dist/driftCacheFilesystem.d.ts +64 -0
  67. package/dist/driftCacheFilesystem.js +313 -0
  68. package/dist/driftCacheModes.d.ts +38 -0
  69. package/dist/driftCacheModes.js +147 -0
  70. package/dist/driftCacheStore.d.ts +80 -0
  71. package/dist/driftCacheStore.js +603 -0
  72. package/dist/driftCatalogo.d.ts +65 -0
  73. package/dist/driftCatalogo.js +516 -0
  74. package/dist/driftEscopo.d.ts +21 -0
  75. package/dist/driftEscopo.js +647 -0
  76. package/dist/driftEscopoReferencias.d.ts +8 -0
  77. package/dist/driftEscopoReferencias.js +612 -0
  78. package/dist/driftOrcamento.d.ts +6 -0
  79. package/dist/driftOrcamento.js +20 -3
  80. package/dist/geracaoCore.js +4 -6
  81. package/dist/iaPrompts.d.ts +3 -3
  82. package/dist/iaPrompts.js +13 -14
  83. package/dist/index.d.ts +4 -1
  84. package/dist/index.js +6 -25
  85. package/dist/index.part01.d.ts +21 -14
  86. package/dist/index.part01.js +20 -165
  87. package/dist/index.part02.js +57 -43
  88. package/dist/index.part03.d.ts +23 -1
  89. package/dist/index.part03.js +83 -8
  90. package/dist/index.part04.d.ts +10 -2
  91. package/dist/index.part04.js +48 -14
  92. package/dist/index.part05.d.ts +1 -1
  93. package/dist/index.part05.js +109 -30
  94. package/dist/index.part06.js +34 -16
  95. package/dist/index.part07.js +31 -27
  96. package/dist/index.part08.d.ts +1 -1
  97. package/dist/index.part08.js +23 -28
  98. package/dist/init/templates.part01.js +393 -393
  99. package/dist/init/templates.part02.js +189 -189
  100. package/dist/initCommand.js +5 -1
  101. package/dist/initTemplatesBackend.js +73 -73
  102. package/dist/initTemplatesBase.js +7 -5
  103. package/dist/initTemplatesFlutter.js +137 -137
  104. package/dist/initTemplatesRuntime.js +350 -350
  105. package/dist/initTemplatesWeb.js +309 -309
  106. package/dist/pipelineConteudo/command.d.ts +1 -0
  107. package/dist/pipelineConteudo/command.js +4 -32
  108. package/dist/pipelineConteudo/help.d.ts +2 -0
  109. package/dist/pipelineConteudo/help.js +33 -0
  110. package/dist/profileAuthorCommand.js +3 -7
  111. package/dist/profileCommand.js +3 -7
  112. package/dist/projeto.d.ts +1 -1
  113. package/dist/projetoCarregar.d.ts +2 -2
  114. package/dist/projetoCarregar.js +69 -28
  115. package/dist/projetoCatalogo.d.ts +8 -0
  116. package/dist/projetoCatalogo.js +164 -0
  117. package/dist/projetoOrigens.d.ts +2 -0
  118. package/dist/projetoOrigens.js +65 -9
  119. package/dist/projetoTipos.d.ts +15 -5
  120. package/dist/resultadoCli.d.ts +20 -0
  121. package/dist/resultadoCli.js +57 -0
  122. package/dist/saidaCli.d.ts +35 -0
  123. package/dist/saidaCli.js +118 -0
  124. package/dist/sistemasInterativos/acceptanceEvidence.d.ts +22 -0
  125. package/dist/sistemasInterativos/acceptanceEvidence.js +345 -0
  126. package/dist/sistemasInterativos/engineObservation.d.ts +12 -0
  127. package/dist/sistemasInterativos/engineObservation.js +438 -0
  128. package/dist/sistemasInterativos/jobOrchestration.d.ts +2 -0
  129. package/dist/sistemasInterativos/jobOrchestration.js +204 -0
  130. package/dist/sistemasInterativos/operationPrimitives.d.ts +21 -0
  131. package/dist/sistemasInterativos/operationPrimitives.js +194 -0
  132. package/dist/sistemasInterativos/operations.d.ts +4 -39
  133. package/dist/sistemasInterativos/operations.js +5 -1164
  134. package/dist/skillCommand.d.ts +5 -0
  135. package/dist/skillCommand.js +88 -0
  136. package/dist/sync/index.js +35 -35
  137. package/docs/README.md +11 -7
  138. package/docs/ai-integration.md +18 -11
  139. package/docs/ai-onboarding.md +81 -62
  140. package/docs/ai-workflow.md +10 -4
  141. package/docs/auth.md +26 -26
  142. package/docs/cli.md +197 -79
  143. package/docs/commands.md +30 -6
  144. package/docs/database.md +15 -15
  145. package/docs/deploy.md +54 -41
  146. package/docs/documentation.md +11 -10
  147. package/docs/drift-cache.md +108 -0
  148. package/docs/env.md +16 -16
  149. package/docs/frontend.md +41 -41
  150. package/docs/getting-started.md +82 -57
  151. package/docs/i18n.md +15 -15
  152. package/docs/repositories.md +60 -43
  153. package/docs/rollback.md +38 -31
  154. package/docs/security.md +54 -32
  155. package/docs/sistemas-interativos.md +27 -27
  156. package/docs/support.md +8 -8
  157. package/docs/testing.md +123 -17
  158. package/docs/vocabulary.md +29 -29
  159. package/exemplos/agendamento.sema +1 -1
  160. package/exemplos/assinatura.sema +1 -1
  161. package/exemplos/auditoria.sema +1 -1
  162. package/exemplos/autenticacao.sema +1 -1
  163. package/exemplos/author_obra_comum.sema +1 -1
  164. package/exemplos/author_tema_sensivel.sema +1 -1
  165. package/exemplos/automacao.sema +1 -1
  166. package/exemplos/cadastro_usuario.sema +1 -1
  167. package/exemplos/calculadora.sema +1 -1
  168. package/exemplos/crud_simples.sema +1 -1
  169. package/exemplos/estoque.sema +1 -1
  170. package/exemplos/exportacao.sema +1 -1
  171. package/exemplos/fila.sema +1 -1
  172. package/exemplos/integracao_externa.sema +1 -1
  173. package/exemplos/multi_tenant.sema +1 -1
  174. package/exemplos/notificacao.sema +1 -1
  175. package/exemplos/operacao_estrategia.sema +132 -132
  176. package/exemplos/operacao_estrategia_discovery.sema +220 -220
  177. package/exemplos/operacao_estrategia_fluxo.sema +114 -114
  178. package/exemplos/operacao_estrategia_gates.sema +106 -106
  179. package/exemplos/operacao_estrategia_quarentena.sema +133 -133
  180. package/exemplos/operacao_estrategia_rollout.sema +124 -124
  181. package/exemplos/pagamento.sema +1 -1
  182. package/exemplos/pagamento_dominio.sema +1 -1
  183. package/exemplos/pedido.sema +1 -1
  184. package/exemplos/permissao.sema +1 -1
  185. package/exemplos/persistencia_vendor_first.sema +1 -1
  186. package/exemplos/profile_conversas.sema +165 -165
  187. package/exemplos/profile_game.sema +1 -1
  188. package/exemplos/profile_legal.sema +1 -1
  189. package/exemplos/profile_ops.sema +1 -1
  190. package/exemplos/profile_research.sema +1 -1
  191. package/exemplos/profile_software.sema +1 -1
  192. package/exemplos/profile_workflow_n8n.sema +1 -1
  193. package/exemplos/relatorio.sema +1 -1
  194. package/exemplos/replica_analitica_erp.sema +1 -1
  195. package/exemplos/testes_embutidos.sema +1 -1
  196. package/exemplos/tratamento_erro.sema +1 -1
  197. package/exemplos/upload_arquivo.sema +1 -1
  198. package/exemplos/webhook.sema +1 -1
  199. package/node_modules/@sema/gerador-cpp/dist/index.js +176 -176
  200. package/node_modules/@sema/gerador-css/dist/index.part01.js +10 -10
  201. package/node_modules/@sema/gerador-css/dist/index.part02.js +460 -460
  202. package/node_modules/@sema/gerador-dotnet/dist/index.js +169 -169
  203. package/node_modules/@sema/gerador-html/dist/index.js +17 -17
  204. package/node_modules/@sema/gerador-python/dist/index.part02.js +3 -3
  205. package/node_modules/@sema/gerador-typescript/dist/index.part02.js +11 -11
  206. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +42 -42
  207. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +1 -0
  208. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +1 -0
  209. package/package.json +7 -2
  210. package/scripts/postinstall.mjs +148 -0
  211. package/skills/sema/SKILL.md +199 -0
  212. package/skills/sema/agents/openai.yaml +4 -0
  213. package/node_modules/@sema/gerador-cpp/dist/index.js.map +0 -1
  214. package/node_modules/@sema/gerador-css/dist/index.js.map +0 -1
  215. package/node_modules/@sema/gerador-css/dist/index.part01.js.map +0 -1
  216. package/node_modules/@sema/gerador-css/dist/index.part02.js.map +0 -1
  217. package/node_modules/@sema/gerador-dart/dist/index.js.map +0 -1
  218. package/node_modules/@sema/gerador-dotnet/dist/index.js.map +0 -1
  219. package/node_modules/@sema/gerador-html/dist/index.js.map +0 -1
  220. package/node_modules/@sema/gerador-javascript/dist/index.js.map +0 -1
  221. package/node_modules/@sema/gerador-lua/dist/index.js.map +0 -1
  222. package/node_modules/@sema/gerador-php/dist/index.js.map +0 -1
  223. package/node_modules/@sema/gerador-python/dist/index.js.map +0 -1
  224. package/node_modules/@sema/gerador-python/dist/index.part01.js.map +0 -1
  225. package/node_modules/@sema/gerador-python/dist/index.part02.js.map +0 -1
  226. package/node_modules/@sema/gerador-typescript/dist/index.js.map +0 -1
  227. package/node_modules/@sema/gerador-typescript/dist/index.part01.js.map +0 -1
  228. package/node_modules/@sema/gerador-typescript/dist/index.part02.js.map +0 -1
  229. package/node_modules/@sema/gerador-typescript/dist/index.part03.js.map +0 -1
  230. package/node_modules/@sema/nucleo/dist/ast/tipos.js.map +0 -1
  231. package/node_modules/@sema/nucleo/dist/diagnosticos/index.js.map +0 -1
  232. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +0 -1
  233. package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.js.map +0 -1
  234. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +0 -1
  235. package/node_modules/@sema/nucleo/dist/formatador/index.part01.js.map +0 -1
  236. package/node_modules/@sema/nucleo/dist/formatador/index.part02.js.map +0 -1
  237. package/node_modules/@sema/nucleo/dist/index.js.map +0 -1
  238. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +0 -1
  239. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js.map +0 -1
  240. package/node_modules/@sema/nucleo/dist/ir/conversor.part02.js.map +0 -1
  241. package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js.map +0 -1
  242. package/node_modules/@sema/nucleo/dist/ir/modelos.js.map +0 -1
  243. package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +0 -1
  244. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +0 -1
  245. package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js.map +0 -1
  246. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +0 -1
  247. package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js.map +0 -1
  248. package/node_modules/@sema/nucleo/dist/parser/parser.part01.js.map +0 -1
  249. package/node_modules/@sema/nucleo/dist/parser/parser.part02.js.map +0 -1
  250. package/node_modules/@sema/nucleo/dist/parser/parser.part03.js.map +0 -1
  251. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +0 -1
  252. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +0 -1
  253. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js.map +0 -1
  254. package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.js.map +0 -1
  255. package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.js.map +0 -1
  256. package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.js.map +0 -1
  257. package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.js.map +0 -1
  258. package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.js.map +0 -1
  259. package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.js.map +0 -1
  260. package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js.map +0 -1
  261. package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +0 -1
  262. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.js.map +0 -1
  263. package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.js.map +0 -1
  264. package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.js.map +0 -1
  265. package/node_modules/@sema/nucleo/dist/semantico/seguranca.js.map +0 -1
  266. package/node_modules/@sema/nucleo/dist/util/arquivos.js.map +0 -1
  267. package/node_modules/@sema/padroes/dist/index.js.map +0 -1
@@ -0,0 +1,520 @@
1
+ // SEMA-GOVERNED: sema.produto.distribuicao_global, sema.produto.distribuicao_global.transacao
2
+ // Descrição: serializa transações globais por HOME com lease, identidade e nonce verificáveis.
3
+ import { randomUUID } from "node:crypto";
4
+ import { constants } from "node:fs";
5
+ import { link, lstat, open, readdir, unlink } from "node:fs/promises";
6
+ import os from "node:os";
7
+ import { threadId } from "node:worker_threads";
8
+ import { FalhaDistribuicaoGlobal, caminhosIguais, identidadeDiretorioSeguro, lstatOuNull, mesmaIdentidadeDiretorio, removerArquivoSeguro, resolverDentroDaHome, resolverHomeReal, } from "./filesystemGlobal.js";
9
+ import { executarComTokenLockDistribuicaoGlobal, tokenLockDistribuicaoGlobalAtual, } from "./lockContextGlobal.js";
10
+ const ESQUEMA_LOCK = "sema.distribuicao-global-lock/v1";
11
+ const NOME_LOCK = ".sema-distribuicao-global.lock";
12
+ const PREFIXO_TEMP_LOCK = `${NOME_LOCK}.`;
13
+ const LIMITE_LOCK_BYTES = 4096;
14
+ const TIMEOUT_LOCK_MS = 30_000;
15
+ const LEASE_STALE_MS = 15_000;
16
+ const HEARTBEAT_MS = 2_000;
17
+ const OBSERVACAO_RECLAIM_MS = HEARTBEAT_MS + 250;
18
+ const INTERVALO_MINIMO_MS = 20;
19
+ const INTERVALO_VARIACAO_MS = 30;
20
+ const filasLocais = new Map();
21
+ function mesmaIdentidade(a, b) {
22
+ return a.dev === b.dev && a.ino === b.ino;
23
+ }
24
+ function chavesExatas(valor, esperadas) {
25
+ const atuais = Object.keys(valor).sort();
26
+ const ordenadas = [...esperadas].sort();
27
+ return atuais.length === ordenadas.length
28
+ && atuais.every((chave, indice) => chave === ordenadas[indice]);
29
+ }
30
+ function reciboValido(valor) {
31
+ if (!valor || typeof valor !== "object" || Array.isArray(valor))
32
+ return false;
33
+ const candidato = valor;
34
+ return chavesExatas(candidato, ["schema", "pid", "threadId", "nonce", "criadoEm"])
35
+ && candidato.schema === ESQUEMA_LOCK
36
+ && Number.isSafeInteger(candidato.pid)
37
+ && (candidato.pid ?? 0) > 0
38
+ && Number.isSafeInteger(candidato.threadId)
39
+ && (candidato.threadId ?? -1) >= 0
40
+ && typeof candidato.nonce === "string"
41
+ && /^[a-f0-9-]{36}$/u.test(candidato.nonce)
42
+ && typeof candidato.criadoEm === "string"
43
+ && Number.isFinite(Date.parse(candidato.criadoEm));
44
+ }
45
+ function processoVivo(pid) {
46
+ try {
47
+ process.kill(pid, 0);
48
+ return true;
49
+ }
50
+ catch (erro) {
51
+ const codigo = erro.code;
52
+ return codigo !== "ESRCH";
53
+ }
54
+ }
55
+ function idadeMs(info) {
56
+ return Math.max(0, Date.now() - Number(info.mtimeMs));
57
+ }
58
+ function esperar(ms) {
59
+ return new Promise((resolve) => setTimeout(resolve, ms));
60
+ }
61
+ async function entrarFilaLocal(homeReal) {
62
+ const chave = process.platform === "win32" ? homeReal.toLocaleLowerCase("en-US") : homeReal;
63
+ const anterior = filasLocais.get(chave);
64
+ let resolver;
65
+ const atual = new Promise((resolve) => {
66
+ resolver = resolve;
67
+ });
68
+ filasLocais.set(chave, atual);
69
+ if (anterior)
70
+ await anterior;
71
+ return () => {
72
+ if (filasLocais.get(chave) === atual)
73
+ filasLocais.delete(chave);
74
+ resolver();
75
+ };
76
+ }
77
+ async function inspecionarArquivoLock(caminho) {
78
+ const infoAntes = await lstat(caminho, { bigint: true });
79
+ if (!infoAntes.isFile() || infoAntes.isSymbolicLink()
80
+ || infoAntes.nlink < 1n || infoAntes.nlink > 2n
81
+ || infoAntes.size > BigInt(LIMITE_LOCK_BYTES)) {
82
+ return { info: infoAntes, recibo: null };
83
+ }
84
+ const handle = await open(caminho, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
85
+ try {
86
+ const infoHandle = await handle.stat({ bigint: true });
87
+ if (!mesmaIdentidade(infoAntes, infoHandle) || infoHandle.nlink !== infoAntes.nlink) {
88
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
89
+ }
90
+ const bytes = await handle.readFile();
91
+ const infoDepois = await lstat(caminho, { bigint: true });
92
+ if (bytes.byteLength > LIMITE_LOCK_BYTES
93
+ || !mesmaIdentidade(infoAntes, infoDepois)
94
+ || infoDepois.nlink !== infoAntes.nlink) {
95
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
96
+ }
97
+ try {
98
+ const valor = JSON.parse(bytes.toString("utf8"));
99
+ return { info: infoDepois, recibo: reciboValido(valor) ? valor : null };
100
+ }
101
+ catch {
102
+ return { info: infoDepois, recibo: null };
103
+ }
104
+ }
105
+ catch {
106
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
107
+ }
108
+ finally {
109
+ await handle.close().catch(() => undefined);
110
+ }
111
+ }
112
+ function nomeTempLock(nonce) {
113
+ return `${PREFIXO_TEMP_LOCK}${nonce}.tmp`;
114
+ }
115
+ function nomeReclaimLock(nonce) {
116
+ return `${NOME_LOCK}.reclaim.${nonce}`;
117
+ }
118
+ async function inspecionarLockFinal(homeReal, caminho) {
119
+ const inspecao = await inspecionarArquivoLock(caminho);
120
+ if (!inspecao.recibo || inspecao.info.nlink === 1n)
121
+ return inspecao;
122
+ for (const [tipo, nome] of [
123
+ ["tempPublicado", nomeTempLock(inspecao.recibo.nonce)],
124
+ ["reclaimPublicado", nomeReclaimLock(inspecao.recibo.nonce)],
125
+ ]) {
126
+ const auxiliar = resolverDentroDaHome(homeReal, nome);
127
+ const infoAuxiliar = await lstatOuNull(auxiliar);
128
+ if (infoAuxiliar?.isFile() && !infoAuxiliar.isSymbolicLink()
129
+ && infoAuxiliar.nlink === 2n && mesmaIdentidade(inspecao.info, infoAuxiliar)) {
130
+ return { ...inspecao, [tipo]: auxiliar };
131
+ }
132
+ }
133
+ return { ...inspecao, recibo: null };
134
+ }
135
+ async function removerTempPublicado(homeReal, caminhoFinal, caminhoTemp, identidade) {
136
+ const identidadePai = await identidadeDiretorioSeguro(homeReal);
137
+ const [finalAntes, tempAntes] = await Promise.all([
138
+ lstat(caminhoFinal, { bigint: true }),
139
+ lstat(caminhoTemp, { bigint: true }),
140
+ ]);
141
+ if (!finalAntes.isFile() || finalAntes.isSymbolicLink()
142
+ || !tempAntes.isFile() || tempAntes.isSymbolicLink()
143
+ || finalAntes.nlink !== 2n || tempAntes.nlink !== 2n
144
+ || !mesmaIdentidade(finalAntes, tempAntes)
145
+ || !mesmaIdentidade(finalAntes, identidade)) {
146
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
147
+ }
148
+ await unlink(caminhoTemp);
149
+ const [finalDepois, paiDepois] = await Promise.all([
150
+ lstat(caminhoFinal, { bigint: true }),
151
+ identidadeDiretorioSeguro(homeReal),
152
+ ]);
153
+ if (finalDepois.nlink !== 1n
154
+ || !mesmaIdentidade(finalDepois, identidade)
155
+ || !mesmaIdentidadeDiretorio(identidadePai, paiDepois)) {
156
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
157
+ }
158
+ }
159
+ async function removerAuxiliarCriado(homeReal, caminho) {
160
+ const identidadePai = await identidadeDiretorioSeguro(homeReal);
161
+ const antes = await lstat(caminho, { bigint: true });
162
+ if (!antes.isFile() || antes.isSymbolicLink()
163
+ || antes.nlink < 1n || antes.nlink > 2n) {
164
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
165
+ }
166
+ await unlink(caminho);
167
+ const paiDepois = await identidadeDiretorioSeguro(homeReal);
168
+ if (!mesmaIdentidadeDiretorio(identidadePai, paiDepois)) {
169
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
170
+ }
171
+ }
172
+ async function limparTemporariosObsoletos(homeReal) {
173
+ const padroes = [
174
+ /^\.sema-distribuicao-global\.lock\.([a-f0-9-]{36})\.tmp$/u,
175
+ /^\.sema-distribuicao-global\.lock\.reclaim\.([a-f0-9-]{36})$/u,
176
+ ];
177
+ const entradas = await readdir(homeReal, { withFileTypes: true });
178
+ for (const entrada of entradas) {
179
+ const nonceNome = padroes.map((padrao) => entrada.name.match(padrao)?.[1])
180
+ .find((nonce) => nonce !== undefined);
181
+ if (!nonceNome || !entrada.isFile())
182
+ continue;
183
+ const caminho = resolverDentroDaHome(homeReal, entrada.name);
184
+ const info = await lstatOuNull(caminho);
185
+ if (!info || info.nlink !== 1n)
186
+ continue;
187
+ let inspecao;
188
+ try {
189
+ inspecao = await inspecionarArquivoLock(caminho);
190
+ }
191
+ catch {
192
+ continue;
193
+ }
194
+ const receiptDoProprioTemp = inspecao.recibo?.nonce === nonceNome;
195
+ if (!receiptDoProprioTemp)
196
+ continue;
197
+ const expirado = idadeMs(inspecao.info) >= LEASE_STALE_MS;
198
+ const donoMorto = !processoVivo(inspecao.recibo.pid);
199
+ if (!donoMorto && !expirado)
200
+ continue;
201
+ await removerArquivoSeguro(homeReal, caminho, {
202
+ dev: inspecao.info.dev,
203
+ ino: inspecao.info.ino,
204
+ }).catch(() => undefined);
205
+ }
206
+ }
207
+ async function removerFinalCercado(homeReal, caminhoFinal, caminhoCerca, identidade) {
208
+ const identidadePai = await identidadeDiretorioSeguro(homeReal);
209
+ const [finalAntes, cercaAntes] = await Promise.all([
210
+ lstat(caminhoFinal, { bigint: true }),
211
+ lstat(caminhoCerca, { bigint: true }),
212
+ ]);
213
+ if (!finalAntes.isFile() || finalAntes.isSymbolicLink()
214
+ || !cercaAntes.isFile() || cercaAntes.isSymbolicLink()
215
+ || finalAntes.nlink !== 2n || cercaAntes.nlink !== 2n
216
+ || !mesmaIdentidade(finalAntes, cercaAntes)
217
+ || !mesmaIdentidade(finalAntes, identidade)) {
218
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
219
+ }
220
+ await unlink(caminhoFinal);
221
+ const [cercaDepois, paiDepois] = await Promise.all([
222
+ lstat(caminhoCerca, { bigint: true }),
223
+ identidadeDiretorioSeguro(homeReal),
224
+ ]);
225
+ if (cercaDepois.nlink !== 1n
226
+ || !mesmaIdentidade(cercaDepois, identidade)
227
+ || !mesmaIdentidadeDiretorio(identidadePai, paiDepois)) {
228
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
229
+ }
230
+ await removerArquivoSeguro(homeReal, caminhoCerca, identidade);
231
+ }
232
+ async function cercarLockParaReclaim(homeReal, caminho, inspecao) {
233
+ const recibo = inspecao.recibo;
234
+ const reclaim = resolverDentroDaHome(homeReal, nomeReclaimLock(recibo.nonce));
235
+ let criado = false;
236
+ try {
237
+ await link(caminho, reclaim);
238
+ criado = true;
239
+ }
240
+ catch (erro) {
241
+ if (erro.code !== "EEXIST")
242
+ throw erro;
243
+ const existente = await lstatOuNull(reclaim);
244
+ if (!existente || existente.nlink !== 2n
245
+ || !mesmaIdentidade(existente, inspecao.info)) {
246
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "CONTEUDO_NAO_GERENCIADO");
247
+ }
248
+ }
249
+ try {
250
+ const cercado = await inspecionarLockFinal(homeReal, caminho);
251
+ if (!cercado.reclaimPublicado || !mesmaIdentidade(cercado.info, inspecao.info)) {
252
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
253
+ }
254
+ return cercado;
255
+ }
256
+ catch (erro) {
257
+ if (criado && await lstatOuNull(reclaim)) {
258
+ await removerAuxiliarCriado(homeReal, reclaim).catch(() => undefined);
259
+ }
260
+ throw erro;
261
+ }
262
+ }
263
+ async function concluirReclaimCercado(homeReal, caminho, inspecao, mtimeObservado, observarHeartbeat) {
264
+ if (!inspecao.reclaimPublicado) {
265
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
266
+ }
267
+ if (Number(inspecao.info.mtimeMs) > mtimeObservado) {
268
+ await removerTempPublicado(homeReal, caminho, inspecao.reclaimPublicado, { dev: inspecao.info.dev, ino: inspecao.info.ino });
269
+ return false;
270
+ }
271
+ if (observarHeartbeat)
272
+ await esperar(OBSERVACAO_RECLAIM_MS);
273
+ let depois;
274
+ try {
275
+ depois = await inspecionarLockFinal(homeReal, caminho);
276
+ }
277
+ catch (erro) {
278
+ if (["ENOENT", "ENOTDIR"].includes(erro.code ?? ""))
279
+ return true;
280
+ throw erro;
281
+ }
282
+ if (!mesmaIdentidade(depois.info, inspecao.info))
283
+ return false;
284
+ if (!depois.reclaimPublicado)
285
+ return false;
286
+ if (Number(depois.info.mtimeMs) > mtimeObservado) {
287
+ await removerTempPublicado(homeReal, caminho, depois.reclaimPublicado, { dev: depois.info.dev, ino: depois.info.ino });
288
+ return false;
289
+ }
290
+ await removerFinalCercado(homeReal, caminho, depois.reclaimPublicado, { dev: depois.info.dev, ino: depois.info.ino });
291
+ return true;
292
+ }
293
+ async function removerLockObsoleto(homeReal, caminho) {
294
+ let inspecao;
295
+ try {
296
+ inspecao = await inspecionarLockFinal(homeReal, caminho);
297
+ }
298
+ catch (erro) {
299
+ if (["ENOENT", "ENOTDIR"].includes(erro.code ?? ""))
300
+ return true;
301
+ throw erro;
302
+ }
303
+ if (!inspecao.recibo) {
304
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "CONTEUDO_NAO_GERENCIADO");
305
+ }
306
+ const expirado = idadeMs(inspecao.info) >= LEASE_STALE_MS;
307
+ const donoVivo = processoVivo(inspecao.recibo.pid);
308
+ if (!expirado && donoVivo) {
309
+ if (inspecao.reclaimPublicado) {
310
+ await removerTempPublicado(homeReal, caminho, inspecao.reclaimPublicado, { dev: inspecao.info.dev, ino: inspecao.info.ino });
311
+ }
312
+ return false;
313
+ }
314
+ if (inspecao.tempPublicado) {
315
+ await removerFinalCercado(homeReal, caminho, inspecao.tempPublicado, { dev: inspecao.info.dev, ino: inspecao.info.ino });
316
+ return true;
317
+ }
318
+ const mtimeObservado = Number(inspecao.info.mtimeMs);
319
+ const cercado = inspecao.reclaimPublicado
320
+ ? inspecao
321
+ : await cercarLockParaReclaim(homeReal, caminho, inspecao);
322
+ return concluirReclaimCercado(homeReal, caminho, cercado, mtimeObservado, donoVivo);
323
+ }
324
+ async function publicarLock(homeReal, caminhoFinal, caminhoTemp, identidade) {
325
+ const identidadePai = await identidadeDiretorioSeguro(homeReal);
326
+ await link(caminhoTemp, caminhoFinal);
327
+ const paiDepoisLink = await identidadeDiretorioSeguro(homeReal);
328
+ if (!mesmaIdentidadeDiretorio(identidadePai, paiDepoisLink)) {
329
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
330
+ }
331
+ await removerTempPublicado(homeReal, caminhoFinal, caminhoTemp, identidade);
332
+ }
333
+ async function confirmarOwnershipLock(lock, homeReal) {
334
+ if (!lock.ativo || !caminhosIguais(lock.homeReal, homeReal)) {
335
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
336
+ }
337
+ try {
338
+ const inspecao = await inspecionarLockFinal(lock.homeReal, lock.caminho);
339
+ if (inspecao.info.nlink !== 1n
340
+ || !mesmaIdentidade(lock.identidade, inspecao.info)
341
+ || inspecao.recibo?.nonce !== lock.nonce
342
+ || inspecao.recibo.pid !== process.pid
343
+ || inspecao.recibo.threadId !== threadId) {
344
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
345
+ }
346
+ }
347
+ catch {
348
+ lock.ativo = false;
349
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
350
+ }
351
+ }
352
+ async function tentarAdquirir(homeReal, caminho) {
353
+ const nonce = randomUUID();
354
+ const caminhoTemp = resolverDentroDaHome(homeReal, nomeTempLock(nonce));
355
+ const handle = await open(caminhoTemp, constants.O_CREAT | constants.O_EXCL | constants.O_RDWR, 0o600);
356
+ let identidade;
357
+ let publicado = false;
358
+ try {
359
+ const infoHandle = await handle.stat({ bigint: true });
360
+ identidade = { dev: infoHandle.dev, ino: infoHandle.ino };
361
+ const recibo = {
362
+ schema: ESQUEMA_LOCK,
363
+ pid: process.pid,
364
+ threadId,
365
+ nonce,
366
+ criadoEm: new Date().toISOString(),
367
+ };
368
+ await handle.writeFile(`${JSON.stringify(recibo)}\n`, "utf8");
369
+ await handle.sync();
370
+ const tempValidado = await inspecionarArquivoLock(caminhoTemp);
371
+ if (!tempValidado.recibo
372
+ || tempValidado.recibo.nonce !== nonce
373
+ || !mesmaIdentidade(identidade, tempValidado.info)) {
374
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
375
+ }
376
+ try {
377
+ await publicarLock(homeReal, caminho, caminhoTemp, identidade);
378
+ publicado = true;
379
+ }
380
+ catch (erro) {
381
+ if (erro.code !== "EEXIST")
382
+ throw erro;
383
+ await handle.close().catch(() => undefined);
384
+ await removerArquivoSeguro(homeReal, caminhoTemp, identidade);
385
+ try {
386
+ await removerLockObsoleto(homeReal, caminho);
387
+ }
388
+ catch (falha) {
389
+ if (!(falha instanceof FalhaDistribuicaoGlobal)
390
+ || falha.codigo !== "LOCK_PERDIDO")
391
+ throw falha;
392
+ // Troca legítima de owner entre EEXIST e inspeção: volta ao loop.
393
+ }
394
+ return null;
395
+ }
396
+ let lock;
397
+ const heartbeat = setInterval(() => {
398
+ if (!lock.ativo)
399
+ return;
400
+ const agora = new Date();
401
+ void handle.utimes(agora, agora).catch(() => {
402
+ lock.ativo = false;
403
+ });
404
+ }, HEARTBEAT_MS);
405
+ heartbeat.unref();
406
+ lock = {
407
+ homeReal,
408
+ caminho,
409
+ identidade,
410
+ handle,
411
+ recibo,
412
+ nonce: recibo.nonce,
413
+ ativo: true,
414
+ encerrado: false,
415
+ confirmar: async (homeConfirmada) => confirmarOwnershipLock(lock, homeConfirmada),
416
+ heartbeat,
417
+ };
418
+ return lock;
419
+ }
420
+ catch (erro) {
421
+ await handle.close().catch(() => undefined);
422
+ if (publicado && identidade) {
423
+ await removerArquivoSeguro(homeReal, caminho, identidade).catch(() => undefined);
424
+ }
425
+ else if (identidade) {
426
+ await removerArquivoSeguro(homeReal, caminhoTemp, identidade).catch(() => undefined);
427
+ }
428
+ throw erro;
429
+ }
430
+ }
431
+ async function adquirirLock(homeReal) {
432
+ const caminho = resolverDentroDaHome(homeReal, NOME_LOCK);
433
+ const limite = Date.now() + TIMEOUT_LOCK_MS;
434
+ while (Date.now() < limite) {
435
+ await limparTemporariosObsoletos(homeReal);
436
+ const adquirido = await tentarAdquirir(homeReal, caminho);
437
+ if (adquirido)
438
+ return adquirido;
439
+ await esperar(INTERVALO_MINIMO_MS + Math.floor(Math.random() * INTERVALO_VARIACAO_MS));
440
+ }
441
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_TIMEOUT");
442
+ }
443
+ async function liberarLock(lock) {
444
+ clearInterval(lock.heartbeat);
445
+ try {
446
+ try {
447
+ const inspecao = await inspecionarLockFinal(lock.homeReal, lock.caminho);
448
+ if (!mesmaIdentidade(lock.identidade, inspecao.info)
449
+ || inspecao.info.nlink !== 1n
450
+ || inspecao.recibo?.nonce !== lock.nonce
451
+ || inspecao.recibo.pid !== process.pid
452
+ || inspecao.recibo.threadId !== threadId) {
453
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
454
+ }
455
+ }
456
+ catch (erro) {
457
+ if (erro instanceof FalhaDistribuicaoGlobal && erro.codigo === "LOCK_PERDIDO")
458
+ throw erro;
459
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
460
+ }
461
+ }
462
+ finally {
463
+ await lock.handle.close().catch(() => undefined);
464
+ }
465
+ const identidadePai = await identidadeDiretorioSeguro(lock.homeReal);
466
+ const antesUnlink = await lstat(lock.caminho, { bigint: true });
467
+ if (!antesUnlink.isFile() || antesUnlink.isSymbolicLink()
468
+ || antesUnlink.nlink !== 1n
469
+ || !mesmaIdentidade(antesUnlink, lock.identidade)) {
470
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
471
+ }
472
+ await unlink(lock.caminho);
473
+ const paiDepois = await identidadeDiretorioSeguro(lock.homeReal);
474
+ if (!mesmaIdentidadeDiretorio(identidadePai, paiDepois)) {
475
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
476
+ }
477
+ }
478
+ export async function comLockDistribuicaoGlobal(opcoes, operacao) {
479
+ const homeReal = await resolverHomeReal(opcoes.diretorioUsuario ?? os.homedir());
480
+ const atual = tokenLockDistribuicaoGlobalAtual();
481
+ if (atual && caminhosIguais(atual.homeReal, homeReal)) {
482
+ if (atual.ativo)
483
+ return operacao({ diretorioUsuario: homeReal });
484
+ if (!atual.encerrado) {
485
+ throw new FalhaDistribuicaoGlobal("BROKEN_TARGET", "LOCK_PERDIDO");
486
+ }
487
+ }
488
+ const sairFila = await entrarFilaLocal(homeReal);
489
+ try {
490
+ const lock = await adquirirLock(homeReal);
491
+ let resultado;
492
+ let erroOperacao;
493
+ try {
494
+ resultado = await executarComTokenLockDistribuicaoGlobal(lock, async () => (operacao({ diretorioUsuario: homeReal })));
495
+ }
496
+ catch (erro) {
497
+ erroOperacao = erro;
498
+ }
499
+ lock.ativo = false;
500
+ lock.encerrado = true;
501
+ try {
502
+ await liberarLock(lock);
503
+ }
504
+ catch (erro) {
505
+ if (erroOperacao === undefined)
506
+ throw erro;
507
+ }
508
+ if (erroOperacao !== undefined)
509
+ throw erroOperacao;
510
+ return resultado;
511
+ }
512
+ finally {
513
+ sairFila();
514
+ }
515
+ }
516
+ /** Nome fixo exportado apenas para testes de crash/stale sem revelar caminhos reais. */
517
+ export function nomeLockDistribuicaoGlobal() {
518
+ return NOME_LOCK;
519
+ }
520
+ //# sourceMappingURL=lockGlobal.js.map
@@ -0,0 +1,48 @@
1
+ import type { IdentificadorDestinoSkillGlobal, OpcoesAmbienteDistribuicaoGlobal, ResultadoDestinoSkillGlobal, ResultadoSkillGlobal } from "./tipos.js";
2
+ export declare const ARQUIVOS_SKILL_SEMA_GERENCIADOS: readonly ["SKILL.md", "agents/openai.yaml"];
3
+ export declare const NOME_RECIBO_SKILL_SEMA = ".sema-managed.json";
4
+ declare const ESQUEMA_RECIBO = "sema.skill-install-receipt/v1";
5
+ declare const GERENCIADOR_RECIBO = "@semacode/cli";
6
+ interface ReciboSkill {
7
+ schema: typeof ESQUEMA_RECIBO;
8
+ manager: typeof GERENCIADOR_RECIBO;
9
+ skill: "sema";
10
+ packageVersion: string;
11
+ files: Record<(typeof ARQUIVOS_SKILL_SEMA_GERENCIADOS)[number], string>;
12
+ }
13
+ interface SnapshotSkill {
14
+ raizPacote: string;
15
+ origem: string;
16
+ arquivos: Map<(typeof ARQUIVOS_SKILL_SEMA_GERENCIADOS)[number], Buffer>;
17
+ recibo: ReciboSkill;
18
+ reciboTexto: string;
19
+ }
20
+ interface DestinoSkillInterno {
21
+ id: IdentificadorDestinoSkillGlobal;
22
+ caminho: string;
23
+ virtual: ResultadoDestinoSkillGlobal["destino_simbolico"];
24
+ }
25
+ interface AmbienteSkill {
26
+ homeReal: string;
27
+ snapshot: SnapshotSkill;
28
+ espelhoClaudeDetectado: boolean;
29
+ destinos: DestinoSkillInterno[];
30
+ }
31
+ export declare function statusSkillGlobal(opcoes?: OpcoesAmbienteDistribuicaoGlobal): Promise<ResultadoSkillGlobal>;
32
+ export declare function sincronizarSkillGlobal(opcoes?: OpcoesAmbienteDistribuicaoGlobal): Promise<ResultadoSkillGlobal>;
33
+ interface SnapshotDestinoSkillGlobal {
34
+ destino: DestinoSkillInterno;
35
+ existente: boolean;
36
+ vazio: boolean;
37
+ arquivos?: Map<(typeof ARQUIVOS_SKILL_SEMA_GERENCIADOS)[number], Buffer>;
38
+ recibo?: Buffer;
39
+ }
40
+ /** Snapshot opaco usado somente pelo coordenador para compensação local. */
41
+ export interface SnapshotSkillGlobalTransacao {
42
+ readonly ambiente: AmbienteSkill;
43
+ readonly destinos: SnapshotDestinoSkillGlobal[];
44
+ }
45
+ export declare function capturarSnapshotSkillGlobalTransacao(opcoes?: OpcoesAmbienteDistribuicaoGlobal): Promise<SnapshotSkillGlobalTransacao>;
46
+ export declare function sincronizarSkillGlobalTransacional(snapshot: SnapshotSkillGlobalTransacao): Promise<ResultadoSkillGlobal>;
47
+ export declare function restaurarSnapshotSkillGlobalTransacao(snapshot: SnapshotSkillGlobalTransacao): Promise<void>;
48
+ export {};