@orkastery/cli 0.5.1 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/agents/ork-master.md +2 -0
  3. package/adapters/claude-code/commands/master.md +8 -0
  4. package/adapters/claude-code/commands/ork.md +9 -0
  5. package/adapters/claude-code/mods/autoridade.json +56 -0
  6. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  8. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  9. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  10. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  11. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  12. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  13. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  16. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  17. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  18. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  19. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  20. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  21. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  25. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  27. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  28. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  29. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  30. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  33. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  34. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  35. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  36. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  37. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  38. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  44. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  45. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  46. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  47. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  48. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  49. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  52. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  53. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  54. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  55. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  56. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  57. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  59. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  60. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  61. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  62. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  63. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  64. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  67. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  68. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  69. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  70. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  71. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  72. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  77. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  78. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  79. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  80. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  81. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  82. package/adapters/codex/skills/ork/SKILL.md +18 -3
  83. package/adapters/hermes/README.md +1 -0
  84. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  85. package/adapters/hermes/hermes.plugin.json +1 -0
  86. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  87. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +7 -6
  88. package/adapters/openclaw/README.md +26 -5
  89. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  90. package/adapters/openclaw/dist/index.js +46 -11
  91. package/adapters/openclaw/openclaw.plugin.json +5 -1
  92. package/adapters/openclaw/package.json +2 -2
  93. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  94. package/adapters/openclaw/src/index.ts +49 -11
  95. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  96. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  97. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  98. package/assets/docs-en/produto/README.md +14 -0
  99. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  100. package/assets/docs-en/roadmap/README.md +14 -0
  101. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  102. package/assets/orkmind_bridge.py +117 -9
  103. package/dist/adapters/claude-bg.js +116 -18
  104. package/dist/adapters/codex.js +14 -4
  105. package/dist/agents-md.js +24 -14
  106. package/dist/auditrun.js +22 -3
  107. package/dist/board.js +20 -17
  108. package/dist/branch-de-estado.js +88 -10
  109. package/dist/busca-semantica.js +52 -12
  110. package/dist/canarios-rm057.js +149 -0
  111. package/dist/canarios.js +2 -0
  112. package/dist/catalogo.js +33 -0
  113. package/dist/ci.js +21 -8
  114. package/dist/claims-conferir.js +342 -0
  115. package/dist/claims.js +41 -1
  116. package/dist/company-brain-client.js +36 -1
  117. package/dist/company-brain-context.js +158 -22
  118. package/dist/company-brain-journal.js +2 -1
  119. package/dist/company-brain-migration.js +36 -1
  120. package/dist/conducao-sentinela.js +388 -0
  121. package/dist/conducao-texto.js +12 -18
  122. package/dist/conducao.js +122 -30
  123. package/dist/conhecimento.js +490 -0
  124. package/dist/docs.js +70 -17
  125. package/dist/doctor-pulse-cron.js +349 -0
  126. package/dist/doctor-rede.js +150 -0
  127. package/dist/doctor.js +195 -111
  128. package/dist/entrega-pr.js +42 -29
  129. package/dist/escopo-escrita.js +10 -1
  130. package/dist/esgotamentos.js +181 -0
  131. package/dist/estado-thread.js +23 -1
  132. package/dist/experiencia-instalacao.js +45 -25
  133. package/dist/experiencia.js +12 -2
  134. package/dist/fabrica-batida.js +310 -0
  135. package/dist/fabrica-estado.js +52 -14
  136. package/dist/fabrica-publicar.js +9 -1
  137. package/dist/fechamento.js +20 -66
  138. package/dist/fila-pesada.js +444 -0
  139. package/dist/fix.js +3 -2
  140. package/dist/forja.js +31 -7
  141. package/dist/gates.js +3 -24
  142. package/dist/handoff.js +10 -6
  143. package/dist/hitl-contract.js +59 -4
  144. package/dist/hitl-curto.js +11 -6
  145. package/dist/hitl-gates.js +5 -0
  146. package/dist/hitl-local-receipt.js +2 -0
  147. package/dist/hitl-lote.js +5 -2
  148. package/dist/hitl-resumo.js +38 -3
  149. package/dist/hitl-tempo-parado.js +201 -0
  150. package/dist/hitl-texto-livre.js +5 -5
  151. package/dist/hitl.js +29 -33
  152. package/dist/horario.js +41 -7
  153. package/dist/hosts.js +104 -11
  154. package/dist/impedimento.js +299 -0
  155. package/dist/index.js +961 -542
  156. package/dist/indice-vetorial.js +87 -10
  157. package/dist/indice.js +9 -1
  158. package/dist/init.js +56 -43
  159. package/dist/instabilidade.js +144 -0
  160. package/dist/integracoes-locais.js +4 -0
  161. package/dist/intelligence-graph-cli.js +170 -16
  162. package/dist/intelligence-graph-contexto.js +254 -0
  163. package/dist/intelligence-graph-contract.js +2 -1
  164. package/dist/intelligence-graph-extract-md.js +56 -4
  165. package/dist/intelligence-graph-extract-ts.js +71 -3
  166. package/dist/intelligence-graph-parsers.js +6 -4
  167. package/dist/intelligence-graph-query.js +66 -19
  168. package/dist/leases.js +664 -87
  169. package/dist/ledger-stats.js +15 -1
  170. package/dist/ledger.js +18 -1
  171. package/dist/licoes.js +1 -0
  172. package/dist/liveness.js +6 -3
  173. package/dist/locale-ajuda.js +761 -0
  174. package/dist/locale-gerados.js +160 -0
  175. package/dist/locale-master.js +99 -0
  176. package/dist/locale-onboarding.js +92 -0
  177. package/dist/locale-phase.js +151 -0
  178. package/dist/locale-pulse.js +211 -0
  179. package/dist/locale-retry.js +385 -0
  180. package/dist/locale-roadmap.js +102 -0
  181. package/dist/locale-ship.js +494 -0
  182. package/dist/locale-thread.js +277 -0
  183. package/dist/locale-verify.js +125 -0
  184. package/dist/locale.js +714 -0
  185. package/dist/maestro-runtime.js +4 -1
  186. package/dist/manifest.js +149 -4
  187. package/dist/maquina.js +23 -4
  188. package/dist/master-digest.js +6 -1
  189. package/dist/master-nota.js +18 -11
  190. package/dist/master.js +145 -31
  191. package/dist/mcp-artifacts.js +43 -3
  192. package/dist/mcp-git.js +42 -8
  193. package/dist/mcp-grafo-worker.js +5 -3
  194. package/dist/mcp-grafo.js +55 -6
  195. package/dist/mcp-server.js +22 -3
  196. package/dist/mcp-ship.js +3 -1
  197. package/dist/mcp-verify.js +6 -1
  198. package/dist/memoria.js +48 -6
  199. package/dist/modos.js +3 -6
  200. package/dist/network-roadmap.js +196 -18
  201. package/dist/noctum-arco.js +911 -0
  202. package/dist/noctum-capacidade.js +141 -0
  203. package/dist/noctum-envelope.js +810 -0
  204. package/dist/noctum-execucao.js +304 -0
  205. package/dist/noctum-fila.js +280 -0
  206. package/dist/ocupacao.js +40 -5
  207. package/dist/onboarding.js +40 -21
  208. package/dist/orkmind.js +99 -7
  209. package/dist/orquestracao.js +24 -21
  210. package/dist/parado-no-condutor.js +219 -38
  211. package/dist/phase.js +160 -52
  212. package/dist/policies.js +56 -5
  213. package/dist/portfolio.js +8 -3
  214. package/dist/postura-local.js +234 -0
  215. package/dist/preflight.js +11 -10
  216. package/dist/procedencia.js +225 -0
  217. package/dist/projeto-alvo.js +132 -5
  218. package/dist/prompts.js +40 -1
  219. package/dist/prova-ativacao.js +75 -6
  220. package/dist/pulse-delivery.js +47 -4
  221. package/dist/pulse.js +98 -19
  222. package/dist/ratelimit.js +24 -6
  223. package/dist/recall.js +3 -1
  224. package/dist/redacao-saida.js +63 -0
  225. package/dist/rede-adesao.js +399 -0
  226. package/dist/rede-forja.js +289 -0
  227. package/dist/rede-projetos.js +239 -0
  228. package/dist/rede-status.js +337 -0
  229. package/dist/rede.js +980 -0
  230. package/dist/retry.js +291 -140
  231. package/dist/roadmap-reservas.js +20 -3
  232. package/dist/roadmap-status.js +150 -34
  233. package/dist/runtime-context.js +181 -3
  234. package/dist/runtime-profiles.js +22 -1
  235. package/dist/runtimes.js +2 -1
  236. package/dist/saida-segura.js +58 -0
  237. package/dist/session-events.js +7 -3
  238. package/dist/session-watcher-claude.js +120 -24
  239. package/dist/session-watcher.js +185 -33
  240. package/dist/sessoes-contas.js +187 -0
  241. package/dist/sessoes-inventario.js +6 -18
  242. package/dist/sessoes.js +83 -2
  243. package/dist/ship-publicar.js +800 -0
  244. package/dist/ship.js +157 -88
  245. package/dist/steal.js +77 -0
  246. package/dist/thread-close.js +3 -2
  247. package/dist/thread.js +299 -49
  248. package/dist/util.js +8 -1
  249. package/dist/verify.js +141 -52
  250. package/dist/vida-da-thread.js +254 -0
  251. package/dist/worktree-local.js +165 -0
  252. package/dist/worktree.js +25 -2
  253. package/dist/yaml.js +27 -8
  254. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  255. package/package.json +7 -3
  256. package/references/definition-of-done.md +1 -1
  257. package/schemas/code-artifact-graph.v1.schema.json +2 -1
  258. package/skills/README.md +1 -1
  259. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  260. package/skills/phases/master-metrics/SKILL.md +8 -3
