@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,437 @@
1
+ // A Torre de Controle do Orkastery (RM-059, fatia F1; ficha M3 do plano dos mods). Na sessao do dono, um painel
2
+ // com a fabrica inteira: uma linha por thread aberta desta maquina, lida do nucleo pela ponte (`$.ork.retrato`
3
+ // e a lista fechada do `$.ork.ler`), nunca de `.orkastery/` por conta propria. A Torre so le: nenhum caminho
4
+ // daqui age pelo dono. A logica fica nos modulos puros ao lado; aqui so os ganchos e as chamadas ao `$`,
5
+ // sempre escritas como `x.noun.metodo(...)`, como o validador exige.
6
+ import { atom, read, update } from 'claude-code'
7
+ import type { EngineInterface, Register } from 'claude-code'
8
+ import type { TorreDetalhe, TorreLeitura, TorreLinha, TorreMostrado, TorreQuadro, TorreRede } from '../types'
9
+ import {
10
+ escolher, ESPERA_DO_LOTE_MS, IDADE_MAXIMA_ESCONDIDO_MS, IDADE_MAXIMA_MS, INTERVALO_ESCONDIDO_MS, INTERVALO_POR_THREAD_MS,
11
+ marcaDoArquivo, PERIODO_DO_TIQUE_MS, vencidas,
12
+ } from './agenda'
13
+ import type { Dono } from './detalhe'
14
+ import {
15
+ desenharDetalhe, donosCarregados, jsonDoMcp, leituraFalha, leituraFeita, linhasDaObservacao, linhasDasClaims, linhasDoDetalhe,
16
+ linhasDoEstado, linhasDoGit, linhasDosEventos,
17
+ } from './detalhe'
18
+ import {
19
+ abertasDaLista, desenharPainel, linhaDaThread, linhasDoPainel, mostradosDoQuadro, mostradosVisiveis, ordenarLinhas,
20
+ } from './painel'
21
+ import { PERIODO_DA_REDE_MS, redeComErro, redeDoPanorama, textoDaFaixa } from './rede'
22
+
23
+ const MOD = 'ork-torre'
24
+ const PAINEL = 'torre'
25
+ const TITULO = 'Torre'
26
+ const QUADRO_VAZIO: TorreQuadro = { linhas: [], omitidas: 0, lidoEm: null, erro: null }
27
+ const quadro = atom({ plugin: 'ork-torre', key: 'quadro' } as const, QUADRO_VAZIO)
28
+ const aberta = atom({ plugin: 'ork-torre', key: 'aberta' } as const, null as string | null)
29
+ const detalhes = atom({ plugin: 'ork-torre', key: 'detalhes' } as const, {} as Record<string, TorreDetalhe>)
30
+ const donos = atom({ plugin: 'ork-torre', key: 'donos' } as const, {} as Record<string, string>)
31
+ const rede = atom({ plugin: 'ork-torre', key: 'rede' } as const, null as TorreRede | null)
32
+ const fechado = atom({ plugin: 'ork-torre', key: 'fechado' } as const, false)
33
+ const DETALHE_VAZIO: TorreDetalhe = { eventos: null, claims: null, leituras: {} }
34
+ /** O servidor do nucleo pode conectar depois do inicio da sessao: o papel e conferido de novo nestas esperas. */
35
+ const ESPERAS_DO_PAPEL_MS = [3000, 10000, 30000]
36
+ /** Depois delas, enquanto dormente, a cada 5 min: o servidor pode conectar tarde ou ser reconectado. */
37
+ const ESPERA_LONGA_DO_PAPEL_MS = 300000
38
+ /** Teto de cada leitura do nucleo: leitura que nao volta nao trava o laco de leitura (o retrato tem teto de 10 s). */
39
+ const PRAZO_DA_LEITURA_MS = 20000
40
+
41
+ // O que o modulo guarda entre ganchos e nao desenha. Uma recarga do modulo zera tudo, e o `session.start`
42
+ // dispara de novo nela; o estado em `$.state` (o quadro, o detalhe, o painel fechado) fica.
43
+ let ativa = false
44
+ let desistiu = false
45
+ let abriuSozinho = false
46
+ let ciclo: { cancel: () => void } | undefined
47
+ let lote: { cancel: () => void } | undefined
48
+ let lendo: Promise<void> | undefined
49
+ let pendente = false
50
+ let tudoPedido = false
51
+ let listaPedida = true
52
+ let listaLidaEm: number | null = null
53
+ const marcadas = new Set<string>()
54
+ /** Threads que o dono mandou reler agora (o Atualizar do detalhe): passam pelo laco unico, sem o intervalo. */
55
+ const forcadas = new Set<string>()
56
+ const threadLidaEm: Record<string, number> = {}
57
+ /** O que o desenho poe na janela de rolagem e ainda nao foi ao registro da ponte (D10). */
58
+ const vistosNoDesenho = new Map<string, TorreMostrado>()
59
+ /** O que ja foi ao registro nesta sessao, por chave e texto; sai quando o item some do quadro. */
60
+ const jaMostrado = new Set<string>()
61
+ /** A ultima tentativa de ler a rede (comeca na ativacao: nunca no inicio da sessao, D11). */
62
+ let redeTentadaEm = 0
63
+ /** O ultimo texto publicado na faixa; null antes da primeira publicacao. */
64
+ let ultimaFaixa: string | undefined | null = null
65
+
66
+ function mensagem(erro: unknown): string {
67
+ return (erro instanceof Error ? erro.message : String(erro)).replace(/\s+/g, ' ').trim().slice(0, 200)
68
+ }
69
+
70
+ /** A leitura com teto proprio: o relogio da sessao recusa a espera que passar dele. */
71
+ function comPrazo<T>($: EngineInterface, leitura: Promise<T>, ms = PRAZO_DA_LEITURA_MS): Promise<T> {
72
+ return new Promise<T>((resolver, recusar) => {
73
+ const prazo = $.clock.after(ms, () => recusar(new Error(`a leitura passou de ${Math.round(ms / 1000)} s`)))
74
+ leitura.then(v => { prazo.cancel(); resolver(v) }, e => { prazo.cancel(); recusar(e) })
75
+ })
76
+ }
77
+
78
+ /**
79
+ * O papel pela ponte. `null` so quando o `$.ork` nao existe (a ponte nao carregou: a chamada nem acontece);
80
+ * uma falha da propria ponte conta como dormente e o papel e conferido de novo depois.
81
+ */
82
+ async function papelDaSessao($: EngineInterface): Promise<string | null> {
83
+ try {
84
+ return String(await $.ork.papel())
85
+ } catch (erro) {
86
+ return erro instanceof TypeError ? null : 'dormente'
87
+ }
88
+ }
89
+
90
+ /** Liga a Torre na sessao do dono (D12): o `/torre`, o tique e a primeira leitura. */
91
+ async function ativar($: EngineInterface): Promise<void> {
92
+ if (ativa) return
93
+ ativa = true
94
+ redeTentadaEm = await $.clock.now()
95
+ await $.command.register({ name: 'torre', description: 'Abre a Torre de Controle: a fábrica do Orkastery num painel', immediate: true })
96
+ ciclo?.cancel()
97
+ ciclo = $.clock.every(PERIODO_DO_TIQUE_MS, () => { void tique($) })
98
+ agendar($, 1)
99
+ }
100
+
101
+ /** Confere o papel: liga no dono, desiste na fase ou sem a ponte, e tenta de novo enquanto dormente. */
102
+ async function conferirPapel($: EngineInterface, tentativa: number): Promise<void> {
103
+ if (ativa || desistiu) return
104
+ const papel = await papelDaSessao($)
105
+ if (papel === 'dono') return ativar($)
106
+ if (papel === 'fase' || papel === null) {
107
+ desistiu = true
108
+ if (papel === null) $.ui.toast('torre: a ponte ork-ponte não carregou; a Torre de Controle fica desligada nesta sessão')
109
+ return
110
+ }
111
+ const espera = ESPERAS_DO_PAPEL_MS[tentativa] ?? ESPERA_LONGA_DO_PAPEL_MS
112
+ $.clock.after(espera, () => { void conferirPapel($, tentativa + 1) })
113
+ }
114
+
115
+ /** Um lote de leitura daqui a pouco, um por vez: os eventos de arquivo se juntam nele (D7). */
116
+ function agendar($: EngineInterface, ms = ESPERA_DO_LOTE_MS): void {
117
+ if (lote) return
118
+ lote = $.clock.after(Math.max(1, ms), () => {
119
+ lote = undefined
120
+ void atualizar($)
121
+ })
122
+ }
123
+
124
+ /** O painel da Torre esta posto e a vista do dono. */
125
+ async function painelAVista($: EngineInterface): Promise<boolean> {
126
+ const paineis = await $.ui.panes().catch(() => [])
127
+ return paineis.some(p => p.id === PAINEL && p.isPlaced && p.isShown)
128
+ }
129
+
130
+ /** O tique do minuto: a lista das abertas, as linhas que ficaram velhas e, com o painel a vista, a rede. */
131
+ async function tique($: EngineInterface): Promise<void> {
132
+ if (!ativa) return
133
+ const agora = await $.clock.now()
134
+ const aVista = await painelAVista($)
135
+ listaPedida = true
136
+ const idade = aVista ? IDADE_MAXIMA_MS : IDADE_MAXIMA_ESCONDIDO_MS
137
+ for (const t of vencidas((await read($, quadro)).linhas.map(l => l.thread), threadLidaEm, agora, idade)) marcadas.add(t)
138
+ await atualizar($)
139
+ if (aVista && agora - redeTentadaEm >= PERIODO_DA_REDE_MS) await lerRede($)
140
+ await registrarMostrados($)
141
+ }
142
+
143
+ /** A rede pelo panorama do nucleo (D11): pelo botao, ou no tique com o painel a vista, no maximo a cada 10 min. */
144
+ async function lerRede($: EngineInterface): Promise<void> {
145
+ const agora = await $.clock.now()
146
+ redeTentadaEm = agora
147
+ const locais = (await read($, quadro)).linhas.map(l => l.thread)
148
+ try {
149
+ const nova = redeDoPanorama(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_network_roadmap', {}))), locais, agora)
150
+ await update($, rede, () => nova)
151
+ } catch (erro) {
152
+ const motivo = mensagem(erro)
153
+ await update($, rede, anterior => redeComErro(anterior, motivo))
154
+ }
155
+ await publicarFaixa($)
156
+ }
157
+
158
+ /** A linha da faixa pela ponte (D9), so quando o texto muda; sem quadro lido, a linha sai da faixa. */
159
+ async function publicarFaixa($: EngineInterface): Promise<void> {
160
+ const texto = textoDaFaixa(await read($, quadro), await read($, rede))
161
+ if (texto === ultimaFaixa) return
162
+ try {
163
+ if (texto === undefined) await $.ork.faixa({ mod: MOD })
164
+ else await $.ork.faixa({ mod: MOD, texto })
165
+ ultimaFaixa = texto
166
+ } catch {
167
+ // A ponte recusou ou falhou: a proxima leitura tenta de novo.
168
+ }
169
+ }
170
+
171
+ /** Uma leitura por vez; pedido que chega no meio volta a rodar logo depois, e quem pediu espera as duas. */
172
+ async function atualizar($: EngineInterface, tudo = false): Promise<void> {
173
+ if (!ativa) return
174
+ if (tudo) { tudoPedido = true; listaPedida = true }
175
+ if (lendo) {
176
+ pendente = true
177
+ return lendo
178
+ }
179
+ lendo = (async () => {
180
+ try {
181
+ do {
182
+ pendente = false
183
+ await lerUmaVez($)
184
+ } while (pendente)
185
+ } finally {
186
+ lendo = undefined
187
+ }
188
+ })()
189
+ return lendo
190
+ }
191
+
192
+ /** O retrato de uma thread pela ponte; a linha so conta como lida quando o retrato veio (S2 da revisao). */
193
+ async function lerThread($: EngineInterface, thread: string, agora: number): Promise<TorreLinha> {
194
+ try {
195
+ const r = await comPrazo($, $.ork.retrato({ thread }))
196
+ threadLidaEm[thread] = agora
197
+ return linhaDaThread(thread, r.retrato, { fonte: r.fonte, lidoEm: r.lidoEm })
198
+ } catch (erro) {
199
+ return linhaDaThread(thread, null, { fonte: null, lidoEm: null, erro: mensagem(erro) })
200
+ }
201
+ }
202
+
203
+ async function lerUmaVez($: EngineInterface): Promise<void> {
204
+ const tudo = tudoPedido
205
+ tudoPedido = false
206
+ const agora = await $.clock.now()
207
+ const atual = await read($, quadro)
208
+ let abertas = atual.linhas.map(l => l.thread)
209
+ let omitidas = atual.omitidas
210
+ let lidoEm = atual.lidoEm
211
+ let erro = atual.erro
212
+ if (listaPedida || listaLidaEm === null || agora - listaLidaEm >= PERIODO_DO_TIQUE_MS) {
213
+ listaPedida = false
214
+ try {
215
+ const lista = abertasDaLista(await comPrazo($, $.ork.ler({ consulta: 'thread.list' })))
216
+ abertas = lista.ids
217
+ omitidas = lista.omitidas
218
+ listaLidaEm = agora
219
+ lidoEm = agora
220
+ erro = null
221
+ } catch (e) {
222
+ erro = mensagem(e)
223
+ }
224
+ }
225
+ const conhecidas = new Set(atual.linhas.map(l => l.thread))
226
+ const agoraForcadas = abertas.filter(t => forcadas.has(t))
227
+ forcadas.clear()
228
+ const pedidas = tudo ? abertas : abertas.filter(t => (marcadas.has(t) || !conhecidas.has(t)) && !agoraForcadas.includes(t))
229
+ const intervalo = (await painelAVista($)) ? INTERVALO_POR_THREAD_MS : INTERVALO_ESCONDIDO_MS
230
+ const escolha = tudo ? { ler: pedidas, adiadas: [] as string[], proximaEm: null } : escolher(pedidas, threadLidaEm, agora, intervalo)
231
+ for (const t of [...marcadas]) if (pedidas.includes(t) || agoraForcadas.includes(t) || !abertas.includes(t)) marcadas.delete(t)
232
+ for (const t of escolha.adiadas) marcadas.add(t)
233
+ const novas = new Map<string, TorreLinha>()
234
+ for (const t of tudo ? escolha.ler : [...agoraForcadas, ...escolha.ler]) novas.set(t, await lerThread($, t, agora))
235
+ await update($, quadro, anterior => {
236
+ const antigas = new Map(anterior.linhas.map(l => [l.thread, l]))
237
+ const linhas = abertas.map(t => novas.get(t) ?? antigas.get(t) ??
238
+ linhaDaThread(t, null, { fonte: null, lidoEm: null, erro: 'ainda não lida' }))
239
+ return { linhas: ordenarLinhas(linhas), omitidas, lidoEm, erro }
240
+ })
241
+ if (escolha.proximaEm !== null) agendar($, escolha.proximaEm - agora)
242
+ await publicarFaixa($)
243
+ await registrarMostrados($)
244
+ }
245
+
246
+ /**
247
+ * So a thread do detalhe, pelo Atualizar dele (D16): ela entra no proximo passo do laco unico de leitura, sem o
248
+ * intervalo, e o resto do quadro fica como esta. Pelo laco, nenhuma leitura mais velha grava por cima dela.
249
+ */
250
+ async function releerThread($: EngineInterface, thread: string): Promise<void> {
251
+ forcadas.add(thread)
252
+ await atualizar($)
253
+ }
254
+
255
+ /**
256
+ * O que o desenho pos na janela de rolagem do painel posto e a vista vai ao registro da ponte (M5 do dono,
257
+ * D10), uma vez por chave e texto enquanto o item existir no quadro: o Telegram nao repete o que o dono ja viu
258
+ * no terminal, e nada que nao estava na tela entra.
259
+ */
260
+ async function registrarMostrados($: EngineInterface): Promise<void> {
261
+ const existentes = new Set(mostradosDoQuadro(await read($, quadro)).map(m => `${m.chave}|${m.texto}`))
262
+ for (const vista of [...jaMostrado]) if (!existentes.has(vista)) jaMostrado.delete(vista)
263
+ for (const vista of [...vistosNoDesenho.keys()]) if (!existentes.has(vista)) vistosNoDesenho.delete(vista)
264
+ if (vistosNoDesenho.size === 0) return
265
+ // Com o painel escondido, o que foi anotado e descartado: o proximo desenho a vista anota de novo (A-1).
266
+ if (!await painelAVista($)) { vistosNoDesenho.clear(); return }
267
+ for (const [vista, m] of [...vistosNoDesenho]) {
268
+ vistosNoDesenho.delete(vista)
269
+ if (jaMostrado.has(vista)) continue
270
+ try {
271
+ await $.ork.mostrado({ mod: MOD, canal: 'painel', chave: m.chave, thread: m.thread, texto: m.texto })
272
+ jaMostrado.add(vista)
273
+ } catch {
274
+ // A ponte recusou ou falhou: volta para a proxima vez.
275
+ vistosNoDesenho.set(vista, m)
276
+ }
277
+ }
278
+ }
279
+
280
+ /** O desenho anota o que pos na janela; quem registra e o laco de leitura, fora do desenho. */
281
+ function anotarVistos(vistos: readonly TorreMostrado[]): void {
282
+ for (const m of vistos) vistosNoDesenho.set(`${m.chave}|${m.texto}`, m)
283
+ }
284
+
285
+ /**
286
+ * Grava o que o detalhe leu de uma thread, so se ela ainda e a aberta: leitura atrasada nao apaga a de outra.
287
+ * O mapa guarda so o detalhe aberto (o `abrir` o recomeca).
288
+ */
289
+ async function gravarDetalhe($: EngineInterface, thread: string, mudar: (d: TorreDetalhe) => TorreDetalhe): Promise<void> {
290
+ if ((await read($, aberta)) !== thread) return
291
+ await update($, detalhes, todos => ({ ...todos, [thread]: mudar(todos[thread] ?? DETALHE_VAZIO) }))
292
+ }
293
+
294
+ /** Os comandos dos mods donos carregados agora, pelo plugin que registrou cada um (D4). */
295
+ async function lerDonos($: EngineInterface): Promise<Record<string, string>> {
296
+ const carregados = donosCarregados(await $.command.list().catch(() => []))
297
+ await update($, donos, () => carregados)
298
+ return carregados
299
+ }
300
+
301
+ /** Ao abrir o detalhe: os donos das acoes, os ultimos eventos e as claims com estado da thread. */
302
+ async function carregarDetalhe($: EngineInterface, thread: string): Promise<void> {
303
+ await lerDonos($)
304
+ const agora = await $.clock.now()
305
+ let eventos: TorreLeitura
306
+ try {
307
+ eventos = leituraFeita(linhasDosEventos(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_phase_list', { threadId: thread }))), agora), agora)
308
+ } catch (erro) {
309
+ eventos = leituraFalha(mensagem(erro), agora)
310
+ }
311
+ let claims: TorreLeitura
312
+ try {
313
+ claims = leituraFeita(linhasDasClaims(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_claims_list', { threadId: thread })))), agora)
314
+ } catch (erro) {
315
+ claims = leituraFalha(mensagem(erro), agora)
316
+ }
317
+ await gravarDetalhe($, thread, d => ({ ...d, eventos, claims }))
318
+ }
319
+
320
+ async function abrir($: EngineInterface, thread: string): Promise<void> {
321
+ await update($, aberta, () => thread)
322
+ await update($, detalhes, () => ({ [thread]: DETALHE_VAZIO }))
323
+ await carregarDetalhe($, thread)
324
+ await registrarMostrados($)
325
+ }
326
+
327
+ async function recarregar($: EngineInterface, thread: string): Promise<void> {
328
+ await releerThread($, thread)
329
+ await carregarDetalhe($, thread)
330
+ await registrarMostrados($)
331
+ }
332
+
333
+ /** As tres acoes de leitura do retrato (D4): o resultado vai para o detalhe, e nada mais roda. */
334
+ async function lerAcao($: EngineInterface, thread: string, operacao: string): Promise<void> {
335
+ const agora = await $.clock.now()
336
+ let leitura: TorreLeitura
337
+ try {
338
+ if (operacao === 'thread.status') {
339
+ leitura = leituraFeita(linhasDoEstado(await comPrazo($, $.ork.ler({ consulta: 'thread.status', thread })), agora), agora)
340
+ } else if (operacao === 'thread.observe') {
341
+ leitura = leituraFeita(linhasDaObservacao(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_observe', { threadId: thread })))), agora)
342
+ } else if (operacao === 'git.status') {
343
+ leitura = leituraFeita(linhasDoGit(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_git_status', { threadId: thread })))), agora)
344
+ } else return
345
+ } catch (erro) {
346
+ leitura = leituraFalha(mensagem(erro), agora)
347
+ }
348
+ await gravarDetalhe($, thread, d => ({ ...d, leituras: { ...d.leituras, [operacao]: leitura } }))
349
+ await registrarMostrados($)
350
+ }
351
+
352
+ /**
353
+ * A acao com efeito vai ao mod dono dela (D4): o comando dele roda como se o dono o digitasse, com o id da
354
+ * thread, so se a lista de comandos agora o mostra registrado pelo plugin esperado. Senao, o detalhe redesenha
355
+ * com o comando do `ork` em texto, e nada roda.
356
+ */
357
+ async function abrirMod($: EngineInterface, thread: string, dono: Dono): Promise<void> {
358
+ const carregados = await lerDonos($)
359
+ if (carregados[dono.comando] !== dono.plugin) return
360
+ await $.command.run({ command: dono.comando, args: thread }).catch(() => undefined)
361
+ }
362
+
363
+ export const register: Register = on => {
364
+ on('session.start', async ($, e, next) => {
365
+ if (e.isInteractive) await conferirPapel($, 0)
366
+ return next(e)
367
+ })
368
+
369
+ // `/torre` abre o painel em qualquer largura e rele tudo; o dono pediu, entao o painel volta a poder abrir
370
+ // sozinho. O comando so existe com a Torre ligada; a conferencia do papel aqui so cobre o caso raro de o
371
+ // comando ter sobrado de uma carga anterior.
372
+ on('command.run', { command: 'torre' }, async $ => {
373
+ if (!ativa && !desistiu) await conferirPapel($, ESPERAS_DO_PAPEL_MS.length)
374
+ if (!ativa) return { text: 'A Torre de Controle só abre na sessão do dono de um projeto do Orkastery.' }
375
+ await update($, fechado, () => false)
376
+ const aberto = await $.ui.open({ id: PAINEL, title: TITULO })
377
+ await atualizar($, true)
378
+ return { text: aberto.isPlaced ? 'Torre de Controle aberta.' : `Torre de Controle aberta, à espera de lugar: ${aberto.reason}` }
379
+ })
380
+
381
+ // O dono fechou o painel (a Torre nunca fecha o proprio): ele nao abre mais sozinho nesta sessao, nem depois
382
+ // de uma recarga do modulo. O fechamento segue sempre.
383
+ on('ui.close', { id: PAINEL }, async ($, e, next) => {
384
+ if (e.origin.kind !== 'unload') await update($, fechado, () => true)
385
+ return next(e)
386
+ }).catch(($, e, next) => next(e))
387
+
388
+ // O ledger de uma thread ou a pasta das threads mudou: a releitura entra no proximo lote (D7). Os caminhos
389
+ // vigiados sao os que a ponte pede para o papel dono; a Torre nao pede outros.
390
+ on('classic.FileChanged', async ($, e, next) => {
391
+ if (ativa) {
392
+ const marca = marcaDoArquivo(e.file_path)
393
+ if (marca?.tipo === 'thread') marcadas.add(marca.thread)
394
+ if (marca?.tipo === 'lista') listaPedida = true
395
+ if (marca) agendar($)
396
+ }
397
+ return next(e)
398
+ }).catch(($, e, next) => next(e))
399
+
400
+ // D8: sozinho, o painel so abre no fullscreen, uma vez, e nunca depois que o dono o fechou. A linha de dicas
401
+ // e desenhada em toda sessao do terminal e do desktop e traz o viewport; este gancho nao desenha nada e
402
+ // devolve a linha intacta.
403
+ on('ui.render', { component: 'PromptHint' }, async ($, e, next) => {
404
+ if (ativa && !abriuSozinho && e.viewport?.isFullscreen === true && !(await read($, fechado))) {
405
+ abriuSozinho = true
406
+ void $.ui.open({ id: PAINEL, title: TITULO }).catch(() => undefined)
407
+ }
408
+ return next(e)
409
+ })
410
+
411
+ // O painel: a lista das threads, ou o detalhe da thread aberta (T1.2). O desenho nunca escreve: so anota o
412
+ // que pos na janela de rolagem, para o registro do mostrado (D10). Os gestos mudam o estado da Torre e leem o
413
+ // nucleo.
414
+ on('ui.render', { component: 'Pane', requestId: PAINEL }, async ($, e) => {
415
+ const { Box, Text, Button } = $.ui.resolve(e)
416
+ const q = await read($, quadro)
417
+ const agora = await $.clock.now()
418
+ const id = await read($, aberta)
419
+ const linha = id === null ? undefined : q.linhas.find(l => l.thread === id)
420
+ if (linha) {
421
+ const detalhe = (await read($, detalhes))[linha.thread]
422
+ anotarVistos(mostradosVisiveis(linhasDoDetalhe(linha, detalhe, agora), 1, e.props.scroll))
423
+ return desenharDetalhe({ Box, Text, Button }, linha, detalhe, await read($, donos), {
424
+ agora,
425
+ voltar: () => update($, aberta, () => null),
426
+ atualizar: () => recarregar($, linha.thread),
427
+ ler: operacao => lerAcao($, linha.thread, operacao),
428
+ abrirMod: dono => abrirMod($, linha.thread, dono),
429
+ })
430
+ }
431
+ const daRede = await read($, rede)
432
+ anotarVistos(mostradosVisiveis(linhasDoPainel(q, { agora, rede: daRede }), 0, e.props.scroll))
433
+ return desenharPainel({ Box, Text, Button }, q, {
434
+ agora, largura: e.props.bodyColumns, abrir: thread => abrir($, thread), rede: daRede, lerRede: () => lerRede($),
435
+ })
436
+ })
437
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "formato": "ork.mod/v1",
3
+ "papeis": ["dono"],
4
+ "claudeCodeMinimo": "2.1.287"
5
+ }
@@ -0,0 +1,108 @@
1
+ // Contrato do estado da Torre de Controle (`ork-torre`, RM-059, fatia F1). O motor exige que cada chave de
2
+ // `$.state` do mod esteja declarada aqui, em `PluginState`. A Torre nao acrescenta noun ao `$`: le o nucleo
3
+ // pelo `$.ork` da `ork-ponte`, que o plugin.json lista em `dependencies`. Sem import nem referencia.
4
+
5
+ /** As seis fases do ciclo, na ordem do trilho. */
6
+ export type TorreFase = 'GOAL' | 'PLAN' | 'GO' | 'CHECK' | 'SHIP' | 'MASTER'
7
+
8
+ /** O estado da linha (D6 da thread): o que pede acao vem primeiro. */
9
+ export type TorreEstado = 'espera-voce' | 'parada' | 'andando' | 'quieta' | 'sem-leitura'
10
+
11
+ /** Uma acao que o retrato do nucleo declara disponivel para a thread (`available: true`). */
12
+ export type TorreAcao = { operacao: string }
13
+
14
+ /** Um pedido HITL aberto da thread, como o retrato o mostra. */
15
+ export type TorrePedido = { id: string; texto: string; prazo: string; recomendacao: string }
16
+
17
+ /** Uma sessao da thread: o rotulo (`runtime · fase`), o estado nativo e se e ela quem conduz. */
18
+ export type TorreSessao = { id: string; rotulo: string; estado: string; conduz: boolean; confirmada: boolean }
19
+
20
+ /** Uma thread aberta desta maquina, como o retrato dela (`ork.maestro-snapshot/v1`) a mostra. */
21
+ export type TorreLinha = {
22
+ thread: string
23
+ fase: string | null
24
+ modo: string | null
25
+ /** O texto de quem conduz e desde quando, como o nucleo o escreve. */
26
+ conducao: string | null
27
+ bloqueio: { motivo: string; frase: string } | null
28
+ pedidos: TorrePedido[]
29
+ sessoes: TorreSessao[]
30
+ /** O estado da entrega (`delivered`, `incomplete`) e do MASTER (`pending`, `recorded`), quando ha. */
31
+ entrega: string | null
32
+ master: string | null
33
+ acoes: TorreAcao[]
34
+ estado: TorreEstado
35
+ /** De onde veio o retrato (MCP, CLI ou cache da ponte), e quando a ponte o leu. */
36
+ fonte: 'mcp' | 'cli' | 'cache' | null
37
+ lidoEm: number | null
38
+ /** Secoes do retrato que nao vieram inteiras, ou o motivo de a leitura ter falhado. */
39
+ lacunas: string[]
40
+ }
41
+
42
+ /** O que o painel mostrou ao dono e o Telegram tambem avisaria: a chave junta o que e a mesma coisa (D10). */
43
+ export type TorreMostrado = { chave: string; thread: string; texto: string }
44
+
45
+ /** O quadro da fabrica: uma linha por thread aberta, na ordem do estado. */
46
+ export type TorreQuadro = {
47
+ linhas: TorreLinha[]
48
+ /** Quantas threads abertas ficaram de fora pelo teto da Torre. */
49
+ omitidas: number
50
+ /** Quando a lista das abertas foi lida (ms desde a epoca); null antes da primeira leitura. */
51
+ lidoEm: number | null
52
+ /** Por que a lista das abertas nao foi lida, quando nao foi. */
53
+ erro: string | null
54
+ }
55
+
56
+ /** O resultado de uma leitura do detalhe: as linhas a mostrar, ou o motivo de nao ter lido. */
57
+ export type TorreLeitura = { lidoEm: number; linhas: string[]; erro: string | null }
58
+
59
+ /** O que o detalhe de uma thread leu: os ultimos eventos, as claims e cada acao de leitura pedida. */
60
+ export type TorreDetalhe = {
61
+ eventos: TorreLeitura | null
62
+ claims: TorreLeitura | null
63
+ /** Por operacao de leitura do retrato (`thread.status`, `thread.observe`, `git.status`). */
64
+ leituras: Record<string, TorreLeitura>
65
+ }
66
+
67
+ /** Uma thread ativa de outra maquina, como o panorama da rede (`ork.network-roadmap/v1`) a mostra. */
68
+ export type TorreLinhaDaRede = {
69
+ thread: string
70
+ maquina: string
71
+ fase: string
72
+ /** A #TAG do modo, como o retrato da maquina a escreve. */
73
+ modo: string
74
+ esperaVoce: boolean
75
+ pergunta: string | null
76
+ /** Minutos desde a batida da maquina, na hora em que a rede foi lida; null quando a batida e ilegivel. */
77
+ idadeMin: number | null
78
+ semBatida: boolean
79
+ }
80
+
81
+ /** A ultima leitura da rede: as threads das outras maquinas, quantas maquinas e lacunas, e o erro da ultima tentativa. */
82
+ export type TorreRede = {
83
+ /** Quando a rede foi lida com sucesso pela ultima vez; null se nunca foi. */
84
+ lidoEm: number | null
85
+ linhas: TorreLinhaDaRede[]
86
+ maquinas: number
87
+ lacunas: number
88
+ erro: string | null
89
+ }
90
+
91
+ declare module 'claude-code' {
92
+ interface PluginState {
93
+ 'ork-torre': {
94
+ /** O quadro que o painel desenha. */
95
+ quadro: TorreQuadro
96
+ /** A ultima leitura da rede, ou null antes da primeira. */
97
+ rede: TorreRede | null
98
+ /** A thread com o detalhe aberto no painel, ou null para a lista. */
99
+ aberta: string | null
100
+ /** O que o detalhe leu, por thread. */
101
+ detalhes: Record<string, TorreDetalhe>
102
+ /** Os comandos dos mods donos das acoes carregados nesta sessao, com o plugin que registrou cada um. */
103
+ donos: Record<string, string>
104
+ /** O dono fechou o painel nesta sessao: ele nao abre mais sozinho, nem depois de uma recarga do modulo. */
105
+ fechado: boolean
106
+ }
107
+ }
108
+ }
@@ -44,6 +44,8 @@ O dono conversa sobre o objetivo; voce opera o nucleo `ork` e apresenta o result
44
44
  passo. Preserve o modo e as autorizacoes da thread. Se ja recebeu uma fase do Orkastery,
45
45
  execute essa fase no escopo recebido, sem redespachar a si mesmo.
46
46
 
47
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
48
+
47
49
  Quando descobertas, prefira as ferramentas MCP vinculadas ao projeto pelo servidor:
48
50
  `ork_thread_status`, `ork_phase_list`, `ork_hitl_pending`, `ork_thread_new(nome, modo)`,
49
51
  `ork_phase_run(threadId, fase, prompt, runtime?, model?, effort?, dryRun?)`, `ork_observe(threadId)`
@@ -20,7 +20,8 @@ venv do Hermes e um destino explícito `telegram:chat_id[:topic_id]`:
20
20
  }
21
21
  ```
22
22
 
23
- Grave a configuração em `.orkastery/monitor/pulse-host.json`. `HERMES_HOME` e
23
+ Grave a configuração em `.orkastery/monitor/pulse-host.json` (o `ork onboarding` já a grava
24
+ pronta; veja a RM-063 abaixo). `HERMES_HOME` e
24
25
  `HERMES_AGENT_DIR` permitem localizar outra instalação; por padrão usa `~/.hermes`.
25
26
  O adaptador carrega o ambiente do host internamente, sem imprimir credenciais. Marcadores
26
27
  `MEDIA:` presentes no texto do runtime são neutralizados para não anexar arquivos locais.
@@ -48,6 +49,19 @@ ork adapter install hermes --dry-run # lista o que seria escrito
48
49
  | `bin/ork-roadmap-status.sh` | `ork_roadmap_status`: o status report do roadmap so desta maquina (`ork roadmap status`) |
49
50
  | `bin/ork-network-roadmap.sh` | `ork_network_roadmap`: o roadmap da rede (`ork network roadmap`), com as threads de todas as maquinas, fonte, hora e lacunas; a fonte do status do roadmap e o panorama da frase `orkastery maestro` sem projeto (RM-054) |
50
51
  | `bin/ork-network-status.sh` | `ork_network_status`: as maquinas da pessoa na Orkastery Network (`ork network status`), com a batida, as forjas, os runtimes, os hosts, a fonte e as lacunas; sem projeto (RM-054, fatia 3) |
52
+ | `bin/ork-vigia-batida.py` | A batida do host (RM-063): roda `ork doctor --json` a cada 30 min e avisa o dono quando a batida da fabrica passou de 30 min, sem LLM |
53
+ | `bin/ork-conhecimento-listar.sh`, `-mostrar.sh`, `-colecoes.sh` e `-verificar.sh` | `ork_conhecimento_listar`, `ork_conhecimento_mostrar`, `ork_conhecimento_colecoes` e `ork_conhecimento_verificar`: o conhecimento escrito do projeto (`ork conhecimento <consulta> --json`), as mesmas tools do MCP e do OpenClaw (RM-026 K7, fatia 3) |
54
+
55
+ ## Conhecimento escrito (RM-026 K7)
56
+
57
+ Os quatro wrappers `bin/ork-conhecimento-*.sh` sao as tools MCP do conhecimento escrito com os mesmos nomes no
58
+ manifesto: cada um chama `ork conhecimento <consulta> "$@" --json`, com `ORK_PROJETO_EXPLICITO=1` e
59
+ `ORK_CANAL=hermes`, e devolve o JSON do nucleo e a saida dele como vem (saida 1 e a consulta que nao respondeu, com as
60
+ lacunas dizendo por que). O `--json` vai no fim, depois do `<doc-id>` do `mostrar`. A skill manda citar o documento
61
+ pela versao e pela fonte e mostrar cada lacuna como lacuna, nunca como resposta, com a mesma frase das descricoes do
62
+ OpenClaw ([contrato](../../docs/referencia/contratos/conhecimento-rm026.md)).
63
+
64
+ Verificacao: `python3 -m unittest discover -s adapters/hermes/test -p conhecimento_test.py -v`.
51
65
 
52
66
  ## Tickets `obj-*` aposentados
53
67
 
@@ -123,6 +137,41 @@ não ratifica nada. Cada página oferece no máximo doze opções e cabe em 3.90
123
137
  Contrato do teclado: [Telegram ReplyKeyboardMarkup](https://core.telegram.org/bots/api#replykeyboardmarkup).
124
138
  Prova local: `python3 -m unittest discover -s adapters/hermes/test -p master_transport_test.py`.
125
139
 
140
+ ## Batida do host e retomada pelo canal (RM-063)
141
+
142
+ **H1, a batida do host.** A cada 30 min, `bin/ork-vigia-batida.py` roda `ork doctor --json`. Se a
143
+ batida da fábrica passou de 30 min, manda ao dono o aviso pronto do núcleo; `ork` ausente ou com
144
+ falha vira alerta; o resto não manda nada. Com `--target`, envia pela mesma API do
145
+ `ork-pulse-enviar.py` (sai 1 se a entrega falha); sem ele, só imprime. Rode pelo cron ou por um
146
+ timer do systemd (ou pelo agendador do Hermes, num job que roda o script sem LLM):
147
+
148
+ ```text
149
+ */30 * * * * PATH=<dir do node>:/usr/bin:/bin ORK_BIN=<caminho do ork> <hermes-agent>/venv/bin/python3 <hermes>/bin/ork-vigia-batida.py --projeto <projeto> --target telegram:<chat>
150
+ ```
151
+
152
+ Nunca um cron LLM com `deliver=origin`. O cron não carrega o perfil do shell: o `ORK_BIN` e o
153
+ `PATH` com o `node` vão na própria linha.
154
+
155
+ **H2, retomada pelo canal.** `#OrkRetomar` ou `#OrkFabrica`, sozinhos na mensagem do chat Telegram
156
+ autorizado, passam pelo mesmo ingresso assinado do pulse (`pre_gateway_dispatch`). `#OrkRetomar`
157
+ responde na hora e roda a batida da condução nesta máquina; o que voltou a andar chega logo depois,
158
+ pelo transporte do pulse. `#OrkFabrica` responde o `ork fabrica`. No meio de uma frase, a tag vai ao assistente.
159
+
160
+ **H3, transporte gravado no onboarding.**
161
+ `ork onboarding set maestro --conteudo '{"canal":{"host":"hermes","destino":"telegram:<chat>"}}' --por <dono>`
162
+ (ou `telegram:<chat>:<topico>`) grava o canal e o `.orkastery/monitor/pulse-host.json` pronto, fora
163
+ do git: a máquina nunca fica sem transporte. O Python vem de `HERMES_AGENT_DIR` (ou
164
+ `$HERMES_HOME/hermes-agent`) e o script, de `$HERMES_HOME/bin/ork-pulse-enviar.py`; `executavel` e
165
+ `script` (absolutos) trocam os dois. O JSON de "Transporte determinístico do pulse" mostra, por
166
+ dentro, o que é gravado.
167
+
168
+ **H4, o outro host.** Com o canal gravado para os dois hosts, o último vira o principal e o outro, o
169
+ alternativo. Se a entrega falha, o transporte tenta o outro host; cada entrega vai ao
170
+ `.orkastery/monitor/transporte.log`, e o `ork doctor` mostra o check "transporte do pulse": aviso
171
+ quando caiu no alternativo, falha quando nenhum entregou.
172
+
173
+ Verificação: `python3 -m unittest discover -s adapters/hermes/test -p conducao_canal_test.py -v`.
174
+
126
175
  ## Respostas HITL no Telegram
127
176
 
128
177
  O gateway autenticado entrega o update original por stdin a `bin/ork-hitl-answer.py ork_gate_answer <thread> <pedido>` ou `ork_session_answer`. Configure `ORK_BIN`, `ORK_HITL_TELEGRAM_USERS` e `ORK_HITL_TELEGRAM_CHATS` com os ids permitidos. Responda ao alerta que contém a linha `ork-hitl <thread> <pedido>`; botões usam `ork:<thread>:<pedido>:<número>`. O transporte recusa bots, chat/usuário não autorizado e resposta sem correlação. O núcleo decide sobre prazo, modo e validade do pedido.
@@ -131,6 +180,20 @@ O script deve receber eventos diretamente do gateway, cuja autenticação do Tel
131
180
 
132
181
  Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_answer_test.py -v`.
133
182
 
183
+ ## Arco #Noctum pelo Telegram (RM-058)
184
+
185
+ O mesmo plugin `hitl-ingress/` recebe `/ork noctum <arco> autorizar <sha256>` e `/ork noctum <arco> revogar`, com as mesmas conferências do `/ork gate` (autorização do host, usuário, chat, bot, mensagem de até 60 s e a chave `ORK_HITL_INGRESS_KEY_HERMES`). O envelope é assinado no endereço `noctum` / `arco:<arco>`, que nenhum `/ork gate` alcança, e vai pela entrada a `ork noctum responder <arco>`. Só o recibo tipado `ork.noctum-ingresso/v1` do mesmo arco confirma ao dono, e o ato que já valia não ganha segunda confirmação. A proposta do envelope é `ork noctum propor --arquivo <envelope.json>`, e ela não autoriza nada. A gramática mora no núcleo (`GRAMATICA_DO_NOCTUM`), e o teste `noctum-gateways` do núcleo confere a cópia daqui. Desde a RM-057, a proposta chega ao dono como pergunta com código curto, e ele a responde como está na seção seguinte; o `/ork noctum <arco> autorizar <sha256>` segue aceito, mas não é mais o caminho ensinado.
186
+
187
+ Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_noctum_test.py -v`.
188
+
189
+ ## A resposta curta à pergunta (RM-057)
190
+
191
+ A pergunta ao dono (a do arco #Noctum e a mensagem curta de um gate) chega com código curto e alternativas e termina em "Responda a, b ou c". Pelo mesmo ingresso assinado do pulse (`ork pulse responder`), o dono responde com o código e a letra (`K7QX a`) de qualquer chat autorizado, com o número da pergunta e a letra (`1a`), ou em reply à mensagem da pergunta do arco só com a letra ou a palavra (`a`, `sim`, `autorizo`). O reply só vale para a mensagem em que a pergunta foi entregue: o transporte (`bin/ork-pulse-enviar.py`) devolve o id dela, e o núcleo o guarda com a pergunta. O plugin tira a referência só da mensagem do próprio bot (`ORK_HITL_TELEGRAM_BOT_ID`) cuja primeira linha é o título da pergunta do arco (`🔔 N. arco <arco> · <código>`), e só quando o texto do dono é uma resposta (a palavra, o código com a resposta ou o número com a letra); assina o envelope no endereço `resposta:<código>:<id>`, com o id da mensagem respondida, e manda `--em-resposta-a <código>:<id>` ao núcleo; a resposta em reply vale mesmo com a janela da palavra solta fechada. A confirmação do "b", a recusa e qualquer outra mensagem não dão referência, e o reply à mensagem curta de um gate não vale (o gate segue pelo número e pelo código). A palavra solta em reply a qualquer mensagem que não é a pergunta do arco (a confirmação de um gate, a mensagem de outra pessoa do grupo, a do assistente) nunca vira palavra solta: com a janela aberta, o plugin a assina no endereço `resposta:outra` e manda `--em-resposta-a outra`, e o núcleo a recusa dizendo por onde responder, sem gravar nada; com a janela fechada, ela segue ao assistente. O código e o número em reply a outra mensagem valem como sem reply, porque dizem a pergunta. A abertura do tópico do fórum, que o Telegram põe em toda mensagem do tópico, não conta como reply. Sem reply, a palavra solta só vale com uma pergunta esperando no chat em que ela saiu, e nunca com a mensagem de antes de ela sair; com duas, o núcleo pergunta qual. Conversa comum, mesmo em reply, segue ao assistente. Quem decide é o núcleo: a pergunta de agora, o prazo, a mensagem repetida (uma mensagem responde a uma pergunta só, em qualquer arco) e, no reply, o id da entrega e o chat em que ela saiu; o código digitado vale de qualquer chat autorizado.
192
+
193
+ As recusas na borda do plugin saem caladas, de propósito: a mensagem de usuário ou de chat fora da lista, a de mais de 60 s (contados da mensagem original, também na edição) e a mensagem já recebida que volta com outro texto (o cache de reentrega a recusa) nem chegam ao núcleo, e o bot não responde a elas, para nunca conversar com quem não é o dono nem responder a uma mensagem atrasada. Só as recusas do núcleo voltam ao dono com o porquê.
194
+
195
+ Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_resposta_curta_test.py -v`.
196
+
134
197
  ## Confirmação pelo plugin nativo HITL
135
198
 
136
199
  O plugin `hitl-ingress/` recebe `/ork gate <thread> <pedido> <resposta>` e