@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.
- package/adapters/claude-code/README.md +158 -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/hermes/skills/orkastery-devmaster/SKILL.md +1 -1
- package/adapters/openclaw/README.md +2 -1
- package/adapters/openclaw/openclaw.plugin.json +1 -1
- package/adapters/openclaw/package.json +1 -1
- 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/dist/adapters/claude-bg.js +77 -13
- package/dist/adapters/codex.js +10 -1
- package/dist/agents-md.js +24 -15
- package/dist/auditrun.js +17 -2
- package/dist/board.js +4 -3
- package/dist/branch-de-estado.js +23 -1
- package/dist/catalogo.js +33 -0
- package/dist/ci.js +13 -7
- package/dist/claims-conferir.js +342 -0
- package/dist/claims.js +3 -1
- package/dist/company-brain-client.js +36 -1
- 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 +22 -8
- package/dist/doctor-pulse-cron.js +182 -27
- package/dist/doctor-rede.js +18 -17
- package/dist/doctor.js +115 -111
- package/dist/entrega-pr.js +22 -21
- package/dist/escopo-escrita.js +10 -1
- package/dist/estado-thread.js +23 -1
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/fabrica-batida.js +310 -0
- package/dist/fabrica-estado.js +38 -8
- package/dist/fabrica-publicar.js +3 -1
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +3 -2
- package/dist/forja.js +1 -1
- package/dist/gates.js +3 -28
- package/dist/handoff.js +10 -6
- package/dist/hitl-local-receipt.js +2 -0
- package/dist/hitl-resumo.js +29 -3
- package/dist/hitl-tempo-parado.js +4 -4
- package/dist/hitl.js +29 -33
- package/dist/horario.js +14 -7
- package/dist/hosts.js +52 -1
- package/dist/impedimento.js +108 -14
- package/dist/index.js +623 -521
- package/dist/indice.js +7 -1
- package/dist/init.js +43 -47
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +92 -21
- package/dist/intelligence-graph-contexto.js +56 -17
- 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-query.js +66 -19
- package/dist/ledger.js +15 -1
- 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/manifest.js +129 -3
- package/dist/maquina.js +23 -4
- package/dist/master-digest.js +6 -1
- package/dist/master-nota.js +4 -6
- package/dist/master.js +21 -24
- package/dist/mcp-artifacts.js +11 -2
- package/dist/mcp-git.js +23 -6
- package/dist/mcp-grafo.js +7 -4
- package/dist/mcp-server.js +8 -2
- package/dist/mcp-ship.js +3 -1
- package/dist/mcp-verify.js +6 -1
- package/dist/modos.js +3 -6
- package/dist/network-roadmap.js +5 -2
- 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 +29 -2
- package/dist/onboarding.js +40 -21
- package/dist/orkmind.js +9 -2
- package/dist/orquestracao.js +13 -12
- package/dist/parado-no-condutor.js +34 -9
- package/dist/phase.js +94 -39
- package/dist/policies.js +4 -4
- package/dist/portfolio.js +4 -2
- package/dist/postura-local.js +234 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +225 -0
- package/dist/projeto-alvo.js +127 -4
- package/dist/prompts.js +6 -2
- package/dist/pulse-delivery.js +13 -2
- package/dist/pulse.js +52 -19
- package/dist/ratelimit.js +4 -2
- package/dist/redacao-saida.js +63 -0
- package/dist/rede-status.js +3 -2
- package/dist/retry.js +232 -148
- package/dist/roadmap-reservas.js +20 -3
- package/dist/roadmap-status.js +129 -33
- package/dist/runtime-context.js +181 -3
- package/dist/runtimes.js +2 -1
- package/dist/session-events.js +7 -3
- package/dist/session-watcher-claude.js +7 -1
- package/dist/session-watcher.js +185 -33
- package/dist/sessoes-contas.js +1 -1
- package/dist/ship-publicar.js +800 -0
- package/dist/ship.js +84 -81
- package/dist/steal.js +77 -0
- package/dist/thread-close.js +3 -2
- package/dist/thread.js +153 -82
- 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 +20 -0
- package/dist/yaml.js +27 -8
- package/package.json +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +2 -1
|
@@ -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
|
+
}
|
|
@@ -12,7 +12,7 @@ Mensagem literal `orkastery maestro`: a primeira ação é a `ork_maestro`; só
|
|
|
12
12
|
|
|
13
13
|
Mensagem literal `orkastery maestro`: use `ork_maestro` (wrapper de `ork maestro --json`) para o panorama do projeto pedido; o nome dito pelo dono ("do orkastery") vai como `--projeto <nome>` (RM-052). Sem projeto nomeado, ofereça o panorama da rede: `ork_network_roadmap` (wrapper de `ork network roadmap`), com cada projeto conhecido, as threads de todas as máquinas, fontes, frescor e lacunas, transportado como vem (RM-054).
|
|
14
14
|
Não abra thread por essa consulta. O gateway não tem diretório de projeto: `projeto.escolha` traz os candidatos; apresente-os e pergunte, nunca escolha pelo cwd.
|
|
15
|
-
Apresente fontes/lacunas e próximas ações; ausência/ambiguidade de projeto exige contexto permitido; leia o cabeçalho "Projeto consultado" e o "Não lido" antes de responder.
|
|
15
|
+
Apresente fontes/lacunas e próximas ações; ausência/ambiguidade de projeto exige contexto permitido; leia o cabeçalho "Projeto consultado" e o "Não lido" antes de responder. No terminal, todo `ork` de projeto leva `--projeto <nome>` do projeto pedido; sem ele, quem escolhe é o cwd do gateway.
|
|
16
16
|
Em sessão de fase já despachada, siga o bloco recebido sem abrir outra orquestração.
|
|
17
17
|
Ações usam os comandos tipados do núcleo com precondições e readback.
|
|
18
18
|
|
|
@@ -79,7 +79,8 @@ nunca um caminho. Ele vai ao `ork` como `--projeto <nome>`. O adaptador declara
|
|
|
79
79
|
`ORK_PROJETO_EXPLICITO=1`: o diretorio do gateway nao escolhe projeto. Sem `projeto` e com mais de
|
|
80
80
|
um projeto conhecido, a resposta e a escolha tipada `projeto.escolha`, com os candidatos; com um
|
|
81
81
|
so, vale ele. Toda resposta de `ork_maestro`, `ork_board` e `ork_roadmap_status` comeca dizendo o
|
|
82
|
-
projeto consultado e o que nao foi lido
|
|
82
|
+
projeto consultado e o que nao foi lido; as demais tools de projeto terminam com a linha
|
|
83
|
+
`Projeto consultado: ...` (RM-052, fatia 2), que vem no stderr e o plugin junta ao texto da tool.
|
|
83
84
|
|
|
84
85
|
### O roadmap da rede (RM-054, fatia 2)
|
|
85
86
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "orkastery",
|
|
3
3
|
"name": "Orkastery",
|
|
4
4
|
"description": "Conducao de looping threads em 6 fases pelo nucleo `ork`, exposta ao OpenClaw como tools `ork_*`. Zero regra de negocio no host: cada tool e uma chamada de CLI.",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.6",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"properties": {},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkastery/openclaw-plugin",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Plugin Orkastery para OpenClaw: 28 tools ork_* que traduzem intencao em chamada de CLI do nucleo `ork`. Zero regra de negocio no host.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": true,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Markdown style of the product documentation and of the roadmap (Orkastery, I-44).
|
|
2
|
+
// Division of labor: this linter covers the FORM of the Markdown; `ork docs verificar` covers
|
|
3
|
+
// the frontmatter, reading (ADHD), and parity with the code and with git.
|
|
4
|
+
{
|
|
5
|
+
"globs": [
|
|
6
|
+
"docs/produto/**/*.md",
|
|
7
|
+
"docs/roadmap/**/*.md",
|
|
8
|
+
"docs/padroes/**/*.md",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"config": {
|
|
12
|
+
"default": true,
|
|
13
|
+
// Prose does not wrap at 80 columns: one paragraph is one line.
|
|
14
|
+
"MD013": false,
|
|
15
|
+
// "Histórico" and "Comportamento" repeat across pages, never among siblings under the same title.
|
|
16
|
+
"MD024": { "siblings_only": true },
|
|
17
|
+
// The template uses the same ordered list style as the owner's standard.
|
|
18
|
+
"MD029": { "style": "one_or_ordered" },
|
|
19
|
+
// HTML only for images, badges and detail folds; HTML layout hides the answer in the first line.
|
|
20
|
+
"MD033": { "allowed_elements": ["img", "picture", "source", "br", "sub", "sup", "kbd", "details", "summary"] }
|
|
21
|
+
}
|
|
22
|
+
}
|