@@ -0,0 +1,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
+ }
@@ -6,14 +6,20 @@ license: MIT
6
6
 
7
7
  # Orkastery no Codex
8
8
 
9
- Consulte `ork experiencia show --json` no projeto da sessão. Quando `experience` for true,
9
+ Ao receber literalmente `orkastery maestro`, a primeira ação é a ferramenta `ork_maestro` do
10
+ servidor MCP `orkastery`, descoberta no namespace efetivamente exposto: ela consulta o projeto
11
+ fixado. Com a ferramenta exposta, não rode `ork maestro`, `ork doctor`, `ork onboarding` nem
12
+ `ork experiencia show` no shell antes nem no lugar dela: o CLI resolve o projeto pelo diretório da sessão, e é essa a
13
+ classe de erro que a frase evita (prova de ativação do Codex, RM-032).
14
+
15
+ Só depois da `ork_maestro` (ou, sem MCP, do `ork maestro --json`), consulte `ork experiencia show --json`
16
+ no projeto da sessão. Quando `experience` for true,
10
17
  leia `../core/<skill>/SKILL.md`, usando o nome devolvido em `skill` pelo núcleo:
11
18
  `orchestration-experience-pt-br` ou `orchestration-experience`. Idioma, fuso e profundidade
12
19
  vêm da mesma consulta. Se false, não ative o pacote. O bloco próprio de AGENTS.md também
