@orkastery/cli 0.5.3 → 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 (212) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/mods/autoridade.json +56 -0
  3. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  4. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  5. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  6. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  8. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  9. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  10. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  11. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  12. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  13. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  16. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  17. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  18. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  19. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  20. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  21. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  25. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  26. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  27. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  28. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  29. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  30. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  33. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  34. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  35. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  36. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  37. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  38. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  44. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  45. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  46. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  47. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  48. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  49. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  52. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  53. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  54. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  55. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  56. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  57. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  59. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  60. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  61. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  62. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  63. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  64. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  67. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  68. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  69. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  70. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  71. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  72. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  77. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  78. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  79. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +1 -1
  80. package/adapters/openclaw/README.md +2 -1
  81. package/adapters/openclaw/openclaw.plugin.json +1 -1
  82. package/adapters/openclaw/package.json +1 -1
  83. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  84. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  85. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  86. package/assets/docs-en/produto/README.md +14 -0
  87. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  88. package/assets/docs-en/roadmap/README.md +14 -0
  89. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  90. package/dist/adapters/claude-bg.js +77 -13
  91. package/dist/adapters/codex.js +10 -1
  92. package/dist/agents-md.js +24 -15
  93. package/dist/auditrun.js +17 -2
  94. package/dist/board.js +4 -3
  95. package/dist/branch-de-estado.js +23 -1
  96. package/dist/catalogo.js +33 -0
  97. package/dist/ci.js +13 -7
  98. package/dist/claims-conferir.js +342 -0
  99. package/dist/claims.js +3 -1
  100. package/dist/company-brain-client.js +36 -1
  101. package/dist/company-brain-journal.js +2 -1
  102. package/dist/company-brain-migration.js +36 -1
  103. package/dist/conducao-sentinela.js +388 -0
  104. package/dist/conducao-texto.js +12 -18
  105. package/dist/conducao.js +122 -30
  106. package/dist/conhecimento.js +490 -0
  107. package/dist/docs.js +22 -8
  108. package/dist/doctor-pulse-cron.js +182 -27
  109. package/dist/doctor-rede.js +18 -17
  110. package/dist/doctor.js +115 -111
  111. package/dist/entrega-pr.js +22 -21
  112. package/dist/escopo-escrita.js +10 -1
  113. package/dist/estado-thread.js +23 -1
  114. package/dist/experiencia-instalacao.js +45 -25
  115. package/dist/fabrica-batida.js +310 -0
  116. package/dist/fabrica-estado.js +38 -8
  117. package/dist/fabrica-publicar.js +3 -1
  118. package/dist/fila-pesada.js +444 -0
  119. package/dist/fix.js +3 -2
  120. package/dist/forja.js +1 -1
  121. package/dist/gates.js +3 -28
  122. package/dist/handoff.js +10 -6
  123. package/dist/hitl-local-receipt.js +2 -0
  124. package/dist/hitl-resumo.js +29 -3
  125. package/dist/hitl-tempo-parado.js +4 -4
  126. package/dist/hitl.js +29 -33
  127. package/dist/horario.js +14 -7
  128. package/dist/hosts.js +52 -1
  129. package/dist/impedimento.js +108 -14
  130. package/dist/index.js +623 -521
  131. package/dist/indice.js +7 -1
  132. package/dist/init.js +43 -47
  133. package/dist/instabilidade.js +144 -0
  134. package/dist/integracoes-locais.js +2 -0
  135. package/dist/intelligence-graph-cli.js +92 -21
  136. package/dist/intelligence-graph-contexto.js +56 -17
  137. package/dist/intelligence-graph-contract.js +2 -1
  138. package/dist/intelligence-graph-extract-md.js +56 -4
  139. package/dist/intelligence-graph-extract-ts.js +71 -3
  140. package/dist/intelligence-graph-query.js +66 -19
  141. package/dist/ledger.js +15 -1
  142. package/dist/liveness.js +6 -3
  143. package/dist/locale-ajuda.js +761 -0
  144. package/dist/locale-gerados.js +160 -0
  145. package/dist/locale-master.js +99 -0
  146. package/dist/locale-onboarding.js +92 -0
  147. package/dist/locale-phase.js +151 -0
  148. package/dist/locale-pulse.js +211 -0
  149. package/dist/locale-retry.js +385 -0
  150. package/dist/locale-roadmap.js +102 -0
  151. package/dist/locale-ship.js +494 -0
  152. package/dist/locale-thread.js +277 -0
  153. package/dist/locale-verify.js +125 -0
  154. package/dist/locale.js +714 -0
  155. package/dist/manifest.js +129 -3
  156. package/dist/maquina.js +23 -4
  157. package/dist/master-digest.js +6 -1
  158. package/dist/master-nota.js +4 -6
  159. package/dist/master.js +21 -24
  160. package/dist/mcp-artifacts.js +11 -2
  161. package/dist/mcp-git.js +23 -6
  162. package/dist/mcp-grafo.js +7 -4
  163. package/dist/mcp-server.js +8 -2
  164. package/dist/mcp-ship.js +3 -1
  165. package/dist/mcp-verify.js +6 -1
  166. package/dist/modos.js +3 -6
  167. package/dist/network-roadmap.js +5 -2
  168. package/dist/noctum-arco.js +911 -0
  169. package/dist/noctum-capacidade.js +141 -0
  170. package/dist/noctum-envelope.js +810 -0
  171. package/dist/noctum-execucao.js +304 -0
  172. package/dist/noctum-fila.js +280 -0
  173. package/dist/ocupacao.js +29 -2
  174. package/dist/onboarding.js +40 -21
  175. package/dist/orkmind.js +9 -2
  176. package/dist/orquestracao.js +13 -12
  177. package/dist/parado-no-condutor.js +34 -9
  178. package/dist/phase.js +94 -39
  179. package/dist/policies.js +4 -4
  180. package/dist/portfolio.js +4 -2
  181. package/dist/postura-local.js +234 -0
  182. package/dist/preflight.js +11 -10
  183. package/dist/procedencia.js +225 -0
  184. package/dist/projeto-alvo.js +127 -4
  185. package/dist/prompts.js +6 -2
  186. package/dist/pulse-delivery.js +13 -2
  187. package/dist/pulse.js +52 -19
  188. package/dist/ratelimit.js +4 -2
  189. package/dist/redacao-saida.js +63 -0
  190. package/dist/rede-status.js +3 -2
  191. package/dist/retry.js +232 -148
  192. package/dist/roadmap-reservas.js +20 -3
  193. package/dist/roadmap-status.js +129 -33
  194. package/dist/runtime-context.js +181 -3
  195. package/dist/runtimes.js +2 -1
  196. package/dist/session-events.js +7 -3
  197. package/dist/session-watcher-claude.js +7 -1
  198. package/dist/session-watcher.js +185 -33
  199. package/dist/sessoes-contas.js +1 -1
  200. package/dist/ship-publicar.js +800 -0
  201. package/dist/ship.js +84 -81
  202. package/dist/steal.js +77 -0
  203. package/dist/thread-close.js +3 -2
  204. package/dist/thread.js +153 -82
  205. package/dist/util.js +8 -1
  206. package/dist/verify.js +141 -52
  207. package/dist/vida-da-thread.js +254 -0
  208. package/dist/worktree-local.js +165 -0
  209. package/dist/worktree.js +20 -0
  210. package/dist/yaml.js +27 -8
  211. package/package.json +1 -1
  212. package/schemas/code-artifact-graph.v1.schema.json +2 -1
