@orkastery/cli 0.5.1 → 0.5.6

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 (260) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/agents/ork-master.md +2 -0
  3. package/adapters/claude-code/commands/master.md +8 -0
  4. package/adapters/claude-code/commands/ork.md +9 -0
  5. package/adapters/claude-code/mods/autoridade.json +56 -0
  6. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  8. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  9. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  10. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  11. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  12. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  13. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  16. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  17. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  18. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  19. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  20. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  21. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  25. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  27. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  28. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  29. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  30. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  33. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  34. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  35. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  36. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  37. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  38. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  44. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  45. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  46. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  47. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  48. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  49. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  52. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  53. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  54. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  55. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  56. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  57. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  59. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  60. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  61. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  62. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  63. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  64. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  67. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  68. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  69. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  70. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  71. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  72. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  77. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  78. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  79. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  80. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  81. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  82. package/adapters/codex/skills/ork/SKILL.md +18 -3
  83. package/adapters/hermes/README.md +1 -0
  84. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  85. package/adapters/hermes/hermes.plugin.json +1 -0
  86. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  87. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +7 -6
  88. package/adapters/openclaw/README.md +26 -5
  89. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  90. package/adapters/openclaw/dist/index.js +46 -11
  91. package/adapters/openclaw/openclaw.plugin.json +5 -1
  92. package/adapters/openclaw/package.json +2 -2
  93. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  94. package/adapters/openclaw/src/index.ts +49 -11
  95. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  96. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  97. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  98. package/assets/docs-en/produto/README.md +14 -0
  99. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  100. package/assets/docs-en/roadmap/README.md +14 -0
  101. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  102. package/assets/orkmind_bridge.py +117 -9
  103. package/dist/adapters/claude-bg.js +116 -18
  104. package/dist/adapters/codex.js +14 -4
  105. package/dist/agents-md.js +24 -14
  106. package/dist/auditrun.js +22 -3
  107. package/dist/board.js +20 -17
  108. package/dist/branch-de-estado.js +88 -10
  109. package/dist/busca-semantica.js +52 -12
  110. package/dist/canarios-rm057.js +149 -0
  111. package/dist/canarios.js +2 -0
  112. package/dist/catalogo.js +33 -0
  113. package/dist/ci.js +21 -8
  114. package/dist/claims-conferir.js +342 -0
  115. package/dist/claims.js +41 -1
  116. package/dist/company-brain-client.js +36 -1
  117. package/dist/company-brain-context.js +158 -22
  118. package/dist/company-brain-journal.js +2 -1
  119. package/dist/company-brain-migration.js +36 -1
  120. package/dist/conducao-sentinela.js +388 -0
  121. package/dist/conducao-texto.js +12 -18
  122. package/dist/conducao.js +122 -30
  123. package/dist/conhecimento.js +490 -0
  124. package/dist/docs.js +70 -17
  125. package/dist/doctor-pulse-cron.js +349 -0
  126. package/dist/doctor-rede.js +150 -0
  127. package/dist/doctor.js +195 -111
  128. package/dist/entrega-pr.js +42 -29
  129. package/dist/escopo-escrita.js +10 -1
  130. package/dist/esgotamentos.js +181 -0
  131. package/dist/estado-thread.js +23 -1
  132. package/dist/experiencia-instalacao.js +45 -25
  133. package/dist/experiencia.js +12 -2
  134. package/dist/fabrica-batida.js +310 -0
  135. package/dist/fabrica-estado.js +52 -14
  136. package/dist/fabrica-publicar.js +9 -1
  137. package/dist/fechamento.js +20 -66
  138. package/dist/fila-pesada.js +444 -0
  139. package/dist/fix.js +3 -2
  140. package/dist/forja.js +31 -7
  141. package/dist/gates.js +3 -24
  142. package/dist/handoff.js +10 -6
  143. package/dist/hitl-contract.js +59 -4
  144. package/dist/hitl-curto.js +11 -6
  145. package/dist/hitl-gates.js +5 -0
  146. package/dist/hitl-local-receipt.js +2 -0
  147. package/dist/hitl-lote.js +5 -2
  148. package/dist/hitl-resumo.js +38 -3
  149. package/dist/hitl-tempo-parado.js +201 -0
  150. package/dist/hitl-texto-livre.js +5 -5
  151. package/dist/hitl.js +29 -33
  152. package/dist/horario.js +41 -7
  153. package/dist/hosts.js +104 -11
  154. package/dist/impedimento.js +299 -0
  155. package/dist/index.js +961 -542
  156. package/dist/indice-vetorial.js +87 -10
  157. package/dist/indice.js +9 -1
  158. package/dist/init.js +56 -43
  159. package/dist/instabilidade.js +144 -0
  160. package/dist/integracoes-locais.js +4 -0
  161. package/dist/intelligence-graph-cli.js +170 -16
  162. package/dist/intelligence-graph-contexto.js +254 -0
  163. package/dist/intelligence-graph-contract.js +2 -1
  164. package/dist/intelligence-graph-extract-md.js +56 -4
  165. package/dist/intelligence-graph-extract-ts.js +71 -3
  166. package/dist/intelligence-graph-parsers.js +6 -4
  167. package/dist/intelligence-graph-query.js +66 -19
  168. package/dist/leases.js +664 -87
  169. package/dist/ledger-stats.js +15 -1
  170. package/dist/ledger.js +18 -1
  171. package/dist/licoes.js +1 -0
  172. package/dist/liveness.js +6 -3
  173. package/dist/locale-ajuda.js +761 -0
  174. package/dist/locale-gerados.js +160 -0
  175. package/dist/locale-master.js +99 -0
  176. package/dist/locale-onboarding.js +92 -0
  177. package/dist/locale-phase.js +151 -0
  178. package/dist/locale-pulse.js +211 -0
  179. package/dist/locale-retry.js +385 -0
  180. package/dist/locale-roadmap.js +102 -0
  181. package/dist/locale-ship.js +494 -0
  182. package/dist/locale-thread.js +277 -0
  183. package/dist/locale-verify.js +125 -0
  184. package/dist/locale.js +714 -0
  185. package/dist/maestro-runtime.js +4 -1
  186. package/dist/manifest.js +149 -4
  187. package/dist/maquina.js +23 -4
  188. package/dist/master-digest.js +6 -1
  189. package/dist/master-nota.js +18 -11
  190. package/dist/master.js +145 -31
  191. package/dist/mcp-artifacts.js +43 -3
  192. package/dist/mcp-git.js +42 -8
  193. package/dist/mcp-grafo-worker.js +5 -3
  194. package/dist/mcp-grafo.js +55 -6
  195. package/dist/mcp-server.js +22 -3
  196. package/dist/mcp-ship.js +3 -1
  197. package/dist/mcp-verify.js +6 -1
  198. package/dist/memoria.js +48 -6
  199. package/dist/modos.js +3 -6
  200. package/dist/network-roadmap.js +196 -18
  201. package/dist/noctum-arco.js +911 -0
  202. package/dist/noctum-capacidade.js +141 -0
  203. package/dist/noctum-envelope.js +810 -0
  204. package/dist/noctum-execucao.js +304 -0
  205. package/dist/noctum-fila.js +280 -0
  206. package/dist/ocupacao.js +40 -5
  207. package/dist/onboarding.js +40 -21
  208. package/dist/orkmind.js +99 -7
  209. package/dist/orquestracao.js +24 -21
  210. package/dist/parado-no-condutor.js +219 -38
  211. package/dist/phase.js +160 -52
  212. package/dist/policies.js +56 -5
  213. package/dist/portfolio.js +8 -3
  214. package/dist/postura-local.js +234 -0
  215. package/dist/preflight.js +11 -10
  216. package/dist/procedencia.js +225 -0
  217. package/dist/projeto-alvo.js +132 -5
  218. package/dist/prompts.js +40 -1
  219. package/dist/prova-ativacao.js +75 -6
  220. package/dist/pulse-delivery.js +47 -4
  221. package/dist/pulse.js +98 -19
  222. package/dist/ratelimit.js +24 -6
  223. package/dist/recall.js +3 -1
  224. package/dist/redacao-saida.js +63 -0
  225. package/dist/rede-adesao.js +399 -0
  226. package/dist/rede-forja.js +289 -0
  227. package/dist/rede-projetos.js +239 -0
  228. package/dist/rede-status.js +337 -0
  229. package/dist/rede.js +980 -0
  230. package/dist/retry.js +291 -140
  231. package/dist/roadmap-reservas.js +20 -3
  232. package/dist/roadmap-status.js +150 -34
  233. package/dist/runtime-context.js +181 -3
  234. package/dist/runtime-profiles.js +22 -1
  235. package/dist/runtimes.js +2 -1
  236. package/dist/saida-segura.js +58 -0
  237. package/dist/session-events.js +7 -3
  238. package/dist/session-watcher-claude.js +120 -24
  239. package/dist/session-watcher.js +185 -33
  240. package/dist/sessoes-contas.js +187 -0
  241. package/dist/sessoes-inventario.js +6 -18
  242. package/dist/sessoes.js +83 -2
  243. package/dist/ship-publicar.js +800 -0
  244. package/dist/ship.js +157 -88
  245. package/dist/steal.js +77 -0
  246. package/dist/thread-close.js +3 -2
  247. package/dist/thread.js +299 -49
  248. package/dist/util.js +8 -1
  249. package/dist/verify.js +141 -52
  250. package/dist/vida-da-thread.js +254 -0
  251. package/dist/worktree-local.js +165 -0
  252. package/dist/worktree.js +25 -2
  253. package/dist/yaml.js +27 -8
  254. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  255. package/package.json +7 -3
  256. package/references/definition-of-done.md +1 -1
  257. package/schemas/code-artifact-graph.v1.schema.json +2 -1
  258. package/skills/README.md +1 -1
  259. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  260. package/skills/phases/master-metrics/SKILL.md +8 -3
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fatosDeCapacidade = fatosDeCapacidade;
4
+ exports.admitir = admitir;
5
+ exports.escolherConta = escolherConta;
6
+ const conducao_1 = require("./conducao");
7
+ const ledger_1 = require("./ledger");
8
+ const ocupacao_1 = require("./ocupacao");
9
+ const sessoes_contas_1 = require("./sessoes-contas");
10
+ const thread_1 = require("./thread");
11
+ const TERMINAIS = ['done', 'completed', 'exited', 'stopped', 'failed'];
12
+ /** O runtime mostra a sessão trabalhando agora: o claude-bg diz `running` ou `busy` (o watcher chama de `working`). */
13
+ const TRABALHANDO = ['running', 'busy', 'working'];
14
+ const estadoDe = (s) => String(s.state ?? s.status ?? '').trim().toLowerCase();
15
+ /**
16
+ * O runtime prova que a sessão do lease acabou? Presente com estado terminal ou fantasma, sim. Ausente, só no
17
+ * claude-bg (o `claude agents` lista as sessões que o daemon da conta mantém), com todas as fontes lidas e a conta
18
+ * dela entre as consultadas. O codex lista só rollouts recentes: ausência lá não prova nada.
19
+ */
20
+ function encerradaPeloRuntime(dono, leitura, porSessao, semLacuna) {
21
+ const vista = porSessao.get(dono.sessionId);
22
+ if (vista)
23
+ return vista.fantasma || TERMINAIS.includes(estadoDe(vista));
24
+ if (!semLacuna || dono.runtime !== 'claude-bg')
25
+ return false;
26
+ return leitura.contas.some(c => c.runtime === 'claude-bg' && (c.perfil?.id ?? null) === dono.perfil);
27
+ }
28
+ /**
29
+ * A ocupação desta máquina agora, relida a cada chamada. `consultar` é dependência dos testes; sem ela, as sessões de
30
+ * todas as contas pelo `consultarContas`, a mesma leitura do escalonador.
31
+ */
32
+ function fatosDeCapacidade(carregado, opcoes = {}) {
33
+ const quando = opcoes.quando ?? new Date().toISOString();
34
+ const { raiz, manifesto } = carregado;
35
+ const staleMin = manifesto.concurrency.stale_after_min;
36
+ const leitura = (opcoes.consultar ?? (() => (0, sessoes_contas_1.consultarContas)(raiz, { staleMin })))();
37
+ const lacunas = leitura.fontes.filter(f => !f.ok).map(f => `${f.origem}: ${f.detalhe}`);
38
+ const porSessao = new Map(leitura.sessoes.map(s => [s.sessionId, s]));
39
+ const ocupantes = [];
40
+ const encerradasPeloRuntime = [];
41
+ const contadas = new Set();
42
+ // A sessão que a regra da vaga solta (turno encerrado, espera do dono, parada) não volta pela lista do runtime,
43
+ // a não ser que o runtime a mostre trabalhando agora (A8 do CHECK): a regra da vaga lê só o ledger.
44
+ const soltas = new Set();
45
+ for (const id of (0, thread_1.listarIds)(raiz)) {
46
+ let atual = null;
47
+ try {
48
+ atual = (0, conducao_1.conducaoDaThread)(raiz, id);
49
+ }
50
+ catch {
51
+ continue;
52
+ }
53
+ if (!atual)
54
+ continue;
55
+ if (atual.dono.tipo === 'processo' && (atual.operacao === 'phase.run' || atual.operacao === 'retry.run')) {
56
+ ocupantes.push({ sessionId: null, thread: id, runtime: null, conta: null, revisao: atual.fase === 'CHECK', origem: 'despacho' });
57
+ continue;
58
+ }
59
+ if (atual.dono.tipo !== 'sessao')
60
+ continue;
61
+ const dono = atual.dono;
62
+ const vista = porSessao.get(dono.sessionId);
63
+ try {
64
+ if ((0, ocupacao_1.sessaoLivreDaVaga)((0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id)), atual.desde, quando, staleMin, dono.sessionId) &&
65
+ !(vista?.viva && TRABALHANDO.includes(estadoDe(vista)))) {
66
+ soltas.add(dono.sessionId);
67
+ continue;
68
+ }
69
+ }
70
+ catch { /* ledger ilegível: a condução viva continua contando, como no portão do phase run */ }
71
+ if (encerradaPeloRuntime(dono, leitura, porSessao, lacunas.length === 0)) {
72
+ encerradasPeloRuntime.push(dono.sessionId);
73
+ continue;
74
+ }
75
+ contadas.add(dono.sessionId);
76
+ // A5 do CHECK: o despacho sem `--perfil` grava o lease sem conta; a conta é a que o runtime atribui à sessão.
77
+ ocupantes.push({ sessionId: dono.sessionId, thread: id, runtime: dono.runtime, conta: dono.perfil ?? vista?.perfil ?? null,
78
+ revisao: atual.fase === 'CHECK', origem: 'conducao' });
79
+ }
80
+ for (const s of leitura.sessoes) {
81
+ if (!s.viva || contadas.has(s.sessionId) || soltas.has(s.sessionId) || encerradasPeloRuntime.includes(s.sessionId))
82
+ continue;
83
+ contadas.add(s.sessionId);
84
+ ocupantes.push({ sessionId: s.sessionId, thread: null, runtime: s.runtime, conta: s.perfil, revisao: false, origem: 'runtime' });
85
+ }
86
+ return { quando, ocupantes, lacunas, encerradasPeloRuntime };
87
+ }
88
+ const limiteDe = (lista, chave, nome) => lista.find(x => x[chave] === nome)?.sessoes ?? null;
89
+ /**
90
+ * Cabe mais esta sessão? Todos os limites ao mesmo tempo, na ordem: leitura completa, conta e runtime autorizados,
91
+ * o projeto (o portão do `phase run`, que o chamador consulta para a thread), a máquina, a margem de revisão (a
92
+ * execução não usa os slots reservados ao CHECK), a conta e o runtime.
93
+ */
94
+ function admitir(pedido, limites, fatos, vagaDoProjeto) {
95
+ if (fatos.lacunas.length) {
96
+ return { ok: false, motivo: 'capacidade.fonte-indisponivel', detalhe: `sessões sem leitura: ${fatos.lacunas.join('; ')}` };
97
+ }
98
+ const limiteDoRuntime = limiteDe(limites.porRuntime, 'runtime', pedido.runtime);
99
+ if (limiteDoRuntime === null) {
100
+ return { ok: false, motivo: 'capacidade.runtime-nao-autorizado', detalhe: `o runtime ${pedido.runtime} não está no envelope` };
101
+ }
102
+ const limiteDaConta = limiteDe(limites.porConta, 'conta', pedido.conta);
103
+ if (limiteDaConta === null) {
104
+ return { ok: false, motivo: 'capacidade.conta-nao-autorizada', detalhe: `a conta ${pedido.conta} não está no envelope` };
105
+ }
106
+ if (vagaDoProjeto)
107
+ return { ok: false, motivo: 'capacidade.projeto', detalhe: vagaDoProjeto.detalhe };
108
+ const total = fatos.ocupantes.length;
109
+ if (total >= limites.maquina) {
110
+ return { ok: false, motivo: 'capacidade.maquina', detalhe: `${total} sessão(ões) nesta máquina e o limite do envelope é ${limites.maquina}` };
111
+ }
112
+ const execucao = fatos.ocupantes.filter(o => !o.revisao).length;
113
+ if (!pedido.revisao && execucao >= limites.maquina - limites.revisao) {
114
+ return { ok: false, motivo: 'capacidade.revisao', detalhe: `${execucao} sessão(ões) de execução e ${limites.revisao} slot(s) ` +
115
+ `reservado(s) à revisão de ${limites.maquina}: só o CHECK usa o que sobra` };
116
+ }
117
+ const naConta = fatos.ocupantes.filter(o => o.conta === pedido.conta).length;
118
+ if (naConta >= limiteDaConta) {
119
+ return { ok: false, motivo: 'capacidade.conta', detalhe: `${naConta} sessão(ões) na conta ${pedido.conta} e o limite é ${limiteDaConta}` };
120
+ }
121
+ const noRuntime = fatos.ocupantes.filter(o => o.runtime === pedido.runtime).length;
122
+ if (noRuntime >= limiteDoRuntime) {
123
+ return { ok: false, motivo: 'capacidade.runtime', detalhe: `${noRuntime} sessão(ões) no ${pedido.runtime} e o limite é ${limiteDoRuntime}` };
124
+ }
125
+ return { ok: true };
126
+ }
127
+ /**
128
+ * A conta do despacho: entre as do envelope que são perfis do runtime (`perfisDoRuntime`, do store de contas), a com
129
+ * mais folga no limite dela; empate pela ordem do envelope. `null` quando nenhuma tem vaga.
130
+ */
131
+ function escolherConta(limites, fatos, perfisDoRuntime) {
132
+ let melhor = null;
133
+ for (const { conta, sessoes } of limites.porConta) {
134
+ if (!perfisDoRuntime.includes(conta))
135
+ continue;
136
+ const folga = sessoes - fatos.ocupantes.filter(o => o.conta === conta).length;
137
+ if (folga > 0 && (!melhor || folga > melhor.folga))
138
+ melhor = { conta, folga };
139
+ }
140
+ return melhor?.conta ?? null;
141
+ }