13
20
  aponta para esse catálogo; instalação não altera permissões nativas.
14
21
 
15
- Ao receber literalmente `orkastery maestro`, descubra `ork_maestro` no namespace
16
- efetivamente exposto e consulte o projeto fixado pelo MCP. A frase pede panorama,
22
+ Depois de `ork_maestro`, a frase `orkastery maestro` continua pedindo só panorama,
17
23
  sem abrir trabalho. Sem projeto nomeado, ofereça também o panorama da rede
18
24
  (`ork_network_roadmap`, ou `ork network roadmap` no CLI), com fontes, frescor e lacunas.
19
25
  Siga a seleção de contexto e os limites do bootstrap comum.
@@ -26,6 +32,13 @@ com rótulos claros; UUID interno. Use `ork_request_decision` na condutora e pre
26
32
  a resposta literal/cancelamento da elicitation. Não use pergunta genérica do agente
27
33
  como aprovação de gate nem texto em toolargs como identidade humana.
28
34
 
35
+ HITL de condução é seleção (RM-057): de 3 a 5 alternativas, exatamente uma com o selo
36
+ "Recomendação". Nunca peça ao dono um "confirmo" em texto livre nem que ele cole texto; o pedido
37
+ que ele colou com autorização explícita vale como instrução dele, dentro dessa autorização.
38
+ Dúvida dentro da autorização vira `ork decisao registrar` e a thread segue. Texto só quando a
39
+ fábrica não consegue seguir sozinha e o dono precisa rodar um comando no terminal: mostre o
40
+ comando exato.
41
+
29
42
  Use a skill `orkastery-bootstrap` do mesmo catalogo instalado para conduzir o pedido.
