@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,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
|
+
}
|
|
@@ -44,6 +44,8 @@ O dono conversa sobre o objetivo; voce opera o nucleo `ork` e apresenta o result
|
|
|
44
44
|
passo. Preserve o modo e as autorizacoes da thread. Se ja recebeu uma fase do Orkastery,
|
|
45
45
|
execute essa fase no escopo recebido, sem redespachar a si mesmo.
|
|
46
46
|
|
|
47
|
+
- Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
|
|
48
|
+
|
|
47
49
|
Quando descobertas, prefira as ferramentas MCP vinculadas ao projeto pelo servidor:
|
|
48
50
|
`ork_thread_status`, `ork_phase_list`, `ork_hitl_pending`, `ork_thread_new(nome, modo)`,
|
|
49
51
|
`ork_phase_run(threadId, fase, prompt, runtime?, model?, effort?, dryRun?)`, `ork_observe(threadId)`
|
|
@@ -20,7 +20,8 @@ venv do Hermes e um destino explícito `telegram:chat_id[:topic_id]`:
|
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Grave a configuração em `.orkastery/monitor/pulse-host.json
|
|
23
|
+
Grave a configuração em `.orkastery/monitor/pulse-host.json` (o `ork onboarding` já a grava
|
|
24
|
+
pronta; veja a RM-063 abaixo). `HERMES_HOME` e
|
|
24
25
|
`HERMES_AGENT_DIR` permitem localizar outra instalação; por padrão usa `~/.hermes`.
|
|
25
26
|
O adaptador carrega o ambiente do host internamente, sem imprimir credenciais. Marcadores
|
|
26
27
|
`MEDIA:` presentes no texto do runtime são neutralizados para não anexar arquivos locais.
|
|
@@ -48,6 +49,19 @@ ork adapter install hermes --dry-run # lista o que seria escrito
|
|
|
48
49
|
| `bin/ork-roadmap-status.sh` | `ork_roadmap_status`: o status report do roadmap so desta maquina (`ork roadmap status`) |
|
|
49
50
|
| `bin/ork-network-roadmap.sh` | `ork_network_roadmap`: o roadmap da rede (`ork network roadmap`), com as threads de todas as maquinas, fonte, hora e lacunas; a fonte do status do roadmap e o panorama da frase `orkastery maestro` sem projeto (RM-054) |
|
|
50
51
|
| `bin/ork-network-status.sh` | `ork_network_status`: as maquinas da pessoa na Orkastery Network (`ork network status`), com a batida, as forjas, os runtimes, os hosts, a fonte e as lacunas; sem projeto (RM-054, fatia 3) |
|
|
52
|
+
| `bin/ork-vigia-batida.py` | A batida do host (RM-063): roda `ork doctor --json` a cada 30 min e avisa o dono quando a batida da fabrica passou de 30 min, sem LLM |
|
|
53
|
+
| `bin/ork-conhecimento-listar.sh`, `-mostrar.sh`, `-colecoes.sh` e `-verificar.sh` | `ork_conhecimento_listar`, `ork_conhecimento_mostrar`, `ork_conhecimento_colecoes` e `ork_conhecimento_verificar`: o conhecimento escrito do projeto (`ork conhecimento <consulta> --json`), as mesmas tools do MCP e do OpenClaw (RM-026 K7, fatia 3) |
|
|
54
|
+
|
|
55
|
+
## Conhecimento escrito (RM-026 K7)
|
|
56
|
+
|
|
57
|
+
Os quatro wrappers `bin/ork-conhecimento-*.sh` sao as tools MCP do conhecimento escrito com os mesmos nomes no
|
|
58
|
+
manifesto: cada um chama `ork conhecimento <consulta> "$@" --json`, com `ORK_PROJETO_EXPLICITO=1` e
|
|
59
|
+
`ORK_CANAL=hermes`, e devolve o JSON do nucleo e a saida dele como vem (saida 1 e a consulta que nao respondeu, com as
|
|
60
|
+
lacunas dizendo por que). O `--json` vai no fim, depois do `<doc-id>` do `mostrar`. A skill manda citar o documento
|
|
61
|
+
pela versao e pela fonte e mostrar cada lacuna como lacuna, nunca como resposta, com a mesma frase das descricoes do
|
|
62
|
+
OpenClaw ([contrato](../../docs/referencia/contratos/conhecimento-rm026.md)).
|
|
63
|
+
|
|
64
|
+
Verificacao: `python3 -m unittest discover -s adapters/hermes/test -p conhecimento_test.py -v`.
|
|
51
65
|
|
|
52
66
|
## Tickets `obj-*` aposentados
|
|
53
67
|
|
|
@@ -123,6 +137,41 @@ não ratifica nada. Cada página oferece no máximo doze opções e cabe em 3.90
|
|
|
123
137
|
Contrato do teclado: [Telegram ReplyKeyboardMarkup](https://core.telegram.org/bots/api#replykeyboardmarkup).
|
|
124
138
|
Prova local: `python3 -m unittest discover -s adapters/hermes/test -p master_transport_test.py`.
|
|
125
139
|
|
|
140
|
+
## Batida do host e retomada pelo canal (RM-063)
|
|
141
|
+
|
|
142
|
+
**H1, a batida do host.** A cada 30 min, `bin/ork-vigia-batida.py` roda `ork doctor --json`. Se a
|
|
143
|
+
batida da fábrica passou de 30 min, manda ao dono o aviso pronto do núcleo; `ork` ausente ou com
|
|
144
|
+
falha vira alerta; o resto não manda nada. Com `--target`, envia pela mesma API do
|
|
145
|
+
`ork-pulse-enviar.py` (sai 1 se a entrega falha); sem ele, só imprime. Rode pelo cron ou por um
|
|
146
|
+
timer do systemd (ou pelo agendador do Hermes, num job que roda o script sem LLM):
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
*/30 * * * * PATH=<dir do node>:/usr/bin:/bin ORK_BIN=<caminho do ork> <hermes-agent>/venv/bin/python3 <hermes>/bin/ork-vigia-batida.py --projeto <projeto> --target telegram:<chat>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Nunca um cron LLM com `deliver=origin`. O cron não carrega o perfil do shell: o `ORK_BIN` e o
|
|
153
|
+
`PATH` com o `node` vão na própria linha.
|
|
154
|
+
|
|
155
|
+
**H2, retomada pelo canal.** `#OrkRetomar` ou `#OrkFabrica`, sozinhos na mensagem do chat Telegram
|
|
156
|
+
autorizado, passam pelo mesmo ingresso assinado do pulse (`pre_gateway_dispatch`). `#OrkRetomar`
|
|
157
|
+
responde na hora e roda a batida da condução nesta máquina; o que voltou a andar chega logo depois,
|
|
158
|
+
pelo transporte do pulse. `#OrkFabrica` responde o `ork fabrica`. No meio de uma frase, a tag vai ao assistente.
|
|
159
|
+
|
|
160
|
+
**H3, transporte gravado no onboarding.**
|
|
161
|
+
`ork onboarding set maestro --conteudo '{"canal":{"host":"hermes","destino":"telegram:<chat>"}}' --por <dono>`
|
|
162
|
+
(ou `telegram:<chat>:<topico>`) grava o canal e o `.orkastery/monitor/pulse-host.json` pronto, fora
|
|
163
|
+
do git: a máquina nunca fica sem transporte. O Python vem de `HERMES_AGENT_DIR` (ou
|
|
164
|
+
`$HERMES_HOME/hermes-agent`) e o script, de `$HERMES_HOME/bin/ork-pulse-enviar.py`; `executavel` e
|
|
165
|
+
`script` (absolutos) trocam os dois. O JSON de "Transporte determinístico do pulse" mostra, por
|
|
166
|
+
dentro, o que é gravado.
|
|
167
|
+
|
|
168
|
+
**H4, o outro host.** Com o canal gravado para os dois hosts, o último vira o principal e o outro, o
|
|
169
|
+
alternativo. Se a entrega falha, o transporte tenta o outro host; cada entrega vai ao
|
|
170
|
+
`.orkastery/monitor/transporte.log`, e o `ork doctor` mostra o check "transporte do pulse": aviso
|
|
171
|
+
quando caiu no alternativo, falha quando nenhum entregou.
|
|
172
|
+
|
|
173
|
+
Verificação: `python3 -m unittest discover -s adapters/hermes/test -p conducao_canal_test.py -v`.
|
|
174
|
+
|
|
126
175
|
## Respostas HITL no Telegram
|
|
127
176
|
|
|
128
177
|
O gateway autenticado entrega o update original por stdin a `bin/ork-hitl-answer.py ork_gate_answer <thread> <pedido>` ou `ork_session_answer`. Configure `ORK_BIN`, `ORK_HITL_TELEGRAM_USERS` e `ORK_HITL_TELEGRAM_CHATS` com os ids permitidos. Responda ao alerta que contém a linha `ork-hitl <thread> <pedido>`; botões usam `ork:<thread>:<pedido>:<número>`. O transporte recusa bots, chat/usuário não autorizado e resposta sem correlação. O núcleo decide sobre prazo, modo e validade do pedido.
|
|
@@ -131,6 +180,20 @@ O script deve receber eventos diretamente do gateway, cuja autenticação do Tel
|
|
|
131
180
|
|
|
132
181
|
Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_answer_test.py -v`.
|
|
133
182
|
|
|
183
|
+
## Arco #Noctum pelo Telegram (RM-058)
|
|
184
|
+
|
|
185
|
+
O mesmo plugin `hitl-ingress/` recebe `/ork noctum <arco> autorizar <sha256>` e `/ork noctum <arco> revogar`, com as mesmas conferências do `/ork gate` (autorização do host, usuário, chat, bot, mensagem de até 60 s e a chave `ORK_HITL_INGRESS_KEY_HERMES`). O envelope é assinado no endereço `noctum` / `arco:<arco>`, que nenhum `/ork gate` alcança, e vai pela entrada a `ork noctum responder <arco>`. Só o recibo tipado `ork.noctum-ingresso/v1` do mesmo arco confirma ao dono, e o ato que já valia não ganha segunda confirmação. A proposta do envelope é `ork noctum propor --arquivo <envelope.json>`, e ela não autoriza nada. A gramática mora no núcleo (`GRAMATICA_DO_NOCTUM`), e o teste `noctum-gateways` do núcleo confere a cópia daqui. Desde a RM-057, a proposta chega ao dono como pergunta com código curto, e ele a responde como está na seção seguinte; o `/ork noctum <arco> autorizar <sha256>` segue aceito, mas não é mais o caminho ensinado.
|
|
186
|
+
|
|
187
|
+
Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_noctum_test.py -v`.
|
|
188
|
+
|
|
189
|
+
## A resposta curta à pergunta (RM-057)
|
|
190
|
+
|
|
191
|
+
A pergunta ao dono (a do arco #Noctum e a mensagem curta de um gate) chega com código curto e alternativas e termina em "Responda a, b ou c". Pelo mesmo ingresso assinado do pulse (`ork pulse responder`), o dono responde com o código e a letra (`K7QX a`) de qualquer chat autorizado, com o número da pergunta e a letra (`1a`), ou em reply à mensagem da pergunta do arco só com a letra ou a palavra (`a`, `sim`, `autorizo`). O reply só vale para a mensagem em que a pergunta foi entregue: o transporte (`bin/ork-pulse-enviar.py`) devolve o id dela, e o núcleo o guarda com a pergunta. O plugin tira a referência só da mensagem do próprio bot (`ORK_HITL_TELEGRAM_BOT_ID`) cuja primeira linha é o título da pergunta do arco (`🔔 N. arco <arco> · <código>`), e só quando o texto do dono é uma resposta (a palavra, o código com a resposta ou o número com a letra); assina o envelope no endereço `resposta:<código>:<id>`, com o id da mensagem respondida, e manda `--em-resposta-a <código>:<id>` ao núcleo; a resposta em reply vale mesmo com a janela da palavra solta fechada. A confirmação do "b", a recusa e qualquer outra mensagem não dão referência, e o reply à mensagem curta de um gate não vale (o gate segue pelo número e pelo código). A palavra solta em reply a qualquer mensagem que não é a pergunta do arco (a confirmação de um gate, a mensagem de outra pessoa do grupo, a do assistente) nunca vira palavra solta: com a janela aberta, o plugin a assina no endereço `resposta:outra` e manda `--em-resposta-a outra`, e o núcleo a recusa dizendo por onde responder, sem gravar nada; com a janela fechada, ela segue ao assistente. O código e o número em reply a outra mensagem valem como sem reply, porque dizem a pergunta. A abertura do tópico do fórum, que o Telegram põe em toda mensagem do tópico, não conta como reply. Sem reply, a palavra solta só vale com uma pergunta esperando no chat em que ela saiu, e nunca com a mensagem de antes de ela sair; com duas, o núcleo pergunta qual. Conversa comum, mesmo em reply, segue ao assistente. Quem decide é o núcleo: a pergunta de agora, o prazo, a mensagem repetida (uma mensagem responde a uma pergunta só, em qualquer arco) e, no reply, o id da entrega e o chat em que ela saiu; o código digitado vale de qualquer chat autorizado.
|
|
192
|
+
|
|
193
|
+
As recusas na borda do plugin saem caladas, de propósito: a mensagem de usuário ou de chat fora da lista, a de mais de 60 s (contados da mensagem original, também na edição) e a mensagem já recebida que volta com outro texto (o cache de reentrega a recusa) nem chegam ao núcleo, e o bot não responde a elas, para nunca conversar com quem não é o dono nem responder a uma mensagem atrasada. Só as recusas do núcleo voltam ao dono com o porquê.
|
|
194
|
+
|
|
195
|
+
Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_resposta_curta_test.py -v`.
|
|
196
|
+
|
|
134
197
|
## Confirmação pelo plugin nativo HITL
|
|
135
198
|
|
|
136
199
|
O plugin `hitl-ingress/` recebe `/ork gate <thread> <pedido> <resposta>` e
|