@orkastery/cli 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/README.md +18 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
- package/adapters/claude-code/README.md +195 -5
- package/adapters/claude-code/agents/ork-check.md +1 -0
- package/adapters/claude-code/agents/ork-go.md +1 -0
- package/adapters/claude-code/agents/ork-goal.md +1 -0
- package/adapters/claude-code/agents/ork-master.md +1 -0
- package/adapters/claude-code/agents/ork-plan.md +1 -0
- package/adapters/claude-code/agents/ork-ship.md +1 -0
- package/adapters/claude-code/hooks/hooks.json +2 -1
- package/adapters/claude-code/hooks/ork-guard.js +15 -1
- package/adapters/claude-code/hooks/ork-resposta.js +91 -0
- package/adapters/claude-code/hooks/ork-sensor.js +18 -2
- package/adapters/claude-code/hooks/quota-signal.js +14 -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-mensageiro/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
- package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -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 +121 -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-ritual/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
- package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -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 +2 -0
- package/adapters/hermes/README.md +64 -1
- package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
- package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
- package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
- package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
- package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
- package/adapters/hermes/hermes.plugin.json +4 -0
- package/adapters/hermes/hitl-ingress/__init__.py +101 -8
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +3 -3
- package/adapters/openclaw/README.md +83 -10
- package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
- package/adapters/openclaw/dist/hitl-ingress.js +106 -9
- package/adapters/openclaw/dist/index.js +86 -0
- package/adapters/openclaw/openclaw.plugin.json +34 -4
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +103 -9
- package/adapters/openclaw/src/index.ts +94 -0
- package/assets/adapters-en/claude-code/README.md +403 -0
- package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
- package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
- package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
- package/assets/adapters-en/claude-code/commands/check.md +46 -0
- package/assets/adapters-en/claude-code/commands/go.md +46 -0
- package/assets/adapters-en/claude-code/commands/goal.md +55 -0
- package/assets/adapters-en/claude-code/commands/master.md +54 -0
- package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
- package/assets/adapters-en/claude-code/commands/ork.md +126 -0
- package/assets/adapters-en/claude-code/commands/plan.md +47 -0
- package/assets/adapters-en/claude-code/commands/ship.md +45 -0
- package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
- package/assets/adapters-en/hermes/README.md +273 -0
- package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
- 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/references-en/README.md +25 -0
- package/assets/references-en/code-review-axes.md +82 -0
- package/assets/references-en/definition-of-done.md +74 -0
- package/assets/references-en/performance-checklist.md +53 -0
- package/assets/references-en/security-checklist.md +101 -0
- package/assets/references-en/testing-patterns.md +51 -0
- package/assets/security-scan/defaults/.golangci.yml +2 -0
- package/assets/security-scan/defaults/eslint.config.mjs +11 -0
- package/assets/security-scan/defaults/gitleaks.toml +3 -0
- package/assets/security-scan/defaults/ruff.toml +1 -0
- package/assets/security-scan/tools-agil.json +87 -0
- package/assets/security-scan/tools.json +625 -0
- package/assets/skills-en/core/onboarding/SKILL.md +58 -0
- package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
- package/assets/skills-en/core/thread-state/SKILL.md +88 -0
- package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
- package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
- package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
- package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
- package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
- package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
- package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
- package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
- package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
- package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
- package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
- package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
- package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
- package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
- package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
- package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
- package/dist/adapters/claude-bg.js +193 -15
- package/dist/adapters/codex-controller-worker.js +12 -5
- package/dist/adapters/codex-events.js +16 -4
- package/dist/adapters/codex.js +13 -2
- package/dist/agents-md.js +24 -15
- package/dist/atualizar-branch.js +245 -0
- package/dist/auditoria.js +13 -11
- package/dist/auditrun.js +68 -48
- package/dist/autorizacao-duravel.js +327 -0
- package/dist/board.js +98 -43
- package/dist/branch-de-estado.js +39 -9
- package/dist/busca-semantica.js +7 -5
- package/dist/catalogo.js +35 -1
- package/dist/changelog-reconciliacao.js +290 -0
- package/dist/check-agil.js +500 -0
- package/dist/check-modo.js +41 -0
- package/dist/check-paralelo.js +183 -0
- package/dist/ci.js +255 -46
- package/dist/ciclos.js +8 -6
- package/dist/claim-lint.js +12 -8
- package/dist/claims-conferir.js +350 -0
- package/dist/claims.js +13 -10
- package/dist/company-brain-client.js +45 -3
- package/dist/company-brain-journal.js +2 -1
- package/dist/company-brain-migration.js +47 -6
- package/dist/conducao-batida.js +759 -0
- package/dist/conducao-sentinela.js +405 -0
- package/dist/conducao-texto.js +12 -18
- package/dist/conducao.js +206 -59
- package/dist/conhecimento-consulta.js +270 -0
- package/dist/conhecimento.js +514 -0
- package/dist/conta-esgotada.js +127 -0
- package/dist/dado-privado.js +816 -0
- package/dist/decisao-autonoma.js +5 -4
- package/dist/demo.js +14 -12
- package/dist/dependencias-da-worktree.js +25 -0
- package/dist/divida.js +38 -36
- package/dist/docs.js +103 -82
- package/dist/doctor-forja.js +345 -0
- package/dist/doctor-pulse-cron.js +294 -27
- package/dist/doctor-rede.js +18 -17
- package/dist/doctor.js +278 -116
- package/dist/dsn-da-memoria.js +417 -0
- package/dist/entrega-por-mod.js +503 -0
- package/dist/entrega-pr.js +158 -57
- package/dist/escopo-escrita.js +10 -1
- package/dist/esgotamentos.js +13 -11
- package/dist/estado-thread.js +42 -17
- package/dist/evalrunner.js +35 -32
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/fabrica-batida.js +323 -0
- package/dist/fabrica-estado.js +49 -16
- package/dist/fabrica-publicar.js +3 -1
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +24 -21
- package/dist/forja/adaptador.js +6 -0
- package/dist/forja/ambiente-de-ci.js +27 -0
- package/dist/forja/api.js +256 -0
- package/dist/forja/cache.js +89 -0
- package/dist/forja/cli.js +60 -0
- package/dist/forja/contrato.js +9 -0
- package/dist/forja/endereco.js +43 -0
- package/dist/forja/estado.js +22 -0
- package/dist/forja/executor.js +73 -0
- package/dist/forja/github/ci.js +95 -0
- package/dist/forja/github/dono-da-rede.js +18 -0
- package/dist/forja/github/metadados.js +15 -0
- package/dist/forja/github/pedidos.js +200 -0
- package/dist/forja/gitlab/ci.js +141 -0
- package/dist/forja/gitlab/consultas.js +59 -0
- package/dist/forja/gitlab/dono-da-rede.js +43 -0
- package/dist/forja/gitlab/metadados.js +15 -0
- package/dist/forja/gitlab/pedidos-abertos.js +158 -0
- package/dist/forja/gitlab/pedidos.js +141 -0
- package/dist/forja/produtor.js +32 -0
- package/dist/forja/registro.js +31 -0
- package/dist/forja/resolver.js +121 -0
- package/dist/forja/texto.js +13 -0
- package/dist/forja/versao.js +71 -0
- package/dist/forja.js +124 -81
- package/dist/gates.js +3 -28
- package/dist/handoff.js +33 -19
- package/dist/hitl-contract.js +46 -43
- package/dist/hitl-curto.js +37 -25
- package/dist/hitl-gates.js +13 -11
- package/dist/hitl-local-receipt.js +53 -0
- package/dist/hitl-local.js +11 -2
- package/dist/hitl-lock.js +5 -11
- package/dist/hitl-public-receipt.js +11 -0
- package/dist/hitl-resumo.js +72 -3
- package/dist/hitl-sessions.js +62 -9
- package/dist/hitl-tempo-parado.js +4 -4
- package/dist/hitl-texto-livre.js +7 -4
- package/dist/hitl.js +63 -64
- package/dist/horario.js +30 -7
- package/dist/hosts.js +155 -134
- package/dist/impedimento.js +108 -14
- package/dist/index.js +1421 -1019
- package/dist/indice-vetorial.js +14 -12
- package/dist/indice.js +7 -1
- package/dist/init.js +54 -49
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +213 -88
- 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 +96 -34
- package/dist/leases.js +19 -18
- package/dist/ledger-stats.js +17 -16
- package/dist/ledger.js +46 -2
- package/dist/licoes.js +12 -11
- package/dist/liveness.js +6 -3
- package/dist/locale-accounts.js +220 -0
- package/dist/locale-adapter.js +291 -0
- package/dist/locale-ajuda.js +833 -0
- package/dist/locale-audit.js +199 -0
- package/dist/locale-claims.js +213 -0
- package/dist/locale-conducao.js +138 -0
- package/dist/locale-conhecimento.js +181 -0
- package/dist/locale-decisao.js +205 -0
- package/dist/locale-docs.js +230 -0
- package/dist/locale-estado.js +101 -0
- package/dist/locale-forja.js +290 -0
- package/dist/locale-gerados.js +165 -0
- package/dist/locale-grafo.js +129 -0
- package/dist/locale-master.js +182 -0
- package/dist/locale-network.js +524 -0
- package/dist/locale-onboarding.js +92 -0
- package/dist/locale-operacao-restante.js +931 -0
- package/dist/locale-phase.js +151 -0
- package/dist/locale-projetos.js +100 -0
- package/dist/locale-prompts.js +194 -0
- package/dist/locale-pulse.js +349 -0
- package/dist/locale-reservas.js +87 -0
- package/dist/locale-retry.js +524 -0
- package/dist/locale-roadmap.js +102 -0
- package/dist/locale-security-scan.js +69 -0
- package/dist/locale-setup.js +192 -0
- package/dist/locale-ship.js +597 -0
- package/dist/locale-thread.js +421 -0
- package/dist/locale-verify.js +201 -0
- package/dist/locale-worktree.js +246 -0
- package/dist/locale.js +1258 -0
- package/dist/maestro-runtime.js +22 -3
- package/dist/manifest.js +415 -13
- package/dist/maquina-ociosa.js +211 -0
- package/dist/maquina.js +31 -7
- package/dist/master-digest.js +6 -1
- package/dist/master-nota-local.js +200 -0
- package/dist/master-nota.js +14 -8
- package/dist/master.js +139 -65
- package/dist/mcp-artifacts.js +11 -2
- package/dist/mcp-conhecimento.js +52 -0
- package/dist/mcp-experiencia.js +26 -5
- package/dist/mcp-git.js +23 -6
- package/dist/mcp-grafo.js +7 -4
- package/dist/mcp-install.js +73 -8
- package/dist/mcp-noctum.js +101 -0
- package/dist/mcp-server.js +90 -16
- package/dist/mcp-ship-transporte.js +977 -0
- package/dist/mcp-ship.js +71 -25
- package/dist/mcp-transportes.js +17 -0
- package/dist/mcp-verify.js +6 -1
- package/dist/memoria.js +63 -58
- package/dist/modos-migracao.js +8 -6
- package/dist/modos.js +20 -24
- package/dist/network-roadmap.js +90 -51
- package/dist/noctum-aceite.js +789 -0
- package/dist/noctum-arco.js +1418 -0
- package/dist/noctum-capacidade.js +141 -0
- package/dist/noctum-changelog.js +399 -0
- package/dist/noctum-cli.js +482 -0
- package/dist/noctum-coordenacao.js +1225 -0
- package/dist/noctum-entrega.js +1169 -0
- package/dist/noctum-envelope.js +1046 -0
- package/dist/noctum-execucao.js +376 -0
- package/dist/noctum-fechamento.js +405 -0
- package/dist/noctum-fila.js +314 -0
- package/dist/noctum-guarda.js +256 -0
- package/dist/noctum-integracao.js +507 -0
- package/dist/noctum-maquinas.js +383 -0
- package/dist/noctum-medicao.js +450 -0
- package/dist/noctum-modo.js +362 -0
- package/dist/noctum-pergunta-canal.js +96 -0
- package/dist/noctum-pergunta.js +115 -0
- package/dist/noctum-provas.js +838 -0
- package/dist/noctum-reconciliacao.js +591 -0
- package/dist/noctum-registro.js +215 -0
- package/dist/noctum-relatorio.js +827 -0
- package/dist/noctum-resposta.js +207 -0
- package/dist/noctum-sessoes-em-voo.js +93 -0
- package/dist/noctum-supervisao.js +649 -0
- package/dist/noctum-terminal.js +459 -0
- package/dist/noctum-transporte.js +655 -0
- package/dist/noctum-vigia.js +639 -0
- package/dist/ocupacao.js +32 -3
- package/dist/onboarding.js +56 -26
- package/dist/orkmind.js +48 -25
- package/dist/orquestracao.js +44 -47
- package/dist/parado-no-condutor.js +174 -127
- package/dist/phase.js +144 -63
- package/dist/policies.js +37 -4
- package/dist/portfolio.js +4 -2
- package/dist/postura-local.js +235 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +220 -0
- package/dist/projeto-alvo.js +186 -24
- package/dist/prompts.js +140 -42
- package/dist/prova-minima.js +5 -6
- package/dist/pulse-cadencia.js +5 -4
- package/dist/pulse-consentimento.js +53 -1
- package/dist/pulse-delivery.js +151 -24
- package/dist/pulse-resposta.js +368 -4
- package/dist/pulse.js +188 -22
- package/dist/ratelimit.js +16 -6
- package/dist/recall.js +14 -13
- package/dist/redacao-saida.js +63 -0
- package/dist/rede-adesao.js +13 -8
- package/dist/rede-forja.js +108 -24
- package/dist/rede-status.js +66 -47
- package/dist/rede.js +86 -46
- package/dist/retomada-checkpoint.js +101 -0
- package/dist/retry.js +451 -212
- package/dist/roadmap-reservas.js +45 -28
- package/dist/roadmap-status.js +129 -33
- package/dist/runtime-ambiente.js +5 -0
- package/dist/runtime-context.js +284 -32
- package/dist/runtime-escada.js +423 -0
- package/dist/runtime-profiles.js +103 -46
- package/dist/runtimes.js +2 -1
- package/dist/saida-segura.js +3 -2
- package/dist/security-scan/agil.js +355 -0
- package/dist/security-scan/cli.js +76 -0
- package/dist/security-scan/compare.js +149 -0
- package/dist/security-scan/config.js +93 -0
- package/dist/security-scan/detect.js +97 -0
- package/dist/security-scan/executor.js +188 -0
- package/dist/security-scan/guard.js +180 -0
- package/dist/security-scan/imagem-de-lint.js +96 -0
- package/dist/security-scan/normalize/actionlint.js +12 -0
- package/dist/security-scan/normalize/eslint.js +12 -0
- package/dist/security-scan/normalize/gitleaks.js +13 -0
- package/dist/security-scan/normalize/golangci-lint.js +13 -0
- package/dist/security-scan/normalize/govulncheck.js +36 -0
- package/dist/security-scan/normalize/index.js +25 -0
- package/dist/security-scan/normalize/npm-audit.js +30 -0
- package/dist/security-scan/normalize/osv-scanner.js +32 -0
- package/dist/security-scan/normalize/oxlint.js +51 -0
- package/dist/security-scan/normalize/pip-audit.js +16 -0
- package/dist/security-scan/normalize/ruff.js +12 -0
- package/dist/security-scan/normalize/semgrep.js +20 -0
- package/dist/security-scan/normalize/trivy.js +33 -0
- package/dist/security-scan/normalize/util.js +204 -0
- package/dist/security-scan/normalize/zizmor.js +19 -0
- package/dist/security-scan/report.js +156 -0
- package/dist/security-scan/run.js +448 -0
- package/dist/security-scan/tools.js +62 -0
- package/dist/security-scan/trabalhador.js +74 -0
- package/dist/security-scan/types.js +15 -0
- package/dist/session-events.js +26 -5
- package/dist/session-watcher-claude.js +81 -20
- package/dist/session-watcher.js +340 -42
- package/dist/sessoes-contas.js +10 -1
- package/dist/sessoes-inventario.js +1 -1
- package/dist/sessoes.js +25 -23
- package/dist/setup.js +59 -58
- package/dist/ship-publicar.js +971 -0
- package/dist/ship.js +243 -97
- package/dist/steal.js +77 -0
- package/dist/superficie.js +14 -11
- package/dist/thread-close.js +12 -11
- package/dist/thread.js +274 -100
- package/dist/tokens.js +15 -11
- package/dist/trabalho-thread.js +297 -0
- package/dist/transporte-do-canal.js +189 -0
- package/dist/types.js +12 -1
- package/dist/util.js +13 -3
- package/dist/varredura-acoes.js +507 -0
- package/dist/verify.js +608 -76
- package/dist/vida-da-thread.js +254 -0
- package/dist/worktree-local.js +167 -0
- package/dist/worktree.js +99 -83
- package/dist/yaml.js +27 -8
- package/eval/casos/check-quality.json +77 -0
- package/eval/casos/security-auditor.json +148 -0
- package/eval/casos/security-remediation.json +161 -0
- package/eval/fixtures/security-scan/README.md +8 -0
- package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/go/Dockerfile +4 -0
- package/eval/fixtures/security-scan/go/README.md +4 -0
- package/eval/fixtures/security-scan/go/config.go +4 -0
- package/eval/fixtures/security-scan/go/go.mod +5 -0
- package/eval/fixtures/security-scan/go/go.sum +2 -0
- package/eval/fixtures/security-scan/go/main.go +31 -0
- package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/js/Dockerfile +3 -0
- package/eval/fixtures/security-scan/js/README.md +4 -0
- package/eval/fixtures/security-scan/js/package-lock.json +844 -0
- package/eval/fixtures/security-scan/js/package.json +10 -0
- package/eval/fixtures/security-scan/js/src/config.js +4 -0
- package/eval/fixtures/security-scan/js/src/server.js +17 -0
- package/eval/fixtures/security-scan/js/src/util.ts +4 -0
- package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
- package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/python/Dockerfile +3 -0
- package/eval/fixtures/security-scan/python/README.md +4 -0
- package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
- package/eval/fixtures/security-scan/python/app/config.py +2 -0
- package/eval/fixtures/security-scan/python/app/main.py +19 -0
- package/eval/fixtures/security-scan/python/requirements.txt +1 -0
- package/package.json +9 -4
- package/references/security-checklist.md +3 -3
- package/schemas/code-artifact-graph.v1.schema.json +2 -1
- package/skills/README.md +1 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/check-quality/SKILL.md +16 -0
- package/skills/phases/go-implementation/SKILL.md +6 -0
- package/skills/phases/security-remediation/SKILL.md +70 -0
- package/skills/reviewers/security-auditor/SKILL.md +25 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
// A Pista de Entrega do Orkastery (RM-059, fatia F7; ficha M7 do plano dos mods). Na sessao do dono, um painel com a
|
|
2
|
+
// pista de cada entrega: do CHECK verde ao merge, cada etapa com a prova que o nucleo deu e o proximo passo que ele
|
|
3
|
+
// declara. A Pista le o nucleo pela ponte (`$.ork.retrato`, que diz quando uma entrega andou) e pelo comando de
|
|
4
|
+
// leitura `ork ship pista --json`, nunca o estado em `.orkastery/` por conta propria (D8 da thread ork-rm059pista). A
|
|
5
|
+
// logica fica nos modulos puros ao lado; aqui so os ganchos e as chamadas ao `$`, sempre escritas como
|
|
6
|
+
// `x.noun.metodo(...)`, como o validador exige.
|
|
7
|
+
import type { EngineInterface, Register } from 'claude-code'
|
|
8
|
+
import type { PistaAcao, PistaCi, PistaLinha, PistaMostrado, PistaQuadro } from '../types'
|
|
9
|
+
import type { AcaoDoBotao } from './acoes'
|
|
10
|
+
import { argvDoPublicar, argvDoRegistro, botaoDaPista, lerPublicacao, lerRegistro, ROTULO_DO_BOTAO } from './acoes'
|
|
11
|
+
import {
|
|
12
|
+
argvDoCi, comCi, INTERVALO_DO_CI_A_VISTA_MS, INTERVALO_DO_CI_ESCONDIDO_MS, lerCi, mudouOCi, pistasDoEvento, vencidasDoCi,
|
|
13
|
+
} from './ci'
|
|
14
|
+
import type { BotaoDaPista } from './pista'
|
|
15
|
+
import {
|
|
16
|
+
argvDaPista, assinaturaDoRetrato, desenharPista, exigirThread, lerPista, linhasDoPainel, mostradosVisiveis, textoDaFaixa,
|
|
17
|
+
threadDoLedger, umaLinha,
|
|
18
|
+
} from './pista'
|
|
19
|
+
|
|
20
|
+
const MOD = 'ork-pista'
|
|
21
|
+
const PAINEL = 'pista'
|
|
22
|
+
const TITULO = 'Pista de Entrega'
|
|
23
|
+
const QUADRO = { plugin: 'ork-pista', key: 'quadro' } as const
|
|
24
|
+
const FOCO = { plugin: 'ork-pista', key: 'foco' } as const
|
|
25
|
+
const ACOES = { plugin: 'ork-pista', key: 'acoes' } as const
|
|
26
|
+
const CI = { plugin: 'ork-pista', key: 'ci' } as const
|
|
27
|
+
const QUADRO_VAZIO: PistaQuadro = { linhas: [], lidoEm: null, erro: null, avisos: [] }
|
|
28
|
+
/** O tique: idade da pista, assinatura do retrato e registro do mostrado. */
|
|
29
|
+
const PERIODO_DO_TIQUE_MS = 60000
|
|
30
|
+
/** A pista e relida por idade: a cada 5 min com o painel a vista, a cada 15 min escondido. */
|
|
31
|
+
const IDADE_A_VISTA_MS = 5 * 60000
|
|
32
|
+
const IDADE_ESCONDIDO_MS = 15 * 60000
|
|
33
|
+
/** Entre duas leituras que nao foram pedidas pelo dono, no minimo isto: a leitura vai ao remoto e a forja. */
|
|
34
|
+
const INTERVALO_MINIMO_MS = 30000
|
|
35
|
+
/** Os ledgers que mudam juntos entram numa leitura so. */
|
|
36
|
+
const ESPERA_DO_LOTE_MS = 5000
|
|
37
|
+
/**
|
|
38
|
+
* Teto do `ork ship pista`: o `ls-remote --heads` (ate 60 s), a leitura dos PRs (ate 60 s) e o git local; 3 min deixam
|
|
39
|
+
* folga em rede lenta (S11 da revisao).
|
|
40
|
+
*/
|
|
41
|
+
const PRAZO_DA_PISTA_MS = 180000
|
|
42
|
+
/**
|
|
43
|
+
* Teto do `ork ship publicar`: o pior caso do nucleo (ls-remote, lista de PRs, push, ls-remote, criacao e releitura do
|
|
44
|
+
* PR) soma 435 s; 9 min cabem nele com folga, abaixo dos 10 min que o motor da a um processo.
|
|
45
|
+
*/
|
|
46
|
+
const PRAZO_DO_PUBLICAR_MS = 540000
|
|
47
|
+
/** Teto do `ork ship registrar-pr` (fetch, prova e CI). */
|
|
48
|
+
const PRAZO_DO_REGISTRO_MS = 180000
|
|
49
|
+
/** Teto do `ork ci status`: uma consulta ao GitHub. */
|
|
50
|
+
const PRAZO_DO_CI_MS = 60000
|
|
51
|
+
/** O servidor do nucleo pode conectar depois do inicio da sessao: o papel e conferido de novo nestas esperas. */
|
|
52
|
+
const ESPERAS_DO_PAPEL_MS = [3000, 10000, 30000]
|
|
53
|
+
const ESPERA_LONGA_DO_PAPEL_MS = 300000
|
|
54
|
+
|
|
55
|
+
// O que o modulo guarda entre ganchos. O estado em `$.state` (o quadro e o foco) e o que o desenho le; aqui ficam a
|
|
56
|
+
// copia dele, sempre gravada inteira por `$.state.set` sem versao (uma gravacao por mudanca, nunca o laco de
|
|
57
|
+
// releitura no mesmo despacho), e o que nao se desenha. Uma recarga do modulo zera tudo, e o `session.start` dispara
|
|
58
|
+
// de novo nela.
|
|
59
|
+
let ativa = false
|
|
60
|
+
let desistiu = false
|
|
61
|
+
let ciclo: { cancel: () => void } | undefined
|
|
62
|
+
let lote: { cancel: () => void } | undefined
|
|
63
|
+
let lendo: Promise<void> | undefined
|
|
64
|
+
let pendente = false
|
|
65
|
+
let quadro: PistaQuadro = QUADRO_VAZIO
|
|
66
|
+
let foco: string | null = null
|
|
67
|
+
/** O ultimo botao de cada thread, como o estado o guarda; e as threads com um clique rodando no nucleo agora. */
|
|
68
|
+
let acoes: Record<string, PistaAcao> = {}
|
|
69
|
+
const emCurso = new Set<string>()
|
|
70
|
+
/** O CI lido de cada pista (T7.4), e as pistas com uma consulta de CI rodando agora. */
|
|
71
|
+
let ci: Record<string, PistaCi> = {}
|
|
72
|
+
const ciEmCurso = new Set<string>()
|
|
73
|
+
/** As leituras do CI que ja fizeram a pista ser relida (thread, head e estado): a mesma nao rele de novo. */
|
|
74
|
+
const relidasPeloCi = new Set<string>()
|
|
75
|
+
/** A ultima tentativa de leitura (ms), lida ou nao: segura o intervalo minimo. */
|
|
76
|
+
let tentadaEm = 0
|
|
77
|
+
let assinatura: string | null = null
|
|
78
|
+
/** O que o desenho pos na janela de rolagem e ainda nao foi ao registro da ponte (D9). */
|
|
79
|
+
const vistosNoDesenho = new Map<string, PistaMostrado>()
|
|
80
|
+
/** O que ja foi ao registro nesta sessao, por chave e texto. */
|
|
81
|
+
const jaMostrado = new Set<string>()
|
|
82
|
+
/** O ultimo texto publicado na faixa; null antes da primeira publicacao. */
|
|
83
|
+
let ultimaFaixa: string | undefined | null = null
|
|
84
|
+
/** A falha de um trabalho em segundo plano que nem o quadro conseguiu guardar. */
|
|
85
|
+
let problemaSemAviso: string | null = null
|
|
86
|
+
|
|
87
|
+
function mensagem(erro: unknown): string {
|
|
88
|
+
return umaLinha(erro, 200)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Trabalho em segundo plano (o tique, o lote, a leitura pedida): a falha vai ao quadro, como aviso; sem como gravar o
|
|
93
|
+
* aviso (a sessao acabou ou o estado recusou), ela fica guardada aqui e o proximo desenho a mostra.
|
|
94
|
+
*/
|
|
95
|
+
function emSegundoPlano($: EngineInterface, trabalho: Promise<unknown>, oQue: string): void {
|
|
96
|
+
trabalho.catch(async erro => {
|
|
97
|
+
const texto = `${oQue} parou: ${mensagem(erro)}`
|
|
98
|
+
try {
|
|
99
|
+
await gravarQuadro($, { ...quadro, erro: texto })
|
|
100
|
+
} catch (erroDoAviso) {
|
|
101
|
+
problemaSemAviso = `${texto} (o aviso também falhou: ${mensagem(erroDoAviso)})`
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function gravarQuadro($: EngineInterface, novo: PistaQuadro): Promise<void> {
|
|
107
|
+
quadro = novo
|
|
108
|
+
await $.state.set(QUADRO, novo)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* O papel pela ponte. `null` so quando o `$.ork` nao existe (a ponte nao carregou); uma falha da propria ponte conta
|
|
113
|
+
* como dormente e o papel e conferido de novo depois.
|
|
114
|
+
*/
|
|
115
|
+
async function papelDaSessao($: EngineInterface): Promise<string | null> {
|
|
116
|
+
try {
|
|
117
|
+
return String(await $.ork.papel())
|
|
118
|
+
} catch (erro) {
|
|
119
|
+
return erro instanceof TypeError ? null : 'dormente'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Liga a Pista na sessao do dono: o `/pista`, o tique e a primeira leitura. */
|
|
124
|
+
async function ativar($: EngineInterface): Promise<void> {
|
|
125
|
+
if (ativa) return
|
|
126
|
+
ativa = true
|
|
127
|
+
try {
|
|
128
|
+
await $.command.register({ name: 'pista', description: 'Abre a Pista de Entrega: do CHECK verde ao merge, cada passo com o botão do núcleo', immediate: true })
|
|
129
|
+
} catch (erro) {
|
|
130
|
+
// Sem o /pista o painel nao abre: a Pista volta a dormente e tenta de novo na espera longa.
|
|
131
|
+
ativa = false
|
|
132
|
+
$.clock.after(ESPERA_LONGA_DO_PAPEL_MS, () => { emSegundoPlano($, conferirPapel($, ESPERAS_DO_PAPEL_MS.length), 'a conferência do papel') })
|
|
133
|
+
throw erro
|
|
134
|
+
}
|
|
135
|
+
quadro = (await $.state.get(QUADRO)).value ?? QUADRO_VAZIO
|
|
136
|
+
foco = (await $.state.get(FOCO)).value ?? null
|
|
137
|
+
// Depois de uma recarga do modulo, nenhum clique esta rodando: o que ficou "rodando" no estado vira falha.
|
|
138
|
+
const guardadas = (await $.state.get(ACOES)).value ?? {}
|
|
139
|
+
acoes = Object.fromEntries(Object.entries(guardadas).map(([t, a]) =>
|
|
140
|
+
[t, a.estado === 'rodando' ? { ...a, estado: 'falhou' as const, texto: 'o clique anterior foi interrompido por uma recarga' } : a]))
|
|
141
|
+
await $.state.set(ACOES, acoes)
|
|
142
|
+
ci = (await $.state.get(CI)).value ?? {}
|
|
143
|
+
ciclo?.cancel()
|
|
144
|
+
ciclo = $.clock.every(PERIODO_DO_TIQUE_MS, () => { emSegundoPlano($, tique($), 'o tique da Pista') })
|
|
145
|
+
agendar($, 1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Confere o papel: liga no dono, desiste na fase ou sem a ponte, e tenta de novo enquanto dormente. */
|
|
149
|
+
async function conferirPapel($: EngineInterface, tentativa: number): Promise<void> {
|
|
150
|
+
if (ativa || desistiu) return
|
|
151
|
+
const papel = await papelDaSessao($)
|
|
152
|
+
if (papel === 'dono') return ativar($)
|
|
153
|
+
if (papel === 'fase' || papel === null) {
|
|
154
|
+
desistiu = true
|
|
155
|
+
if (papel === null) $.ui.toast('pista: a ponte ork-ponte não carregou; a Pista de Entrega fica desligada nesta sessão')
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
const espera = ESPERAS_DO_PAPEL_MS[tentativa] ?? ESPERA_LONGA_DO_PAPEL_MS
|
|
159
|
+
$.clock.after(espera, () => { emSegundoPlano($, conferirPapel($, tentativa + 1), 'a conferência do papel') })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Uma leitura daqui a pouco, uma por vez: os ledgers que mudam juntos entram nela. */
|
|
163
|
+
function agendar($: EngineInterface, ms = ESPERA_DO_LOTE_MS): void {
|
|
164
|
+
if (lote) return
|
|
165
|
+
lote = $.clock.after(Math.max(1, ms), () => {
|
|
166
|
+
lote = undefined
|
|
167
|
+
emSegundoPlano($, atualizar($), 'a leitura da pista')
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** O painel da Pista esta posto e a vista do dono. */
|
|
172
|
+
async function painelAVista($: EngineInterface): Promise<boolean> {
|
|
173
|
+
const paineis = await $.ui.panes().catch(() => [])
|
|
174
|
+
return paineis.some(p => p.id === PAINEL && p.isPlaced && p.isShown)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Uma leitura por vez; pedido que chega no meio volta a rodar logo depois. Fora do pedido do dono (`forcar`), a
|
|
179
|
+
* leitura respeita o intervalo minimo e volta a ser agendada para quando ele vencer.
|
|
180
|
+
*/
|
|
181
|
+
async function atualizar($: EngineInterface, forcar = false): Promise<void> {
|
|
182
|
+
if (!ativa) return
|
|
183
|
+
const agora = await $.clock.now()
|
|
184
|
+
if (!forcar && agora - tentadaEm < INTERVALO_MINIMO_MS) {
|
|
185
|
+
agendar($, INTERVALO_MINIMO_MS - (agora - tentadaEm))
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
if (lendo) {
|
|
189
|
+
pendente = true
|
|
190
|
+
return lendo
|
|
191
|
+
}
|
|
192
|
+
lendo = (async () => {
|
|
193
|
+
try {
|
|
194
|
+
do {
|
|
195
|
+
pendente = false
|
|
196
|
+
await lerUmaVez($)
|
|
197
|
+
} while (pendente)
|
|
198
|
+
} finally {
|
|
199
|
+
lendo = undefined
|
|
200
|
+
}
|
|
201
|
+
})()
|
|
202
|
+
return lendo
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** A pista pelo nucleo (`ork ship pista --json`); a falha fica no quadro, com a leitura anterior. */
|
|
206
|
+
async function lerUmaVez($: EngineInterface): Promise<void> {
|
|
207
|
+
tentadaEm = await $.clock.now()
|
|
208
|
+
try {
|
|
209
|
+
const r = await $.process.run(argvDaPista(), { timeoutMs: PRAZO_DA_PISTA_MS })
|
|
210
|
+
await gravarQuadro($, lerPista(r, await $.clock.now()))
|
|
211
|
+
// A leitura do CI que nao e mais do head de um PR aberto sai: o painel nao mostra CI de commit velho.
|
|
212
|
+
const atuais = Object.fromEntries(Object.entries(ci).filter(([t, c]) => quadro.linhas.some(l => l.thread === t && l.pr?.head === c.sha)))
|
|
213
|
+
if (Object.keys(atuais).length !== Object.keys(ci).length) {
|
|
214
|
+
ci = atuais
|
|
215
|
+
await $.state.set(CI, ci)
|
|
216
|
+
}
|
|
217
|
+
} catch (erro) {
|
|
218
|
+
await gravarQuadro($, { ...quadro, erro: mensagem(erro) })
|
|
219
|
+
}
|
|
220
|
+
await publicarFaixa($)
|
|
221
|
+
await registrarMostrados($)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* O CI das pistas pedidas pelo nucleo (`ork ci status --sha <head> --json`, D7): pelo evento do GitHub que as cita, pelo
|
|
226
|
+
* relogio de reserva ou pelo dono. Uma consulta por pista por vez. Quando a leitura diz do CI outra coisa que a pista (o
|
|
227
|
+
* CI fechou, ou mudou depois de uma rodada nova), a pista inteira e relida, uma vez por leitura: o proximo passo do
|
|
228
|
+
* nucleo muda com ele.
|
|
229
|
+
*/
|
|
230
|
+
async function lerCiDe($: EngineInterface, threads: readonly string[], motivo: PistaCi['motivo']): Promise<void> {
|
|
231
|
+
let mudou = false
|
|
232
|
+
for (const thread of threads) {
|
|
233
|
+
const linha = quadro.linhas.find(l => l.thread === thread)
|
|
234
|
+
if (!linha?.pr || linha.pr.estado !== 'aberto' || ciEmCurso.has(thread)) continue
|
|
235
|
+
ciEmCurso.add(thread)
|
|
236
|
+
try {
|
|
237
|
+
const lido = lerCi(await $.process.run(argvDoCi(linha.pr.head), { timeoutMs: PRAZO_DO_CI_MS }), linha.pr.head, await $.clock.now(), motivo)
|
|
238
|
+
const chave = `${thread}|${lido.sha}|${lido.estado}`
|
|
239
|
+
if (mudouOCi(linha, lido) && !relidasPeloCi.has(chave)) {
|
|
240
|
+
relidasPeloCi.add(chave)
|
|
241
|
+
mudou = true
|
|
242
|
+
}
|
|
243
|
+
ci = { ...ci, [thread]: lido }
|
|
244
|
+
await $.state.set(CI, ci)
|
|
245
|
+
} catch (erro) {
|
|
246
|
+
ci = { ...ci, [thread]: { sha: linha.pr.head, estado: 'unavailable', texto: `o CI não foi lido: ${mensagem(erro)}`, url: null,
|
|
247
|
+
lidoEm: await $.clock.now(), motivo } }
|
|
248
|
+
await $.state.set(CI, ci)
|
|
249
|
+
} finally {
|
|
250
|
+
ciEmCurso.delete(thread)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
await publicarFaixa($)
|
|
254
|
+
if (mudou) await atualizar($, true)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** O tique: a assinatura do retrato (uma entrega andou), a idade da pista e o registro do que o painel mostrou. */
|
|
258
|
+
async function tique($: EngineInterface): Promise<void> {
|
|
259
|
+
if (!ativa) return
|
|
260
|
+
const agora = await $.clock.now()
|
|
261
|
+
const aVista = await painelAVista($)
|
|
262
|
+
let nova: string | null = null
|
|
263
|
+
try {
|
|
264
|
+
nova = assinaturaDoRetrato(await $.ork.retrato({ secao: 'ship' }))
|
|
265
|
+
} catch {
|
|
266
|
+
// O retrato nao veio: so a idade decide nesta volta.
|
|
267
|
+
}
|
|
268
|
+
const mudou = nova !== null && assinatura !== null && nova !== assinatura
|
|
269
|
+
if (nova !== null) assinatura = nova
|
|
270
|
+
const idade = quadro.lidoEm === null ? Infinity : agora - quadro.lidoEm
|
|
271
|
+
if (mudou || idade >= (aVista ? IDADE_A_VISTA_MS : IDADE_ESCONDIDO_MS)) await atualizar($)
|
|
272
|
+
// A reserva do CI sem evento do GitHub (D7): so as pistas com PR aberto e CI ainda aberto.
|
|
273
|
+
const vencidas = vencidasDoCi(quadro.linhas, ci, agora, aVista ? INTERVALO_DO_CI_A_VISTA_MS : INTERVALO_DO_CI_ESCONDIDO_MS)
|
|
274
|
+
if (vencidas.length) await lerCiDe($, vencidas, 'consulta')
|
|
275
|
+
await registrarMostrados($)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** A linha da faixa pela ponte (D9), so quando o texto muda; sem nada que peca o dono, a linha sai da faixa. */
|
|
279
|
+
async function publicarFaixa($: EngineInterface): Promise<void> {
|
|
280
|
+
const texto = textoDaFaixa(comCi(quadro, ci))
|
|
281
|
+
if (texto === ultimaFaixa) return
|
|
282
|
+
try {
|
|
283
|
+
if (texto === undefined) await $.ork.faixa({ mod: MOD })
|
|
284
|
+
else await $.ork.faixa({ mod: MOD, texto })
|
|
285
|
+
ultimaFaixa = texto
|
|
286
|
+
} catch {
|
|
287
|
+
// A ponte recusou ou falhou: a proxima leitura tenta de novo.
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* O que o desenho pos na janela de rolagem do painel posto e a vista vai ao registro da ponte (M5 do dono, D9), uma
|
|
293
|
+
* vez por chave e texto enquanto o texto existir na pista: o Telegram nao repete o que o dono ja viu no terminal.
|
|
294
|
+
*/
|
|
295
|
+
async function registrarMostrados($: EngineInterface): Promise<void> {
|
|
296
|
+
const existentes = new Set(linhasDoPainel(comCi(quadro, ci), { agora: 0, foco, acoes }).flatMap(l => (l.mostrado ? [`${l.mostrado.chave}|${l.mostrado.texto}`] : [])))
|
|
297
|
+
for (const vista of [...jaMostrado]) if (!existentes.has(vista)) jaMostrado.delete(vista)
|
|
298
|
+
for (const vista of [...vistosNoDesenho.keys()]) if (!existentes.has(vista)) vistosNoDesenho.delete(vista)
|
|
299
|
+
if (vistosNoDesenho.size === 0) return
|
|
300
|
+
// Com o painel escondido, o que foi anotado e descartado: o proximo desenho a vista anota de novo.
|
|
301
|
+
if (!await painelAVista($)) { vistosNoDesenho.clear(); return }
|
|
302
|
+
for (const [vista, m] of [...vistosNoDesenho]) {
|
|
303
|
+
vistosNoDesenho.delete(vista)
|
|
304
|
+
if (jaMostrado.has(vista)) continue
|
|
305
|
+
try {
|
|
306
|
+
await $.ork.mostrado({ mod: MOD, canal: 'painel', chave: m.chave, thread: m.thread, texto: m.texto })
|
|
307
|
+
jaMostrado.add(vista)
|
|
308
|
+
} catch {
|
|
309
|
+
// A ponte recusou ou falhou: volta para a proxima vez.
|
|
310
|
+
vistosNoDesenho.set(vista, m)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Os botoes que o nucleo declara agora, um por pista (D6). */
|
|
316
|
+
function botoesDo(q: PistaQuadro): Record<string, BotaoDaPista> {
|
|
317
|
+
const saida: Record<string, BotaoDaPista> = {}
|
|
318
|
+
for (const l of q.linhas) {
|
|
319
|
+
const acao = botaoDaPista(l)
|
|
320
|
+
if (acao) saida[l.thread] = { acao, rotulo: ROTULO_DO_BOTAO[acao] }
|
|
321
|
+
}
|
|
322
|
+
return saida
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function gravarAcao($: EngineInterface, thread: string, a: PistaAcao): Promise<void> {
|
|
326
|
+
acoes = { ...acoes, [thread]: a }
|
|
327
|
+
await $.state.set(ACOES, acoes)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* O clique num botao (D6). Primeiro relê so a pista da thread: o clique vale contra o que o nucleo declara agora, e
|
|
332
|
+
* nao contra o desenho de antes. Se a acao continua disponivel, roda o comando do nucleo pelo construtor de argv deste
|
|
333
|
+
* mod (nunca `git` nem `gh`, nunca texto vindo do JSON) e guarda o resultado na linha da pista. Um clique por vez por
|
|
334
|
+
* thread; o painel e relido no fim.
|
|
335
|
+
*/
|
|
336
|
+
async function acionar($: EngineInterface, thread: string, acao: AcaoDoBotao): Promise<void> {
|
|
337
|
+
if (emCurso.has(thread)) return
|
|
338
|
+
emCurso.add(thread)
|
|
339
|
+
try {
|
|
340
|
+
await gravarAcao($, thread, { acao, estado: 'rodando', texto: '', em: await $.clock.now() })
|
|
341
|
+
let atual: PistaLinha | undefined
|
|
342
|
+
try {
|
|
343
|
+
const relida = lerPista(await $.process.run(argvDaPista(thread), { timeoutMs: PRAZO_DA_PISTA_MS }), await $.clock.now())
|
|
344
|
+
atual = relida.linhas.find(l => l.thread === thread)
|
|
345
|
+
} catch (erro) {
|
|
346
|
+
await gravarAcao($, thread, { acao, estado: 'falhou', texto: `a releitura da pista falhou: ${mensagem(erro)}`, em: await $.clock.now() })
|
|
347
|
+
return
|
|
348
|
+
}
|
|
349
|
+
if (!atual || botaoDaPista(atual) !== acao) {
|
|
350
|
+
const agora = atual ? atual.proximo.texto : 'a thread saiu da pista'
|
|
351
|
+
await gravarAcao($, thread, { acao, estado: 'mudou', texto: `o núcleo não declara mais esta ação: ${agora}`, em: await $.clock.now() })
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const r = acao === 'publicar'
|
|
356
|
+
? lerPublicacao(await $.process.run(argvDoPublicar(thread), { timeoutMs: PRAZO_DO_PUBLICAR_MS }))
|
|
357
|
+
: lerRegistro(await $.process.run(argvDoRegistro(thread), { timeoutMs: PRAZO_DO_REGISTRO_MS }), thread)
|
|
358
|
+
await gravarAcao($, thread, { acao, estado: r.estado, texto: r.texto, em: await $.clock.now() })
|
|
359
|
+
} catch (erro) {
|
|
360
|
+
await gravarAcao($, thread, { acao, estado: 'falhou', texto: mensagem(erro), em: await $.clock.now() })
|
|
361
|
+
}
|
|
362
|
+
} finally {
|
|
363
|
+
emCurso.delete(thread)
|
|
364
|
+
await atualizar($, true)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** O desenho anota o que pos na janela; quem registra e o tique ou a leitura, fora do desenho. */
|
|
369
|
+
function anotarVistos(vistos: readonly PistaMostrado[]): void {
|
|
370
|
+
for (const m of vistos) vistosNoDesenho.set(`${m.chave}|${m.texto}`, m)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export const register: Register = on => {
|
|
374
|
+
on('session.start', async ($, e, next) => {
|
|
375
|
+
if (e.isInteractive) await conferirPapel($, 0)
|
|
376
|
+
return next(e)
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
// `/pista [thread]` abre o painel em qualquer largura e rele a pista agora. Com uma thread (a Torre abre a Pista
|
|
380
|
+
// assim), ela fica em foco no alto do painel. O comando so existe com a Pista ligada; a conferencia do papel aqui so
|
|
381
|
+
// cobre o caso raro de o comando ter sobrado de uma carga anterior.
|
|
382
|
+
on('command.run', { command: 'pista' }, async ($, e) => {
|
|
383
|
+
if (!ativa && !desistiu) await conferirPapel($, ESPERAS_DO_PAPEL_MS.length)
|
|
384
|
+
if (!ativa) return { text: 'A Pista de Entrega só abre na sessão do dono de um projeto do Orkastery.' }
|
|
385
|
+
const pedida = typeof e.args === 'string' ? e.args.trim() : ''
|
|
386
|
+
let aviso = ''
|
|
387
|
+
if (pedida) {
|
|
388
|
+
try {
|
|
389
|
+
foco = exigirThread(pedida)
|
|
390
|
+
} catch {
|
|
391
|
+
aviso = ` O id ${umaLinha(pedida, 80)} não é de thread; a pista abre sem foco.`
|
|
392
|
+
foco = null
|
|
393
|
+
}
|
|
394
|
+
} else foco = null
|
|
395
|
+
await $.state.set(FOCO, foco)
|
|
396
|
+
const aberto = await $.ui.open({ id: PAINEL, title: TITULO })
|
|
397
|
+
emSegundoPlano($, atualizar($, true), 'a leitura da pista')
|
|
398
|
+
return { text: (aberto.isPlaced ? 'Pista de Entrega aberta.' : `Pista de Entrega aberta, à espera de lugar: ${aberto.reason}`) + aviso }
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
// Uma entrega do GitHub chegou a sessao (D7): o evento que cita o PR, a branch ou o head de uma pista so dispara a
|
|
402
|
+
// consulta do CI pelo nucleo, em segundo plano, e o conteudo dele nunca vira estado. A entrega segue sempre para o
|
|
403
|
+
// modelo, como chegou: a Pista nao consome nem reescreve nada.
|
|
404
|
+
on('session.receive', async ($, e, next) => {
|
|
405
|
+
if (ativa && e.event?.source === 'github') {
|
|
406
|
+
const citadas = pistasDoEvento(e.event, quadro.linhas)
|
|
407
|
+
if (citadas.length) emSegundoPlano($, lerCiDe($, citadas, 'evento'), 'o CI pelo evento do GitHub')
|
|
408
|
+
}
|
|
409
|
+
return next(e)
|
|
410
|
+
}).catch(($, e, next) => next(e))
|
|
411
|
+
|
|
412
|
+
// O ledger de uma thread mudou (commit, verify, claim, entrega): a releitura entra no proximo lote. Os caminhos
|
|
413
|
+
// vigiados sao os que a ponte pede para o papel dono; a Pista nao pede outros.
|
|
414
|
+
on('classic.FileChanged', async ($, e, next) => {
|
|
415
|
+
if (ativa && threadDoLedger(e.file_path) !== null) agendar($)
|
|
416
|
+
return next(e)
|
|
417
|
+
}).catch(($, e, next) => next(e))
|
|
418
|
+
|
|
419
|
+
// O painel: uma pista por entrega, com as etapas e o proximo passo do nucleo. O desenho nunca escreve: so anota o
|
|
420
|
+
// que pos na janela de rolagem, para o registro do mostrado (D9).
|
|
421
|
+
on('ui.render', { component: 'Pane', requestId: PAINEL }, async ($, e) => {
|
|
422
|
+
const { Box, Text, Button } = $.ui.resolve(e)
|
|
423
|
+
const q = (await $.state.get(QUADRO)).value ?? QUADRO_VAZIO
|
|
424
|
+
const emFoco = (await $.state.get(FOCO)).value ?? null
|
|
425
|
+
const ultimas = (await $.state.get(ACOES)).value ?? {}
|
|
426
|
+
const lidos = (await $.state.get(CI)).value ?? {}
|
|
427
|
+
const agora = await $.clock.now()
|
|
428
|
+
const comLeitura = comCi(q, lidos)
|
|
429
|
+
const comProblema: PistaQuadro = problemaSemAviso ? { ...comLeitura, avisos: [...comLeitura.avisos, problemaSemAviso] } : comLeitura
|
|
430
|
+
const botoes = botoesDo(comProblema)
|
|
431
|
+
anotarVistos(mostradosVisiveis(linhasDoPainel(comProblema, { agora, foco: emFoco, acoes: ultimas, botoes }), e.props.scroll, e.props.bodyColumns))
|
|
432
|
+
return desenharPista({ Box, Text, Button }, comProblema, {
|
|
433
|
+
agora, foco: emFoco, acoes: ultimas, botoes,
|
|
434
|
+
atualizar: () => { emSegundoPlano($, atualizar($, true), 'a leitura da pista') },
|
|
435
|
+
publicar: thread => { emSegundoPlano($, acionar($, thread, 'publicar'), 'o botão Publicar') },
|
|
436
|
+
registrar: thread => { emSegundoPlano($, acionar($, thread, 'registrar'), 'o botão Registrar') },
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Contrato do estado da Pista de Entrega (`ork-pista`, RM-059, fatia F7). O motor exige que cada chave de `$.state`
|
|
2
|
+
// do mod esteja declarada aqui, em `PluginState`. A Pista nao acrescenta noun ao `$`: le o nucleo pelo `$.ork` da
|
|
3
|
+
// `ork-ponte`, que o plugin.json lista em `dependencies`, e pelos comandos `ork ... --json` da lista fechada dela.
|
|
4
|
+
// Sem import nem referencia.
|
|
5
|
+
|
|
6
|
+
/** As oito etapas da pista, na ordem do contrato `ork.ship-pista/v1` do nucleo. */
|
|
7
|
+
export type PistaIdDaEtapa = 'check' | 'verify' | 'bundle' | 'branch' | 'pr' | 'ci' | 'conflito' | 'entrega'
|
|
8
|
+
|
|
9
|
+
export type PistaEstadoDaEtapa = 'feita' | 'pendente' | 'falhou' | 'nao-lida' | 'nao-se-aplica'
|
|
10
|
+
|
|
11
|
+
export type PistaEtapa = { id: PistaIdDaEtapa; estado: PistaEstadoDaEtapa; texto: string }
|
|
12
|
+
|
|
13
|
+
/** O proximo passo que o nucleo declara: so `publicar` e `registrar` viram botao, e so com `disponivel`. */
|
|
14
|
+
export type PistaProximo = {
|
|
15
|
+
acao: 'publicar' | 'registrar' | null
|
|
16
|
+
disponivel: boolean
|
|
17
|
+
texto: string
|
|
18
|
+
/** O comando do nucleo que resolve, ou o que o dono roda no terminal dele (texto, nunca rodado pela Pista). */
|
|
19
|
+
comando: string | null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type PistaPr = { numero: number; url: string | null; estado: 'aberto' | 'mesclado' | 'fechado'; rascunho: boolean; head: string }
|
|
23
|
+
|
|
24
|
+
/** A pista de uma thread, como o `ork ship pista --json` a dá. */
|
|
25
|
+
export type PistaLinha = {
|
|
26
|
+
thread: string
|
|
27
|
+
nome: string
|
|
28
|
+
tag: string
|
|
29
|
+
/** O modo da thread ja autoriza o push (#Auto e #Maestro). */
|
|
30
|
+
publicavel: boolean
|
|
31
|
+
conduzida: boolean
|
|
32
|
+
branch: string
|
|
33
|
+
head: string | null
|
|
34
|
+
pr: PistaPr | null
|
|
35
|
+
etapas: PistaEtapa[]
|
|
36
|
+
proximo: PistaProximo
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A leitura da pista inteira: uma linha por thread aberta na entrega. */
|
|
40
|
+
export type PistaQuadro = {
|
|
41
|
+
linhas: PistaLinha[]
|
|
42
|
+
/** Quando a pista foi lida (ms desde a epoca); null antes da primeira leitura. */
|
|
43
|
+
lidoEm: number | null
|
|
44
|
+
/** Por que a ultima leitura falhou, quando falhou (a anterior continua no quadro). */
|
|
45
|
+
erro: string | null
|
|
46
|
+
/** Avisos da leitura do nucleo: o remoto ou os PRs que nao responderam. */
|
|
47
|
+
avisos: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** O que um botao fez, uma linha por thread: em curso, ou o resultado do comando do nucleo. */
|
|
51
|
+
export type PistaAcao = {
|
|
52
|
+
acao: 'publicar' | 'registrar'
|
|
53
|
+
estado: 'rodando' | 'feita' | 'recusada' | 'mudou' | 'falhou'
|
|
54
|
+
texto: string
|
|
55
|
+
em: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** O CI de uma pista lido por consulta ao nucleo (`ork ci status --sha`), pelo evento do GitHub ou pelo relogio. */
|
|
59
|
+
export type PistaCi = {
|
|
60
|
+
sha: string
|
|
61
|
+
estado: 'success' | 'pending' | 'failure' | 'missing' | 'unavailable' | 'disabled'
|
|
62
|
+
texto: string
|
|
63
|
+
url: string | null
|
|
64
|
+
lidoEm: number
|
|
65
|
+
/** O que pediu a leitura: um evento do GitHub, o relogio de reserva ou o dono. */
|
|
66
|
+
motivo: 'evento' | 'consulta' | 'dono'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** O que o painel mostrou ao dono e o Telegram tambem diria: a chave junta o que e a mesma coisa (M5). */
|
|
70
|
+
export type PistaMostrado = { chave: string; thread: string; texto: string }
|
|
71
|
+
|
|
72
|
+
declare module 'claude-code' {
|
|
73
|
+
interface PluginState {
|
|
74
|
+
'ork-pista': {
|
|
75
|
+
/** A ultima leitura da pista do nucleo. */
|
|
76
|
+
quadro: PistaQuadro
|
|
77
|
+
/** A thread em foco, pedida por `/pista <thread>` (a Torre abre a Pista assim). */
|
|
78
|
+
foco: string | null
|
|
79
|
+
/** O ultimo botao de cada thread. */
|
|
80
|
+
acoes: Record<string, PistaAcao>
|
|
81
|
+
/** O CI lido de cada thread com PR aberto. */
|
|
82
|
+
ci: Record<string, PistaCi>
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ork-ponte",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Ponte dos mods do Orkastery no Claude Code: o papel da sessão, a leitura do núcleo, a faixa e os caminhos vigiados com dono único, e a guarda de autoridade que nenhum mod passa.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Orkastery contributors",
|
|
7
|
+
"url": "https://github.com/orkastery"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://orkastery.com/",
|
|
10
|
+
"repository": "https://github.com/orkastery/orkastery",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"types": "./types/index.d.ts"
|
|
13
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// A faixa acima do prompt dos mods do Orkastery (RM-059, T0.4; D7 do plano dos mods). A faixa e uma
|
|
2
|
+
// instancia so, e a arvore de um mod esconde a dos seguintes: por isso so a ponte desenha, uma linha por
|
|
3
|
+
// mod, a partir do que cada mod publica por `$.ork.faixa`. Modulo puro; o `$` fica no register.ts.
|
|
4
|
+
import type { OrkLinhaDaFaixa } from '../types'
|
|
5
|
+
|
|
6
|
+
export const TETO_DE_LINHAS = 4
|
|
7
|
+
export const TETO_DO_TEXTO = 200
|
|
8
|
+
const NOME_DE_MOD = /^[a-z0-9][a-z0-9-]{0,63}$/
|
|
9
|
+
|
|
10
|
+
export function nomeDeModValido(mod: unknown): mod is string {
|
|
11
|
+
return typeof mod === 'string' && NOME_DE_MOD.test(mod)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Troca a linha de um mod (ou tira, sem texto), uma linha por mod, texto de uma linha e com teto. */
|
|
15
|
+
export function trocarLinha(linhas: readonly OrkLinhaDaFaixa[] | undefined, mod: string, texto: string | undefined,
|
|
16
|
+
agora: number): OrkLinhaDaFaixa[] {
|
|
17
|
+
const resto = (linhas ?? []).filter(l => l.mod !== mod)
|
|
18
|
+
const limpo = typeof texto === 'string' ? texto.replace(/\s+/g, ' ').trim().slice(0, TETO_DO_TEXTO) : ''
|
|
19
|
+
return limpo === '' ? resto : [...resto, { mod, texto: limpo, em: agora }]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function rotulo(mod: string): string {
|
|
23
|
+
return mod.startsWith('ork-') ? mod.slice(4) : mod
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cortar(texto: string, largura: number): string {
|
|
27
|
+
if (largura < 2) return ''
|
|
28
|
+
return texto.length <= largura ? texto : texto.slice(0, largura - 1) + '…'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* As linhas que a faixa mostra: uma por mod, em ordem de nome, cortadas a largura do corpo, no maximo
|
|
33
|
+
* `TETO_DE_LINHAS` (e nunca mais que as linhas que a faixa pode ter), a ultima dizendo quantas ficaram.
|
|
34
|
+
*/
|
|
35
|
+
export function comporFaixa(linhas: readonly OrkLinhaDaFaixa[] | undefined, largura: number, maxLinhas: number): string[] {
|
|
36
|
+
const todas = [...(linhas ?? [])].filter(l => l.texto !== '').sort((a, b) => (a.mod < b.mod ? -1 : a.mod > b.mod ? 1 : 0))
|
|
37
|
+
const cabem = Math.max(0, Math.min(TETO_DE_LINHAS, Math.floor(maxLinhas)))
|
|
38
|
+
if (todas.length === 0 || cabem === 0) return []
|
|
39
|
+
const mostradas = todas.length <= cabem ? todas : todas.slice(0, cabem - 1)
|
|
40
|
+
const saida = mostradas.map(l => cortar(`${rotulo(l.mod)}: ${l.texto}`, largura))
|
|
41
|
+
if (mostradas.length < todas.length) saida.push(cortar(`+${todas.length - mostradas.length} mods do Orkastery`, largura))
|
|
42
|
+
return saida.filter(l => l !== '')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A arvore da faixa com os elementos que a superficie resolveu (`$.ui.resolve(e)` no register.ts). */
|
|
46
|
+
export function desenharFaixa(el: { Box: any; Text: any }, linhas: readonly string[]) {
|
|
47
|
+
const { Box, Text } = el
|
|
48
|
+
return (
|
|
49
|
+
<Box flexDirection="column">
|
|
50
|
+
{linhas.map((linha, i) => (
|
|
51
|
+
<Text key={`ork-faixa-${i}`} dimColor wrap="truncate">
|
|
52
|
+
{linha}
|
|
53
|
+
</Text>
|
|
54
|
+
))}
|
|
55
|
+
</Box>
|
|
56
|
+
)
|
|
57
|
+
}
|