@@ -0,0 +1,493 @@
1
+ // A Mesa do Dono do Orkastery (RM-059, fatia F5; ficha M4 do plano dos mods). Na sessao do dono, um painel com tudo
2
+ // que espera o dono, lido do nucleo pela ponte (`$.ork.retrato` e `$.ork.ler`) e por tres ferramentas MCP, nunca de
3
+ // `.orkastery/` por conta propria. O botao Decidir so pede ao nucleo o dialogo nativo do pedido
4
+ // (`ork_request_decision`, com os dois ids); a decisao obvia, pelo teste das quatro condicoes, vira decisao autonoma do
5
+ // nucleo (`ork_decision_record`). Nenhum caminho daqui responde o pedido. A logica fica nos modulos puros ao lado; aqui
6
+ // so os ganchos e as chamadas ao `$`, sempre escritas como `x.noun.metodo(...)`, como o validador exige.
7
+ import { atom, read, update } from 'claude-code'
8
+ import type { EngineInterface, Register } from 'claude-code'
9
+ import type { MesaDecidindo, MesaFila, MesaObvia, MesaPergunta } from '../types'
10
+ import type { MesaMostrado } from './cartoes'
11
+ import { desenharMesa, linhasDaMesa, mostradosVisiveis, paginaDoLote } from './cartoes'
12
+ import { argsDaDecisaoObvia, argsDoDecidir, jaDecidida, motivoDaNotificacao, resultadoDoDecidir, soltarAbrindo } from './decidir'
13
+ import {
14
+ assinaturaDoRetrato, conferirNoNucleo, decisoesVistas, esperamODono, FILA_VAZIA, filaDoPulse, jsonDoMcp, ordenarPerguntas,
15
+ pedidosNotificados, textoDaFaixa, threadsComPergunta, umaLinha,
16
+ } from './fila'
17
+ import { testeDaObvia } from './obvia'
18
+
19
+ const MOD = 'ork-mesa'
20
+ const PAINEL = 'mesa'
21
+ const TITULO = 'Mesa do Dono'
22
+ const fila = atom({ plugin: 'ork-mesa', key: 'fila' } as const, FILA_VAZIA)
23
+ const foco = atom({ plugin: 'ork-mesa', key: 'foco' } as const, null as string | null)
24
+ const pagina = atom({ plugin: 'ork-mesa', key: 'pagina' } as const, 0)
25
+ const decidindo = atom({ plugin: 'ork-mesa', key: 'decidindo' } as const, {} as Record<string, MesaDecidindo>)
26
+ const obvias = atom({ plugin: 'ork-mesa', key: 'obvias' } as const, {} as Record<string, MesaObvia>)
27
+
28
+ /** O tique: a vista, o retrato a cada um; escondido, a cada quatro (D3). */
29
+ const PERIODO_DO_TIQUE_MS = 30000
30
+ const TIQUES_ESCONDIDO = 4
31
+ /** O pulse velho e relido mesmo sem mudanca no retrato. */
32
+ const IDADE_DO_PULSE_A_VISTA_MS = 5 * 60000
33
+ const IDADE_DO_PULSE_ESCONDIDO_MS = 15 * 60000
34
+ /** Teto de cada leitura do nucleo; o Decidir espera o dialogo, que o ingresso local fecha em ate 300 s. */
35
+ const PRAZO_DA_LEITURA_MS = 20000
36
+ const PRAZO_DO_DECIDIR_MS = 310000
37
+ /** A gravacao da decisao obvia e local e rapida; passado este teto ela fica incerta, nunca recusada de cara. */
38
+ const PRAZO_DA_DECISAO_MS = 60000
39
+ /** A decisao incerta que o pulse nao mostra nesse tempo vira recusada, e a pergunta volta a esperar o dono. */
40
+ const INCERTEZA_MAXIMA_MS = 10 * 60000
41
+ /** O servidor do nucleo pode conectar depois do inicio da sessao: o papel e conferido de novo nestas esperas. */
42
+ const ESPERAS_DO_PAPEL_MS = [3000, 10000, 30000]
43
+ const ESPERA_LONGA_DO_PAPEL_MS = 300000
44
+ const MAXIMO_DE_AVISOS = 5
45
+ /** O pulse que falha volta com recuo: 30 s, depois o dobro, ate 5 min (o retrato que muda nao fura o recuo). */
46
+ const RECUO_INICIAL_MS = 30000
47
+ const RECUO_MAXIMO_MS = 300000
48
+ const ID = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/
49
+
50
+ // O que o modulo guarda entre ganchos e nao desenha. Uma recarga do modulo zera tudo, e o `session.start` dispara
51
+ // de novo nela; o estado em `$.state` (a fila, o foco, o Decidir e as decisoes obvias) fica.
52
+ let ativa = false
53
+ let desistiu = false
54
+ let ciclo: { cancel: () => void } | undefined
55
+ let tiques = 0
56
+ let assinatura: string | null = null
57
+ let pulseLidoEm: number | null = null
58
+ /** A ultima falha do pulse e o recuo ate a proxima tentativa automatica. */
59
+ let pulseFalhouEm: number | null = null
60
+ let recuoMs = 0
61
+ /** O retrato mudou e o pulse ainda nao foi relido por causa disso (a mudanca vista no recuo nao se perde). */
62
+ let mudancaPendente = false
63
+ let lendo: Promise<void> | undefined
64
+ let pendente = false
65
+ /** Pedidos que esta sessao ja levou ao dono por notificacao. */
66
+ const notificados = new Set<string>()
67
+ /** Pedidos com a decisao obvia sendo registrada agora. */
68
+ const registrando = new Set<string>()
69
+ /** Pedidos com o Decidir em curso. */
70
+ const emDialogo = new Set<string>()
71
+ /** O que o desenho pos na janela de rolagem e ainda nao foi ao registro da ponte. */
72
+ const vistosNoDesenho = new Map<string, MesaMostrado>()
73
+ /** O que ja foi ao registro nesta sessao, por chave e texto. */
74
+ const jaMostrado = new Set<string>()
75
+ /** O ultimo texto publicado na faixa; null antes da primeira publicacao. */
76
+ let ultimaFaixa: string | undefined | null = null
77
+ /** A falha de um trabalho em segundo plano que nem o aviso do painel conseguiu guardar. */
78
+ let problemaSemAviso: string | null = null
79
+
80
+ function mensagem(erro: unknown): string {
81
+ return umaLinha(erro instanceof Error ? erro.message : String(erro))
82
+ }
83
+
84
+ /** A leitura com teto proprio: o relogio da sessao recusa a espera que passar dele. */
85
+ function comPrazo<T>($: EngineInterface, leitura: Promise<T>, ms = PRAZO_DA_LEITURA_MS): Promise<T> {
86
+ return new Promise<T>((resolver, recusar) => {
87
+ const prazo = $.clock.after(ms, () => recusar(new Error(`a leitura passou de ${Math.round(ms / 1000)} s`)))
88
+ leitura.then(v => { prazo.cancel(); resolver(v) }, e => { prazo.cancel(); recusar(e) })
89
+ })
90
+ }
91
+
92
+ /** Um aviso no painel, sem repetir e com teto: o que falhou fica a vista do dono. */
93
+ async function anotarAviso($: EngineInterface, texto: string): Promise<void> {
94
+ await update($, fila, f => (f.avisos.includes(texto) ? f : { ...f, avisos: [...f.avisos, texto].slice(-MAXIMO_DE_AVISOS) }))
95
+ }
96
+
97
+ /**
98
+ * Trabalho em segundo plano (o tique, a primeira leitura, os gestos do painel): a falha vai ao aviso do painel; sem
99
+ * como gravar o aviso (a sessao acabou ou o estado recusou), ela fica guardada aqui e o proximo desenho a mostra.
100
+ */
101
+ function emSegundoPlano($: EngineInterface, trabalho: Promise<unknown>, oQue: string): void {
102
+ trabalho.catch(async erro => {
103
+ const texto = `${oQue} parou: ${mensagem(erro)}`
104
+ try {
105
+ await anotarAviso($, texto)
106
+ } catch (erroDoAviso) {
107
+ problemaSemAviso = `${texto} (o aviso também falhou: ${mensagem(erroDoAviso)})`
108
+ }
109
+ })
110
+ }
111
+
112
+ /**
113
+ * O papel pela ponte. `null` so quando o `$.ork` nao existe (a ponte nao carregou); uma falha da propria ponte conta
114
+ * como dormente e o papel e conferido de novo depois.
115
+ */
116
+ async function papelDaSessao($: EngineInterface): Promise<string | null> {
117
+ try {
118
+ return String(await $.ork.papel())
119
+ } catch (erro) {
120
+ return erro instanceof TypeError ? null : 'dormente'
121
+ }
122
+ }
123
+
124
+ /** Liga a Mesa na sessao do dono: o `/mesa`, o tique e a primeira leitura. */
125
+ async function ativar($: EngineInterface): Promise<void> {
126
+ if (ativa) return
127
+ ativa = true
128
+ try {
129
+ await $.command.register({ name: 'mesa', description: 'Abre a Mesa do Dono: o que espera você no Orkastery, com a recomendação na frente', immediate: true })
130
+ } catch (erro) {
131
+ // Sem o /mesa o painel nao abre: a Mesa volta a dormente e tenta de novo na espera longa.
132
+ ativa = false
133
+ $.clock.after(ESPERA_LONGA_DO_PAPEL_MS, () => { emSegundoPlano($, conferirPapel($, ESPERAS_DO_PAPEL_MS.length), 'a conferência do papel') })
134
+ throw erro
135
+ }
136
+ // Depois de uma recarga do modulo, nenhum Decidir esta em curso: o que ficou "abrindo" no estado volta a ter botao.
137
+ await update($, decidindo, soltarAbrindo)
138
+ ciclo?.cancel()
139
+ ciclo = $.clock.every(PERIODO_DO_TIQUE_MS, () => { emSegundoPlano($, tique($), 'o tique da Mesa') })
140
+ emSegundoPlano($, atualizar($), 'a primeira leitura da fila')
141
+ }
142
+
143
+ /** Confere o papel: liga no dono, desiste na fase ou sem a ponte, e tenta de novo enquanto dormente. */
144
+ async function conferirPapel($: EngineInterface, tentativa: number): Promise<void> {
145
+ if (ativa || desistiu) return
146
+ const papel = await papelDaSessao($)
147
+ if (papel === 'dono') return ativar($)
148
+ if (papel === 'fase' || papel === null) {
149
+ desistiu = true
150
+ if (papel === null) $.ui.toast('mesa: a ponte ork-ponte não carregou; a Mesa do Dono fica desligada nesta sessão')
151
+ return
152
+ }
153
+ const espera = ESPERAS_DO_PAPEL_MS[tentativa] ?? ESPERA_LONGA_DO_PAPEL_MS
154
+ $.clock.after(espera, () => { emSegundoPlano($, conferirPapel($, tentativa + 1), 'a conferência do papel') })
155
+ }
156
+
157
+ /** O painel da Mesa esta posto e a vista do dono. */
158
+ async function painelAVista($: EngineInterface): Promise<boolean> {
159
+ const paineis = await $.ui.panes().catch(() => [])
160
+ return paineis.some(p => p.id === PAINEL && p.isPlaced && p.isShown)
161
+ }
162
+
163
+ /** O tique: a conferencia do retrato (a vista, toda vez; escondido, a cada quatro) e o registro do mostrado. */
164
+ async function tique($: EngineInterface): Promise<void> {
165
+ if (!ativa) return
166
+ tiques++
167
+ const aVista = await painelAVista($)
168
+ if (aVista || tiques % TIQUES_ESCONDIDO === 0) await conferirMudanca($, aVista)
169
+ await registrarMostrados($)
170
+ }
171
+
172
+ /** O retrato da secao `hitl` como sinal de mudanca, e o pulse quando o retrato muda ou o pulse fica velho (D3). */
173
+ async function conferirMudanca($: EngineInterface, aVista: boolean): Promise<void> {
174
+ const agora = await $.clock.now()
175
+ try {
176
+ const r = await comPrazo($, $.ork.retrato({ secao: 'hitl' }))
177
+ const nova = assinaturaDoRetrato(r.retrato)
178
+ if (assinatura !== null && nova !== assinatura) mudancaPendente = true
179
+ assinatura = nova
180
+ } catch (erro) {
181
+ await anotarAviso($, `não li o retrato do núcleo: ${mensagem(erro)}`)
182
+ }
183
+ const idade = pulseLidoEm === null ? Number.POSITIVE_INFINITY : agora - pulseLidoEm
184
+ if (pulseFalhouEm !== null && agora - pulseFalhouEm < recuoMs) return
185
+ // Decisao obvia incerta de pedido ainda na fila: o pulse e relido a cada conferencia ate ela se resolver.
186
+ const naFila = new Set((await read($, fila)).perguntas.map(p => p.pedidoId))
187
+ const incerta = Object.entries(await read($, obvias)).some(([id, o]) => o.estado === 'incerta' && naFila.has(id))
188
+ if (mudancaPendente || incerta || idade >= (aVista ? IDADE_DO_PULSE_A_VISTA_MS : IDADE_DO_PULSE_ESCONDIDO_MS)) {
189
+ mudancaPendente = false
190
+ await atualizar($)
191
+ }
192
+ }
193
+
194
+ /** Uma leitura por vez; pedido que chega no meio volta a rodar logo depois, e quem pediu espera as duas. */
195
+ async function atualizar($: EngineInterface): Promise<void> {
196
+ if (!ativa) return
197
+ if (lendo) {
198
+ pendente = true
199
+ return lendo
200
+ }
201
+ lendo = (async () => {
202
+ try {
203
+ do {
204
+ pendente = false
205
+ await lerUmaVez($)
206
+ } while (pendente)
207
+ } finally {
208
+ lendo = undefined
209
+ }
210
+ })()
211
+ return lendo
212
+ }
213
+
214
+ /** O pulse, as decisoes ja mostradas e os pedidos de cada thread com pergunta; depois a decisao obvia e o aviso. */
215
+ async function lerUmaVez($: EngineInterface): Promise<void> {
216
+ const agora = await $.clock.now()
217
+ let pulse: unknown
218
+ try {
219
+ pulse = await comPrazo($, $.ork.ler({ consulta: 'pulse' }))
220
+ } catch (erro) {
221
+ const motivo = mensagem(erro)
222
+ pulseFalhouEm = agora
223
+ recuoMs = Math.min(recuoMs ? recuoMs * 2 : RECUO_INICIAL_MS, RECUO_MAXIMO_MS)
224
+ await update($, fila, anterior => ({ ...anterior, erro: motivo }))
225
+ await publicarFaixa($)
226
+ return
227
+ }
228
+ pulseLidoEm = agora
229
+ pulseFalhouEm = null
230
+ recuoMs = 0
231
+ const avisos: string[] = []
232
+ let vistas = new Set<string>()
233
+ let jaNotificados = new Set<string>()
234
+ try {
235
+ const registro = await comPrazo($, $.ork.mostrados())
236
+ vistas = decisoesVistas(registro)
237
+ jaNotificados = pedidosNotificados(registro)
238
+ } catch (erro) {
239
+ avisos.push(`não li o registro do que a Mesa já mostrou: ${mensagem(erro)}`)
240
+ }
241
+ const base = filaDoPulse(pulse, vistas, agora)
242
+ const perguntas: MesaPergunta[] = []
243
+ for (const thread of threadsComPergunta(base.perguntas)) {
244
+ const daThread = base.perguntas.filter(p => p.thread === thread)
245
+ try {
246
+ const pendentes = jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_hitl_pending', { threadId: thread })))
247
+ for (const p of daThread) {
248
+ const conferida = conferirNoNucleo(p, pendentes)
249
+ if (conferida) perguntas.push(conferida)
250
+ }
251
+ } catch (erro) {
252
+ avisos.push(`não conferi os pedidos da ${thread} no núcleo: ${mensagem(erro)}`)
253
+ perguntas.push(...daThread)
254
+ }
255
+ }
256
+ const nova: MesaFila = { ...base, perguntas: ordenarPerguntas(perguntas), lidoEm: agora, erro: null, avisos }
257
+ await update($, fila, () => nova)
258
+ const registrou = await registrarObvias($, nova, agora)
259
+ await notificarNovas($, nova, jaNotificados)
260
+ await publicarFaixa($)
261
+ await registrarMostrados($)
262
+ // A decisao pedida agora chega no lote seguinte: o pulse e relido logo depois (e a incerta se resolve nele).
263
+ if (registrou) pendente = true
264
+ }
265
+
266
+ /**
267
+ * A decisao obvia (D5 e D6): para cada pergunta conferida no nucleo que passa no teste das quatro condicoes e que a
268
+ * Mesa ainda nao decidiu (nesta sessao, nem na janela do pulse), uma chamada de `ork_decision_record`. Nunca responde
269
+ * o pedido e nunca abre o dialogo. Chamada que falha ou passa do prazo fica `incerta`, porque a escrita pode ter
270
+ * chegado ao nucleo: o pulse e relido ate ela aparecer (`registrada`) ou vencer a incerteza (`recusada`: a pergunta
271
+ * volta a esperar o dono, com o motivo no cartao). Decisao que aparece no pulse depois sempre vira `registrada`.
272
+ */
273
+ async function registrarObvias($: EngineInterface, f: MesaFila, agora: number): Promise<boolean> {
274
+ let pediu = false
275
+ const ja = await read($, obvias)
276
+ // A incerta de pedido que saiu da fila (respondido, substituido ou vencido) nao tem mais o que confirmar.
277
+ const naFila = new Set(f.perguntas.map(p => p.pedidoId))
278
+ const sairam = Object.keys(ja).filter(id => ja[id]?.estado === 'incerta' && !naFila.has(id))
279
+ if (sairam.length) await update($, obvias, o => Object.fromEntries(Object.entries(o).filter(([id]) => !sairam.includes(id))))
280
+ for (const p of f.perguntas) {
281
+ const anterior = ja[p.pedidoId]
282
+ if (anterior) {
283
+ // A incerteza vence em 10 min ou no prazo do pedido, o que vier antes: o dono ainda precisa de tempo para decidir.
284
+ const prazo = Date.parse(p.prazo ?? '')
285
+ const vence = Math.min(anterior.em + INCERTEZA_MAXIMA_MS, Number.isFinite(prazo) ? prazo : Number.POSITIVE_INFINITY)
286
+ if (anterior.estado !== 'registrada' && jaDecidida(f.decisoes, p)) {
287
+ await update($, obvias, o => ({ ...o, [p.pedidoId]: { estado: 'registrada', texto: 'registrada no núcleo (conferida no pulse)', em: agora } }))
288
+ } else if (anterior.estado === 'incerta' && agora >= vence) {
289
+ await update($, obvias, o => ({ ...o, [p.pedidoId]: { estado: 'recusada',
290
+ texto: `o pulse não mostrou a decisão gravada a tempo (${anterior.texto}); vale como pergunta`, em: agora } }))
291
+ }
292
+ continue
293
+ }
294
+ if (registrando.has(p.pedidoId) || !p.conferida) continue
295
+ const teste = testeDaObvia(p, agora)
296
+ if (!teste.obvia) continue
297
+ if (jaDecidida(f.decisoes, p)) {
298
+ await update($, obvias, o => ({ ...o, [p.pedidoId]: { estado: 'registrada', texto: 'já registrada pela Mesa', em: agora } }))
299
+ continue
300
+ }
301
+ registrando.add(p.pedidoId)
302
+ let obvia: MesaObvia
303
+ try {
304
+ const args = argsDaDecisaoObvia(p, teste.alternativa, teste.referencia, new Date(agora).toISOString())
305
+ let resposta: unknown
306
+ try {
307
+ resposta = await comPrazo($, $.mcp.call('orkastery', 'ork_decision_record', args), PRAZO_DA_DECISAO_MS)
308
+ } catch (erro) {
309
+ // Sem resposta do nucleo (prazo ou transporte): a escrita pode ter chegado.
310
+ resposta = undefined
311
+ obvia = { estado: 'incerta', texto: mensagem(erro), em: agora }
312
+ }
313
+ if (resposta !== undefined) {
314
+ try {
315
+ jsonDoMcp(resposta)
316
+ obvia = { estado: 'registrada', texto: 'registrada no núcleo', em: agora }
317
+ } catch (erro) {
318
+ // O nucleo respondeu com recusa: nada foi gravado.
319
+ obvia = { estado: 'recusada', texto: mensagem(erro), em: agora }
320
+ }
321
+ }
322
+ } finally {
323
+ registrando.delete(p.pedidoId)
324
+ }
325
+ const final = obvia!
326
+ await update($, obvias, o => ({ ...o, [p.pedidoId]: final }))
327
+ pediu = true
328
+ }
329
+ return pediu
330
+ }
331
+
332
+ /**
333
+ * A pergunta nova que espera o dono (nao obvia, ainda nao notificada nesta sessao nem no registro da ponte) vira uma
334
+ * notificacao do sistema, uma so por leitura. So a que saiu de fato conta como notificada e entra no registro do
335
+ * mostrado com o canal `notificacao` (D8 e M5): a que nao saiu fica no aviso do painel e volta na leitura seguinte.
336
+ */
337
+ async function notificarNovas($: EngineInterface, f: MesaFila, jaNotificados: ReadonlySet<string>): Promise<void> {
338
+ const novas = esperamODono(f, await read($, obvias)).filter(p => !notificados.has(p.pedidoId) && !jaNotificados.has(p.pedidoId))
339
+ if (!novas.length) return
340
+ const primeira = novas[0] as MesaPergunta
341
+ const texto = novas.length === 1
342
+ ? umaLinha(`${primeira.thread} espera você: ${primeira.pergunta}`)
343
+ : umaLinha(`${novas.length} pedidos esperam você: ${[...new Set(novas.map(p => p.thread))].join(', ')}`)
344
+ let motivo: string | null
345
+ try {
346
+ const enviada = await $.ui.notify(texto, { title: TITULO })
347
+ if (!enviada.isSent && enviada.reason === 'disabled') {
348
+ // O dono desligou as notificacoes: escolha dele, sem aviso e sem nova tentativa; a faixa e o painel seguem.
349
+ for (const p of novas) notificados.add(p.pedidoId)
350
+ return
351
+ }
352
+ motivo = enviada.isSent ? null : motivoDaNotificacao(enviada.reason)
353
+ } catch (erro) {
354
+ motivo = mensagem(erro)
355
+ }
356
+ if (motivo !== null) {
357
+ await anotarAviso($, `não avisei o dono do pedido novo: ${motivo}; a faixa e o painel seguem`)
358
+ return
359
+ }
360
+ for (const p of novas) notificados.add(p.pedidoId)
361
+ try {
362
+ for (const p of novas) await $.ork.mostrado({ mod: MOD, canal: 'notificacao', chave: `hitl:${p.pedidoId}`, thread: p.thread, texto })
363
+ } catch (erro) {
364
+ await anotarAviso($, `não registrei a notificação na ponte: ${mensagem(erro)}`)
365
+ }
366
+ }
367
+
368
+ /** A linha da faixa pela ponte, so quando o texto muda; sem nada, a linha sai da faixa. */
369
+ async function publicarFaixa($: EngineInterface): Promise<void> {
370
+ const texto = textoDaFaixa(await read($, fila), await read($, obvias))
371
+ if (texto === ultimaFaixa) return
372
+ try {
373
+ if (texto === undefined) await $.ork.faixa({ mod: MOD })
374
+ else await $.ork.faixa({ mod: MOD, texto })
375
+ ultimaFaixa = texto
376
+ } catch (erro) {
377
+ await anotarAviso($, `não publiquei a linha da faixa: ${mensagem(erro)}`)
378
+ }
379
+ }
380
+
381
+ /** O desenho anota o que pos na janela; quem registra e o laco de leitura e o tique, fora do desenho. */
382
+ function anotarVistos(vistos: readonly MesaMostrado[]): void {
383
+ for (const m of vistos) vistosNoDesenho.set(`${m.chave}|${m.texto}`, m)
384
+ }
385
+
386
+ /**
387
+ * O que o desenho pos na janela do painel posto e a vista vai ao registro da ponte (M5 do dono, D8), uma vez por
388
+ * chave e texto nesta sessao. Com o painel escondido, o anotado e descartado: o proximo desenho a vista anota de novo.
389
+ */
390
+ async function registrarMostrados($: EngineInterface): Promise<void> {
391
+ if (vistosNoDesenho.size === 0) return
392
+ if (!await painelAVista($)) {
393
+ vistosNoDesenho.clear()
394
+ return
395
+ }
396
+ for (const [vista, m] of [...vistosNoDesenho]) {
397
+ vistosNoDesenho.delete(vista)
398
+ if (jaMostrado.has(vista)) continue
399
+ try {
400
+ const thread = m.thread && ID.test(m.thread) ? { thread: m.thread } : {}
401
+ await $.ork.mostrado({ mod: MOD, canal: 'painel', chave: m.chave, ...thread, texto: m.texto })
402
+ jaMostrado.add(vista)
403
+ } catch (erro) {
404
+ vistosNoDesenho.set(vista, m)
405
+ await anotarAviso($, `não registrei o que o painel mostrou: ${mensagem(erro)}`)
406
+ return
407
+ }
408
+ }
409
+ }
410
+
411
+ /**
412
+ * O Decidir (D7): so com o canal `claude-code` disponivel para o pedido, um por pedido, em segundo plano. A chamada
413
+ * leva exatamente o `threadId` e o `pedidoId`; quem responde e o dono, no dialogo nativo do host.
414
+ */
415
+ async function decidir($: EngineInterface, pedidoId: string): Promise<void> {
416
+ if (!ID.test(pedidoId) || emDialogo.has(pedidoId)) return
417
+ // Marcado antes de qualquer espera: dois toques ao mesmo tempo abrem um dialogo so.
418
+ emDialogo.add(pedidoId)
419
+ let emCurso = false
420
+ try {
421
+ const p = (await read($, fila)).perguntas.find(x => x.pedidoId === pedidoId)
422
+ if (!p || p.canalClaudeCode !== 'disponivel') return
423
+ const pedidoEm = await $.clock.now()
424
+ await update($, decidindo, d => ({ ...d, [pedidoId]: { estado: 'abrindo', texto: 'diálogo pedido', em: pedidoEm } }))
425
+ emCurso = true
426
+ pedirDialogo($, p)
427
+ } finally {
428
+ if (!emCurso) emDialogo.delete(pedidoId)
429
+ }
430
+ }
431
+
432
+ /** O pedido do dialogo ao nucleo, em segundo plano; quem libera o pedido para outro Decidir e o fim desta espera. */
433
+ function pedirDialogo($: EngineInterface, p: MesaPergunta): void {
434
+ const pedidoId = p.pedidoId
435
+ emSegundoPlano($, (async () => {
436
+ let r: MesaDecidindo
437
+ try {
438
+ const resposta = jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_request_decision', argsDoDecidir(p)), PRAZO_DO_DECIDIR_MS))
439
+ r = resultadoDoDecidir(resposta, await $.clock.now())
440
+ } catch (erro) {
441
+ r = { estado: 'erro', texto: `o Decidir falhou: ${mensagem(erro)}; use a reserva`, em: await $.clock.now() }
442
+ } finally {
443
+ emDialogo.delete(pedidoId)
444
+ }
445
+ await update($, decidindo, d => ({ ...d, [pedidoId]: r }))
446
+ await atualizar($)
447
+ })(), `o Decidir do pedido ${pedidoId.slice(0, 8)}`)
448
+ }
449
+
450
+ export const register: Register = on => {
451
+ on('session.start', async ($, e, next) => {
452
+ if (e.isInteractive) await conferirPapel($, 0)
453
+ return next(e)
454
+ })
455
+
456
+ // `/mesa` abre o painel e rele a fila; `/mesa <thread>` (a Torre o usa para a acao `hitl.decide`) mostra so a
457
+ // thread pedida. O comando so existe com a Mesa ligada; a conferencia do papel aqui cobre o comando que sobrou de
458
+ // uma carga anterior.
459
+ on('command.run', { command: 'mesa' }, async ($, e) => {
460
+ if (!ativa && !desistiu) await conferirPapel($, ESPERAS_DO_PAPEL_MS.length)
461
+ if (!ativa) return { text: 'A Mesa do Dono só abre na sessão do dono de um projeto do Orkastery.' }
462
+ const pedida = String(e.args ?? '').trim()
463
+ const thread = ID.test(pedida) ? pedida : null
464
+ await update($, foco, () => thread)
465
+ await update($, pagina, () => 0)
466
+ const aberto = await $.ui.open({ id: PAINEL, title: TITULO })
467
+ await atualizar($)
468
+ const sufixo = thread ? ` (só ${thread})` : ''
469
+ return { text: aberto.isPlaced ? `Mesa do Dono aberta${sufixo}.` : `Mesa do Dono aberta${sufixo}, à espera de lugar: ${aberto.reason}` }
470
+ })
471
+
472
+ // O painel: o placar, o lote de perguntas, as decisoes por voce e as paradas. O desenho nunca escreve: so anota o
473
+ // que pos na janela de rolagem, para o registro do mostrado. Os gestos mudam o estado da Mesa e pedem ao nucleo.
474
+ on('ui.render', { component: 'Pane', requestId: PAINEL }, async ($, e) => {
475
+ const { Box, Text, Button } = $.ui.resolve(e)
476
+ const lida = await read($, fila)
477
+ const estado = {
478
+ fila: problemaSemAviso ? { ...lida, avisos: [...lida.avisos, problemaSemAviso] } : lida, foco: await read($, foco),
479
+ pagina: await read($, pagina), decidindo: await read($, decidindo), obvias: await read($, obvias),
480
+ }
481
+ const linhas = linhasDaMesa(estado, { agora: await $.clock.now() })
482
+ anotarVistos(mostradosVisiveis(linhas, e.props.scroll))
483
+ const total = estado.foco ? estado.fila.perguntas.filter(p => p.thread === estado.foco).length : estado.fila.perguntas.length
484
+ return desenharMesa({ Box, Text, Button }, linhas, {
485
+ decidir: pedidoId => { emSegundoPlano($, decidir($, pedidoId), 'o Decidir') },
486
+ atualizar: () => { emSegundoPlano($, atualizar($), 'a releitura da fila') },
487
+ verTodas: () => { emSegundoPlano($, update($, foco, () => null), 'o Ver todas') },
488
+ // A pagina guardada pode passar do fim depois que a fila encolhe: o passo parte da pagina que esta na tela.
489
+ anteriores: () => { emSegundoPlano($, update($, pagina, n => paginaDoLote(total, paginaDoLote(total, n).pagina - 1).pagina), 'o lote anterior') },
490
+ proximas: () => { emSegundoPlano($, update($, pagina, n => paginaDoLote(total, paginaDoLote(total, n).pagina + 1).pagina), 'o lote seguinte') },
491
+ })
492
+ })
493
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "formato": "ork.mod/v1",
3
+ "papeis": ["dono"],
4
+ "claudeCodeMinimo": "2.1.287"
5
+ }
@@ -0,0 +1,131 @@
1
+ // Contrato do estado da Mesa do Dono (`ork-mesa`, RM-059 fatia F5; ficha M4 do plano dos mods). Sem import nem
2
+ // referencia, como o motor exige de um contrato: as chaves de `$.state` que a Mesa usa ficam declaradas aqui. A
3
+ // Mesa le o nucleo pela ponte (`$.ork.retrato` e `$.ork.ler`) e por tres ferramentas MCP; nada aqui e resposta
4
+ // do dono, e nenhum campo guarda a opcao que o dono escolheu.
5
+
6
+ /** Uma alternativa de um pedido, como a Mesa a mostra: letra no `ork.hitl/v2`, numero no `ork.hitl/v1`. */
7
+ export type MesaAlternativa = {
8
+ chave: string
9
+ texto: string
10
+ acao: string
11
+ /** O que acontece se escolher, em uma linha (so no v2). */
12
+ consequencia: string | null
13
+ recomendada: boolean
14
+ /** O porque da recomendada (so no v2). */
15
+ porque: string | null
16
+ }
17
+
18
+ /** A oferta do canal `claude-code` para o pedido, lida do `ork_hitl_pending`; sem leitura, desconhecida. */
19
+ export type MesaCanal = 'disponivel' | 'indisponivel' | 'desconhecido'
20
+
21
+ /** Um pedido aberto que espera o dono, montado do pulse e conferido no `ork_hitl_pending`. */
22
+ export type MesaPergunta = {
23
+ thread: string
24
+ fase: string | null
25
+ modo: string | null
26
+ pedidoId: string
27
+ codigo: string | null
28
+ contrato: 'ork.hitl/v1' | 'ork.hitl/v2'
29
+ alvo: 'gate' | 'session'
30
+ motivo: string
31
+ pergunta: string
32
+ /** A recomendacao em texto, como o nucleo a escreve. */
33
+ recomendacao: string
34
+ alternativas: MesaAlternativa[]
35
+ irreversivel: boolean
36
+ ato: string | null
37
+ tipoDeResposta: string | null
38
+ respostaAceita: string | null
39
+ dependenciaTecnica: boolean
40
+ acaoAoExpirar: string | null
41
+ prazo: string | null
42
+ prazoLocal: string | null
43
+ desdeEm: string | null
44
+ /** O estado do pedido no nucleo (`aberto`, `esperar`, `escalar`, `seguir-recomendada`); `desconhecido` sem conferir. */
45
+ estado: string
46
+ /** O pedido foi conferido agora no `ork_hitl_pending`; sem isso a Mesa nao decide nem oferece o Decidir. */
47
+ conferida: boolean
48
+ canalClaudeCode: MesaCanal
49
+ /** O que o dono digita pelo Telegram ou no terminal, quando o dialogo nao serve. */
50
+ reserva: string | null
51
+ }
52
+
53
+ /** Uma parada sem pedido ou um impedimento que so o dono resolve: so leitura. */
54
+ export type MesaOutro = {
55
+ chave: string
56
+ thread: string | null
57
+ fase: string | null
58
+ motivo: string
59
+ texto: string
60
+ recomendacao: string
61
+ comando: string
62
+ desdeEm: string | null
63
+ impedimento: boolean
64
+ }
65
+
66
+ /** Uma decisao que a fabrica (ou a Mesa) tomou pelo dono, como o pulse a traz. */
67
+ export type MesaDecisao = {
68
+ id: string
69
+ thread: string
70
+ fase: string
71
+ em: string
72
+ decidido: string
73
+ porque: string
74
+ comoMudar: string
75
+ custoAgora: string
76
+ custoDepois: string
77
+ quemDecidiu: string
78
+ /** A decisao que esta desfaz, quando desfaz uma. */
79
+ reverte: string | null
80
+ /** A decisao posterior que desfez esta, quando ha. */
81
+ revertidaPor: string | null
82
+ /** Ainda nao mostrada ao dono pela Mesa (registro do mostrado da ponte), das ultimas 24 h e nao revertida. */
83
+ nova: boolean
84
+ }
85
+
86
+ export type MesaFila = {
87
+ perguntas: MesaPergunta[]
88
+ outros: MesaOutro[]
89
+ decisoes: MesaDecisao[]
90
+ /** Quantas decisoes a janela do pulse tinha; o painel mostra so as primeiras. */
91
+ totalDeDecisoes: number
92
+ lidoEm: number | null
93
+ erro: string | null
94
+ /** O que nao saiu inteiro na ultima leitura (uma conferencia, a faixa, o registro): o painel mostra cada um. */
95
+ avisos: string[]
96
+ }
97
+
98
+ /** O Decidir de um pedido: o dialogo pedido ao nucleo e o que ele devolveu. */
99
+ export type MesaDecidindo = {
100
+ estado: 'abrindo' | 'respondido' | 'sem-resposta' | 'erro'
101
+ texto: string
102
+ em: number
103
+ }
104
+
105
+ /**
106
+ * A decisao obvia que a Mesa pediu ao nucleo: `registrada` quando ele aceitou ou o pulse a mostra; `incerta` quando a
107
+ * chamada falhou ou passou do prazo e a escrita pode ter chegado (a proxima leitura do pulse decide); `recusada` quando
108
+ * a leitura seguinte nao a mostra.
109
+ */
110
+ export type MesaObvia = {
111
+ estado: 'registrada' | 'incerta' | 'recusada'
112
+ texto: string
113
+ em: number
114
+ }
115
+
116
+ declare module 'claude-code' {
117
+ interface PluginState {
118
+ 'ork-mesa': {
119
+ /** A fila lida do nucleo. */
120
+ fila: MesaFila
121
+ /** A thread que o `/mesa <thread>` pediu; `null` mostra todas. */
122
+ foco: string | null
123
+ /** A pagina do lote de perguntas, de cinco em cinco. */
124
+ pagina: number
125
+ /** O Decidir de cada pedido, pelo id do pedido. */
126
+ decidindo: Record<string, MesaDecidindo>
127
+ /** As decisoes obvias desta sessao, pelo id do pedido. */
128
+ obvias: Record<string, MesaObvia>
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "ork-pista",
3
+ "version": "0.1.0",
4
+ "description": "Pista de Entrega do Orkastery no Claude Code: do CHECK verde ao merge, cada entrega numa pista com a prova de cada etapa (bundle, branch publicada, PR, CI ork-verify, conflito com a base e ship_done) e o próximo passo que o núcleo declara. Publica só pelo ork ship publicar, no modo que já autoriza o push; nunca faz merge nem tag.",
5
+ "author": {
6
+ "name": "Orkastery contributors",
7
+ "url": "https://github.com/orkastery"
8
+ },
9
+ "homepage": "https://orkastery.com/",
10
+ "repository": "https://github.com/orkastery/orkastery",
11
+ "license": "MIT",
12
+ "types": "./types/index.d.ts",
13
+ "dependencies": ["ork-ponte"]
14
+ }