30
43
  O dono conversa sobre o objetivo; voce opera o nucleo `ork` e apresenta o resultado e o proximo
31
44
  passo. Preserve o modo e as autorizacoes da thread. Se ja recebeu uma fase do Orkastery,
@@ -42,6 +55,8 @@ e `ork_request_decision(threadId, pedidoId)`. Use o namespace efetivamente expos
42
55
  - Status do roadmap: use `ork_network_roadmap` (ou `ork network roadmap --projeto <nome>`) e mostre o
43
56
  texto como vem, com as threads de todas as maquinas, as fontes e as lacunas; `ork_roadmap_status` e
44
57
  so desta maquina. Nao escreva relatorio proprio de roadmap: lacuna nunca e roadmap vazio.
58
+ - Maquinas da pessoa (RM-053): use `ork_network_status` (ou `ork network status`) e mostre o texto como
59
+ vem, com a batida de cada maquina, a fonte e as lacunas; lacuna nunca e "nenhuma maquina".
45
60
  - Status: apresente a evidencia da thread; `ork pulse --json` mostra quem precisa agir.
46
61
  As pausas dos blocos do modo sao previstas: so diga "aguardando voce" com pendencia
47
62
  humana atual comprovada no estado/ultimo resultado, identificando gate, pedido ou evento.
@@ -47,6 +47,7 @@ ork adapter install hermes --dry-run # lista o que seria escrito
47
47
  | `bin/ork-maestro.sh` | `ork_maestro`: o panorama Maestro do projeto pedido (`ork maestro --json`) |
48
48
  | `bin/ork-roadmap-status.sh` | `ork_roadmap_status`: o status report do roadmap so desta maquina (`ork roadmap status`) |
49
49
  | `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
+ | `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) |
50
51
 
51
52
  ## Tickets `obj-*` aposentados
52
53
 
