@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,649 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.correlacaoDoArco = exports.faseValida = exports.RecusaDaSupervisao = exports.MOTIVOS_DA_SUPERVISAO = exports.CONTRATO_SUPERVISAO = void 0;
|
|
37
|
+
exports.parametrosPadrao = parametrosPadrao;
|
|
38
|
+
exports.dirDaSupervisao = dirDaSupervisao;
|
|
39
|
+
exports.gravarNaSupervisao = gravarNaSupervisao;
|
|
40
|
+
exports.gravarComEstado = gravarComEstado;
|
|
41
|
+
exports.assumirConducao = assumirConducao;
|
|
42
|
+
exports.parametrosDoArco = parametrosDoArco;
|
|
43
|
+
exports.lerSupervisao = lerSupervisao;
|
|
44
|
+
exports.eventosDaSupervisao = eventosDaSupervisao;
|
|
45
|
+
exports.retomadasDe = retomadasDe;
|
|
46
|
+
exports.contaForaAgora = contaForaAgora;
|
|
47
|
+
exports.threadsDoArco = threadsDoArco;
|
|
48
|
+
exports.contasDoArco = contasDoArco;
|
|
49
|
+
exports.alvosDaFase = alvosDaFase;
|
|
50
|
+
exports.observarContas = observarContas;
|
|
51
|
+
/**
|
|
52
|
+
* RM-058, fatia N4 (D1 a D4 da ork-rm058n4): os checkpoints da supervisão do arco.
|
|
53
|
+
*
|
|
54
|
+
* O histórico da supervisão mora num log append-only próprio, `.orkastery/noctum/arcos/<arco>/supervisao.jsonl`, na raiz
|
|
55
|
+
* do estado, ao lado do log do arco (N1 e N2) e com as mesmas garantias: cada linha leva o sha256 da anterior e um MAC de
|
|
56
|
+
* subchave derivada da chave local do núcleo, num domínio próprio (a chave do log do arco não serve aqui, nem o
|
|
57
|
+
* contrário). O limite também é o mesmo: a chave local é legível por qualquer processo com o mesmo usuário do sistema, que
|
|
58
|
+
* pode escrever linha nova ou truncar o log, como no ledger.
|
|
59
|
+
*
|
|
60
|
+
* O log do arco não ganha linha da supervisão (D1): a supervisão nunca autoriza, renova nem emenda o envelope, e a
|
|
61
|
+
* contabilidade da reserva continua no `concluirDespacho`. Aqui ficam as gerações de quem conduz, as batidas, os tiques do
|
|
62
|
+
* vigia, as retomadas autorizadas, as sessões paradas, as contas que o arco tirou da seleção, os trabalhos isolados, as
|
|
63
|
+
* recusas de ambiente, a parada, os efeitos de resultado incerto e os pedidos da fila de rate limit já tratados.
|
|
64
|
+
*
|
|
65
|
+
* Os parâmetros (cadência, carências, prazos e tetos) são gravados uma vez, na primeira linha (D2), e relidos dali: um
|
|
66
|
+
* processo novo, um manifesto mudado ou outra conta não mudam as regras de um arco que já começou, nem zeram nada. Nada
|
|
67
|
+
* fica em memória: toda leitura relê o disco.
|
|
68
|
+
*/
|
|
69
|
+
const fs = __importStar(require("node:fs"));
|
|
70
|
+
const path = __importStar(require("node:path"));
|
|
71
|
+
const node_crypto_1 = require("node:crypto");
|
|
72
|
+
const estado_thread_1 = require("./estado-thread");
|
|
73
|
+
const fila_pesada_1 = require("./fila-pesada");
|
|
74
|
+
const hitl_local_receipt_1 = require("./hitl-local-receipt");
|
|
75
|
+
const horario_1 = require("./horario");
|
|
76
|
+
const ledger_1 = require("./ledger");
|
|
77
|
+
const noctum_envelope_1 = require("./noctum-envelope");
|
|
78
|
+
const noctum_fila_1 = require("./noctum-fila");
|
|
79
|
+
const ocupacao_1 = require("./ocupacao");
|
|
80
|
+
const setup_1 = require("./setup");
|
|
81
|
+
const thread_1 = require("./thread");
|
|
82
|
+
const types_1 = require("./types");
|
|
83
|
+
exports.CONTRATO_SUPERVISAO = 'ork.noctum-supervisao/v1';
|
|
84
|
+
/** D1: tipo fechado próprio, fora do `MotivoGate` e do `MotivoDeRecusaDoArco`. */
|
|
85
|
+
exports.MOTIVOS_DA_SUPERVISAO = [
|
|
86
|
+
'noctum.supervisao.adulterada', 'noctum.supervisao.invalida', 'noctum.supervisao.ocupada', 'noctum.supervisao.sem-kernel',
|
|
87
|
+
];
|
|
88
|
+
class RecusaDaSupervisao extends Error {
|
|
89
|
+
motivo;
|
|
90
|
+
constructor(motivo, detalhe) {
|
|
91
|
+
super(`${motivo}: ${detalhe}`);
|
|
92
|
+
this.motivo = motivo;
|
|
93
|
+
this.name = 'RecusaDaSupervisao';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.RecusaDaSupervisao = RecusaDaSupervisao;
|
|
97
|
+
/** Os valores de partida; o teto de retomadas vem do `retry.max_tentativas` do manifesto no instante da gravação. */
|
|
98
|
+
function parametrosPadrao(manifesto) {
|
|
99
|
+
return {
|
|
100
|
+
cadenciaMs: noctum_fila_1.CADENCIA_MS,
|
|
101
|
+
carenciaMs: ocupacao_1.CARENCIA_DO_TURNO_ENCERRADO_MIN * 60_000,
|
|
102
|
+
vigiaAusenteMs: 3 * noctum_fila_1.CADENCIA_MS,
|
|
103
|
+
interrupcoesQueParam: 3,
|
|
104
|
+
primeiroTurnoMs: 15 * 60_000,
|
|
105
|
+
semAvancoMs: 90 * 60_000,
|
|
106
|
+
tetoDeRetomadas: Math.max(1, manifesto.retry.max_tentativas),
|
|
107
|
+
retomadasSemPrimeiroTurno: 1,
|
|
108
|
+
recusasDeAmbienteQueParam: 2,
|
|
109
|
+
carenciaDaReservaMs: ocupacao_1.CARENCIA_DO_TURNO_ENCERRADO_MIN * 60_000,
|
|
110
|
+
leiturasDoEfeito: 2,
|
|
111
|
+
ausenciaMinimaMs: noctum_fila_1.CADENCIA_MS,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const TIPOS = ['parametros', 'conducao_assumida', 'batida', 'passo_em_espera', 'passo_recusado', 'passo_retomado',
|
|
115
|
+
'tique_iniciado', 'tique_concluido',
|
|
116
|
+
'vigia_interrompido', 'retomada_autorizada', 'sessao_parada', 'conta_fora', 'isolado', 'recusa_de_ambiente', 'parada',
|
|
117
|
+
'efeito_incerto', 'efeito_reconciliado', 'pedido_tratado'];
|
|
118
|
+
const ZERO = '0'.repeat(64);
|
|
119
|
+
const ARQUIVO = 'supervisao.jsonl';
|
|
120
|
+
const TRAVA = 'supervisao.lock';
|
|
121
|
+
/** A trava do log é curta: quem grava lê, confere e anexa algumas linhas. */
|
|
122
|
+
const ESPERA_DA_TRAVA_MS = 10_000;
|
|
123
|
+
const PAUSA_MS = 50;
|
|
124
|
+
const sha = (s) => (0, node_crypto_1.createHash)('sha256').update(s).digest('hex');
|
|
125
|
+
const objeto = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
126
|
+
const adulterado = (detalhe) => new RecusaDaSupervisao('noctum.supervisao.adulterada', `${detalhe}; a supervisão do arco exige inspeção`);
|
|
127
|
+
const dormir = (ms) => { if (ms > 0)
|
|
128
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.ceil(ms)); };
|
|
129
|
+
/** O diretório do arco na raiz do estado; a supervisão nunca o cria (o arco nasce da proposta da N1). */
|
|
130
|
+
function dirDaSupervisao(raiz, arco) {
|
|
131
|
+
if (typeof arco !== 'string' || !noctum_envelope_1.ID_DO_ARCO.test(arco))
|
|
132
|
+
throw new RecusaDaSupervisao('noctum.supervisao.invalida', 'identificador de arco inválido');
|
|
133
|
+
const principal = (0, estado_thread_1.raizDoEstado)(raiz);
|
|
134
|
+
(0, estado_thread_1.exigirEstadoSemLink)(principal, ['.orkastery', 'noctum', 'arcos', arco]);
|
|
135
|
+
return path.join(principal, '.orkastery', 'noctum', 'arcos', arco);
|
|
136
|
+
}
|
|
137
|
+
/** Subchave própria da supervisão: o mesmo segredo do recibo local, separado por domínio do log do arco. */
|
|
138
|
+
function chaveDaSupervisao(raiz, criar) {
|
|
139
|
+
return (0, node_crypto_1.createHmac)('sha256', (0, hitl_local_receipt_1.chaveLocal)(raiz, criar)).update(exports.CONTRATO_SUPERVISAO).digest();
|
|
140
|
+
}
|
|
141
|
+
/** Lê e confere o log inteiro; a cauda sem quebra de linha está sendo gravada e não conta. */
|
|
142
|
+
function lerLog(raiz, arco) {
|
|
143
|
+
const file = path.join(dirDaSupervisao(raiz, arco), ARQUIVO);
|
|
144
|
+
let bruto;
|
|
145
|
+
try {
|
|
146
|
+
const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
147
|
+
try {
|
|
148
|
+
const st = fs.fstatSync(fd);
|
|
149
|
+
if (!st.isFile() || st.nlink !== 1 || st.uid !== process.getuid?.() || (st.mode & 0o077) !== 0) {
|
|
150
|
+
throw adulterado('log da supervisão não é arquivo privado do núcleo');
|
|
151
|
+
}
|
|
152
|
+
bruto = fs.readFileSync(fd);
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
fs.closeSync(fd);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
if (e.code === 'ENOENT')
|
|
160
|
+
return { linhas: [], ultimaLinha: null, terminaEmQuebra: true, bytesCompletos: 0, bytesLidos: 0 };
|
|
161
|
+
if (e instanceof RecusaDaSupervisao)
|
|
162
|
+
throw e;
|
|
163
|
+
throw adulterado('log da supervisão ilegível');
|
|
164
|
+
}
|
|
165
|
+
const fim = bruto.lastIndexOf(0x0a) + 1;
|
|
166
|
+
const textos = bruto.subarray(0, fim).toString('utf8').split('\n').slice(0, -1);
|
|
167
|
+
const tamanhos = { terminaEmQuebra: fim === bruto.length, bytesCompletos: fim, bytesLidos: bruto.length };
|
|
168
|
+
if (!textos.length)
|
|
169
|
+
return { linhas: [], ultimaLinha: null, ...tamanhos };
|
|
170
|
+
let chave;
|
|
171
|
+
try {
|
|
172
|
+
chave = chaveDaSupervisao(raiz, false);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
throw adulterado('chave do núcleo ausente para conferir o log');
|
|
176
|
+
}
|
|
177
|
+
let anterior = ZERO;
|
|
178
|
+
const linhas = textos.map((texto, i) => {
|
|
179
|
+
let l;
|
|
180
|
+
try {
|
|
181
|
+
l = JSON.parse(texto);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
throw adulterado(`linha ${i + 1} não é JSON`);
|
|
185
|
+
}
|
|
186
|
+
if (!objeto(l) || Object.keys(l).sort().join(',') !== 'dados,mac' || typeof l.mac !== 'string' || !/^[a-f0-9]{64}$/.test(l.mac)) {
|
|
187
|
+
throw adulterado(`linha ${i + 1} fora do formato`);
|
|
188
|
+
}
|
|
189
|
+
const esperado = (0, node_crypto_1.createHmac)('sha256', chave).update(JSON.stringify(l.dados)).digest();
|
|
190
|
+
if (!(0, node_crypto_1.timingSafeEqual)(Buffer.from(l.mac, 'hex'), esperado))
|
|
191
|
+
throw adulterado(`linha ${i + 1} com MAC que não confere`);
|
|
192
|
+
const d = l.dados;
|
|
193
|
+
if (d.contrato !== exports.CONTRATO_SUPERVISAO || d.arco !== arco || d.seq !== i + 1 || d.anterior !== anterior) {
|
|
194
|
+
throw adulterado(`linha ${i + 1} fora da cadeia`);
|
|
195
|
+
}
|
|
196
|
+
if (!objeto(d.evento) || !TIPOS.includes(d.evento.tipo) || typeof d.em !== 'string' || !Number.isFinite(Date.parse(d.em))) {
|
|
197
|
+
throw adulterado(`linha ${i + 1} com evento desconhecido`);
|
|
198
|
+
}
|
|
199
|
+
// D2: os parâmetros são a primeira linha e só ela.
|
|
200
|
+
if ((d.evento.tipo === 'parametros') !== (i === 0))
|
|
201
|
+
throw adulterado(`linha ${i + 1}: os parâmetros são a primeira linha, e só ela`);
|
|
202
|
+
anterior = sha(texto);
|
|
203
|
+
return d;
|
|
204
|
+
});
|
|
205
|
+
return { linhas, ultimaLinha: textos.at(-1), ...tamanhos };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Grava uma linha, sob a trava, depois de `lerLog`. A cauda sem quebra é escrita abortada e sai antes da linha nova; a
|
|
209
|
+
* escrita curta volta o arquivo ao tamanho de antes e é acusada.
|
|
210
|
+
*/
|
|
211
|
+
function anexar(raiz, arco, log, evento, quando) {
|
|
212
|
+
const dados = { contrato: exports.CONTRATO_SUPERVISAO, arco, seq: log.linhas.length + 1,
|
|
213
|
+
anterior: log.ultimaLinha === null ? ZERO : sha(log.ultimaLinha), em: quando, evento };
|
|
214
|
+
const texto = JSON.stringify({ dados, mac: (0, node_crypto_1.createHmac)('sha256', chaveDaSupervisao(raiz, true)).update(JSON.stringify(dados)).digest('hex') });
|
|
215
|
+
const linha = Buffer.from(texto + '\n', 'utf8');
|
|
216
|
+
const file = path.join(dirDaSupervisao(raiz, arco), ARQUIVO);
|
|
217
|
+
const fd = fs.openSync(file, fs.constants.O_WRONLY | fs.constants.O_APPEND | fs.constants.O_CREAT | fs.constants.O_NOFOLLOW, 0o600);
|
|
218
|
+
try {
|
|
219
|
+
if (fs.fstatSync(fd).size !== log.bytesLidos)
|
|
220
|
+
throw adulterado('o log mudou entre a leitura e a escrita sob a trava');
|
|
221
|
+
if (log.bytesLidos !== log.bytesCompletos)
|
|
222
|
+
fs.ftruncateSync(fd, log.bytesCompletos);
|
|
223
|
+
const escritos = fs.writeSync(fd, linha);
|
|
224
|
+
if (escritos !== linha.length) {
|
|
225
|
+
fs.ftruncateSync(fd, log.bytesCompletos);
|
|
226
|
+
fs.fsyncSync(fd);
|
|
227
|
+
throw adulterado(`escrita curta no log (${escritos} de ${linha.length} bytes); nada foi gravado`);
|
|
228
|
+
}
|
|
229
|
+
fs.fsyncSync(fd);
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
fs.closeSync(fd);
|
|
233
|
+
}
|
|
234
|
+
const bytes = log.bytesCompletos + linha.length;
|
|
235
|
+
return { linhas: [...log.linhas, dados], ultimaLinha: texto, terminaEmQuebra: true, bytesCompletos: bytes, bytesLidos: bytes };
|
|
236
|
+
}
|
|
237
|
+
/** A trava do log: a do kernel, curta, com espera em passos. */
|
|
238
|
+
function comTrava(raiz, arco, executar) {
|
|
239
|
+
if (!(0, fila_pesada_1.kernelDisponivel)())
|
|
240
|
+
throw new RecusaDaSupervisao('noctum.supervisao.sem-kernel', 'a supervisão do arco exige /usr/bin/flock');
|
|
241
|
+
const dir = dirDaSupervisao(raiz, arco);
|
|
242
|
+
if (!fs.existsSync(dir))
|
|
243
|
+
throw new RecusaDaSupervisao('noctum.supervisao.invalida', `arco ${arco} sem proposta`);
|
|
244
|
+
const prazo = Date.now() + ESPERA_DA_TRAVA_MS;
|
|
245
|
+
for (;;) {
|
|
246
|
+
const fd = (0, fila_pesada_1.tentarTravaExclusiva)(path.join(dir, TRAVA));
|
|
247
|
+
if (fd !== null) {
|
|
248
|
+
try {
|
|
249
|
+
return executar();
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
fs.closeSync(fd);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (Date.now() >= prazo)
|
|
256
|
+
throw new RecusaDaSupervisao('noctum.supervisao.ocupada', 'outro processo segura o log da supervisão');
|
|
257
|
+
dormir(Math.min(PAUSA_MS, prazo - Date.now()));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Grava eventos na supervisão do arco, na ordem, e devolve o estado relido do disco. Log vazio ganha antes a linha dos
|
|
262
|
+
* parâmetros (D2), com os valores de partida e o teto de retomadas do manifesto de agora; depois, vale o que foi gravado.
|
|
263
|
+
*/
|
|
264
|
+
function gravarNaSupervisao(carregado, arco, eventos, quando = new Date().toISOString()) {
|
|
265
|
+
return gravarComEstado(carregado, arco, () => eventos, quando);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* A gravação que decide o que gravar a partir do estado lido sob a trava (a geração seguinte, o que ainda não foi
|
|
269
|
+
* gravado). O que seria gravado é conferido antes, com o estado inteiro (A4 do CHECK): uma linha que tornaria o log
|
|
270
|
+
* ilegível (uma geração fora de ordem, um efeito repetido) é recusada como inválida e não vai ao disco.
|
|
271
|
+
*/
|
|
272
|
+
function gravarComEstado(carregado, arco, montar, quando = new Date().toISOString()) {
|
|
273
|
+
const { raiz } = carregado;
|
|
274
|
+
return comTrava(raiz, arco, () => {
|
|
275
|
+
let log = lerLog(raiz, arco);
|
|
276
|
+
const eventos = montar(derivar(arco, log.linhas));
|
|
277
|
+
if (eventos.some(e => e.tipo === 'parametros'))
|
|
278
|
+
throw new RecusaDaSupervisao('noctum.supervisao.invalida', 'os parâmetros só a primeira gravação escreve');
|
|
279
|
+
const primeira = log.linhas.length ? [] : [{ tipo: 'parametros', parametros: parametrosPadrao(carregado.manifesto) }];
|
|
280
|
+
const novas = [...primeira, ...eventos].map((evento, i) => ({ contrato: exports.CONTRATO_SUPERVISAO, arco,
|
|
281
|
+
seq: log.linhas.length + 1 + i, anterior: '', em: quando, evento }));
|
|
282
|
+
try {
|
|
283
|
+
derivar(arco, [...log.linhas, ...novas]);
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
if (!(e instanceof RecusaDaSupervisao))
|
|
287
|
+
throw e;
|
|
288
|
+
throw new RecusaDaSupervisao('noctum.supervisao.invalida', `a gravação deixaria o log ilegível (${e.message}); nada foi gravado`);
|
|
289
|
+
}
|
|
290
|
+
for (const e of [...primeira, ...eventos])
|
|
291
|
+
log = anexar(raiz, arco, log, e, quando);
|
|
292
|
+
const relido = lerLog(raiz, arco);
|
|
293
|
+
if (relido.linhas.length !== log.linhas.length || !relido.terminaEmQuebra)
|
|
294
|
+
throw adulterado('a gravação não ficou inteira no log');
|
|
295
|
+
return derivar(arco, relido.linhas);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* D4 e A4 do CHECK: assume a condução com a geração seguinte, lida sob a trava do log (nunca de uma leitura de antes).
|
|
300
|
+
* Devolve o número da geração gravada.
|
|
301
|
+
*/
|
|
302
|
+
function assumirConducao(carregado, arco, quem, prova, quando = new Date().toISOString()) {
|
|
303
|
+
let numero = 0;
|
|
304
|
+
gravarComEstado(carregado, arco, (s) => {
|
|
305
|
+
numero = (s.geracao?.numero ?? 0) + 1;
|
|
306
|
+
return [{ tipo: 'conducao_assumida', geracao: numero, quem, prova: prova(s.geracao) }];
|
|
307
|
+
}, quando);
|
|
308
|
+
return numero;
|
|
309
|
+
}
|
|
310
|
+
/** Garante a linha dos parâmetros e devolve os que valem no arco. */
|
|
311
|
+
function parametrosDoArco(carregado, arco, quando = new Date().toISOString()) {
|
|
312
|
+
const atual = lerSupervisao(carregado.raiz, arco);
|
|
313
|
+
if (atual.parametros)
|
|
314
|
+
return atual.parametros;
|
|
315
|
+
return gravarNaSupervisao(carregado, arco, [], quando).parametros;
|
|
316
|
+
}
|
|
317
|
+
/** O estado da supervisão, relido do disco. Arco sem log de supervisão devolve o estado vazio. */
|
|
318
|
+
function lerSupervisao(raiz, arco) {
|
|
319
|
+
return derivar(arco, lerLog(raiz, arco).linhas);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* RM-058, integração (T8 da ork-rm058integra, D12): os eventos do log da supervisão, conferidos como na leitura do estado,
|
|
323
|
+
* cada um com o instante dele. O aceite do piloto mede por eles a recuperação de cada falha injetada (a geração nova, a
|
|
324
|
+
* retomada, o vigia interrompido), que o estado derivado guarda só pela última.
|
|
325
|
+
*/
|
|
326
|
+
function eventosDaSupervisao(raiz, arco) {
|
|
327
|
+
return lerLog(raiz, arco).linhas.map(l => ({ em: l.em, evento: l.evento }));
|
|
328
|
+
}
|
|
329
|
+
function derivar(arco, linhas) {
|
|
330
|
+
const s = { contrato: exports.CONTRATO_SUPERVISAO, arco, linhas: linhas.length, parametros: null, geracao: null,
|
|
331
|
+
batidas: { condutor: null, vigia: null }, espera: null, recusaDoPasso: null, tiqueAberto: null, interrupcoesSeguidas: 0, retomadas: [], sessoesParadas: [],
|
|
332
|
+
contasFora: new Map(), isolados: new Map(), recusasDeAmbiente: [], parada: null, efeitos: new Map(), pedidos: new Map() };
|
|
333
|
+
for (const { evento: e, em } of linhas) {
|
|
334
|
+
switch (e.tipo) {
|
|
335
|
+
case 'parametros':
|
|
336
|
+
s.parametros = e.parametros;
|
|
337
|
+
break;
|
|
338
|
+
case 'conducao_assumida':
|
|
339
|
+
if (e.geracao !== (s.geracao?.numero ?? 0) + 1)
|
|
340
|
+
throw adulterado(`geração ${e.geracao} fora de ordem`);
|
|
341
|
+
s.geracao = { numero: e.geracao, quem: e.quem, desde: em, prova: e.prova };
|
|
342
|
+
if (e.quem.papel === 'condutor')
|
|
343
|
+
s.batidas.condutor = { em, quem: e.quem };
|
|
344
|
+
break;
|
|
345
|
+
case 'batida':
|
|
346
|
+
s.batidas[e.quem.papel] = { em, quem: e.quem };
|
|
347
|
+
break;
|
|
348
|
+
case 'passo_em_espera':
|
|
349
|
+
s.espera = { motivo: e.motivo, desde: em, papel: e.papel, ocupantes: e.ocupantes };
|
|
350
|
+
s.recusaDoPasso = null;
|
|
351
|
+
break;
|
|
352
|
+
case 'passo_recusado':
|
|
353
|
+
s.espera = null;
|
|
354
|
+
s.recusaDoPasso = { trabalho: e.trabalho, motivo: e.motivo, detalhe: e.detalhe, desde: em, papel: e.papel };
|
|
355
|
+
break;
|
|
356
|
+
case 'passo_retomado':
|
|
357
|
+
s.espera = null;
|
|
358
|
+
s.recusaDoPasso = null;
|
|
359
|
+
break;
|
|
360
|
+
case 'tique_iniciado':
|
|
361
|
+
s.tiqueAberto = { quem: e.quem, em };
|
|
362
|
+
s.batidas.vigia = { em, quem: e.quem };
|
|
363
|
+
break;
|
|
364
|
+
case 'tique_concluido':
|
|
365
|
+
if (s.tiqueAberto?.quem.instancia === e.quem.instancia)
|
|
366
|
+
s.tiqueAberto = null;
|
|
367
|
+
s.interrupcoesSeguidas = 0;
|
|
368
|
+
s.batidas.vigia = { em, quem: e.quem };
|
|
369
|
+
break;
|
|
370
|
+
case 'vigia_interrompido':
|
|
371
|
+
if (s.tiqueAberto?.quem.instancia === e.interrompido)
|
|
372
|
+
s.tiqueAberto = null;
|
|
373
|
+
s.interrupcoesSeguidas += 1;
|
|
374
|
+
break;
|
|
375
|
+
case 'retomada_autorizada':
|
|
376
|
+
s.retomadas.push({ trabalho: e.trabalho, thread: e.thread, fase: e.fase, tentativa: e.tentativa, motivo: e.motivo, sessao: e.sessao,
|
|
377
|
+
prova: e.prova, em, aposReserva: typeof e.aposReserva === 'number' && Number.isSafeInteger(e.aposReserva) ? e.aposReserva : null });
|
|
378
|
+
break;
|
|
379
|
+
case 'sessao_parada':
|
|
380
|
+
s.sessoesParadas.push({ trabalho: e.trabalho, thread: e.thread, sessionId: e.sessionId, motivo: e.motivo, confirmada: e.confirmada === true,
|
|
381
|
+
prova: e.prova, em });
|
|
382
|
+
break;
|
|
383
|
+
case 'conta_fora':
|
|
384
|
+
s.contasFora.set(e.conta, { conta: e.conta, runtime: e.runtime, motivo: e.motivo, ate: e.ate, prova: e.prova, em });
|
|
385
|
+
break;
|
|
386
|
+
case 'isolado':
|
|
387
|
+
// O primeiro isolamento vale: o trabalho não sai do isolamento sozinho neste arco.
|
|
388
|
+
if (!s.isolados.has(e.trabalho))
|
|
389
|
+
s.isolados.set(e.trabalho, { trabalho: e.trabalho, thread: e.thread, motivo: e.motivo, detalhe: e.detalhe, em });
|
|
390
|
+
break;
|
|
391
|
+
case 'recusa_de_ambiente':
|
|
392
|
+
s.recusasDeAmbiente.push({ trabalho: e.trabalho, thread: e.thread, detalhe: e.detalhe, em });
|
|
393
|
+
break;
|
|
394
|
+
case 'parada':
|
|
395
|
+
if (!s.parada)
|
|
396
|
+
s.parada = { motivo: e.motivo, detalhe: e.detalhe, em };
|
|
397
|
+
break;
|
|
398
|
+
case 'efeito_incerto':
|
|
399
|
+
if (s.efeitos.has(e.id))
|
|
400
|
+
throw adulterado(`efeito ${e.id} registrado duas vezes`);
|
|
401
|
+
s.efeitos.set(e.id, { id: e.id, efeito: e.efeito, registradoEm: em, desfechos: [] });
|
|
402
|
+
break;
|
|
403
|
+
case 'efeito_reconciliado': {
|
|
404
|
+
const ef = s.efeitos.get(e.id);
|
|
405
|
+
if (!ef)
|
|
406
|
+
throw adulterado(`desfecho do efeito ${e.id} sem registro`);
|
|
407
|
+
ef.desfechos.push({ desfecho: e.desfecho, prova: e.prova, em });
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
case 'pedido_tratado':
|
|
411
|
+
s.pedidos.set(e.pedido, { thread: e.thread, acao: e.acao, motivo: e.motivo, em });
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return s;
|
|
416
|
+
}
|
|
417
|
+
/** Quantas retomadas o trabalho já teve nesta fase. É a tentativa de quem vem depois, menos um. */
|
|
418
|
+
function retomadasDe(s, trabalho, fase) {
|
|
419
|
+
return s.retomadas.filter(r => r.trabalho === trabalho && r.fase === fase).length;
|
|
420
|
+
}
|
|
421
|
+
/** A conta que o arco tirou e que ainda está fora no instante dado: reset conhecido que passou devolve a conta. */
|
|
422
|
+
function contaForaAgora(s, conta, quando) {
|
|
423
|
+
const f = s.contasFora.get(conta);
|
|
424
|
+
if (!f)
|
|
425
|
+
return null;
|
|
426
|
+
return f.ate !== null && Date.parse(f.ate) <= Date.parse(quando) ? null : f;
|
|
427
|
+
}
|
|
428
|
+
/** Uma fase do ciclo, para validar o que vem de fora (fixtures e ledgers). */
|
|
429
|
+
const faseValida = (v) => typeof v === 'string' && types_1.FASES.includes(v);
|
|
430
|
+
exports.faseValida = faseValida;
|
|
431
|
+
/** As threads do arco: a de cada trabalho (a que o envelope diz, ou a que casa com o item e o sha256 do pedido) e as dos despachos. */
|
|
432
|
+
function threadsDoArco(raiz, conteudo, estado) {
|
|
433
|
+
const porTrabalho = new Map();
|
|
434
|
+
const pedidos = conteudo.trabalhos.filter(t => t.pedido !== undefined);
|
|
435
|
+
const lidas = [];
|
|
436
|
+
if (pedidos.length)
|
|
437
|
+
for (const id of (0, thread_1.listarIds)(raiz)) {
|
|
438
|
+
try {
|
|
439
|
+
lidas.push((0, thread_1.lerThread)(raiz, id));
|
|
440
|
+
}
|
|
441
|
+
catch { /* ilegível: a fila diz a lacuna */ }
|
|
442
|
+
}
|
|
443
|
+
for (const t of conteudo.trabalhos) {
|
|
444
|
+
if (t.thread !== undefined) {
|
|
445
|
+
porTrabalho.set(t.id, t.thread);
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
const alvo = (0, noctum_envelope_1.shaDoPedido)(t.pedido);
|
|
449
|
+
const casam = lidas.filter(x => x.roadmap === t.item && x.pedido?.sha256 === alvo);
|
|
450
|
+
if (casam.length === 1)
|
|
451
|
+
porTrabalho.set(t.id, casam[0].id);
|
|
452
|
+
}
|
|
453
|
+
for (const d of estado.despachos) {
|
|
454
|
+
const th = d.threadDespachada ?? d.thread;
|
|
455
|
+
if (th && !porTrabalho.has(d.trabalho))
|
|
456
|
+
porTrabalho.set(d.trabalho, th);
|
|
457
|
+
}
|
|
458
|
+
return porTrabalho;
|
|
459
|
+
}
|
|
460
|
+
/** A correlação que o passo do arco grava em todo despacho dele. */
|
|
461
|
+
const correlacaoDoArco = (arco) => `noctum:${arco}`;
|
|
462
|
+
exports.correlacaoDoArco = correlacaoDoArco;
|
|
463
|
+
/**
|
|
464
|
+
* D13: as contas que o passo pode usar. Só as do envelope (capacidade e orçamento), que o store dá como disponíveis (com o
|
|
465
|
+
* registro compartilhado da RM-040) e que o arco não tirou: a linha `conta_fora` do arco vale até o reset conhecido, e a
|
|
466
|
+
* sem reset vale pelo resto do arco. O subteto esgotado tira a conta; o teto do arco esgotado para o arco. `store` nulo é
|
|
467
|
+
* store ilegível: nenhuma conta, e a lacuna diz por quê.
|
|
468
|
+
*/
|
|
469
|
+
function contasDoArco(conteudo, estado, sup, store, quando) {
|
|
470
|
+
const agora = Date.parse(quando);
|
|
471
|
+
const lacunas = store ? [] : ['o store de perfis não pôde ser lido: nenhuma conta é dada como disponível'];
|
|
472
|
+
const tetoDoArco = conteudo.orcamento.arco;
|
|
473
|
+
const parada = tetoDoArco.unidade === 'sessoes' && estado.consumo.arco >= tetoDoArco.valor
|
|
474
|
+
? { motivo: 'teto-do-arco', detalhe: `o teto do arco é de ${tetoDoArco.valor} sessoes e ${estado.consumo.arco} já foram reservadas` }
|
|
475
|
+
: null;
|
|
476
|
+
let provider = null;
|
|
477
|
+
const contas = conteudo.capacidade.porConta.map(({ conta }) => {
|
|
478
|
+
const p = store?.perfis.find(x => x.id === conta) ?? null;
|
|
479
|
+
const fora = (motivo, ate = null) => ({ conta, runtime: p?.runtime ?? null, disponivel: false, motivo, ate });
|
|
480
|
+
if (!store)
|
|
481
|
+
return fora('store-ilegivel');
|
|
482
|
+
if (!p)
|
|
483
|
+
return fora('perfil-ausente');
|
|
484
|
+
const doArco = contaForaAgora(sup, conta, quando);
|
|
485
|
+
if (doArco) {
|
|
486
|
+
if (doArco.ate === null && doArco.motivo !== 'auth')
|
|
487
|
+
lacunas.push(`conta ${conta}: reset desconhecido, fora pelo resto do arco (${doArco.prova})`);
|
|
488
|
+
return fora(doArco.motivo, doArco.ate);
|
|
489
|
+
}
|
|
490
|
+
const teto = conteudo.orcamento.porConta.find(x => x.conta === conta)?.teto;
|
|
491
|
+
if (teto?.unidade === 'sessoes' && (estado.consumo.porConta[conta] ?? 0) >= teto.valor)
|
|
492
|
+
return fora('subteto');
|
|
493
|
+
if (p.estado === 'ativo')
|
|
494
|
+
return { conta, runtime: p.runtime, disponivel: true, motivo: null, ate: null };
|
|
495
|
+
if (p.estado === 'esgotado' && p.esgotadoAte !== null && Date.parse(p.esgotadoAte) <= agora) {
|
|
496
|
+
return { conta, runtime: p.runtime, disponivel: true, motivo: null, ate: null };
|
|
497
|
+
}
|
|
498
|
+
if (p.estado === 'esgotado') {
|
|
499
|
+
// D13 (A1 do CHECK): o prazo do store pode ter sido estimado (a janela padrão), e sem a prova do arco o reset é
|
|
500
|
+
// desconhecido: lacuna. O vigia grava a conta fora do arco (`observarContas`), para valer depois que o store a devolver.
|
|
501
|
+
lacunas.push(`conta ${conta}: esgotada no store sem prova do arco do reset, fora do arco como lacuna`);
|
|
502
|
+
return fora('cota-sem-reset', null);
|
|
503
|
+
}
|
|
504
|
+
if (p.estado === 'provider-pago')
|
|
505
|
+
provider = conta;
|
|
506
|
+
return fora(p.estado);
|
|
507
|
+
});
|
|
508
|
+
// D15 (A2 do CHECK): uma conta do envelope que virou provider pago para o arco, como a recusa por custo.
|
|
509
|
+
const porCusto = provider ? { motivo: 'violacao-de-custo',
|
|
510
|
+
detalhe: `a conta ${provider} do envelope está com credencial de provider pago no store: o arco para, sem retry nem troca de conta` } : null;
|
|
511
|
+
return { perfis: contas.filter(c => c.disponivel && c.runtime).map(c => ({ id: c.conta, runtime: c.runtime })), contas, lacunas,
|
|
512
|
+
parada: parada ?? porCusto };
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* D14: os runtimes em que a fase pode sair, em ordem: o do bloco e depois a ordem de fallback do bloco (o modelo e o
|
|
516
|
+
* esforço de cada item), só os que o envelope admite (capacidade e orçamento) e com o subteto em `sessoes` ainda aberto.
|
|
517
|
+
*/
|
|
518
|
+
function alvosDaFase(carregado, conteudo, estado, fase, runtimeDoBloco, modo) {
|
|
519
|
+
let bloco = null;
|
|
520
|
+
try {
|
|
521
|
+
bloco = (0, setup_1.configDoBloco)((0, setup_1.lerSetup)(carregado.raiz), modo, fase);
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
bloco = null;
|
|
525
|
+
}
|
|
526
|
+
const doEnvelope = (r) => conteudo.capacidade.porRuntime.some(x => x.runtime === r) &&
|
|
527
|
+
conteudo.orcamento.porRuntime.some(x => x.runtime === r);
|
|
528
|
+
const aberto = (r) => {
|
|
529
|
+
const teto = conteudo.orcamento.porRuntime.find(x => x.runtime === r)?.teto;
|
|
530
|
+
return !teto || teto.unidade !== 'sessoes' || (estado.consumo.porRuntime[r] ?? 0) < teto.valor;
|
|
531
|
+
};
|
|
532
|
+
const lista = [{ runtime: runtimeDoBloco }, ...(0, setup_1.alvosDaOrdemDeFallback)(bloco?.fallback, runtimeDoBloco)
|
|
533
|
+
.map(a => ({ runtime: a.runtime, model: a.model, ...(a.effort ? { effort: a.effort } : {}) }))];
|
|
534
|
+
const vistos = new Set();
|
|
535
|
+
return lista.filter(a => { if (vistos.has(a.runtime))
|
|
536
|
+
return false; vistos.add(a.runtime); return doEnvelope(a.runtime) && aberto(a.runtime); });
|
|
537
|
+
}
|
|
538
|
+
/** O id do perfil de um evento de despacho (o `perfil` gravado pelo `phase run`: objeto com `id`, ou o id). */
|
|
539
|
+
function perfilDoEvento(e) {
|
|
540
|
+
const p = e.perfil;
|
|
541
|
+
if (typeof p === 'string')
|
|
542
|
+
return p;
|
|
543
|
+
if (objeto(p) && typeof p.id === 'string')
|
|
544
|
+
return p.id;
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* D13 e D15: o que o arco sabe das contas, desde a autorização. Dos despachos do arco: a cota esgotada com o reset dito
|
|
549
|
+
* (fora até ele), a cota sem reset dito (fora pelo resto do arco), o login perdido e o limite de uso transitório (até o
|
|
550
|
+
* `liberaEm` do pedido da fila durável, dito ou estimado, como a fila B3). Da sessão do arco que viu a cota no meio do
|
|
551
|
+
* turno (`runtime_quota_detected`), o mesmo. Do store (A1 do CHECK): a conta esgotada sem a prova do arco do reset, e a
|
|
552
|
+
* sem login, ficam fora do arco, porque o reset é desconhecido e o login só o dono refaz. Devolve as linhas `conta_fora`
|
|
553
|
+
* novas (a decisão já gravada não se repete) e a parada por violação de custo, quando o núcleo recusou um despacho do
|
|
554
|
+
* arco por provider pago.
|
|
555
|
+
*/
|
|
556
|
+
function observarContas(raiz, arco, conteudo, estado, sup, store, quando) {
|
|
557
|
+
const desde = Date.parse(estado.autorizadoPor?.recebidoEm ?? conteudo.janela.inicio);
|
|
558
|
+
const agora = Date.parse(quando);
|
|
559
|
+
const correlacao = (0, exports.correlacaoDoArco)(arco);
|
|
560
|
+
// A falha mais nova de cada conta decide, entre todas as threads do arco.
|
|
561
|
+
const decisoes = new Map();
|
|
562
|
+
const decidir = (conta, evento, em) => {
|
|
563
|
+
if (!((decisoes.get(conta)?.em ?? -Infinity) > em))
|
|
564
|
+
decisoes.set(conta, { evento, em });
|
|
565
|
+
};
|
|
566
|
+
let parada = null;
|
|
567
|
+
for (const thread of new Set(threadsDoArco(raiz, conteudo, estado).values())) {
|
|
568
|
+
let eventos;
|
|
569
|
+
try {
|
|
570
|
+
eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, thread));
|
|
571
|
+
}
|
|
572
|
+
catch {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const sessoesDoArco = new Set(eventos.filter(e => e.tipo === 'phase_dispatch' && e.correlacao === correlacao).map(e => e.sessionId));
|
|
576
|
+
eventos.forEach((e, i) => {
|
|
577
|
+
if (!(Date.parse(e.ts) >= desde))
|
|
578
|
+
return;
|
|
579
|
+
if (e.tipo === 'runtime_quota_detected' && typeof e.sessionId === 'string' && sessoesDoArco.has(e.sessionId)) {
|
|
580
|
+
const conta = perfilDoEvento(e);
|
|
581
|
+
if (!conta)
|
|
582
|
+
return;
|
|
583
|
+
const reset = typeof e.resetEm === 'string' && Date.parse(e.resetEm) > Date.parse(e.ts) ? e.resetEm : null;
|
|
584
|
+
decidir(conta, { tipo: 'conta_fora', conta, runtime: typeof e.runtime === 'string' ? e.runtime : '', motivo: reset ? 'cota' : 'cota-sem-reset',
|
|
585
|
+
ate: reset, prova: `${thread}: runtime_quota_detected ${String(e.eventId ?? '')} da sessão ${e.sessionId}` }, Date.parse(e.ts));
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (e.tipo !== 'phase_dispatch_failed' || e.correlacao !== correlacao)
|
|
589
|
+
return;
|
|
590
|
+
const conta = perfilDoEvento(e);
|
|
591
|
+
const runtime = typeof e.runtime === 'string' ? e.runtime : '';
|
|
592
|
+
// O que o núcleo gravou logo depois desta falha, até o próximo despacho: o gate tipado e o pedido da fila durável.
|
|
593
|
+
const depois = [];
|
|
594
|
+
for (const x of eventos.slice(i + 1)) {
|
|
595
|
+
if (x.tipo === 'phase_dispatch' || x.tipo === 'phase_dispatch_failed' || x.tipo === 'phase_prompt_recorded')
|
|
596
|
+
break;
|
|
597
|
+
depois.push(x);
|
|
598
|
+
}
|
|
599
|
+
const gate = depois.find(x => x.tipo === 'gate_blocked');
|
|
600
|
+
const falha = objeto(gate?.falhaDeConta) ? gate.falhaDeConta : null;
|
|
601
|
+
const prova = `${thread}: ${gate ? `gate_blocked ${String(gate.motivo)}` : 'phase_dispatch_failed'} ${String((gate ?? e).eventId ?? '')}`.trim();
|
|
602
|
+
if (gate?.motivo === 'cost.violation') {
|
|
603
|
+
parada ??= { motivo: 'violacao-de-custo', detalhe: `o núcleo recusou um despacho do arco por custo (${prova}); sem retry nem troca de conta` };
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (!conta)
|
|
607
|
+
return;
|
|
608
|
+
const fila = depois.find(x => x.tipo === 'rate_limit_queued');
|
|
609
|
+
const em = Date.parse(e.ts);
|
|
610
|
+
if (falha?.motivo === 'runtime.quota-exhausted') {
|
|
611
|
+
const reset = typeof falha.resetEm === 'string' && Date.parse(falha.resetEm) > Date.parse(e.ts) ? falha.resetEm : null;
|
|
612
|
+
decidir(conta, { tipo: 'conta_fora', conta, runtime, motivo: reset ? 'cota' : 'cota-sem-reset', ate: reset, prova }, em);
|
|
613
|
+
}
|
|
614
|
+
else if (falha?.motivo === 'runtime.auth-missing') {
|
|
615
|
+
decidir(conta, { tipo: 'conta_fora', conta, runtime, motivo: 'auth', ate: null, prova }, em);
|
|
616
|
+
}
|
|
617
|
+
else if (fila && typeof fila.liberaEm === 'string') {
|
|
618
|
+
decidir(conta, { tipo: 'conta_fora', conta, runtime, motivo: 'limite-de-uso', ate: fila.liberaEm,
|
|
619
|
+
prova: `${thread}: rate_limit_queued ${String(fila.pedido ?? '')} (${fila.janelaEstimada === true ? 'janela estimada' : 'hora dita pelo runtime'})` }, em);
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
// A1 do CHECK: o que só o store sabe, sem decisão do arco valendo agora. A decisão do arco que já venceu (a cota com o
|
|
624
|
+
// reset dito no passado) não segura a do store (NS4 da rodada 2): senão a janela estimada do store voltaria a valer.
|
|
625
|
+
const valendo = (d) => !!d && (d.evento.ate === null || Date.parse(d.evento.ate) > agora);
|
|
626
|
+
for (const { conta } of conteudo.capacidade.porConta) {
|
|
627
|
+
const p = store?.perfis.find(x => x.id === conta);
|
|
628
|
+
if (!p || valendo(decisoes.get(conta)) || contaForaAgora(sup, conta, quando))
|
|
629
|
+
continue;
|
|
630
|
+
if (p.estado === 'esgotado' && p.esgotadoAte !== null && Date.parse(p.esgotadoAte) > agora) {
|
|
631
|
+
decisoes.set(conta, { em: agora, evento: { tipo: 'conta_fora', conta, runtime: p.runtime, motivo: 'cota-sem-reset', ate: null,
|
|
632
|
+
prova: `o store de perfis dá a conta como esgotada até ${(0, horario_1.formatarDataHora)(p.esgotadoAte)}, prazo que pode ser estimado: sem a prova do arco, ` +
|
|
633
|
+
'o reset é desconhecido' } });
|
|
634
|
+
}
|
|
635
|
+
else if (p.estado === 'sem-auth') {
|
|
636
|
+
decisoes.set(conta, { em: agora, evento: { tipo: 'conta_fora', conta, runtime: p.runtime, motivo: 'auth', ate: null,
|
|
637
|
+
prova: 'o store de perfis dá a conta sem login: só o dono refaz o login' } });
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
// RA1 da rodada 3: a decisão que já venceu (a cota com o reset dito no passado) não se grava: senão ela trocaria, tique
|
|
641
|
+
// sim, tique não, a decisão do store gravada depois dela.
|
|
642
|
+
const eventos = [...decisoes.values()].map(d => d.evento)
|
|
643
|
+
.filter(d => d.ate === null || Date.parse(d.ate) > agora)
|
|
644
|
+
.filter(d => {
|
|
645
|
+
const atual = sup.contasFora.get(d.conta);
|
|
646
|
+
return !atual || atual.motivo !== d.motivo || atual.ate !== d.ate || atual.prova !== d.prova;
|
|
647
|
+
});
|
|
648
|
+
return { eventos, parada };
|
|
649
|
+
}
|