@orkastery/cli 0.5.3 → 0.6.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 (502) hide show
  1. package/adapters/README.md +18 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
  3. package/adapters/claude-code/README.md +195 -5
  4. package/adapters/claude-code/agents/ork-check.md +1 -0
  5. package/adapters/claude-code/agents/ork-go.md +1 -0
  6. package/adapters/claude-code/agents/ork-goal.md +1 -0
  7. package/adapters/claude-code/agents/ork-master.md +1 -0
  8. package/adapters/claude-code/agents/ork-plan.md +1 -0
  9. package/adapters/claude-code/agents/ork-ship.md +1 -0
  10. package/adapters/claude-code/hooks/hooks.json +2 -1
  11. package/adapters/claude-code/hooks/ork-guard.js +15 -1
  12. package/adapters/claude-code/hooks/ork-resposta.js +91 -0
  13. package/adapters/claude-code/hooks/ork-sensor.js +18 -2
  14. package/adapters/claude-code/hooks/quota-signal.js +14 -0
  15. package/adapters/claude-code/mods/autoridade.json +56 -0
  16. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  17. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  18. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  19. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  20. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  21. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  22. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  23. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  24. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  25. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  26. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  27. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  28. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  29. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  30. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  31. package/adapters/claude-code/mods/ork-mensageiro/.claude-plugin/plugin.json +14 -0
  32. package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
  33. package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
  34. package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
  35. package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
  36. package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
  37. package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
  38. package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -0
  39. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  40. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  41. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  42. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  43. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  44. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  45. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  46. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  47. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  48. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  49. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  50. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +121 -0
  51. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  52. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  53. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  54. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  55. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  56. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  57. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  58. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  59. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  60. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  61. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  62. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  63. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  64. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  65. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  66. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  67. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  68. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  69. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  70. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  71. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  72. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  73. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  74. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  75. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  76. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  77. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  78. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  79. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  80. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  81. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  82. package/adapters/claude-code/mods/ork-ritual/.claude-plugin/plugin.json +14 -0
  83. package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
  84. package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
  85. package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
  86. package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
  87. package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
  88. package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
  89. package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -0
  90. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  91. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  92. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  93. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  94. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  95. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  96. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  97. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  98. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  99. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  100. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  101. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  102. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  103. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  104. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  105. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  106. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  107. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  108. package/adapters/codex/skills/ork/SKILL.md +2 -0
  109. package/adapters/hermes/README.md +64 -1
  110. package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
  111. package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
  112. package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
  113. package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
  114. package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
  115. package/adapters/hermes/hermes.plugin.json +4 -0
  116. package/adapters/hermes/hitl-ingress/__init__.py +101 -8
  117. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +3 -3
  118. package/adapters/openclaw/README.md +83 -10
  119. package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
  120. package/adapters/openclaw/dist/hitl-ingress.js +106 -9
  121. package/adapters/openclaw/dist/index.js +86 -0
  122. package/adapters/openclaw/openclaw.plugin.json +34 -4
  123. package/adapters/openclaw/package.json +2 -2
  124. package/adapters/openclaw/src/hitl-ingress.ts +103 -9
  125. package/adapters/openclaw/src/index.ts +94 -0
  126. package/assets/adapters-en/claude-code/README.md +403 -0
  127. package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
  128. package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
  129. package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
  130. package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
  131. package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
  132. package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
  133. package/assets/adapters-en/claude-code/commands/check.md +46 -0
  134. package/assets/adapters-en/claude-code/commands/go.md +46 -0
  135. package/assets/adapters-en/claude-code/commands/goal.md +55 -0
  136. package/assets/adapters-en/claude-code/commands/master.md +54 -0
  137. package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
  138. package/assets/adapters-en/claude-code/commands/ork.md +126 -0
  139. package/assets/adapters-en/claude-code/commands/plan.md +47 -0
  140. package/assets/adapters-en/claude-code/commands/ship.md +45 -0
  141. package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
  142. package/assets/adapters-en/hermes/README.md +273 -0
  143. package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
  144. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  145. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  146. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  147. package/assets/docs-en/produto/README.md +14 -0
  148. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  149. package/assets/docs-en/roadmap/README.md +14 -0
  150. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  151. package/assets/references-en/README.md +25 -0
  152. package/assets/references-en/code-review-axes.md +82 -0
  153. package/assets/references-en/definition-of-done.md +74 -0
  154. package/assets/references-en/performance-checklist.md +53 -0
  155. package/assets/references-en/security-checklist.md +101 -0
  156. package/assets/references-en/testing-patterns.md +51 -0
  157. package/assets/security-scan/defaults/.golangci.yml +2 -0
  158. package/assets/security-scan/defaults/eslint.config.mjs +11 -0
  159. package/assets/security-scan/defaults/gitleaks.toml +3 -0
  160. package/assets/security-scan/defaults/ruff.toml +1 -0
  161. package/assets/security-scan/tools-agil.json +87 -0
  162. package/assets/security-scan/tools.json +625 -0
  163. package/assets/skills-en/core/onboarding/SKILL.md +58 -0
  164. package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
  165. package/assets/skills-en/core/thread-state/SKILL.md +88 -0
  166. package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
  167. package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
  168. package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
  169. package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
  170. package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
  171. package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
  172. package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
  173. package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
  174. package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
  175. package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
  176. package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
  177. package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
  178. package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
  179. package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
  180. package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
  181. package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
  182. package/dist/adapters/claude-bg.js +193 -15
  183. package/dist/adapters/codex-controller-worker.js +12 -5
  184. package/dist/adapters/codex-events.js +16 -4
  185. package/dist/adapters/codex.js +13 -2
  186. package/dist/agents-md.js +24 -15
  187. package/dist/atualizar-branch.js +245 -0
  188. package/dist/auditoria.js +13 -11
  189. package/dist/auditrun.js +68 -48
  190. package/dist/autorizacao-duravel.js +327 -0
  191. package/dist/board.js +98 -43
  192. package/dist/branch-de-estado.js +39 -9
  193. package/dist/busca-semantica.js +7 -5
  194. package/dist/catalogo.js +35 -1
  195. package/dist/changelog-reconciliacao.js +290 -0
  196. package/dist/check-agil.js +500 -0
  197. package/dist/check-modo.js +41 -0
  198. package/dist/check-paralelo.js +183 -0
  199. package/dist/ci.js +255 -46
  200. package/dist/ciclos.js +8 -6
  201. package/dist/claim-lint.js +12 -8
  202. package/dist/claims-conferir.js +350 -0
  203. package/dist/claims.js +13 -10
  204. package/dist/company-brain-client.js +45 -3
  205. package/dist/company-brain-journal.js +2 -1
  206. package/dist/company-brain-migration.js +47 -6
  207. package/dist/conducao-batida.js +759 -0
  208. package/dist/conducao-sentinela.js +405 -0
  209. package/dist/conducao-texto.js +12 -18
  210. package/dist/conducao.js +206 -59
  211. package/dist/conhecimento-consulta.js +270 -0
  212. package/dist/conhecimento.js +514 -0
  213. package/dist/conta-esgotada.js +127 -0
  214. package/dist/dado-privado.js +816 -0
  215. package/dist/decisao-autonoma.js +5 -4
  216. package/dist/demo.js +14 -12
  217. package/dist/dependencias-da-worktree.js +25 -0
  218. package/dist/divida.js +38 -36
  219. package/dist/docs.js +103 -82
  220. package/dist/doctor-forja.js +345 -0
  221. package/dist/doctor-pulse-cron.js +294 -27
  222. package/dist/doctor-rede.js +18 -17
  223. package/dist/doctor.js +278 -116
  224. package/dist/dsn-da-memoria.js +417 -0
  225. package/dist/entrega-por-mod.js +503 -0
  226. package/dist/entrega-pr.js +158 -57
  227. package/dist/escopo-escrita.js +10 -1
  228. package/dist/esgotamentos.js +13 -11
  229. package/dist/estado-thread.js +42 -17
  230. package/dist/evalrunner.js +35 -32
  231. package/dist/experiencia-instalacao.js +45 -25
  232. package/dist/fabrica-batida.js +323 -0
  233. package/dist/fabrica-estado.js +49 -16
  234. package/dist/fabrica-publicar.js +3 -1
  235. package/dist/fila-pesada.js +444 -0
  236. package/dist/fix.js +24 -21
  237. package/dist/forja/adaptador.js +6 -0
  238. package/dist/forja/ambiente-de-ci.js +27 -0
  239. package/dist/forja/api.js +256 -0
  240. package/dist/forja/cache.js +89 -0
  241. package/dist/forja/cli.js +60 -0
  242. package/dist/forja/contrato.js +9 -0
  243. package/dist/forja/endereco.js +43 -0
  244. package/dist/forja/estado.js +22 -0
  245. package/dist/forja/executor.js +73 -0
  246. package/dist/forja/github/ci.js +95 -0
  247. package/dist/forja/github/dono-da-rede.js +18 -0
  248. package/dist/forja/github/metadados.js +15 -0
  249. package/dist/forja/github/pedidos.js +200 -0
  250. package/dist/forja/gitlab/ci.js +141 -0
  251. package/dist/forja/gitlab/consultas.js +59 -0
  252. package/dist/forja/gitlab/dono-da-rede.js +43 -0
  253. package/dist/forja/gitlab/metadados.js +15 -0
  254. package/dist/forja/gitlab/pedidos-abertos.js +158 -0
  255. package/dist/forja/gitlab/pedidos.js +141 -0
  256. package/dist/forja/produtor.js +32 -0
  257. package/dist/forja/registro.js +31 -0
  258. package/dist/forja/resolver.js +121 -0
  259. package/dist/forja/texto.js +13 -0
  260. package/dist/forja/versao.js +71 -0
  261. package/dist/forja.js +124 -81
  262. package/dist/gates.js +3 -28
  263. package/dist/handoff.js +33 -19
  264. package/dist/hitl-contract.js +46 -43
  265. package/dist/hitl-curto.js +37 -25
  266. package/dist/hitl-gates.js +13 -11
  267. package/dist/hitl-local-receipt.js +53 -0
  268. package/dist/hitl-local.js +11 -2
  269. package/dist/hitl-lock.js +5 -11
  270. package/dist/hitl-public-receipt.js +11 -0
  271. package/dist/hitl-resumo.js +72 -3
  272. package/dist/hitl-sessions.js +62 -9
  273. package/dist/hitl-tempo-parado.js +4 -4
  274. package/dist/hitl-texto-livre.js +7 -4
  275. package/dist/hitl.js +63 -64
  276. package/dist/horario.js +30 -7
  277. package/dist/hosts.js +155 -134
  278. package/dist/impedimento.js +108 -14
  279. package/dist/index.js +1421 -1019
  280. package/dist/indice-vetorial.js +14 -12
  281. package/dist/indice.js +7 -1
  282. package/dist/init.js +54 -49
  283. package/dist/instabilidade.js +144 -0
  284. package/dist/integracoes-locais.js +4 -0
  285. package/dist/intelligence-graph-cli.js +213 -88
  286. package/dist/intelligence-graph-contexto.js +56 -17
  287. package/dist/intelligence-graph-contract.js +2 -1
  288. package/dist/intelligence-graph-extract-md.js +56 -4
  289. package/dist/intelligence-graph-extract-ts.js +71 -3
  290. package/dist/intelligence-graph-query.js +96 -34
  291. package/dist/leases.js +19 -18
  292. package/dist/ledger-stats.js +17 -16
  293. package/dist/ledger.js +46 -2
  294. package/dist/licoes.js +12 -11
  295. package/dist/liveness.js +6 -3
  296. package/dist/locale-accounts.js +220 -0
  297. package/dist/locale-adapter.js +291 -0
  298. package/dist/locale-ajuda.js +833 -0
  299. package/dist/locale-audit.js +199 -0
  300. package/dist/locale-claims.js +213 -0
  301. package/dist/locale-conducao.js +138 -0
  302. package/dist/locale-conhecimento.js +181 -0
  303. package/dist/locale-decisao.js +205 -0
  304. package/dist/locale-docs.js +230 -0
  305. package/dist/locale-estado.js +101 -0
  306. package/dist/locale-forja.js +290 -0
  307. package/dist/locale-gerados.js +165 -0
  308. package/dist/locale-grafo.js +129 -0
  309. package/dist/locale-master.js +182 -0
  310. package/dist/locale-network.js +524 -0
  311. package/dist/locale-onboarding.js +92 -0
  312. package/dist/locale-operacao-restante.js +931 -0
  313. package/dist/locale-phase.js +151 -0
  314. package/dist/locale-projetos.js +100 -0
  315. package/dist/locale-prompts.js +194 -0
  316. package/dist/locale-pulse.js +349 -0
  317. package/dist/locale-reservas.js +87 -0
  318. package/dist/locale-retry.js +524 -0
  319. package/dist/locale-roadmap.js +102 -0
  320. package/dist/locale-security-scan.js +69 -0
  321. package/dist/locale-setup.js +192 -0
  322. package/dist/locale-ship.js +597 -0
  323. package/dist/locale-thread.js +421 -0
  324. package/dist/locale-verify.js +201 -0
  325. package/dist/locale-worktree.js +246 -0
  326. package/dist/locale.js +1258 -0
  327. package/dist/maestro-runtime.js +22 -3
  328. package/dist/manifest.js +415 -13
  329. package/dist/maquina-ociosa.js +211 -0
  330. package/dist/maquina.js +31 -7
  331. package/dist/master-digest.js +6 -1
  332. package/dist/master-nota-local.js +200 -0
  333. package/dist/master-nota.js +14 -8
  334. package/dist/master.js +139 -65
  335. package/dist/mcp-artifacts.js +11 -2
  336. package/dist/mcp-conhecimento.js +52 -0
  337. package/dist/mcp-experiencia.js +26 -5
  338. package/dist/mcp-git.js +23 -6
  339. package/dist/mcp-grafo.js +7 -4
  340. package/dist/mcp-install.js +73 -8
  341. package/dist/mcp-noctum.js +101 -0
  342. package/dist/mcp-server.js +90 -16
  343. package/dist/mcp-ship-transporte.js +977 -0
  344. package/dist/mcp-ship.js +71 -25
  345. package/dist/mcp-transportes.js +17 -0
  346. package/dist/mcp-verify.js +6 -1
  347. package/dist/memoria.js +63 -58
  348. package/dist/modos-migracao.js +8 -6
  349. package/dist/modos.js +20 -24
  350. package/dist/network-roadmap.js +90 -51
  351. package/dist/noctum-aceite.js +789 -0
  352. package/dist/noctum-arco.js +1418 -0
  353. package/dist/noctum-capacidade.js +141 -0
  354. package/dist/noctum-changelog.js +399 -0
  355. package/dist/noctum-cli.js +482 -0
  356. package/dist/noctum-coordenacao.js +1225 -0
  357. package/dist/noctum-entrega.js +1169 -0
  358. package/dist/noctum-envelope.js +1046 -0
  359. package/dist/noctum-execucao.js +376 -0
  360. package/dist/noctum-fechamento.js +405 -0
  361. package/dist/noctum-fila.js +314 -0
  362. package/dist/noctum-guarda.js +256 -0
  363. package/dist/noctum-integracao.js +507 -0
  364. package/dist/noctum-maquinas.js +383 -0
  365. package/dist/noctum-medicao.js +450 -0
  366. package/dist/noctum-modo.js +362 -0
  367. package/dist/noctum-pergunta-canal.js +96 -0
  368. package/dist/noctum-pergunta.js +115 -0
  369. package/dist/noctum-provas.js +838 -0
  370. package/dist/noctum-reconciliacao.js +591 -0
  371. package/dist/noctum-registro.js +215 -0
  372. package/dist/noctum-relatorio.js +827 -0
  373. package/dist/noctum-resposta.js +207 -0
  374. package/dist/noctum-sessoes-em-voo.js +93 -0
  375. package/dist/noctum-supervisao.js +649 -0
  376. package/dist/noctum-terminal.js +459 -0
  377. package/dist/noctum-transporte.js +655 -0
  378. package/dist/noctum-vigia.js +639 -0
  379. package/dist/ocupacao.js +32 -3
  380. package/dist/onboarding.js +56 -26
  381. package/dist/orkmind.js +48 -25
  382. package/dist/orquestracao.js +44 -47
  383. package/dist/parado-no-condutor.js +174 -127
  384. package/dist/phase.js +144 -63
  385. package/dist/policies.js +37 -4
  386. package/dist/portfolio.js +4 -2
  387. package/dist/postura-local.js +235 -0
  388. package/dist/preflight.js +11 -10
  389. package/dist/procedencia.js +220 -0
  390. package/dist/projeto-alvo.js +186 -24
  391. package/dist/prompts.js +140 -42
  392. package/dist/prova-minima.js +5 -6
  393. package/dist/pulse-cadencia.js +5 -4
  394. package/dist/pulse-consentimento.js +53 -1
  395. package/dist/pulse-delivery.js +151 -24
  396. package/dist/pulse-resposta.js +368 -4
  397. package/dist/pulse.js +188 -22
  398. package/dist/ratelimit.js +16 -6
  399. package/dist/recall.js +14 -13
  400. package/dist/redacao-saida.js +63 -0
  401. package/dist/rede-adesao.js +13 -8
  402. package/dist/rede-forja.js +108 -24
  403. package/dist/rede-status.js +66 -47
  404. package/dist/rede.js +86 -46
  405. package/dist/retomada-checkpoint.js +101 -0
  406. package/dist/retry.js +451 -212
  407. package/dist/roadmap-reservas.js +45 -28
  408. package/dist/roadmap-status.js +129 -33
  409. package/dist/runtime-ambiente.js +5 -0
  410. package/dist/runtime-context.js +284 -32
  411. package/dist/runtime-escada.js +423 -0
  412. package/dist/runtime-profiles.js +103 -46
  413. package/dist/runtimes.js +2 -1
  414. package/dist/saida-segura.js +3 -2
  415. package/dist/security-scan/agil.js +355 -0
  416. package/dist/security-scan/cli.js +76 -0
  417. package/dist/security-scan/compare.js +149 -0
  418. package/dist/security-scan/config.js +93 -0
  419. package/dist/security-scan/detect.js +97 -0
  420. package/dist/security-scan/executor.js +188 -0
  421. package/dist/security-scan/guard.js +180 -0
  422. package/dist/security-scan/imagem-de-lint.js +96 -0
  423. package/dist/security-scan/normalize/actionlint.js +12 -0
  424. package/dist/security-scan/normalize/eslint.js +12 -0
  425. package/dist/security-scan/normalize/gitleaks.js +13 -0
  426. package/dist/security-scan/normalize/golangci-lint.js +13 -0
  427. package/dist/security-scan/normalize/govulncheck.js +36 -0
  428. package/dist/security-scan/normalize/index.js +25 -0
  429. package/dist/security-scan/normalize/npm-audit.js +30 -0
  430. package/dist/security-scan/normalize/osv-scanner.js +32 -0
  431. package/dist/security-scan/normalize/oxlint.js +51 -0
  432. package/dist/security-scan/normalize/pip-audit.js +16 -0
  433. package/dist/security-scan/normalize/ruff.js +12 -0
  434. package/dist/security-scan/normalize/semgrep.js +20 -0
  435. package/dist/security-scan/normalize/trivy.js +33 -0
  436. package/dist/security-scan/normalize/util.js +204 -0
  437. package/dist/security-scan/normalize/zizmor.js +19 -0
  438. package/dist/security-scan/report.js +156 -0
  439. package/dist/security-scan/run.js +448 -0
  440. package/dist/security-scan/tools.js +62 -0
  441. package/dist/security-scan/trabalhador.js +74 -0
  442. package/dist/security-scan/types.js +15 -0
  443. package/dist/session-events.js +26 -5
  444. package/dist/session-watcher-claude.js +81 -20
  445. package/dist/session-watcher.js +340 -42
  446. package/dist/sessoes-contas.js +10 -1
  447. package/dist/sessoes-inventario.js +1 -1
  448. package/dist/sessoes.js +25 -23
  449. package/dist/setup.js +59 -58
  450. package/dist/ship-publicar.js +971 -0
  451. package/dist/ship.js +243 -97
  452. package/dist/steal.js +77 -0
  453. package/dist/superficie.js +14 -11
  454. package/dist/thread-close.js +12 -11
  455. package/dist/thread.js +274 -100
  456. package/dist/tokens.js +15 -11
  457. package/dist/trabalho-thread.js +297 -0
  458. package/dist/transporte-do-canal.js +189 -0
  459. package/dist/types.js +12 -1
  460. package/dist/util.js +13 -3
  461. package/dist/varredura-acoes.js +507 -0
  462. package/dist/verify.js +608 -76
  463. package/dist/vida-da-thread.js +254 -0
  464. package/dist/worktree-local.js +167 -0
  465. package/dist/worktree.js +99 -83
  466. package/dist/yaml.js +27 -8
  467. package/eval/casos/check-quality.json +77 -0
  468. package/eval/casos/security-auditor.json +148 -0
  469. package/eval/casos/security-remediation.json +161 -0
  470. package/eval/fixtures/security-scan/README.md +8 -0
  471. package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
  472. package/eval/fixtures/security-scan/go/Dockerfile +4 -0
  473. package/eval/fixtures/security-scan/go/README.md +4 -0
  474. package/eval/fixtures/security-scan/go/config.go +4 -0
  475. package/eval/fixtures/security-scan/go/go.mod +5 -0
  476. package/eval/fixtures/security-scan/go/go.sum +2 -0
  477. package/eval/fixtures/security-scan/go/main.go +31 -0
  478. package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
  479. package/eval/fixtures/security-scan/js/Dockerfile +3 -0
  480. package/eval/fixtures/security-scan/js/README.md +4 -0
  481. package/eval/fixtures/security-scan/js/package-lock.json +844 -0
  482. package/eval/fixtures/security-scan/js/package.json +10 -0
  483. package/eval/fixtures/security-scan/js/src/config.js +4 -0
  484. package/eval/fixtures/security-scan/js/src/server.js +17 -0
  485. package/eval/fixtures/security-scan/js/src/util.ts +4 -0
  486. package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
  487. package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
  488. package/eval/fixtures/security-scan/python/Dockerfile +3 -0
  489. package/eval/fixtures/security-scan/python/README.md +4 -0
  490. package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
  491. package/eval/fixtures/security-scan/python/app/config.py +2 -0
  492. package/eval/fixtures/security-scan/python/app/main.py +19 -0
  493. package/eval/fixtures/security-scan/python/requirements.txt +1 -0
  494. package/package.json +9 -4
  495. package/references/security-checklist.md +3 -3
  496. package/schemas/code-artifact-graph.v1.schema.json +2 -1
  497. package/skills/README.md +1 -0
  498. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  499. package/skills/phases/check-quality/SKILL.md +16 -0
  500. package/skills/phases/go-implementation/SKILL.md +6 -0
  501. package/skills/phases/security-remediation/SKILL.md +70 -0
  502. package/skills/reviewers/security-auditor/SKILL.md +25 -0