@@ -0,0 +1,10 @@
1
+ #!/bin/sh
2
+ # RM-054 (fatia 3): as maquinas da pessoa na Orkastery Network (RM-053), montadas pelo nucleo
3
+ # (`ork network status`): a casa, a batida de cada maquina, forjas, runtimes, hosts e projetos, a
4
+ # fonte e as lacunas. Somente leitura; o Hermes transporta o texto como vem. Argumentos continuam dados.
5
+ set -eu
6
+ export ORK_CANAL="${ORK_CANAL:-hermes}"
7
+ # RM-052 (D3): o cwd do gateway nao e projeto. Com ORK_PROJETO_EXPLICITO=1 o nucleo nao le o projeto
8
+ # do diretorio do gateway; a rede vem da casa, do registro e dos retratos. ORK_PROJETO_EXPLICITO=0 desliga.
9
+ export ORK_PROJETO_EXPLICITO="${ORK_PROJETO_EXPLICITO:-1}"
10
+ exec "${ORK_BIN:-{{ork_bin}}}" network status "$@"
@@ -12,6 +12,7 @@
12
12
  "ork_maestro": "./bin/ork-maestro.sh",
13
13
  "ork_roadmap_status": "./bin/ork-roadmap-status.sh",
14
14
  "ork_network_roadmap": "./bin/ork-network-roadmap.sh",
15
+ "ork_network_status": "./bin/ork-network-status.sh",
15
16
  "ork-abrir-thread": "./bin/ork-abrir-thread.sh",
16
17
  "ork_brain": "./bin/ork-brain.sh",
17
18
  "ork_gate_answer": "./bin/ork-hitl-answer.py",
@@ -32,8 +32,8 @@ PULSE_CADENCIA = re.compile(r'^[ \t]*#OrkPulse(?:On(?:-(?:15|30|60)m)?|Off)[ \t]
32
32
  # ("1. B, 2. aprovo") e interceptada sempre; `livre` ("sim", "aprovo", "a") so enquanto a janela
33
33
  # de escuta do nucleo estiver aberta: fora dela, a palavra vai ao assistente, como sempre foi. A
34
34
  # janela e dica de rota, nao prova: a mensagem ainda passa pela assinatura e pela regra do nucleo.
35
- PULSE_LISTA = re.compile(r'^[ \t]*[0-9]{1,2}(?:[ \t]*[.):-])?[ \t]*(?:[a-d]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?)(?:[ \t\r\n,;]*[0-9]{1,2}(?:[ \t]*[.):-])?[ \t]*(?:[a-d]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?))*[ \t]*(?:[.!][ \t]*)?$', re.IGNORECASE)
36
- PULSE_LIVRE = re.compile(r'^[ \t]*(?:[1-4]|(?:[a-d]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?))[ \t]*(?:[.!]+[ \t]*)?$', re.IGNORECASE)
35
+ PULSE_LISTA = re.compile(r'^[ \t]*[0-9]{1,2}(?:[ \t]*[.):-])?[ \t]*(?:[a-e]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?)(?:[ \t\r\n,;]*[0-9]{1,2}(?:[ \t]*[.):-])?[ \t]*(?:[a-e]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?))*[ \t]*(?:[.!][ \t]*)?$', re.IGNORECASE)
36
+ PULSE_LIVRE = re.compile(r'^[ \t]*(?:[1-5]|(?:[a-e]|pode seguir|pode ir|pode|sim|s|ok|aprovo|aprovado|aprovada|aprovar|aprova|segue|siga|seguir|manda|confirmo|confirmado|de acordo|agora n[aã]o|n[aã]o|n|recuso|recusado|recusar|reprovo|reprovado|revisar|revis[aã]o|refazer|volta|voltar|esperar|espera|aguardar|aguarda|aguarde|depois|mais tarde|detalhes?|evid[eê]ncias?))[ \t]*(?:[.!]+[ \t]*)?$', re.IGNORECASE)
37
37
  # RM-048 (item 8): a linha do teclado do digest ("ratificar <thread> <assinatura> <classe>") vai ao
38
38
  # nucleo pelo mesmo endereco assinado; o agente nao escreve mais `--por` em nome do dono.
39
39
  PULSE_RATIFICACAO = re.compile(r'^[ \t]*ratificar(?:-lote)?(?:[ \t]+[A-Za-z0-9._-]{1,80}){2,3}[ \t]*$', re.IGNORECASE)