@orkastery/cli 0.5.6 → 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 +37 -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/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-pista/hooks/ci.ts +9 -5
- 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/hooks/vigia.ts +1 -1
- 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 +2 -2
- package/adapters/openclaw/README.md +81 -9
- 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/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 +118 -4
- package/dist/adapters/codex-controller-worker.js +12 -5
- package/dist/adapters/codex-events.js +16 -4
- package/dist/adapters/codex.js +3 -1
- package/dist/atualizar-branch.js +245 -0
- package/dist/auditoria.js +13 -11
- package/dist/auditrun.js +51 -46
- package/dist/autorizacao-duravel.js +327 -0
- package/dist/board.js +94 -40
- package/dist/branch-de-estado.js +16 -8
- package/dist/busca-semantica.js +7 -5
- package/dist/catalogo.js +2 -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 +248 -45
- package/dist/ciclos.js +8 -6
- package/dist/claim-lint.js +12 -8
- package/dist/claims-conferir.js +47 -39
- package/dist/claims.js +10 -9
- package/dist/company-brain-client.js +10 -3
- package/dist/company-brain-migration.js +11 -5
- package/dist/conducao-batida.js +759 -0
- package/dist/conducao-sentinela.js +25 -8
- package/dist/conducao.js +84 -29
- package/dist/conhecimento-consulta.js +270 -0
- package/dist/conhecimento.js +111 -87
- 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 +81 -74
- package/dist/doctor-forja.js +345 -0
- package/dist/doctor-pulse-cron.js +113 -1
- package/dist/doctor.js +164 -6
- package/dist/dsn-da-memoria.js +417 -0
- package/dist/entrega-por-mod.js +503 -0
- package/dist/entrega-pr.js +143 -43
- package/dist/esgotamentos.js +13 -11
- package/dist/estado-thread.js +21 -18
- package/dist/evalrunner.js +35 -32
- package/dist/fabrica-batida.js +34 -21
- package/dist/fabrica-estado.js +13 -10
- package/dist/fix.js +21 -19
- 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 +123 -80
- package/dist/handoff.js +23 -13
- 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 +51 -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 +44 -1
- package/dist/hitl-sessions.js +62 -9
- package/dist/hitl-texto-livre.js +7 -4
- package/dist/hitl.js +34 -31
- package/dist/horario.js +16 -0
- package/dist/hosts.js +104 -134
- package/dist/index.js +848 -548
- package/dist/indice-vetorial.js +14 -12
- package/dist/init.js +11 -2
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +123 -69
- package/dist/intelligence-graph-query.js +37 -22
- package/dist/leases.js +19 -18
- package/dist/ledger-stats.js +17 -16
- package/dist/ledger.js +31 -1
- package/dist/licoes.js +12 -11
- package/dist/locale-accounts.js +220 -0
- package/dist/locale-adapter.js +291 -0
- package/dist/locale-ajuda.js +76 -4
- 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 +5 -0
- package/dist/locale-grafo.js +129 -0
- package/dist/locale-master.js +83 -0
- package/dist/locale-network.js +524 -0
- package/dist/locale-operacao-restante.js +931 -0
- package/dist/locale-projetos.js +100 -0
- package/dist/locale-prompts.js +194 -0
- package/dist/locale-pulse.js +140 -2
- package/dist/locale-reservas.js +87 -0
- package/dist/locale-retry.js +145 -6
- package/dist/locale-security-scan.js +69 -0
- package/dist/locale-setup.js +192 -0
- package/dist/locale-ship.js +169 -66
- package/dist/locale-thread.js +149 -5
- package/dist/locale-verify.js +80 -4
- package/dist/locale-worktree.js +246 -0
- package/dist/locale.js +553 -9
- package/dist/maestro-runtime.js +22 -3
- package/dist/manifest.js +287 -11
- package/dist/maquina-ociosa.js +211 -0
- package/dist/maquina.js +10 -5
- package/dist/master-nota-local.js +200 -0
- package/dist/master-nota.js +10 -2
- package/dist/master.js +118 -41
- package/dist/mcp-conhecimento.js +52 -0
- package/dist/mcp-experiencia.js +26 -5
- package/dist/mcp-install.js +73 -8
- package/dist/mcp-noctum.js +101 -0
- package/dist/mcp-server.js +82 -14
- package/dist/mcp-ship-transporte.js +977 -0
- package/dist/mcp-ship.js +68 -24
- package/dist/mcp-transportes.js +17 -0
- package/dist/memoria.js +63 -58
- package/dist/modos-migracao.js +8 -6
- package/dist/modos.js +17 -18
- package/dist/network-roadmap.js +85 -49
- package/dist/noctum-aceite.js +789 -0
- package/dist/noctum-arco.js +540 -33
- package/dist/noctum-capacidade.js +3 -3
- 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 +252 -16
- package/dist/noctum-execucao.js +95 -23
- package/dist/noctum-fechamento.js +405 -0
- package/dist/noctum-fila.js +43 -9
- 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 +3 -1
- package/dist/onboarding.js +16 -5
- package/dist/orkmind.js +39 -23
- package/dist/orquestracao.js +31 -35
- package/dist/parado-no-condutor.js +146 -124
- package/dist/phase.js +53 -27
- package/dist/policies.js +33 -0
- package/dist/postura-local.js +4 -3
- package/dist/procedencia.js +9 -14
- package/dist/projeto-alvo.js +59 -20
- package/dist/prompts.js +136 -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 +143 -27
- package/dist/pulse-resposta.js +368 -4
- package/dist/pulse.js +136 -3
- package/dist/ratelimit.js +12 -4
- package/dist/recall.js +14 -13
- package/dist/rede-adesao.js +13 -8
- package/dist/rede-forja.js +108 -24
- package/dist/rede-status.js +63 -45
- package/dist/rede.js +86 -46
- package/dist/retomada-checkpoint.js +101 -0
- package/dist/retry.js +228 -73
- package/dist/roadmap-reservas.js +32 -32
- package/dist/runtime-ambiente.js +5 -0
- package/dist/runtime-context.js +117 -43
- package/dist/runtime-escada.js +423 -0
- package/dist/runtime-profiles.js +103 -46
- 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 +19 -2
- package/dist/session-watcher-claude.js +74 -19
- package/dist/session-watcher.js +156 -10
- package/dist/sessoes-contas.js +9 -0
- package/dist/sessoes-inventario.js +1 -1
- package/dist/sessoes.js +25 -23
- package/dist/setup.js +59 -58
- package/dist/ship-publicar.js +263 -92
- package/dist/ship.js +160 -17
- package/dist/superficie.js +14 -11
- package/dist/thread-close.js +9 -9
- package/dist/thread.js +121 -18
- 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 +5 -2
- package/dist/varredura-acoes.js +507 -0
- package/dist/verify.js +472 -29
- package/dist/worktree-local.js +12 -10
- package/dist/worktree.js +81 -85
- 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/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,481 @@
|
|
|
1
|
+
// O Mensageiro de Sessoes do Orkastery (RM-059, fatia F9; ficha M9 do plano dos mods). Na sessao do dono, leva a
|
|
2
|
+
// resposta que o dono deu pelo dialogo nativo a sessao de fase `claude-bg` que parou esperando por ela: pega a
|
|
3
|
+
// mensagem na caixa de saida do nucleo (`ork_session_outbox`, so na memoria do servidor desta sessao), envia por
|
|
4
|
+
// `$.session.send` sem mexer no texto e anota o envio no nucleo. Na sessao de fase, so deixa entrar na conversa a
|
|
5
|
+
// mensagem de outra sessao que o nucleo confirma, pela `ork_session_inbox`, como a resposta do dono reservada para
|
|
6
|
+
// ela; o resto que chega de outra sessao e consumido antes do modelo. Le o que segue incerto pelo `$.ork.retrato`,
|
|
7
|
+
// nunca o estado em `.orkastery/` por conta propria. Nunca responde, aprova ou abre pedido pelo dono. A logica fica
|
|
8
|
+
// nos modulos puros ao lado; aqui so os ganchos e as chamadas ao `$`, sempre escritas como `x.noun.metodo(...)`, como
|
|
9
|
+
// o validador exige.
|
|
10
|
+
import type { EngineInterface, Register, SessionReceiveInput, SessionReceiveResult } from 'claude-code'
|
|
11
|
+
import type { MensageiroDono, MensageiroFase, MensageiroMostrado, MensageiroRecebida } from '../types'
|
|
12
|
+
import type { EntradaDaCaixa } from './caixa'
|
|
13
|
+
import {
|
|
14
|
+
argsDaAnotacao, argsDoEnvio, atualizarEntregas, deveEnviar, DONO_VAZIO, entradaAnotada, FERRAMENTA_DA_CAIXA, incertasDoRetrato,
|
|
15
|
+
jsonDoMcp, lerCaixa, pedidosNoRetrato, resultadoDoEnvio, textoDaFaixa, threadDoLedger, umaLinha,
|
|
16
|
+
} from './caixa'
|
|
17
|
+
import { desenharPainel, linhasDaFase, linhasDoDono, mostradosVisiveis } from './painel'
|
|
18
|
+
import type { Conferencia } from './recepcao'
|
|
19
|
+
import {
|
|
20
|
+
argsDaConferencia, argsDaConfirmacao, classificarOrigem, comRecebida, confirmadasDaFase, ESPERAS_DA_CONFIRMACAO_MS, FASE_VAZIA,
|
|
21
|
+
decisaoNaFalha, FERRAMENTA_DA_CONFERENCIA, idsDaMarca, impressaoDoTexto, lerConferencia, lerConfirmacao, LIMITE_DA_MENSAGEM,
|
|
22
|
+
mensagemSemEnvelope, motivoDoConsumo, mudarRecebida, nomeDaOrigem, registroDaRecebida, temMarca, textoComRotulo, textoParaOModelo,
|
|
23
|
+
} from './recepcao'
|
|
24
|
+
|
|
25
|
+
const MOD = 'ork-mensageiro'
|
|
26
|
+
const PAINEL = 'mensageiro'
|
|
27
|
+
const TITULO = 'Mensageiro de Sessões'
|
|
28
|
+
const DONO = { plugin: 'ork-mensageiro', key: 'dono' } as const
|
|
29
|
+
const FASE = { plugin: 'ork-mensageiro', key: 'fase' } as const
|
|
30
|
+
/** D9 da thread ork-rm059mensag: o tique do lado do dono, que tambem mantem o Mensageiro vivo na caixa de saida. */
|
|
31
|
+
const PERIODO_DO_TIQUE_MS = 20000
|
|
32
|
+
/** Os ledgers que mudam juntos entram numa leitura so. */
|
|
33
|
+
const ESPERA_DO_LOTE_MS = 1000
|
|
34
|
+
/** Teto de cada chamada ao nucleo. */
|
|
35
|
+
const PRAZO_DO_NUCLEO_MS = 20000
|
|
36
|
+
/** O servidor do nucleo pode conectar depois do inicio da sessao: o papel e conferido de novo nestas esperas. */
|
|
37
|
+
const ESPERAS_DO_PAPEL_MS = [3000, 10000, 30000]
|
|
38
|
+
const ESPERA_LONGA_DO_PAPEL_MS = 300000
|
|
39
|
+
|
|
40
|
+
// O que o modulo guarda entre ganchos. O estado em `$.state` (o lado do dono e o da fase) e o que o desenho le; aqui
|
|
41
|
+
// ficam a copia dele, gravada inteira por `$.state.set` sem versao (uma gravacao por mudanca), e o que nao se
|
|
42
|
+
// desenha. Uma recarga do modulo zera tudo, e o `session.start` dispara de novo nela.
|
|
43
|
+
let ativa = false
|
|
44
|
+
let naFase = false
|
|
45
|
+
let desistiu = 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 dono: MensageiroDono = DONO_VAZIO
|
|
51
|
+
let fase: MensageiroFase = FASE_VAZIA
|
|
52
|
+
/**
|
|
53
|
+
* O papel e a thread que a ponte deu. O papel `fase` sai do `ORK_DISPATCH_ID` do despacho e nunca muda na sessao, e
|
|
54
|
+
* a sessao que nao e de fase nunca vira: o receptor decide por isto, lido uma vez.
|
|
55
|
+
*/
|
|
56
|
+
let contextoVisto: { papel: string; thread: string | null } | null = null
|
|
57
|
+
/**
|
|
58
|
+
* As mensagens que o nucleo confirmou e que ainda nao entraram na fila, com o texto que o modelo vai ler: o `.catch`
|
|
59
|
+
* do receptor deixa passar so elas, e no envelope do Mensageiro.
|
|
60
|
+
*/
|
|
61
|
+
const confirmadasEmVoo = new Map<string, string>()
|
|
62
|
+
/** O ultimo texto publicado na faixa; null antes da primeira publicacao. */
|
|
63
|
+
let ultimaFaixa: string | undefined | null = null
|
|
64
|
+
/** O que o desenho pos na janela de rolagem e ainda nao foi ao registro da ponte (M5). */
|
|
65
|
+
const vistosNoDesenho = new Map<string, MensageiroMostrado>()
|
|
66
|
+
/** O que ja foi ao registro nesta sessao, por chave e texto. */
|
|
67
|
+
const jaMostrado = new Set<string>()
|
|
68
|
+
/** A falha de um trabalho em segundo plano que nem o painel conseguiu guardar. */
|
|
69
|
+
let problemaSemAviso: string | null = null
|
|
70
|
+
|
|
71
|
+
const mensagem = (erro: unknown) => umaLinha(erro, 200)
|
|
72
|
+
|
|
73
|
+
/** A chamada com teto proprio: o relogio da sessao recusa a espera que passar dele. */
|
|
74
|
+
function comPrazo<T>($: EngineInterface, chamada: Promise<T>, ms = PRAZO_DO_NUCLEO_MS): Promise<T> {
|
|
75
|
+
return new Promise<T>((resolver, recusar) => {
|
|
76
|
+
const prazo = $.clock.after(ms, () => recusar(new Error(`o núcleo passou de ${Math.round(ms / 1000)} s`)))
|
|
77
|
+
chamada.then(v => { prazo.cancel(); resolver(v) }, e => { prazo.cancel(); recusar(e) })
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* O instante do relogio da sessao para as linhas do estado; sem ele, o da ultima linha. O prazo da conferencia nao usa
|
|
83
|
+
* isto: sem relogio, a conferencia falha e a mensagem e consumida.
|
|
84
|
+
*/
|
|
85
|
+
async function instante($: EngineInterface): Promise<number> {
|
|
86
|
+
try {
|
|
87
|
+
return await $.clock.now()
|
|
88
|
+
} catch {
|
|
89
|
+
return fase.recebidas.at(-1)?.em ?? 0
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function gravarDono($: EngineInterface, novo: MensageiroDono): Promise<void> {
|
|
94
|
+
dono = novo
|
|
95
|
+
await $.state.set(DONO, novo)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function gravarFase($: EngineInterface, nova: MensageiroFase): Promise<void> {
|
|
99
|
+
fase = nova
|
|
100
|
+
await $.state.set(FASE, nova)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Trabalho em segundo plano (o tique, o lote, a leitura pedida, o recibo da entrega): a falha vai ao painel; sem como
|
|
105
|
+
* gravar (a sessao acabou ou o estado recusou), ela fica guardada aqui e o proximo desenho a mostra. O `.catch` nao
|
|
106
|
+
* depende do `$`.
|
|
107
|
+
*/
|
|
108
|
+
function emSegundoPlano($: EngineInterface, trabalho: Promise<unknown>, oQue: string): void {
|
|
109
|
+
trabalho.catch(async erro => {
|
|
110
|
+
const texto = `${oQue} parou: ${mensagem(erro)}`
|
|
111
|
+
try {
|
|
112
|
+
if (naFase) await gravarFase($, { ...fase, erro: texto })
|
|
113
|
+
else await gravarDono($, { ...dono, erro: texto })
|
|
114
|
+
} catch (erroDoAviso) {
|
|
115
|
+
problemaSemAviso = `${texto} (o aviso também falhou: ${mensagem(erroDoAviso)})`
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* O papel e a thread pela ponte. `null` so quando o `$.ork` nao existe (a ponte nao carregou); a falha da propria
|
|
122
|
+
* ponte lanca. O que a ponte respondeu fica em `contextoVisto`.
|
|
123
|
+
*/
|
|
124
|
+
async function contextoDaSessao($: EngineInterface): Promise<{ papel: string; thread: string | null } | null> {
|
|
125
|
+
let lido: { papel: unknown; thread: unknown }
|
|
126
|
+
try {
|
|
127
|
+
lido = await comPrazo($, $.ork.contexto())
|
|
128
|
+
} catch (erro) {
|
|
129
|
+
if (erro instanceof TypeError) return null
|
|
130
|
+
throw erro
|
|
131
|
+
}
|
|
132
|
+
contextoVisto = { papel: String(lido.papel), thread: typeof lido.thread === 'string' ? lido.thread : null }
|
|
133
|
+
return contextoVisto
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Liga o lado do dono: o `/mensageiro`, o tique e a primeira leitura da caixa. */
|
|
137
|
+
async function ativarDono($: EngineInterface): Promise<void> {
|
|
138
|
+
if (ativa) return
|
|
139
|
+
ativa = true
|
|
140
|
+
try {
|
|
141
|
+
await $.command.register({ name: 'mensageiro', description: 'Abre o Mensageiro de Sessões: as respostas do dono a caminho das sessões de fase', immediate: true })
|
|
142
|
+
} catch (erro) {
|
|
143
|
+
// Sem o /mensageiro o painel nao abre: o lado do dono volta a dormente e tenta de novo na espera longa.
|
|
144
|
+
ativa = false
|
|
145
|
+
$.clock.after(ESPERA_LONGA_DO_PAPEL_MS, () => { emSegundoPlano($, conferirPapel($, ESPERAS_DO_PAPEL_MS.length), 'a conferência do papel') })
|
|
146
|
+
throw erro
|
|
147
|
+
}
|
|
148
|
+
dono = (await $.state.get(DONO)).value ?? DONO_VAZIO
|
|
149
|
+
ciclo?.cancel()
|
|
150
|
+
ciclo = $.clock.every(PERIODO_DO_TIQUE_MS, () => { emSegundoPlano($, levar($), 'o tique do Mensageiro') })
|
|
151
|
+
agendar($, 1)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Liga o lado da sessao de fase: o `/mensageiro` mostra o que chegou. O filtro do receptor nao depende disto. */
|
|
155
|
+
async function ativarFase($: EngineInterface): Promise<void> {
|
|
156
|
+
if (naFase) return
|
|
157
|
+
naFase = true
|
|
158
|
+
desistiu = true
|
|
159
|
+
const guardada = (await $.state.get(FASE)).value
|
|
160
|
+
// O que chegou antes desta leitura ja esta na memoria e no estado: a copia guardada so volta quando nada chegou.
|
|
161
|
+
if (guardada && !fase.recebidas.length) fase = guardada
|
|
162
|
+
fase = { ...fase, thread: contextoVisto?.thread ?? fase.thread }
|
|
163
|
+
try {
|
|
164
|
+
await $.command.register({ name: 'mensageiro', description: 'Abre o Mensageiro de Sessões: o que chegou de outras sessões a esta sessão de fase', immediate: true })
|
|
165
|
+
} catch (erro) {
|
|
166
|
+
// O filtro segue sem o comando; o painel diz por que ele nao abre.
|
|
167
|
+
await gravarFase($, { ...fase, erro: `o /mensageiro não foi registrado: ${mensagem(erro)}` })
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Confere o papel: o dono liga o lado do dono, a fase liga o da fase, e a sessao dormente e conferida de novo. */
|
|
172
|
+
async function conferirPapel($: EngineInterface, tentativa: number): Promise<void> {
|
|
173
|
+
if (ativa || naFase || desistiu) return
|
|
174
|
+
let papel: string | null
|
|
175
|
+
try {
|
|
176
|
+
papel = (await contextoDaSessao($))?.papel ?? null
|
|
177
|
+
} catch {
|
|
178
|
+
// A ponte falhou: a sessao conta como dormente e o papel e conferido de novo depois.
|
|
179
|
+
papel = 'dormente'
|
|
180
|
+
}
|
|
181
|
+
if (papel === 'dono') return ativarDono($)
|
|
182
|
+
if (papel === 'fase') return ativarFase($)
|
|
183
|
+
if (papel === null) {
|
|
184
|
+
desistiu = true
|
|
185
|
+
$.ui.toast('mensageiro: a ponte ork-ponte não carregou; o Mensageiro de Sessões não leva respostas nesta sessão, e mensagem de outra sessão é consumida antes do modelo')
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
const espera = ESPERAS_DO_PAPEL_MS[tentativa] ?? ESPERA_LONGA_DO_PAPEL_MS
|
|
189
|
+
$.clock.after(espera, () => { emSegundoPlano($, conferirPapel($, tentativa + 1), 'a conferência do papel') })
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Uma leitura daqui a pouco, uma por vez: os ledgers que mudam juntos entram nela. */
|
|
193
|
+
function agendar($: EngineInterface, ms = ESPERA_DO_LOTE_MS): void {
|
|
194
|
+
if (lote) return
|
|
195
|
+
lote = $.clock.after(Math.max(1, ms), () => {
|
|
196
|
+
lote = undefined
|
|
197
|
+
emSegundoPlano($, levar($), 'a leitura da caixa de saída')
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Uma rodada por vez; pedido que chega no meio volta a rodar logo depois, e quem pediu espera as duas. */
|
|
202
|
+
async function levar($: EngineInterface): Promise<void> {
|
|
203
|
+
if (!ativa) return
|
|
204
|
+
if (lendo) {
|
|
205
|
+
pendente = true
|
|
206
|
+
return lendo
|
|
207
|
+
}
|
|
208
|
+
lendo = (async () => {
|
|
209
|
+
try {
|
|
210
|
+
do {
|
|
211
|
+
pendente = false
|
|
212
|
+
await umaRodada($)
|
|
213
|
+
} while (pendente)
|
|
214
|
+
} finally {
|
|
215
|
+
lendo = undefined
|
|
216
|
+
}
|
|
217
|
+
})()
|
|
218
|
+
return lendo
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Uma rodada: a caixa de saida (o `listar` tambem mantem o Mensageiro vivo para o nucleo, D9), o envio do que deve ir
|
|
223
|
+
* (D10), o retrato da secao `hitl` para saber o que ja foi respondido e o que segue noutra sessao, a faixa e o registro
|
|
224
|
+
* do que o painel mostrou.
|
|
225
|
+
*/
|
|
226
|
+
async function umaRodada($: EngineInterface): Promise<void> {
|
|
227
|
+
let caixa: EntradaDaCaixa[]
|
|
228
|
+
try {
|
|
229
|
+
caixa = lerCaixa(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_session_outbox', { operacao: 'listar' })), FERRAMENTA_DA_CAIXA))
|
|
230
|
+
} catch (erro) {
|
|
231
|
+
await gravarDono($, { ...dono, erro: `a caixa de saída não foi lida: ${mensagem(erro)}` })
|
|
232
|
+
await publicarFaixa($)
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const agora = await $.clock.now()
|
|
236
|
+
const levadas: EntradaDaCaixa[] = []
|
|
237
|
+
for (const e of caixa) levadas.push(deveEnviar(e, agora) ? await enviar($, e) : e)
|
|
238
|
+
let retrato: unknown = null
|
|
239
|
+
try {
|
|
240
|
+
retrato = (await comPrazo($, $.ork.retrato({ secao: 'hitl' }))).retrato
|
|
241
|
+
} catch {
|
|
242
|
+
// Sem o retrato, nada se conclui sobre o que saiu da caixa nesta volta.
|
|
243
|
+
}
|
|
244
|
+
const noRetrato = retrato === null ? null : pedidosNoRetrato(retrato)
|
|
245
|
+
const depois = await $.clock.now()
|
|
246
|
+
const entregas = atualizarEntregas(dono.entregas, levadas, noRetrato, depois)
|
|
247
|
+
// So e "noutra sessao" o pedido incerto que esta sessao nao conhece: o que saiu da caixa daqui fica na linha dele.
|
|
248
|
+
await gravarDono($, {
|
|
249
|
+
entregas,
|
|
250
|
+
incertas: retrato === null ? dono.incertas : incertasDoRetrato(retrato).filter(i => !entregas.some(e => e.pedidoId === i.pedidoId)),
|
|
251
|
+
lidoEm: depois,
|
|
252
|
+
erro: null,
|
|
253
|
+
})
|
|
254
|
+
await publicarFaixa($)
|
|
255
|
+
await registrarMostrados($)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Envia a mensagem como o nucleo a compos e anota o resultado no nucleo; a anotacao que falha nao desfaz o envio. */
|
|
259
|
+
async function enviar($: EngineInterface, e: EntradaDaCaixa): Promise<EntradaDaCaixa> {
|
|
260
|
+
let r: { entregue: boolean; motivo: string | null }
|
|
261
|
+
try {
|
|
262
|
+
r = resultadoDoEnvio(await comPrazo($, $.session.send(argsDoEnvio(e))))
|
|
263
|
+
} catch (erro) {
|
|
264
|
+
r = { entregue: false, motivo: `o envio falhou: ${mensagem(erro)}` }
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
const anotada = entradaAnotada(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_session_outbox', argsDaAnotacao(e, r))), FERRAMENTA_DA_CAIXA), e.reservada)
|
|
268
|
+
if (anotada) return anotada
|
|
269
|
+
} catch {
|
|
270
|
+
// O nucleo nao anotou: a proxima leitura da caixa traz a conta dele.
|
|
271
|
+
}
|
|
272
|
+
return { ...e, tentativas: e.tentativas + 1, ultimoEnvio: { em: await $.clock.now(), entregue: r.entregue, motivo: r.motivo } }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** A linha da faixa pela ponte (D7 do plano dos mods), so quando o texto muda; sem nada a dizer, a linha sai. */
|
|
276
|
+
async function publicarFaixa($: EngineInterface): Promise<void> {
|
|
277
|
+
const texto = textoDaFaixa(dono, await $.clock.now())
|
|
278
|
+
if (texto === ultimaFaixa) return
|
|
279
|
+
try {
|
|
280
|
+
if (texto === undefined) await $.ork.faixa({ mod: MOD })
|
|
281
|
+
else await $.ork.faixa({ mod: MOD, texto })
|
|
282
|
+
ultimaFaixa = texto
|
|
283
|
+
} catch {
|
|
284
|
+
// A ponte recusou ou falhou: a proxima rodada tenta de novo.
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** O painel do Mensageiro esta posto e a vista do dono. */
|
|
289
|
+
async function painelAVista($: EngineInterface): Promise<boolean> {
|
|
290
|
+
const paineis = await $.ui.panes().catch(() => [])
|
|
291
|
+
return paineis.some(p => p.id === PAINEL && p.isPlaced && p.isShown)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* O que o desenho pos na janela de rolagem do painel posto e a vista vai ao registro da ponte (M5 do dono), uma vez
|
|
296
|
+
* por chave e texto: o Telegram nao repete o que o dono ja viu no terminal.
|
|
297
|
+
*/
|
|
298
|
+
async function registrarMostrados($: EngineInterface): Promise<void> {
|
|
299
|
+
if (vistosNoDesenho.size === 0) return
|
|
300
|
+
if (!await painelAVista($)) { vistosNoDesenho.clear(); return }
|
|
301
|
+
for (const [vista, m] of [...vistosNoDesenho]) {
|
|
302
|
+
vistosNoDesenho.delete(vista)
|
|
303
|
+
if (jaMostrado.has(vista)) continue
|
|
304
|
+
try {
|
|
305
|
+
await $.ork.mostrado({ mod: MOD, canal: 'painel', chave: m.chave, ...(m.thread ? { thread: m.thread } : {}), texto: m.texto })
|
|
306
|
+
jaMostrado.add(vista)
|
|
307
|
+
} catch {
|
|
308
|
+
// A ponte recusou ou falhou: volta para a proxima vez.
|
|
309
|
+
vistosNoDesenho.set(vista, m)
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Anota o que chegou no estado da fase e, quando a mensagem nao entrou como devia, uma linha no transcript (dim, fora
|
|
316
|
+
* do modelo). Nunca lanca: o receptor decide sem depender do estado nem do transcript.
|
|
317
|
+
*/
|
|
318
|
+
async function anotar($: EngineInterface, mudar: (f: MensageiroFase) => MensageiroFase, registro: MensageiroRecebida | null): Promise<void> {
|
|
319
|
+
try {
|
|
320
|
+
await gravarFase($, mudar(fase))
|
|
321
|
+
} catch (erro) {
|
|
322
|
+
problemaSemAviso = `o estado da sessão de fase não foi gravado: ${mensagem(erro)}`
|
|
323
|
+
}
|
|
324
|
+
const linha = registro ? registroDaRecebida(registro) : null
|
|
325
|
+
if (!linha) return
|
|
326
|
+
try {
|
|
327
|
+
$.ui.log(linha)
|
|
328
|
+
} catch (erro) {
|
|
329
|
+
problemaSemAviso = `o transcript recusou a linha do Mensageiro: ${mensagem(erro)}`
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Consome a mensagem de outra sessao antes do modelo, com o motivo no estado, no transcript e no registro do Claude Code. */
|
|
334
|
+
async function consumir($: EngineInterface, e: SessionReceiveInput, motivo: string, detalhe?: string): Promise<SessionReceiveResult> {
|
|
335
|
+
const r: MensageiroRecebida = { em: await instante($), origem: nomeDaOrigem(e.origin), estado: 'consumida', ...idsDaMarca(e.text),
|
|
336
|
+
motivo: detalhe ? `${motivo}: ${umaLinha(detalhe, 160)}` : motivo, impressao: null }
|
|
337
|
+
await anotar($, f => comRecebida(f, r), r)
|
|
338
|
+
return { consumed: motivoDoConsumo(motivo) }
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* A mensagem de outra sessao (T9.3). Na sessao de fase: sem a marca, consumida sem chamar o nucleo (D13); com ela, vai
|
|
343
|
+
* ao `conferir` do nucleo, e so a confirmada segue para a conversa, no envelope fixo do Mensageiro e com o corpo que o
|
|
344
|
+
* nucleo conferiu (D23, que reve a D11), com o `confirmar` depois de entrar na fila. Falha, prazo vencido e resposta
|
|
345
|
+
* fora do contrato consomem. Sem a ponte, ou sem o papel, consome. Nas sessoes do dono e dormente, passa como chegou.
|
|
346
|
+
*/
|
|
347
|
+
async function receber($: EngineInterface, e: SessionReceiveInput, next: (e: SessionReceiveInput) => Promise<SessionReceiveResult>): Promise<SessionReceiveResult> {
|
|
348
|
+
let contexto = contextoVisto
|
|
349
|
+
if (contexto === null) {
|
|
350
|
+
try {
|
|
351
|
+
contexto = await contextoDaSessao($)
|
|
352
|
+
} catch (erro) {
|
|
353
|
+
return consumir($, e, 'entrega.sem-papel', mensagem(erro))
|
|
354
|
+
}
|
|
355
|
+
if (contexto === null) return consumir($, e, 'entrega.sem-ponte')
|
|
356
|
+
}
|
|
357
|
+
if (contexto.papel !== 'fase') return next(e)
|
|
358
|
+
if (typeof e.text !== 'string' || e.text.length > LIMITE_DA_MENSAGEM) return consumir($, e, 'entrega.grande')
|
|
359
|
+
if (!temMarca(e.text)) return consumir($, e, 'entrega.sem-marca')
|
|
360
|
+
const thread = contexto.thread
|
|
361
|
+
if (thread === null) return consumir($, e, 'entrega.despacho')
|
|
362
|
+
// A mensagem que o nucleo vai conferir, sem o envelope do motor: e so ela que o modelo vai ler (D23).
|
|
363
|
+
const conferivel = mensagemSemEnvelope(e.text)
|
|
364
|
+
if (conferivel === null) return consumir($, e, 'entrega.formato')
|
|
365
|
+
let conferencia: Conferencia
|
|
366
|
+
try {
|
|
367
|
+
const agora = await $.clock.now()
|
|
368
|
+
conferencia = lerConferencia(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_session_inbox', argsDaConferencia(thread, e.text, agora))), FERRAMENTA_DA_CONFERENCIA))
|
|
369
|
+
} catch (erro) {
|
|
370
|
+
return consumir($, e, 'entrega.conferencia-falhou', mensagem(erro))
|
|
371
|
+
}
|
|
372
|
+
if (!conferencia.confirmada) return consumir($, e, conferencia.motivo)
|
|
373
|
+
const { pedidoId, envioId } = conferencia
|
|
374
|
+
const texto = e.text
|
|
375
|
+
const paraOModelo = textoParaOModelo(conferivel)
|
|
376
|
+
// A impressao da mensagem como a linha da conversa a mostra, para o rotulo visual.
|
|
377
|
+
const impressao = impressaoDoTexto(conferivel)
|
|
378
|
+
confirmadasEmVoo.set(texto, paraOModelo)
|
|
379
|
+
let r: SessionReceiveResult
|
|
380
|
+
try {
|
|
381
|
+
const chegada: MensageiroRecebida = { em: await instante($), origem: nomeDaOrigem(e.origin), estado: 'confirmando', pedidoId, envioId,
|
|
382
|
+
motivo: null, impressao }
|
|
383
|
+
await anotar($, f => comRecebida(f, chegada), null)
|
|
384
|
+
r = await next({ ...e, text: paraOModelo })
|
|
385
|
+
} finally {
|
|
386
|
+
confirmadasEmVoo.delete(texto)
|
|
387
|
+
}
|
|
388
|
+
if (r.consumed !== undefined) {
|
|
389
|
+
const caiu: MensageiroRecebida = { em: await instante($), origem: nomeDaOrigem(e.origin), estado: 'nao-entrou', pedidoId, envioId,
|
|
390
|
+
motivo: `outro plugin a consumiu abaixo do Mensageiro (${umaLinha(r.consumed, 120)})`, impressao: null }
|
|
391
|
+
await anotar($, f => mudarRecebida(f, envioId, caiu.estado, caiu.motivo, caiu.em), caiu)
|
|
392
|
+
return r
|
|
393
|
+
}
|
|
394
|
+
emSegundoPlano($, confirmar($, thread, pedidoId, envioId, texto, 0), 'a confirmação da entrega')
|
|
395
|
+
return r
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** O recibo da entrega que entrou na conversa; a falha volta nas esperas e, esgotadas, a linha fica sem recibo. */
|
|
399
|
+
async function confirmar($: EngineInterface, thread: string, pedidoId: string, envioId: string, texto: string, tentativa: number): Promise<void> {
|
|
400
|
+
let r: { ok: boolean; definitiva: boolean; motivo: string | null }
|
|
401
|
+
try {
|
|
402
|
+
r = lerConfirmacao(jsonDoMcp(await comPrazo($, $.mcp.call('orkastery', 'ork_session_inbox', argsDaConfirmacao(thread, envioId, texto))), FERRAMENTA_DA_CONFERENCIA))
|
|
403
|
+
} catch (erro) {
|
|
404
|
+
r = { ok: false, definitiva: false, motivo: mensagem(erro) }
|
|
405
|
+
}
|
|
406
|
+
const em = await instante($)
|
|
407
|
+
if (r.ok) return anotar($, f => mudarRecebida(f, envioId, 'entregue', null, em), null)
|
|
408
|
+
const motivo = r.motivo
|
|
409
|
+
const espera = r.definitiva ? undefined : ESPERAS_DA_CONFIRMACAO_MS[tentativa]
|
|
410
|
+
if (espera === undefined) {
|
|
411
|
+
const semRecibo: MensageiroRecebida = { em, origem: '', estado: 'sem-recibo', pedidoId, envioId, motivo, impressao: null }
|
|
412
|
+
return anotar($, f => mudarRecebida(f, envioId, 'sem-recibo', motivo, em), semRecibo)
|
|
413
|
+
}
|
|
414
|
+
await anotar($, f => mudarRecebida(f, envioId, 'confirmando', `o recibo volta a ser gravado: ${motivo ?? 'sem motivo'}`, em), null)
|
|
415
|
+
$.clock.after(espera, () => { emSegundoPlano($, confirmar($, thread, pedidoId, envioId, texto, tentativa + 1), 'a confirmação da entrega') })
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export const register: Register = on => {
|
|
419
|
+
on('session.start', async ($, e, next) => {
|
|
420
|
+
const iniciada = await next(e)
|
|
421
|
+
await conferirPapel($, 0).catch(() => undefined)
|
|
422
|
+
return iniciada
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
// Toda entrega que chega a sessao. So a de outra sessao passa pelo receptor (G4); Remote Control, notificacao de
|
|
426
|
+
// tarefa, agendamento, canais, agentes e teammates verificados desta sessao seguem como chegaram, sem chamada ao
|
|
427
|
+
// nucleo. O `.catch` fecha: a mensagem de outra sessao que o gancho nao decidiu e consumida, salvo a que o nucleo
|
|
428
|
+
// ja confirmou e reservou, que segue.
|
|
429
|
+
on('session.receive', async ($, e, next) => {
|
|
430
|
+
if (classificarOrigem(e.origin, e.agentId) !== 'outra-sessao') return next(e)
|
|
431
|
+
return receber($, e, next)
|
|
432
|
+
}).catch(($, e, next) => {
|
|
433
|
+
if (next.called) return next(e)
|
|
434
|
+
const decisao = decisaoNaFalha({ origem: e.origin, agentId: e.agentId, texto: e.text, papel: contextoVisto?.papel ?? null, emVoo: confirmadasEmVoo })
|
|
435
|
+
if (decisao.acao === 'passa') return next(e)
|
|
436
|
+
if (decisao.acao === 'conferida') return next({ ...e, text: decisao.texto })
|
|
437
|
+
return { consumed: motivoDoConsumo('entrega.conferencia-falhou') }
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// O ledger de uma thread mudou (uma resposta entrou na caixa, a sessao reservou ou confirmou): a leitura entra no
|
|
441
|
+
// proximo lote. Os caminhos vigiados sao os que a ponte pede para o papel dono; o Mensageiro nao pede outros.
|
|
442
|
+
on('classic.FileChanged', async ($, e, next) => {
|
|
443
|
+
if (ativa && threadDoLedger(e.file_path) !== null) agendar($)
|
|
444
|
+
return next(e)
|
|
445
|
+
}).catch(($, e, next) => next(e))
|
|
446
|
+
|
|
447
|
+
// `/mensageiro` abre o painel: na sessao do dono, as entregas, e le a caixa agora; na de fase, o que chegou.
|
|
448
|
+
on('command.run', { command: 'mensageiro' }, async ($) => {
|
|
449
|
+
if (!ativa && !naFase && !desistiu) await conferirPapel($, ESPERAS_DO_PAPEL_MS.length)
|
|
450
|
+
if (!ativa && !naFase) return { text: 'O Mensageiro de Sessões só abre numa sessão do Orkastery: a do dono ou a de uma fase.' }
|
|
451
|
+
const aberto = await $.ui.open({ id: PAINEL, title: TITULO })
|
|
452
|
+
if (ativa) emSegundoPlano($, levar($), 'a leitura da caixa de saída')
|
|
453
|
+
return { text: aberto.isPlaced ? 'Mensageiro de Sessões aberto.' : `Mensageiro de Sessões aberto, à espera de lugar: ${aberto.reason}` }
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
// O painel: na sessao do dono, as entregas desta sessao e as que seguem noutra; na de fase, o que chegou. O desenho
|
|
457
|
+
// nunca escreve: so anota o que pos na janela de rolagem, para o registro do mostrado (M5).
|
|
458
|
+
on('ui.render', { component: 'Pane', requestId: PAINEL }, async ($, e) => {
|
|
459
|
+
const { Box, Text, Button } = $.ui.resolve(e)
|
|
460
|
+
if (naFase) {
|
|
461
|
+
const daFase = (await $.state.get(FASE)).value ?? fase
|
|
462
|
+
const comProblema: MensageiroFase = problemaSemAviso ? { ...daFase, erro: problemaSemAviso } : daFase
|
|
463
|
+
return desenharPainel({ Box, Text, Button }, linhasDaFase(comProblema, await $.clock.now()), {})
|
|
464
|
+
}
|
|
465
|
+
const atual = (await $.state.get(DONO)).value ?? dono
|
|
466
|
+
const comProblema: MensageiroDono = problemaSemAviso ? { ...atual, erro: problemaSemAviso } : atual
|
|
467
|
+
const linhas = linhasDoDono(comProblema, await $.clock.now())
|
|
468
|
+
for (const m of mostradosVisiveis(linhas, e.props.scroll)) vistosNoDesenho.set(`${m.chave}|${m.texto}`, m)
|
|
469
|
+
return desenharPainel({ Box, Text, Button }, linhas, { atualizar: () => { emSegundoPlano($, levar($), 'a leitura da caixa de saída') } })
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
// Na sessao de fase, a linha da resposta que o nucleo confirmou mostra o rotulo no lugar do cabecalho. So visual: o
|
|
473
|
+
// que fica guardado e o que o modelo le nao mudam.
|
|
474
|
+
on('ui.render', { component: 'UserMessage' }, async ($, e, next) => {
|
|
475
|
+
// So a linha de mensagem de outra sessao (`peer`): a de teammate chega `unclassified`, e a do dono, de outra origem.
|
|
476
|
+
if (!naFase || e.props.origin.kind !== 'peer' || !temMarca(e.props.text)) return next(e)
|
|
477
|
+
const daFase = (await $.state.get(FASE)).value ?? fase
|
|
478
|
+
const texto = textoComRotulo(e.props.text, confirmadasDaFase(daFase))
|
|
479
|
+
return texto === null ? next(e) : next({ ...e, props: { ...e.props, text: texto } })
|
|
480
|
+
}).catch(($, e, next) => next(e))
|
|
481
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Contrato do estado do Mensageiro de Sessoes (`ork-mensageiro`, RM-059, fatia F9). O motor exige que cada chave de
|
|
2
|
+
// `$.state` do mod esteja declarada aqui, em `PluginState`. O Mensageiro nao acrescenta noun ao `$`: le o nucleo pelo
|
|
3
|
+
// `$.ork` da `ork-ponte`, que o plugin.json lista em `dependencies`, e pelas duas ferramentas MCP da entrega. Nenhum
|
|
4
|
+
// campo guarda o texto da resposta do dono (D12 da thread ork-rm059mensag): so ids, estado, motivo e instantes.
|
|
5
|
+
// Sem import nem referencia.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Onde uma entrega esta, vista da sessao do dono que a leva. `sem-recibo`: a sessao de fase reservou e nao gravou o
|
|
9
|
+
* recibo em 5 min (D21).
|
|
10
|
+
*/
|
|
11
|
+
export type MensageiroEstadoDaEntrega =
|
|
12
|
+
| 'na-fila' | 'a-caminho' | 'reservada' | 'sem-recibo' | 'nao-chegou' | 'desistiu' | 'entregue' | 'saiu-da-caixa'
|
|
13
|
+
|
|
14
|
+
/** Uma entrega da caixa de saida desta sessao do dono, sem o texto. */
|
|
15
|
+
export type MensageiroEntrega = {
|
|
16
|
+
thread: string
|
|
17
|
+
pedidoId: string
|
|
18
|
+
envioId: string
|
|
19
|
+
sessionId: string
|
|
20
|
+
estado: MensageiroEstadoDaEntrega
|
|
21
|
+
/** Quantas vezes a mensagem foi enviada (`$.session.send`), pela conta do nucleo. */
|
|
22
|
+
tentativas: number
|
|
23
|
+
/** Por que o ultimo envio nao entrou na fila da sessao, ou por que o Mensageiro parou de tentar. */
|
|
24
|
+
motivo: string | null
|
|
25
|
+
/** Quando a entrega mudou de estado aqui (ms desde a epoca). */
|
|
26
|
+
em: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Um pedido que o retrato mostra com a entrega incerta e que a caixa desta sessao nao tem: segue noutra sessao. */
|
|
30
|
+
export type MensageiroIncerta = { thread: string; pedidoId: string }
|
|
31
|
+
|
|
32
|
+
/** O lado do dono: as entregas desta sessao e as incertas de fora, com a ultima leitura. */
|
|
33
|
+
export type MensageiroDono = {
|
|
34
|
+
entregas: MensageiroEntrega[]
|
|
35
|
+
incertas: MensageiroIncerta[]
|
|
36
|
+
/** Quando a caixa foi lida (ms desde a epoca); null antes da primeira leitura. */
|
|
37
|
+
lidoEm: number | null
|
|
38
|
+
/** Por que a ultima leitura falhou, quando falhou (a anterior fica no painel). */
|
|
39
|
+
erro: string | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* O que aconteceu, na sessao de fase, com uma mensagem que chegou de outra sessao: consumida antes do modelo (sem
|
|
44
|
+
* entrega confirmada pelo nucleo), confirmando (conferida, na conversa, gravando o recibo), entregue (com o recibo),
|
|
45
|
+
* sem recibo (na conversa, mas o recibo nao foi gravado) ou nao entrou (conferida, e outro plugin a consumiu abaixo).
|
|
46
|
+
*/
|
|
47
|
+
export type MensageiroEstadoDaRecebida = 'consumida' | 'confirmando' | 'entregue' | 'sem-recibo' | 'nao-entrou'
|
|
48
|
+
|
|
49
|
+
/** Uma mensagem de outra sessao que chegou a sessao de fase, sem o texto dela. */
|
|
50
|
+
export type MensageiroRecebida = {
|
|
51
|
+
/** Quando chegou ou mudou de estado (ms desde a epoca). */
|
|
52
|
+
em: number
|
|
53
|
+
/** O tipo da origem e o plugin que o remetente diz ser, numa linha. */
|
|
54
|
+
origem: string
|
|
55
|
+
estado: MensageiroEstadoDaRecebida
|
|
56
|
+
/** O pedido e a entrega: conferidos pelo nucleo na entrega confirmada; na consumida, so o que a marca dizia. */
|
|
57
|
+
pedidoId: string | null
|
|
58
|
+
envioId: string | null
|
|
59
|
+
/** Por que foi consumida ou ficou sem recibo, com o codigo do nucleo. */
|
|
60
|
+
motivo: string | null
|
|
61
|
+
/** A impressao do texto da entrega confirmada (FNV-1a e tamanho), para o rotulo; nunca o texto. */
|
|
62
|
+
impressao: string | null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** O lado da sessao de fase: a thread do despacho e o que chegou de outras sessoes. */
|
|
66
|
+
export type MensageiroFase = {
|
|
67
|
+
thread: string | null
|
|
68
|
+
recebidas: MensageiroRecebida[]
|
|
69
|
+
/** Por que um trabalho em segundo plano parou, quando parou. */
|
|
70
|
+
erro: string | null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** O que o painel mostrou ao dono e o Telegram tambem diria: a chave junta o que e a mesma coisa (M5). */
|
|
74
|
+
export type MensageiroMostrado = { chave: string; thread: string | null; texto: string }
|
|
75
|
+
|
|
76
|
+
declare module 'claude-code' {
|
|
77
|
+
interface PluginState {
|
|
78
|
+
'ork-mensageiro': {
|
|
79
|
+
/** O lado do dono: as entregas a caminho das sessoes de fase. */
|
|
80
|
+
dono: MensageiroDono
|
|
81
|
+
/** O lado da sessao de fase: o que chegou de outras sessoes e o que o nucleo confirmou. */
|
|
82
|
+
fase: MensageiroFase
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// O CI de cada pista (RM-059, fatia F7, T7.4; D7 da thread ork-rm059pista). Modulo puro: o argv da consulta ao nucleo
|
|
2
|
-
// (`ork ci status --sha <sha> --json`, contrato `ork.ci-status/
|
|
3
|
-
// cita, as que o relogio de reserva consulta e a etapa de CI que o
|
|
4
|
-
// dispara a consulta: o conteudo dele nunca vira estado, e quem diz o
|
|
2
|
+
// (`ork ci status --sha <sha> --json`, contrato `ork.ci-status/v2`; a v1 dos nucleos anteriores continua lida), a
|
|
3
|
+
// leitura dela, as pistas que um evento do GitHub cita, as que o relogio de reserva consulta e a etapa de CI que o
|
|
4
|
+
// painel mostra com a leitura mais nova. O evento so dispara a consulta: o conteudo dele nunca vira estado, e quem diz o
|
|
5
|
+
// CI e o check do nucleo no sha exato.
|
|
5
6
|
import type { PistaCi, PistaEstadoDaEtapa, PistaLinha, PistaQuadro } from '../types'
|
|
6
7
|
import { jsonDaSaida, umaLinha } from './pista'
|
|
7
8
|
import type { SaidaDoProcesso } from './pista'
|
|
@@ -18,14 +19,17 @@ export function argvDoCi(sha: string): string[] {
|
|
|
18
19
|
return ['ork', 'ci', 'status', '--sha', sha, '--json']
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** Os contratos do `ork ci status --json` que a Pista le: a v2 (forja, fonte e produtor) e a v1 de antes. */
|
|
23
|
+
const CONTRATOS_DO_CI: readonly string[] = ['ork.ci-status/v1', 'ork.ci-status/v2']
|
|
24
|
+
|
|
21
25
|
/**
|
|
22
26
|
* A saida do `ork ci status --sha <sha> --json`: o comando sai 0 so com o check verde, e o JSON vem nos dois casos.
|
|
23
27
|
* Leitura de outro sha nao vale para a pista.
|
|
24
28
|
*/
|
|
25
29
|
export function lerCi(saida: SaidaDoProcesso, sha: string, agora: number, motivo: PistaCi['motivo']): PistaCi {
|
|
26
30
|
const r = jsonDaSaida(saida, 'ork ci status') as Record<string, unknown> | null
|
|
27
|
-
if (!r || typeof r !== 'object' || r.schema
|
|
28
|
-
throw new Error('a saída do ork ci status não é o contrato ork.ci-status
|
|
31
|
+
if (!r || typeof r !== 'object' || !CONTRATOS_DO_CI.includes(r.schema as string) || !ESTADOS.includes(r.state as PistaCi['estado'])) {
|
|
32
|
+
throw new Error('a saída do ork ci status não é o contrato ork.ci-status (v1 ou v2)')
|
|
29
33
|
}
|
|
30
34
|
if (r.sha !== sha) throw new Error(`o ork ci status respondeu pelo commit ${umaLinha(r.sha, 40)}, e não pelo head ${sha.slice(0, 7)}`)
|
|
31
35
|
const estado = r.state as PistaCi['estado']
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ork-ritual",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Ritual do MASTER do Orkastery no Claude Code: as entregas que esperam a sua nota, a prova de cada uma (o que foi entregue, o índice derivado do ledger e as claims com comando e estado, uma por vez) e a nota de 0 a 5 pelo diálogo nativo do host. O mod nunca dá a nota pelo dono.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Orkastery contributors",
|
|
7
|
+
"url": "https://github.com/orkastery"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://orkastery.com/",
|
|
10
|
+
"repository": "https://github.com/orkastery/orkastery",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"types": "./types/index.d.ts",
|
|
13
|
+
"dependencies": ["ork-ponte"]
|
|
14
|
+
}
|