@@ -0,0 +1,393 @@
1
+ // O Clima de Cota (RM-059, onda 1, F4; T4.1): a serie das janelas de limite da conta desta sessao e a
2
+ // previsao de quando cada uma acaba no ritmo atual (D4 a D6 e D12 a D15 da thread). Modulo puro: so dados
3
+ // entram e saem, para o teste do nucleo transpila-lo sem o Claude Code. Nenhum `$` passa por aqui, e o
4
+ // fuso chega explicito: quem chama decide qual e.
5
+ import type { ClimaEstado, ClimaJanela, ClimaPonto, ClimaPrevisao, ClimaProblema, ClimaSerie } from '../types'
6
+
7
+ export const FORMATO_DA_SERIE = 'ork.clima-serie/v1'
8
+ /** A chave da serie no `$.store` do mod, que dura entre sessoes. */
9
+ export const CHAVE_DA_SERIE = 'serie'
10
+ export const TETO_DE_PONTOS = 120
11
+ export const TETO_DE_JANELAS = 8
12
+ /** Diferenca de `resetsAt` que ainda e a mesma janela. */
13
+ export const TOLERANCIA_DA_RENOVACAO_MS = 60 * 1000
14
+ /** Dentro da janela o uso so cresce: uma queda deste tamanho so acontece quando ela renova. */
15
+ export const QUEDA_QUE_RENOVA = 1
16
+ /** O ritmo sai deste intervalo recente, proporcional a janela de cota (D4). */
17
+ export const INTERVALO_DO_RITMO_MS: Readonly<Record<string, number>> = {
18
+ five_hour: 60 * 60 * 1000,
19
+ seven_day: 24 * 60 * 60 * 1000,
20
+ }
21
+ export const INTERVALO_PADRAO_DO_RITMO_MS = 60 * 60 * 1000
22
+ /**
23
+ * Serie mais nova que o intervalo so tem ritmo com esta fracao dele entre a primeira e a ultima leitura: 10 min
24
+ * na janela de 5 h e 4 h na de 7 d (D13).
25
+ */
26
+ export const FRACAO_MINIMA_DO_INTERVALO = 6
27
+ /**
28
+ * Nestas janelas, a serie mais nova que o intervalo so preve o esgotamento ate a distancia que ela ja observou:
29
+ * o ritmo de quatro horas de dia util nao vale pela madrugada (D14), e a serie nova no meio da semana ainda
30
+ * avisa quando o fim esta perto (D15).
31
+ */
32
+ export const JANELAS_COM_HORIZONTE: readonly string[] = ['seven_day']
33
+ /** A partir deste percentual a faixa avisa mesmo sem ritmo (D5). */
34
+ export const LIMIAR_DE_ATENCAO = 90
35
+ /** Na faixa, o percentual vai em degraus e a hora de acabar vai arredondada, para o texto nao mudar a cada ponto (D13). */
36
+ export const DEGRAU_DO_PERCENTUAL = 10
37
+ export const PASSO_DA_HORA_NA_FAIXA_MS = 15 * 60 * 1000
38
+ /** O texto da faixa nunca passa disto, o mesmo teto da ponte. */
39
+ export const TETO_DA_FAIXA = 200
40
+ /** Quantas threads que nao cabem a faixa nomeia antes do `e mais N`. */
41
+ export const TETO_NA_FAIXA = 3
42
+ export const AVISO_DE_AUTORIDADE = 'O Clima só lê e avisa: troca de conta, de runtime ou de modelo fica com o núcleo e com você.'
43
+
44
+ const KIND = /^[a-z0-9][a-z0-9_.-]{0,63}$/i
45
+ const ORDEM_DOS_KINDS = ['five_hour', 'seven_day']
46
+ const ROTULOS: Readonly<Record<string, string>> = { five_hour: '5 h', seven_day: '7 d', spend_limit: 'gasto' }
47
+ const GRAVIDADE: Readonly<Record<ClimaEstado, number>> = { 'esgotada': 0, 'acaba-antes': 1, 'folga': 2, 'sem-ritmo': 3 }
48
+
49
+ function numero(v: unknown): v is number {
50
+ return typeof v === 'number' && Number.isFinite(v)
51
+ }
52
+
53
+ /** `5 h`, `7 d`, `gasto` ou o proprio `kind`. */
54
+ export function rotuloDaJanela(kind: string): string {
55
+ return Object.prototype.hasOwnProperty.call(ROTULOS, kind) ? (ROTULOS[kind] as string) : kind
56
+ }
57
+
58
+ function ordemDoKind(kind: string): number {
59
+ const i = ORDEM_DOS_KINDS.indexOf(kind)
60
+ return i < 0 ? ORDEM_DOS_KINDS.length : i
61
+ }
62
+
63
+ function porKind(a: { kind: string }, b: { kind: string }): number {
64
+ return ordemDoKind(a.kind) - ordemDoKind(b.kind) || (a.kind < b.kind ? -1 : a.kind > b.kind ? 1 : 0)
65
+ }
66
+
67
+ /** O intervalo recente do ritmo de uma janela. */
68
+ export function intervaloDoRitmo(kind: string): number {
69
+ return Object.prototype.hasOwnProperty.call(INTERVALO_DO_RITMO_MS, kind) ? (INTERVALO_DO_RITMO_MS[kind] as number)
70
+ : INTERVALO_PADRAO_DO_RITMO_MS
71
+ }
72
+
73
+ /** Quanto de serie a janela precisa antes de ter ritmo, enquanto e mais nova que o intervalo. */
74
+ export function minimoDaSerieJovem(kind: string): number {
75
+ return intervaloDoRitmo(kind) / FRACAO_MINIMA_DO_INTERVALO
76
+ }
77
+
78
+ /**
79
+ * Ate onde a serie jovem preve, nas janelas com horizonte: o tempo entre a primeira e a ultima leitura. `null`
80
+ * quando a serie ja cobre o intervalo inteiro ou a janela nao tem horizonte (D15).
81
+ */
82
+ export function horizonteDaSerie(j: Pick<ClimaJanela, 'kind' | 'pontos'>): number | null {
83
+ const ultimo = j.pontos[j.pontos.length - 1]
84
+ const primeiro = j.pontos[0]
85
+ if (ultimo === undefined || primeiro === undefined || !JANELAS_COM_HORIZONTE.includes(j.kind)) return null
86
+ return primeiro.em >= ultimo.em - intervaloDoRitmo(j.kind) ? ultimo.em - primeiro.em : null
87
+ }
88
+
89
+ /** A leitura conferida, ou `null` quando ela nao serve (kind estranho, percentual que nao e numero, data ruim). */
90
+ export function conferirLeitura(bruta: unknown): { kind: string; pct: number; renovaEm: number | null } | null {
91
+ const l = (bruta ?? {}) as Record<string, unknown>
92
+ if (typeof l.kind !== 'string' || !KIND.test(l.kind)) return null
93
+ if (!numero(l.percentUsed) || l.percentUsed < 0 || l.percentUsed > 1000) return null
94
+ let renovaEm: number | null = null
95
+ if (l.resetsAt !== undefined && l.resetsAt !== null) {
96
+ const t = typeof l.resetsAt === 'string' ? Date.parse(l.resetsAt) : NaN
97
+ if (!Number.isFinite(t)) return null
98
+ renovaEm = t
99
+ }
100
+ return { kind: l.kind, pct: Math.round(l.percentUsed * 10) / 10, renovaEm }
101
+ }
102
+
103
+ /** A serie guardada, ou uma vazia quando o que esta no store nao e deste formato. */
104
+ export function lerSerie(guardado: unknown): ClimaSerie {
105
+ const s = guardado as Partial<ClimaSerie> | null | undefined
106
+ const janelas: ClimaJanela[] = []
107
+ if (s && s.formato === FORMATO_DA_SERIE && Array.isArray(s.janelas)) {
108
+ for (const bruta of s.janelas) {
109
+ const j = (bruta ?? {}) as Partial<ClimaJanela>
110
+ if (typeof j.kind !== 'string' || !KIND.test(j.kind) || janelas.some(x => x.kind === j.kind)) continue
111
+ if (!(j.renovaEm === null || numero(j.renovaEm))) continue
112
+ const pontos = (Array.isArray(j.pontos) ? j.pontos : [])
113
+ .filter((p): p is ClimaPonto => !!p && numero(p.em) && numero(p.pct))
114
+ .map(p => ({ em: p.em, pct: p.pct }))
115
+ .sort((a, b) => a.em - b.em)
116
+ if (pontos.length > 0) janelas.push({ kind: j.kind, renovaEm: j.renovaEm, pontos: pontos.slice(-TETO_DE_PONTOS) })
117
+ }
118
+ }
119
+ return { formato: FORMATO_DA_SERIE, janelas: janelas.sort(porKind).slice(0, TETO_DE_JANELAS) }
120
+ }
121
+
122
+ /** A janela ja renovou: a ultima leitura dela nao diz mais nada. */
123
+ export function vencida(j: Pick<ClimaJanela, 'renovaEm'>, agora: number): boolean {
124
+ return j.renovaEm !== null && j.renovaEm + TOLERANCIA_DA_RENOVACAO_MS <= agora
125
+ }
126
+
127
+ /** Acrescenta o ponto em ordem de tempo; numa corrida plana ficam so o primeiro e o ultimo ponto. */
128
+ function acrescentar(pontos: readonly ClimaPonto[], novo: ClimaPonto): ClimaPonto[] {
129
+ const ordenados = [...pontos.filter(p => p.em !== novo.em), novo].sort((a, b) => a.em - b.em)
130
+ const saida: ClimaPonto[] = []
131
+ for (const p of ordenados) {
132
+ const ultimo = saida[saida.length - 1]
133
+ const penultimo = saida[saida.length - 2]
134
+ if (ultimo !== undefined && penultimo !== undefined && ultimo.pct === p.pct && penultimo.pct === p.pct) saida[saida.length - 1] = p
135
+ else saida.push(p)
136
+ }
137
+ return saida.slice(-TETO_DE_PONTOS)
138
+ }
139
+
140
+ /**
141
+ * O que a medicao trouxe fora do formato, numa frase, ou `null` quando tudo serviu: a lista de janelas que nem e
142
+ * lista, ou as janelas que `conferirLeitura` descarta. Sem isso, um campo renomeado no motor apagaria o Clima
143
+ * calado (D15).
144
+ */
145
+ export function problemaDaLeitura(leituras: unknown): string | null {
146
+ if (!Array.isArray(leituras)) return 'a medição avisou leitura nova sem a lista de janelas'
147
+ const descartadas = leituras.filter(l => conferirLeitura(l) === null).length
148
+ if (descartadas === 0) return null
149
+ return `a leitura trouxe ${descartadas === 1 ? '1 janela' : `${descartadas} janelas`} num formato que o Clima não conhece`
150
+ }
151
+
152
+ /**
153
+ * Grava as leituras de uma medicao em que as janelas mudaram: uma serie por `kind`, serie nova quando a
154
+ * janela renova (o `resetsAt` muda ou o percentual cai), tetos de pontos e de janelas (D4). A medicao traz
155
+ * todas as janelas da conta, entao a janela vencida e a que saiu da leitura deixam a serie (D13). Com janela
156
+ * fora do formato a leitura nao esta completa, e as outras janelas guardadas ficam (D15).
157
+ */
158
+ export function registrarLeituras(guardado: unknown, leituras: readonly unknown[] | undefined, agora: number): ClimaSerie {
159
+ const brutas = leituras ?? []
160
+ const lidas = brutas.map(conferirLeitura).filter((l): l is NonNullable<ReturnType<typeof conferirLeitura>> => l !== null)
161
+ const anteriores = lerSerie(guardado).janelas.filter(j => !vencida(j, agora))
162
+ const janelas: ClimaJanela[] = lidas.length === brutas.length ? [] : anteriores.filter(a => !lidas.some(l => l.kind === a.kind))
163
+ for (const l of lidas) {
164
+ if (janelas.some(j => j.kind === l.kind)) continue
165
+ const anterior = anteriores.find(j => j.kind === l.kind)
166
+ const ultimo = anterior?.pontos[anterior.pontos.length - 1]
167
+ const renovou = anterior !== undefined && (
168
+ (anterior.renovaEm !== null && l.renovaEm !== null && Math.abs(anterior.renovaEm - l.renovaEm) > TOLERANCIA_DA_RENOVACAO_MS)
169
+ || (ultimo !== undefined && ultimo.pct - l.pct >= QUEDA_QUE_RENOVA))
170
+ const ponto = { em: agora, pct: l.pct }
171
+ janelas.push(anterior === undefined || renovou
172
+ ? { kind: l.kind, renovaEm: l.renovaEm, pontos: [ponto] }
173
+ : { kind: l.kind, renovaEm: l.renovaEm ?? anterior.renovaEm, pontos: acrescentar(anterior.pontos, ponto) })
174
+ }
175
+ return { formato: FORMATO_DA_SERIE, janelas: janelas.sort(porKind).slice(0, TETO_DE_JANELAS) }
176
+ }
177
+
178
+ /**
179
+ * O ritmo da janela, em pontos por ms, no intervalo recente (D13). Como o uso so cresce, o valor no inicio do
180
+ * intervalo sai dos pontos que o cercam: exato quando o ultimo antes e o primeiro dentro sao iguais, e por
181
+ * interpolacao quando nao sao; com leitura esparsa (D12), isso da a inclinacao desde o ultimo ponto antes do
182
+ * intervalo. Serie mais nova que o intervalo precisa de `minimoDaSerieJovem` entre a primeira e a ultima
183
+ * leitura; antes disso, nao ha ritmo.
184
+ */
185
+ export function ritmoDaJanela(j: Pick<ClimaJanela, 'kind' | 'pontos'>): number | null {
186
+ const ultimo = j.pontos[j.pontos.length - 1]
187
+ const primeiro = j.pontos[0]
188
+ if (ultimo === undefined || primeiro === undefined) return null
189
+ const intervalo = intervaloDoRitmo(j.kind)
190
+ const inicio = ultimo.em - intervalo
191
+ const antes = [...j.pontos].reverse().find(p => p.em < inicio)
192
+ const dentro = j.pontos.find(p => p.em >= inicio)
193
+ if (antes !== undefined && dentro !== undefined) {
194
+ const noInicio = antes.pct === dentro.pct ? antes.pct
195
+ : antes.pct + (dentro.pct - antes.pct) * (inicio - antes.em) / (dentro.em - antes.em)
196
+ return (ultimo.pct - noInicio) / intervalo
197
+ }
198
+ if (ultimo.em - primeiro.em < minimoDaSerieJovem(j.kind)) return null
199
+ return (ultimo.pct - primeiro.pct) / (ultimo.em - primeiro.em)
200
+ }
201
+
202
+ /** Pontos por hora com uma casa, ou duas abaixo de 1, para o ritmo lento da semana nao virar zero (D14). */
203
+ function arredondarRitmo(porHora: number): number {
204
+ return Math.abs(porHora) < 1 ? Math.round(porHora * 100) / 100 : Math.round(porHora * 10) / 10
205
+ }
206
+
207
+ /** A previsao de cada janela que ainda nao renovou, da mais urgente para a mais calma. */
208
+ export function prever(guardado: unknown, agora: number): ClimaPrevisao[] {
209
+ const previsoes: ClimaPrevisao[] = []
210
+ for (const j of lerSerie(guardado).janelas) {
211
+ const ultimo = j.pontos[j.pontos.length - 1]
212
+ if (ultimo === undefined || vencida(j, agora)) continue
213
+ const ritmoPorMs = ritmoDaJanela(j)
214
+ let estado: ClimaEstado
215
+ let acabaEm: number | null = null
216
+ if (ultimo.pct >= 100) estado = 'esgotada'
217
+ else if (ritmoPorMs === null) estado = 'sem-ritmo'
218
+ else if (ritmoPorMs <= 0) estado = 'folga'
219
+ else {
220
+ acabaEm = Math.round(ultimo.em + (100 - ultimo.pct) / ritmoPorMs)
221
+ const horizonte = horizonteDaSerie(j)
222
+ if (j.renovaEm !== null && acabaEm >= j.renovaEm) estado = 'folga'
223
+ else if (horizonte !== null && acabaEm - ultimo.em > horizonte) {
224
+ // A serie jovem nao preve alem do que ja observou (D15).
225
+ estado = 'sem-ritmo'
226
+ acabaEm = null
227
+ } else estado = 'acaba-antes'
228
+ }
229
+ previsoes.push({
230
+ kind: j.kind, rotulo: rotuloDaJanela(j.kind), pct: ultimo.pct, lidaEm: ultimo.em, renovaEm: j.renovaEm,
231
+ ritmoPorHora: ritmoPorMs === null ? null : arredondarRitmo(ritmoPorMs * 3600 * 1000), acabaEm, estado,
232
+ })
233
+ }
234
+ return previsoes.sort((a, b) => GRAVIDADE[a.estado] - GRAVIDADE[b.estado] || porKind(a, b))
235
+ }
236
+
237
+ /** A janela ja se esgotou ou acaba antes de renovar no ritmo atual. */
238
+ export function emAlerta(p: ClimaPrevisao): boolean {
239
+ return p.estado === 'esgotada' || p.estado === 'acaba-antes'
240
+ }
241
+
242
+ /** A janela pede atencao na faixa: em alerta, ou no limiar mesmo sem ritmo (D5). */
243
+ export function pedeAtencao(p: ClimaPrevisao): boolean {
244
+ return emAlerta(p) || p.pct >= LIMIAR_DE_ATENCAO
245
+ }
246
+
247
+ type Partes = { ano: string; mes: string; dia: string; hora: string; minuto: string }
248
+
249
+ function partesLocais(ms: number, fuso: string): Partes {
250
+ let f: Intl.DateTimeFormat
251
+ try {
252
+ f = new Intl.DateTimeFormat('en-US', { timeZone: fuso, year: 'numeric', month: '2-digit', day: '2-digit',
253
+ hour: '2-digit', minute: '2-digit', hourCycle: 'h23' })
254
+ } catch {
255
+ f = new Intl.DateTimeFormat('en-US', { timeZone: 'UTC', year: 'numeric', month: '2-digit', day: '2-digit',
256
+ hour: '2-digit', minute: '2-digit', hourCycle: 'h23' })
257
+ }
258
+ const p: Record<string, string> = {}
259
+ for (const parte of f.formatToParts(new Date(ms))) p[parte.type] = parte.value
260
+ return { ano: p.year ?? '', mes: p.month ?? '', dia: p.day ?? '', hora: p.hour ?? '', minuto: p.minute ?? '' }
261
+ }
262
+
263
+ /**
264
+ * A hora no fuso, com o minuto truncado como o nucleo escreve: `16:40` no mesmo dia de `agora`, `13/10 09:00`
265
+ * em outro dia e `13/10/2027 09:00` em outro ano.
266
+ */
267
+ export function formatarHora(ms: number, fuso: string, agora: number): string {
268
+ const p = partesLocais(ms, fuso)
269
+ const a = partesLocais(agora, fuso)
270
+ if (p.ano === a.ano && p.mes === a.mes && p.dia === a.dia) return `${p.hora}:${p.minuto}`
271
+ return `${p.dia}/${p.mes}${p.ano !== a.ano ? `/${p.ano}` : ''} ${p.hora}:${p.minuto}`
272
+ }
273
+
274
+ /** `45min`, `1h30`, `2d 05h`, como o nucleo escreve; abaixo de 1 min, `menos de 1 min`. */
275
+ export function duracao(ms: number): string {
276
+ const minutos = Math.floor(Math.abs(ms) / 60000)
277
+ if (minutos < 1) return 'menos de 1 min'
278
+ if (minutos < 60) return `${minutos}min`
279
+ const horas = Math.floor(minutos / 60)
280
+ if (horas < 24) return `${horas}h${String(minutos % 60).padStart(2, '0')}`
281
+ return `${Math.floor(horas / 24)}d ${String(horas % 24).padStart(2, '0')}h`
282
+ }
283
+
284
+ /** `em 1h30` ou `há 10min`, relativo a `agora`. */
285
+ export function distancia(ms: number, agora: number): string {
286
+ return ms >= agora ? `em ${duracao(ms - agora)}` : `há ${duracao(agora - ms)}`
287
+ }
288
+
289
+ /** O numero com virgula decimal e no maximo `casas` casas. */
290
+ export function numeroBr(n: number, casas = 1): string {
291
+ const fator = 10 ** casas
292
+ return String(Math.round(n * fator) / fator).replace('.', ',')
293
+ }
294
+
295
+ /** O percentual da faixa em degraus: `70% ou mais`, ou `menos de 10%` (D13). */
296
+ export function percentualEmDegrau(pct: number): string {
297
+ const degrau = Math.floor(pct / DEGRAU_DO_PERCENTUAL) * DEGRAU_DO_PERCENTUAL
298
+ return degrau <= 0 ? `menos de ${DEGRAU_DO_PERCENTUAL}%` : `${degrau}% ou mais`
299
+ }
300
+
301
+ /**
302
+ * O trecho de uma janela na faixa: percentual em degraus e hora de acabar arredondada para baixo ao quarto de
303
+ * hora (D13), que assim nunca passa da renovacao (D14). A hora que nao fica depois da leitura vira `acaba em
304
+ * instantes` (D15).
305
+ */
306
+ function trechoDaFaixa(p: ClimaPrevisao, fuso: string, agora: number): string {
307
+ const renova = p.renovaEm === null ? '' : `, renova ${formatarHora(p.renovaEm, fuso, agora)}`
308
+ if (p.estado === 'esgotada') return `${p.rotulo} esgotou${renova}`
309
+ if (p.estado === 'acaba-antes' && p.acabaEm !== null) {
310
+ const acaba = Math.floor(p.acabaEm / PASSO_DA_HORA_NA_FAIXA_MS) * PASSO_DA_HORA_NA_FAIXA_MS
311
+ const quando = acaba > p.lidaEm ? `acaba ~${formatarHora(acaba, fuso, agora)}` : 'acaba em instantes'
312
+ return `${p.rotulo} com ${percentualEmDegrau(p.pct)}, ${quando}${renova}`
313
+ }
314
+ return `${p.rotulo} com ${percentualEmDegrau(p.pct)}${renova}`
315
+ }
316
+
317
+ function cortar(texto: string, teto: number): string {
318
+ return texto.length <= teto ? texto : texto.slice(0, teto - 1) + '…'
319
+ }
320
+
321
+ /**
322
+ * A linha do Clima na faixa da ponte, ou `null` quando nenhuma janela pede atencao (a linha sai). As threads
323
+ * que nao cabem vem primeiro, porque a faixa corta o fim da linha (D13).
324
+ */
325
+ export function textoDaFaixa(previsoes: readonly ClimaPrevisao[], fuso: string, agora: number, naoCabem: readonly string[] = []): string | null {
326
+ const trechos = previsoes.filter(pedeAtencao).map(p => trechoDaFaixa(p, fuso, agora))
327
+ if (trechos.length === 0) return null
328
+ const nomeadas = naoCabem.slice(0, TETO_NA_FAIXA)
329
+ const mais = naoCabem.length > nomeadas.length ? ` e mais ${naoCabem.length - nomeadas.length}` : ''
330
+ const inicio = nomeadas.length > 0 ? `não cabe: ${nomeadas.join(', ')}${mais}; ` : ''
331
+ return cortar(inicio + trechos.join(' · '), TETO_DA_FAIXA)
332
+ }
333
+
334
+ /** `às 14:30` hoje, `em 11/10 14:30` em outro dia. */
335
+ function quandoLida(ms: number, fuso: string, agora: number): string {
336
+ const hora = formatarHora(ms, fuso, agora)
337
+ return hora.includes('/') ? `em ${hora}` : `às ${hora}`
338
+ }
339
+
340
+ /** Uma janela no `/clima`, com o ritmo, a previsao, a renovacao, as distancias e a hora da leitura. */
341
+ export function linhaDaJanela(p: ClimaPrevisao, fuso: string, agora: number): string {
342
+ const ritmo = p.ritmoPorHora === null ? 'ritmo ainda sem leituras suficientes'
343
+ : `ritmo de ${numeroBr(p.ritmoPorHora, Math.abs(p.ritmoPorHora) < 1 ? 2 : 1)} pontos por hora`
344
+ let previsao: string
345
+ if (p.estado === 'esgotada') previsao = 'esgotou'
346
+ else if (p.estado === 'acaba-antes' && p.acabaEm !== null) {
347
+ previsao = `acaba ~${formatarHora(p.acabaEm, fuso, agora)} (${distancia(p.acabaEm, agora)}), antes de renovar`
348
+ } else if (p.estado === 'folga') previsao = 'folga no ritmo atual'
349
+ else previsao = 'sem previsão ainda'
350
+ const renova = p.renovaEm === null ? 'sem hora de renovação' : `renova ${formatarHora(p.renovaEm, fuso, agora)} (${distancia(p.renovaEm, agora)})`
351
+ return `- ${p.rotulo}: ${numeroBr(p.pct)}%, ${ritmo}, ${previsao}, ${renova}. Lida ${quandoLida(p.lidaEm, fuso, agora)}.`
352
+ }
353
+
354
+ /** O problema da ultima medicao numa linha: `A medicao falhou (...) as 14:30.` (D15). */
355
+ export function textoDoProblema(p: ClimaProblema, fuso: string, agora: number): string {
356
+ const quando = p.em === null ? '' : ` ${quandoLida(p.em, fuso, agora)}`
357
+ return `${p.motivo.charAt(0).toUpperCase()}${p.motivo.slice(1)}${quando}.`
358
+ }
359
+
360
+ /**
361
+ * O texto do `/clima`: as janelas da conta desta sessao, o problema da ultima medicao, o que vier depois e o aviso
362
+ * de autoridade. Com problema guardado, a falta de leitura nao e atribuida a conta (D15).
363
+ */
364
+ export function textoDoClima(previsoes: readonly ClimaPrevisao[], fuso: string, agora: number, extras: readonly string[] = [],
365
+ problema: ClimaProblema | null = null): string {
366
+ const linhas = ['Clima de cota da conta desta sessão']
367
+ if (previsoes.length > 0) {
368
+ for (const p of previsoes) linhas.push(linhaDaJanela(p, fuso, agora))
369
+ } else if (problema === null) {
370
+ linhas.push('Sem leitura de cota ainda. A leitura chega na medição depois de uma resposta da API desta sessão, e só existe em conta de assinatura.')
371
+ } else {
372
+ linhas.push('Sem leitura de cota guardada.')
373
+ }
374
+ if (problema !== null) linhas.push(textoDoProblema(problema, fuso, agora))
375
+ return [...linhas, ...extras, AVISO_DE_AUTORIDADE].join('\n')
376
+ }
377
+
378
+ /** O `/clima` fora da sessao do dono: o Clima so roda nela (D3). */
379
+ export function textoForaDoDono(papel: string): string {
380
+ const base = `O Clima de Cota só roda na sessão do dono de um projeto do Orkastery; o papel desta sessão é ${papel}.`
381
+ return papel === 'dormente' ? `${base} Se o servidor orkastery ainda está conectando, tente de novo em instantes.` : base
382
+ }
383
+
384
+ /** O `/clima` sem a ponte, de quem o Clima depende para tudo; o erro interno nao vai ao dono (D13). */
385
+ export const TEXTO_SEM_PONTE = 'O Clima de Cota depende da ponte ork-ponte, que não respondeu nesta sessão; confira se ela está instalada e carregada.'
386
+ /** O mesmo motivo, como problema da medicao (D15). */
387
+ export const MOTIVO_SEM_PONTE = 'a ponte ork-ponte não respondeu; confira se ela está instalada e carregada'
388
+
389
+ /** O motivo de um erro em uma linha curta. */
390
+ export function motivoDoErro(erro: unknown): string {
391
+ const texto = erro instanceof Error ? erro.message : String(erro)
392
+ return texto.replace(/\s+/g, ' ').trim().slice(0, 200)
393
+ }
@@ -0,0 +1,205 @@
1
+ // O Clima de Cota (RM-059, onda 1, F4). Le as janelas de limite da conta desta sessao a cada medicao do
2
+ // motor, guarda a serie no `$.store` do mod, preve quando cada janela acaba no ritmo atual e avisa na faixa
3
+ // da ponte antes de a fase morrer no meio, com as retomadas que nao cabem (T4.2). So na sessao do dono, so
4
+ // le e so avisa: troca de conta, runtime ou modelo fica com o nucleo (rodizio) e com o dono. O `$.ork` vem
5
+ // da `ork-ponte`; a logica fica nos modulos puros ao lado, e aqui so as chamadas ao `$`, sempre escritas
6
+ // pelo nome do noun e do metodo, como o validador exige.
7
+ import type { Register } from 'claude-code'
8
+ import type { ClimaNaoCabe, ClimaProblema } from '../types'
9
+ import {
10
+ cruzar, linhasDoCruzamento, marcasDoRelatorio, naoCabemGuardados, paradasDoRetrato, resumoDoClima, retomadasDaFila,
11
+ textoDoNaoCabe, threadsAbertas, threadsQueNaoCabem,
12
+ } from './contas'
13
+ import {
14
+ CHAVE_DA_SERIE, emAlerta, MOTIVO_SEM_PONTE, motivoDoErro, prever, problemaDaLeitura, registrarLeituras, TEXTO_SEM_PONTE,
15
+ textoDaFaixa, textoDoClima, textoForaDoDono,
16
+ } from './previsao'
17
+
18
+ const MOD = 'ork-clima'
19
+ const FAIXA = { plugin: 'ork-clima', key: 'faixa' } as const
20
+ const NAO_CABEM = { plugin: 'ork-clima', key: 'naoCabem' } as const
21
+ const PROBLEMA = { plugin: 'ork-clima', key: 'problema' } as const
22
+
23
+ /** O fuso da sessao (D6): a ponte nao entrega o `owner.timezone`. */
24
+ function fusoDaSessao(): string {
25
+ try {
26
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'
27
+ } catch {
28
+ return 'UTC'
29
+ }
30
+ }
31
+
32
+ export const register: Register = on => {
33
+ // O `/clima` fica disponivel fora da sessao de fase (D3), e tambem sem a ponte, para dizer o motivo. A faixa
34
+ // so sai na primeira medicao: antes de o servidor `orkastery` conectar, a ponte ainda responde `dormente`.
35
+ // O registro recusado nao segura o inicio da sessao, mas o motivo vai ao transcript (D15).
36
+ on('session.start', async ($, e, next) => {
37
+ let papel: string | null = null
38
+ try {
39
+ papel = await $.ork.papel()
40
+ } catch {
41
+ papel = null
42
+ }
43
+ if (papel !== 'fase') {
44
+ await $.command.register({ name: 'clima', description: 'Previsão da cota da conta desta sessão: quando cada janela acaba no ritmo atual' })
45
+ .catch(erro => $.ui.log(`Clima de Cota: o /clima não foi registrado (${motivoDoErro(erro)}).`))
46
+ }
47
+ return next(e)
48
+ })
49
+
50
+ // Cada medicao: grava a leitura quando as janelas mudaram (D2) e republica a faixa so quando o texto muda (D5).
51
+ // Com janela em alerta e leitura nova, le a fila inteira de retomada e guarda as que nao cabem (D7, D13); a
52
+ // medicao sem leitura nova usa o que ficou guardado. So vai ao registro do mostrado o que a faixa mostrou, e o
53
+ // registro que falhar fica pendente para a medicao seguinte (D15). Fora do papel `dono`, a linha sai (D13).
54
+ // Uma falha nunca segura a medicao: o motivo novo vai uma vez ao transcript e fica no estado para o `/clima`,
55
+ // ate uma medicao boa limpa-lo (D15).
56
+ on('session.measure', async ($, e, next) => {
57
+ let agora: number | null = null
58
+ let problema: ClimaProblema | null = null
59
+ let semLeituraNova = false
60
+ try {
61
+ agora = await $.clock.now()
62
+ let papel: string | null = null
63
+ try {
64
+ papel = await $.ork.papel()
65
+ } catch {
66
+ papel = null
67
+ }
68
+ const anterior = await $.state.get(FAIXA)
69
+ if (papel === null) {
70
+ problema = { motivo: MOTIVO_SEM_PONTE, em: agora, daLeitura: false }
71
+ } else if (papel !== 'dono') {
72
+ if ((anterior.value ?? null) !== null) {
73
+ await $.ork.faixa({ mod: MOD })
74
+ await $.state.set(FAIXA, null, { ifVersion: anterior.version })
75
+ }
76
+ } else {
77
+ const fuso = fusoDaSessao()
78
+ const leu = e.changed.includes('rateLimits')
79
+ semLeituraNova = !leu
80
+ let serie = await $.store.get(CHAVE_DA_SERIE)
81
+ if (leu) {
82
+ const motivo = problemaDaLeitura(e.rateLimits)
83
+ if (motivo !== null) problema = { motivo, em: agora, daLeitura: true }
84
+ // A medicao sem a lista de janelas nao apaga a serie guardada (D15).
85
+ if (Array.isArray(e.rateLimits)) {
86
+ serie = registrarLeituras(serie, e.rateLimits, agora)
87
+ await $.store.set(CHAVE_DA_SERIE, serie)
88
+ }
89
+ }
90
+ const previsoes = prever(serie, agora)
91
+ const alerta = previsoes.some(emAlerta)
92
+ const guardados = await $.state.get(NAO_CABEM)
93
+ let naoCabem: ClimaNaoCabe[] = alerta ? naoCabemGuardados(guardados.value) : []
94
+ if (alerta && leu) {
95
+ try {
96
+ const fila = retomadasDaFila(await $.ork.ler({ consulta: 'retry.list' }))
97
+ if (fila !== null) {
98
+ const antes = naoCabem
99
+ const lidaEm = agora
100
+ naoCabem = cruzar(previsoes, fila, lidaEm).filter(d => d.classe === 'nao-cabe').map(d =>
101
+ antes.find(n => n.id === d.retomada.id)
102
+ ?? { id: d.retomada.id, thread: d.retomada.thread, texto: textoDoNaoCabe(d, fuso, lidaEm), registrada: false })
103
+ }
104
+ } catch {
105
+ // Fila indisponivel: vale o que a ultima leitura deixou, e o `/clima` diz o motivo quando le a fila.
106
+ }
107
+ }
108
+ let versao = guardados.version
109
+ if (JSON.stringify(naoCabem) !== JSON.stringify(guardados.value ?? [])) {
110
+ versao = (await $.state.set(NAO_CABEM, naoCabem, { ifVersion: guardados.version })).version
111
+ }
112
+ const threads = naoCabem.map(n => n.thread).filter((t, i, todas) => todas.indexOf(t) === i)
113
+ const texto = textoDaFaixa(previsoes, fuso, agora, threads)
114
+ let mostrada = (anterior.value ?? null) === texto
115
+ if (!mostrada) {
116
+ const r = await $.ork.faixa(texto === null ? { mod: MOD } : { mod: MOD, texto })
117
+ if (texto === null || r.publicada) {
118
+ await $.state.set(FAIXA, texto, { ifVersion: anterior.version })
119
+ mostrada = true
120
+ }
121
+ }
122
+ if (mostrada && texto !== null && naoCabem.some(n => !n.registrada)) {
123
+ const registradas: ClimaNaoCabe[] = []
124
+ for (const n of naoCabem) {
125
+ if (n.registrada) {
126
+ registradas.push(n)
127
+ continue
128
+ }
129
+ try {
130
+ await $.ork.mostrado({ mod: MOD, canal: 'faixa', chave: `clima:nao-cabe:${n.id}`, thread: n.thread, texto: n.texto })
131
+ registradas.push({ ...n, registrada: true })
132
+ } catch (erro) {
133
+ registradas.push(n)
134
+ if (problema === null) problema = { motivo: `o registro do mostrado na ponte falhou (${motivoDoErro(erro)})`, em: agora, daLeitura: false }
135
+ }
136
+ }
137
+ naoCabem = registradas
138
+ await $.state.set(NAO_CABEM, naoCabem, { ifVersion: versao })
139
+ }
140
+ }
141
+ } catch (erro) {
142
+ problema = { motivo: `a medição falhou (${motivoDoErro(erro)})`, em: agora, daLeitura: false }
143
+ }
144
+ try {
145
+ const guardado = await $.state.get(PROBLEMA)
146
+ const antes = guardado.value ?? null
147
+ const depois = problema ?? (semLeituraNova && antes !== null && antes.daLeitura ? antes : null)
148
+ if (JSON.stringify(depois) !== JSON.stringify(antes)) {
149
+ await $.state.set(PROBLEMA, depois, { ifVersion: guardado.version })
150
+ // So o motivo novo vai ao transcript: a falha que se repete a cada medicao nao enche a tela.
151
+ if (depois !== null && depois.motivo !== antes?.motivo) $.ui.log(`Clima de Cota: ${depois.motivo}. O /clima mostra o que ficou guardado.`)
152
+ }
153
+ } catch (erro) {
154
+ $.ui.log(`Clima de Cota: o problema da medição não foi guardado (${motivoDoErro(erro)}).`, { to: 'debug' })
155
+ }
156
+ return next(e)
157
+ })
158
+
159
+ // O `/clima` le a serie guardada e nao grava ponto: o uso pedido na hora repete a ultima resposta, e um ponto
160
+ // com a hora de agora achataria o ritmo (D2). Le a fila, o retrato, as threads abertas e o registro de contas
161
+ // ao mesmo tempo (D3, D13); leitura que falha vira aviso no texto, o problema da ultima medicao aparece (D15), e
162
+ // o que foi mostrado vai ao registro da ponte (D8).
163
+ on('command.run', { command: 'clima' }, async $ => {
164
+ const agora = await $.clock.now()
165
+ const fuso = fusoDaSessao()
166
+ let papel: string
167
+ try {
168
+ papel = await $.ork.papel()
169
+ } catch {
170
+ return { text: TEXTO_SEM_PONTE }
171
+ }
172
+ if (papel !== 'dono') return { text: textoForaDoDono(papel) }
173
+ const previsoes = prever(await $.store.get(CHAVE_DA_SERIE), agora)
174
+ const problema = (await $.state.get(PROBLEMA)).value ?? null
175
+ const ler = (p: Promise<unknown>) => p.then(valor => ({ ok: true as const, valor }), erro => ({ ok: false as const, erro: motivoDoErro(erro) }))
176
+ const [fila, retrato, abertas, registro] = await Promise.all([
177
+ ler($.ork.ler({ consulta: 'retry.list' })),
178
+ ler($.ork.retrato().then(r => r.retrato)),
179
+ ler($.ork.ler({ consulta: 'thread.list' })),
180
+ ler($.ork.ler({ consulta: 'accounts.esgotamentos' })),
181
+ ])
182
+ const retomadas = fila.ok ? retomadasDaFila(fila.valor) : null
183
+ const despachos = retomadas === null ? null : cruzar(previsoes, retomadas, agora)
184
+ // Sem a lista de threads abertas, as paradas nao sao conferidas: o retrato tambem traz thread fechada (D14).
185
+ const listaDeAbertas = abertas.ok ? threadsAbertas(abertas.valor) : null
186
+ const linhas = linhasDoCruzamento({
187
+ despachos, erroDaFila: fila.ok ? null : fila.erro,
188
+ paradas: retrato.ok && listaDeAbertas !== null ? paradasDoRetrato(retrato.valor, listaDeAbertas) : null,
189
+ erroDoRetrato: !retrato.ok ? retrato.erro
190
+ : listaDeAbertas === null ? `sem a lista de threads abertas: ${abertas.ok ? 'fora do formato' : abertas.erro}` : null,
191
+ marcas: registro.ok ? marcasDoRelatorio(registro.valor) : null, erroDoRegistro: registro.ok ? null : registro.erro,
192
+ }, previsoes, fuso, agora)
193
+ const naoCabem = (despachos ?? []).filter(d => d.classe === 'nao-cabe')
194
+ try {
195
+ await $.ork.mostrado({ mod: MOD, canal: 'transcript', chave: 'clima:consulta', texto: resumoDoClima(previsoes, threadsQueNaoCabem(naoCabem), fuso, agora) })
196
+ for (const d of naoCabem) {
197
+ await $.ork.mostrado({ mod: MOD, canal: 'transcript', chave: `clima:nao-cabe:${d.retomada.id}`, thread: d.retomada.thread,
198
+ texto: textoDoNaoCabe(d, fuso, agora) })
199
+ }
200
+ } catch {
201
+ // O registro do mostrado e melhor esforco: o texto chega ao dono de qualquer jeito, e cada `/clima` registra de novo.
202
+ }
203
+ return { text: textoDoClima(previsoes, fuso, agora, linhas, problema) }
204
+ })
205
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "formato": "ork.mod/v1",
3
+ "papeis": ["dono"],
4
+ "claudeCodeMinimo": "2.1.287"
5
+ }