@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.
- package/adapters/claude-code/README.md +158 -0
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/ork.md +9 -0
- package/adapters/claude-code/mods/autoridade.json +56 -0
- package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
- package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
- package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
- package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
- package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
- package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
- package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
- package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
- package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
- package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
- package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
- package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
- package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
- package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
- package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
- package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
- package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
- package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
- package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
- package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
- package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
- package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
- package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
- package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
- package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
- package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
- package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
- package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
- package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
- package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
- package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
- package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
- package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
- package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
- package/adapters/codex/skills/ork/SKILL.md +18 -3
- package/adapters/hermes/README.md +1 -0
- package/adapters/hermes/bin/ork-network-status.sh +10 -0
- package/adapters/hermes/hermes.plugin.json +1 -0
- package/adapters/hermes/hitl-ingress/__init__.py +2 -2
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +7 -6
- package/adapters/openclaw/README.md +26 -5
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +46 -11
- package/adapters/openclaw/openclaw.plugin.json +5 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +2 -2
- package/adapters/openclaw/src/index.ts +49 -11
- package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
- package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
- package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
- package/assets/docs-en/produto/README.md +14 -0
- package/assets/docs-en/produto/_modelo-feature.md +62 -0
- package/assets/docs-en/roadmap/README.md +14 -0
- package/assets/docs-en/roadmap/_modelo-item.md +75 -0
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +116 -18
- package/dist/adapters/codex.js +14 -4
- package/dist/agents-md.js +24 -14
- package/dist/auditrun.js +22 -3
- package/dist/board.js +20 -17
- package/dist/branch-de-estado.js +88 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/catalogo.js +33 -0
- package/dist/ci.js +21 -8
- package/dist/claims-conferir.js +342 -0
- package/dist/claims.js +41 -1
- package/dist/company-brain-client.js +36 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/company-brain-journal.js +2 -1
- package/dist/company-brain-migration.js +36 -1
- package/dist/conducao-sentinela.js +388 -0
- package/dist/conducao-texto.js +12 -18
- package/dist/conducao.js +122 -30
- package/dist/conhecimento.js +490 -0
- package/dist/docs.js +70 -17
- package/dist/doctor-pulse-cron.js +349 -0
- package/dist/doctor-rede.js +150 -0
- package/dist/doctor.js +195 -111
- package/dist/entrega-pr.js +42 -29
- package/dist/escopo-escrita.js +10 -1
- package/dist/esgotamentos.js +181 -0
- package/dist/estado-thread.js +23 -1
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-batida.js +310 -0
- package/dist/fabrica-estado.js +52 -14
- package/dist/fabrica-publicar.js +9 -1
- package/dist/fechamento.js +20 -66
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +3 -2
- package/dist/forja.js +31 -7
- package/dist/gates.js +3 -24
- package/dist/handoff.js +10 -6
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-local-receipt.js +2 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +38 -3
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/hitl.js +29 -33
- package/dist/horario.js +41 -7
- package/dist/hosts.js +104 -11
- package/dist/impedimento.js +299 -0
- package/dist/index.js +961 -542
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +9 -1
- package/dist/init.js +56 -43
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +170 -16
- package/dist/intelligence-graph-contexto.js +254 -0
- package/dist/intelligence-graph-contract.js +2 -1
- package/dist/intelligence-graph-extract-md.js +56 -4
- package/dist/intelligence-graph-extract-ts.js +71 -3
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-query.js +66 -19
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +18 -1
- package/dist/licoes.js +1 -0
- package/dist/liveness.js +6 -3
- package/dist/locale-ajuda.js +761 -0
- package/dist/locale-gerados.js +160 -0
- package/dist/locale-master.js +99 -0
- package/dist/locale-onboarding.js +92 -0
- package/dist/locale-phase.js +151 -0
- package/dist/locale-pulse.js +211 -0
- package/dist/locale-retry.js +385 -0
- package/dist/locale-roadmap.js +102 -0
- package/dist/locale-ship.js +494 -0
- package/dist/locale-thread.js +277 -0
- package/dist/locale-verify.js +125 -0
- package/dist/locale.js +714 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +149 -4
- package/dist/maquina.js +23 -4
- package/dist/master-digest.js +6 -1
- package/dist/master-nota.js +18 -11
- package/dist/master.js +145 -31
- package/dist/mcp-artifacts.js +43 -3
- package/dist/mcp-git.js +42 -8
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +55 -6
- package/dist/mcp-server.js +22 -3
- package/dist/mcp-ship.js +3 -1
- package/dist/mcp-verify.js +6 -1
- package/dist/memoria.js +48 -6
- package/dist/modos.js +3 -6
- package/dist/network-roadmap.js +196 -18
- package/dist/noctum-arco.js +911 -0
- package/dist/noctum-capacidade.js +141 -0
- package/dist/noctum-envelope.js +810 -0
- package/dist/noctum-execucao.js +304 -0
- package/dist/noctum-fila.js +280 -0
- package/dist/ocupacao.js +40 -5
- package/dist/onboarding.js +40 -21
- package/dist/orkmind.js +99 -7
- package/dist/orquestracao.js +24 -21
- package/dist/parado-no-condutor.js +219 -38
- package/dist/phase.js +160 -52
- package/dist/policies.js +56 -5
- package/dist/portfolio.js +8 -3
- package/dist/postura-local.js +234 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +225 -0
- package/dist/projeto-alvo.js +132 -5
- package/dist/prompts.js +40 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +47 -4
- package/dist/pulse.js +98 -19
- package/dist/ratelimit.js +24 -6
- package/dist/recall.js +3 -1
- package/dist/redacao-saida.js +63 -0
- package/dist/rede-adesao.js +399 -0
- package/dist/rede-forja.js +289 -0
- package/dist/rede-projetos.js +239 -0
- package/dist/rede-status.js +337 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +291 -140
- package/dist/roadmap-reservas.js +20 -3
- package/dist/roadmap-status.js +150 -34
- package/dist/runtime-context.js +181 -3
- package/dist/runtime-profiles.js +22 -1
- package/dist/runtimes.js +2 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-events.js +7 -3
- package/dist/session-watcher-claude.js +120 -24
- package/dist/session-watcher.js +185 -33
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship-publicar.js +800 -0
- package/dist/ship.js +157 -88
- package/dist/steal.js +77 -0
- package/dist/thread-close.js +3 -2
- package/dist/thread.js +299 -49
- package/dist/util.js +8 -1
- package/dist/verify.js +141 -52
- package/dist/vida-da-thread.js +254 -0
- package/dist/worktree-local.js +165 -0
- package/dist/worktree.js +25 -2
- package/dist/yaml.js +27 -8
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +2 -1
- package/skills/README.md +1 -1
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- 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,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
|
-
|
|
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
|
-
|
|
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-
|
|
36
|
-
PULSE_LIVRE = re.compile(r'^[ \t]*(?:[1-
|
|
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)
|