@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,971 @@
|
|
|
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.ETAPAS = exports.MODOS_QUE_PUBLICAM = exports.CONTRATO_DA_PISTA = exports.CONTRATO_DA_PUBLICACAO = void 0;
|
|
37
|
+
exports.conferirCheck = conferirCheck;
|
|
38
|
+
exports.conferirBundle = conferirBundle;
|
|
39
|
+
exports.manifestoDaBranch = manifestoDaBranch;
|
|
40
|
+
exports.tituloDoPr = tituloDoPr;
|
|
41
|
+
exports.entreAspas = entreAspas;
|
|
42
|
+
exports.comandoDoDono = comandoDoDono;
|
|
43
|
+
exports.publicarEntrega = publicarEntrega;
|
|
44
|
+
exports.linhasDaPublicacao = linhasDaPublicacao;
|
|
45
|
+
exports.pistaDeEntrega = pistaDeEntrega;
|
|
46
|
+
/**
|
|
47
|
+
* RM-059 (fatia F7, T7.1; DD4 do plano dos mods): a publicacao provada da branch e do PR, e a pista da entrega.
|
|
48
|
+
*
|
|
49
|
+
* Ate aqui, quem publicava a branch de uma thread #Auto e abria o PR era o script do condutor externo, fora do
|
|
50
|
+
* nucleo e sem prova pelo remoto. O `ork ship publicar` faz o mesmo pelo nucleo, e so no modo que ja autoriza o
|
|
51
|
+
* push pela #TAG (#Auto e #Maestro, a mesma lista do `ork ship`):
|
|
52
|
+
*
|
|
53
|
+
* 1. confere, antes de qualquer efeito, a thread, o modo, a conducao, a branch, o CHECK, o verify e o bundle no
|
|
54
|
+
* HEAD, o remoto, a ponta da branch nele e os PRs da branch; a recusa volta tipada e nada vai ao ledger (D2 da
|
|
55
|
+
* thread ork-rm059pista);
|
|
56
|
+
* 2. empurra sem forca o sha conferido, e nao a ref, com refspec explicito, e prova pelo `git ls-remote` (a prova do
|
|
57
|
+
* `ork ship`);
|
|
58
|
+
* 3. reaproveita o PR (MR no GitLab) aberto da branch ou abre um com o texto do `pr-body.md` da thread, e prova pela releitura da
|
|
59
|
+
* lista;
|
|
60
|
+
* 4. grava `ship_published` com a prova, so quando houve efeito; o push sem prova tambem vai. Repetido, ou com o PR
|
|
61
|
+
* ja mesclado no HEAD, devolve `ja-publicada`.
|
|
62
|
+
*
|
|
63
|
+
* A pista (`ork ship pista`) e a leitura que a Pista de Entrega do Claude Code desenha: por thread aberta que ja
|
|
64
|
+
* esta na entrega, as etapas do CHECK ao `ship_done` e o proximo passo que o nucleo declara disponivel. Ela nao
|
|
65
|
+
* grava nada: uma leitura do remoto (`git ls-remote --heads`) e uma da forja (`lerPrsDaForja`) por chamada.
|
|
66
|
+
*
|
|
67
|
+
* Merge, tag e promocao de site continuam fora daqui: o merge e do dono ou do condutor, e o `ship_done` do PR e do
|
|
68
|
+
* `ork ship registrar-pr`.
|
|
69
|
+
*/
|
|
70
|
+
const fs = __importStar(require("node:fs"));
|
|
71
|
+
const path = __importStar(require("node:path"));
|
|
72
|
+
const branch_de_estado_1 = require("./branch-de-estado");
|
|
73
|
+
const ci_1 = require("./ci");
|
|
74
|
+
const api_1 = require("./forja/api");
|
|
75
|
+
const cli_1 = require("./forja/cli");
|
|
76
|
+
const pedidos_1 = require("./forja/gitlab/pedidos");
|
|
77
|
+
const registro_1 = require("./forja/registro");
|
|
78
|
+
const resolver_1 = require("./forja/resolver");
|
|
79
|
+
const cache_1 = require("./forja/cache");
|
|
80
|
+
const texto_1 = require("./forja/texto");
|
|
81
|
+
const claims_1 = require("./claims");
|
|
82
|
+
const ledger_1 = require("./ledger");
|
|
83
|
+
const manifest_1 = require("./manifest");
|
|
84
|
+
const modos_1 = require("./modos");
|
|
85
|
+
const parado_no_condutor_1 = require("./parado-no-condutor");
|
|
86
|
+
const entrega_pr_1 = require("./entrega-pr");
|
|
87
|
+
const noctum_guarda_1 = require("./noctum-guarda");
|
|
88
|
+
const ship_1 = require("./ship");
|
|
89
|
+
const session_watcher_claude_1 = require("./session-watcher-claude");
|
|
90
|
+
const thread_1 = require("./thread");
|
|
91
|
+
const util_1 = require("./util");
|
|
92
|
+
const verify_1 = require("./verify");
|
|
93
|
+
const worktree_1 = require("./worktree");
|
|
94
|
+
const locale_1 = require("./locale");
|
|
95
|
+
exports.CONTRATO_DA_PUBLICACAO = 'ork.ship-publicar/v1';
|
|
96
|
+
exports.CONTRATO_DA_PISTA = 'ork.ship-pista/v1';
|
|
97
|
+
/** Os modos em que a #TAG ja autoriza o push: a mesma lista do `ork ship` (`autorizacaoDePush`); o `publicar` so age neles. */
|
|
98
|
+
exports.MODOS_QUE_PUBLICAM = ship_1.MODOS_QUE_AUTORIZAM_PUSH;
|
|
99
|
+
const SHA = /^[0-9a-f]{40}$/;
|
|
100
|
+
/** O `pr-body.md` maior que isto nao e corpo de PR: o `publicar` usa o corpo padrao. */
|
|
101
|
+
const TETO_DO_CORPO = 64 * 1024;
|
|
102
|
+
/**
|
|
103
|
+
* Prazos de cada chamada de rede. No pior caso, ls-remote, lista de PRs, push, ls-remote, criacao e releitura somam
|
|
104
|
+
* 435 s, abaixo dos 10 min que o motor do Claude Code da a um processo de mod (a Pista espera 9 min pelo publicar).
|
|
105
|
+
*/
|
|
106
|
+
const PRAZO_DO_GH_MS = 45000;
|
|
107
|
+
const PRAZO_DO_PUSH_MS = 180000;
|
|
108
|
+
const PRAZO_DO_LS_REMOTE_MS = 60000;
|
|
109
|
+
/** Git local sem rede escondida nem pergunta de credencial no terminal. */
|
|
110
|
+
function git(raiz, args, prazoMs = 60000) {
|
|
111
|
+
return (0, util_1.exec)('git', args, raiz, prazoMs, { ...process.env, GIT_NO_LAZY_FETCH: '1', GIT_TERMINAL_PROMPT: '0' });
|
|
112
|
+
}
|
|
113
|
+
const curto = (sha) => (sha ? sha.slice(0, 7) : '-');
|
|
114
|
+
exports.ETAPAS = ['check', 'verify', 'bundle', 'branch', 'pr', 'ci', 'conflito', 'entrega'];
|
|
115
|
+
const etapa = (id, estado, texto) => ({ id, estado, texto });
|
|
116
|
+
/** Os caminhos mudados so cabem no bundle (`.ork-ci/`)? Lista vazia tambem nao e produto. */
|
|
117
|
+
function soOBundle(caminhos) {
|
|
118
|
+
return caminhos.split('\n').map((l) => l.trim()).filter(Boolean).every((l) => l.startsWith('.ork-ci/'));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* O ultimo commit de produto da branch, com a hora do commit. Merge nao conta, nem o commit que so mexe em `.ork-ci/`
|
|
122
|
+
* (o bundle): decide o conteudo do commit, e nao o assunto, porque `ci(` tambem e o tipo de commit de workflow.
|
|
123
|
+
*/
|
|
124
|
+
function ultimoCommitDeProduto(raiz, baseRef, head) {
|
|
125
|
+
const r = git(raiz, ['log', '--no-merges', '--format=%H%x09%ct', baseRef ? `${baseRef}..${head}` : head, '-n', '200']);
|
|
126
|
+
if (!r.ok)
|
|
127
|
+
return null;
|
|
128
|
+
for (const linha of r.stdout.split('\n')) {
|
|
129
|
+
const [sha, ct] = linha.split('\t');
|
|
130
|
+
if (!sha || !SHA.test(sha))
|
|
131
|
+
continue;
|
|
132
|
+
const mudou = git(raiz, ['diff-tree', '--no-commit-id', '--name-only', '-r', '--root', sha]);
|
|
133
|
+
if (mudou.ok && soOBundle(mudou.stdout))
|
|
134
|
+
continue;
|
|
135
|
+
const em = Number(ct) * 1000;
|
|
136
|
+
if (Number.isFinite(em))
|
|
137
|
+
return { sha, em };
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* O CHECK: exatamente um veredito, PASSOU, gravado depois do ultimo commit de produto. RM-063 (F7): a batida da conducao
|
|
143
|
+
* tambem o le antes do merge do PR, para nada entrar na base sem ter passado pelo CHECK.
|
|
144
|
+
*/
|
|
145
|
+
function conferirCheck(raiz, t, baseRef, head) {
|
|
146
|
+
if (!(t.fases ?? []).includes('CHECK')) {
|
|
147
|
+
return { etapa: etapa('check', 'nao-se-aplica', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkSemCiclo((0, modos_1.tagDoModo)(t.modo)))), passou: true };
|
|
148
|
+
}
|
|
149
|
+
const artefato = (0, session_watcher_claude_1.estadoDoArtefato)(raiz, t.id, 'docs/check.md');
|
|
150
|
+
if (artefato.texto === null || artefato.mtimeMs === null) {
|
|
151
|
+
return { etapa: etapa('check', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkAusente)), passou: false };
|
|
152
|
+
}
|
|
153
|
+
const veredito = (0, session_watcher_claude_1.vereditoDoParecer)(artefato.texto);
|
|
154
|
+
if (veredito === null)
|
|
155
|
+
return { etapa: etapa('check', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkSemVeredito)), passou: false };
|
|
156
|
+
if (veredito !== 'PASSOU') {
|
|
157
|
+
return { etapa: etapa('check', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkOutroVeredito(veredito))), passou: false };
|
|
158
|
+
}
|
|
159
|
+
const ultimo = head ? ultimoCommitDeProduto(raiz, baseRef, head) : null;
|
|
160
|
+
if (ultimo && artefato.mtimeMs < ultimo.em) {
|
|
161
|
+
return { etapa: etapa('check', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkVelho(curto(ultimo.sha)))), passou: true };
|
|
162
|
+
}
|
|
163
|
+
return { etapa: etapa('check', 'feita', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.checkFeito)), passou: true };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* O verify: o ultimo `verify_run` passou, com os comandos do manifesto (`esperados`, o build e o test), no HEAD ou num
|
|
167
|
+
* ancestral dele com so `.ork-ci/` mudando depois.
|
|
168
|
+
*/
|
|
169
|
+
function conferirVerify(raiz, eventos, head, esperados) {
|
|
170
|
+
const ultimo = [...eventos].reverse().find((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.verificacao);
|
|
171
|
+
if (!ultimo)
|
|
172
|
+
return etapa('verify', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifyAusente));
|
|
173
|
+
const commit = typeof ultimo.commit === 'string' && SHA.test(ultimo.commit) ? ultimo.commit : null;
|
|
174
|
+
if (ultimo.veredito !== 'verdade sustentada') {
|
|
175
|
+
const motivos = Array.isArray(ultimo.motivos) ? ultimo.motivos.map(String).join(', ') : '';
|
|
176
|
+
return etapa('verify', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifyReprovou(curto(commit), motivos || '-')));
|
|
177
|
+
}
|
|
178
|
+
// S2 da revisao: o `ork verify --so-claims` nao roda o build nem o test do manifesto; nao vale como verify do HEAD.
|
|
179
|
+
if (esperados > 0 && (!Array.isArray(ultimo.comandos) || ultimo.comandos.length === 0)) {
|
|
180
|
+
return etapa('verify', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifySoClaims(curto(commit))));
|
|
181
|
+
}
|
|
182
|
+
if (!commit || !head)
|
|
183
|
+
return etapa('verify', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifyAntigo(curto(commit))));
|
|
184
|
+
if (commit === head)
|
|
185
|
+
return etapa('verify', 'feita', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifyNoHead(curto(head))));
|
|
186
|
+
const ancestral = git(raiz, ['merge-base', '--is-ancestor', commit, head]).ok;
|
|
187
|
+
const diff = ancestral ? git(raiz, ['diff', '--name-only', '--no-renames', commit, head]) : null;
|
|
188
|
+
const soBundle = !!diff?.ok && soOBundle(diff.stdout);
|
|
189
|
+
return soBundle ? etapa('verify', 'feita', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifySoBundle(curto(commit))))
|
|
190
|
+
: etapa('verify', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.verifyAntigo(curto(commit))));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* O bundle no HEAD: desta thread, desta branch, com exatamente as claims ativas (sem claim retirada nem faltando), o
|
|
194
|
+
* comando de cada uma como esta agora e os comandos do manifesto que o runner roda.
|
|
195
|
+
*/
|
|
196
|
+
function conferirBundle(raiz, t, branch, head, comandos) {
|
|
197
|
+
const arquivo = `.ork-ci/${t.id}.json`;
|
|
198
|
+
if (!head)
|
|
199
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleAusente(arquivo)));
|
|
200
|
+
const r = git(raiz, ['show', `${head}:${arquivo}`]);
|
|
201
|
+
if (!r.ok)
|
|
202
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleAusente(arquivo)));
|
|
203
|
+
let bundle;
|
|
204
|
+
try {
|
|
205
|
+
bundle = JSON.parse(r.stdout);
|
|
206
|
+
if (bundle.schema !== 'ork.ci-bundle/v1' || bundle.thread !== t.id || !Array.isArray(bundle.claims))
|
|
207
|
+
throw new Error('formato');
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleInvalido(arquivo)));
|
|
211
|
+
}
|
|
212
|
+
if (typeof bundle.branch === 'string' && bundle.branch !== branch) {
|
|
213
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleOutraBranch(arquivo, String(bundle.branch))));
|
|
214
|
+
}
|
|
215
|
+
const noBundle = new Set([...bundle.claims.map((c) => c.id), ...(bundle.deferredClaims ?? []).map((c) => c.id)]);
|
|
216
|
+
let claimsAtivas = [];
|
|
217
|
+
try {
|
|
218
|
+
claimsAtivas = (0, claims_1.lerClaims)(raiz, t.id).filter((c) => c.estado !== 'retirada');
|
|
219
|
+
}
|
|
220
|
+
catch { /* sem claims: lista vazia */ }
|
|
221
|
+
const ativas = claimsAtivas.map((c) => c.id);
|
|
222
|
+
const faltam = ativas.filter((id) => !noBundle.has(id));
|
|
223
|
+
const sobram = [...noBundle].filter((id) => !ativas.includes(id));
|
|
224
|
+
if (faltam.length || sobram.length) {
|
|
225
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleVelho(faltam.join(', '), sobram.join(', '))));
|
|
226
|
+
}
|
|
227
|
+
// A14 da revisao (rodada 2): a claim que mudou de comando sem mudar de id (o `ork claims anexar`) deixa o bundle velho,
|
|
228
|
+
// e o runner rodaria o comando antigo; o mesmo vale para os comandos do manifesto que o bundle leva.
|
|
229
|
+
const comandoDe = new Map(claimsAtivas.map((c) => [c.id, JSON.stringify(c.verificar)]));
|
|
230
|
+
const mudaram = bundle.claims.filter((c) => comandoDe.has(c.id) && comandoDe.get(c.id) !== JSON.stringify(c.verificar)).map((c) => c.id);
|
|
231
|
+
if (mudaram.length)
|
|
232
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleMudou(mudaram.join(', '))));
|
|
233
|
+
if (JSON.stringify(bundle.commands ?? []) !== JSON.stringify(comandos)) {
|
|
234
|
+
return etapa('bundle', 'pendente', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleManifestoMudou));
|
|
235
|
+
}
|
|
236
|
+
return etapa('bundle', 'feita', (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.bundleFeito(ativas.length)));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* O manifesto que vale para o verify e o bundle de uma branch: o do HEAD dela (A15 da revisao, rodada 3). O `ork verify`
|
|
240
|
+
* e o `ork ci prepare` rodam na worktree, com o `orkastery.yaml` da branch, e o runner do CI roda o codigo dela; quem
|
|
241
|
+
* chama o publicar (a Pista, o condutor) pode estar noutro checkout, com outro manifesto. Sem manifesto versionado no
|
|
242
|
+
* HEAD, ou ilegivel, vale o de quem chama.
|
|
243
|
+
*/
|
|
244
|
+
function manifestoDaBranch(carregado, head) {
|
|
245
|
+
if (!head)
|
|
246
|
+
return carregado;
|
|
247
|
+
for (const nome of [manifest_1.NOME_MANIFESTO, manifest_1.NOME_MANIFESTO_LEGADO]) {
|
|
248
|
+
const r = git(carregado.raiz, ['show', `${head}:./${nome}`]);
|
|
249
|
+
if (!r.ok)
|
|
250
|
+
continue;
|
|
251
|
+
const doHead = (0, manifest_1.comandosDoTextoDoManifesto)(r.stdout);
|
|
252
|
+
if (!doHead)
|
|
253
|
+
return carregado;
|
|
254
|
+
return { ...carregado, manifesto: { ...carregado.manifesto,
|
|
255
|
+
verify: { ...carregado.manifesto.verify, typecheck: doHead.typecheck, build: doHead.build, test: doHead.test, security_scan: doHead.securityScan },
|
|
256
|
+
ci: { ...carregado.manifesto.ci, command: doHead.ciCommand } } };
|
|
257
|
+
}
|
|
258
|
+
return carregado;
|
|
259
|
+
}
|
|
260
|
+
function fatosDaThread(carregado, t, refs, baseRef, quando) {
|
|
261
|
+
const raiz = carregado.raiz;
|
|
262
|
+
let eventos = [];
|
|
263
|
+
try {
|
|
264
|
+
eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id));
|
|
265
|
+
}
|
|
266
|
+
catch { /* ledger ilegivel: sem verify nem conducao provada */ }
|
|
267
|
+
const branch = (0, worktree_1.branchDaWorktree)(t);
|
|
268
|
+
const head = (0, branch_de_estado_1.branchValida)(branch) ? refs.get(`refs/heads/${branch}`) ?? null : null;
|
|
269
|
+
const daBranch = manifestoDaBranch(carregado, head);
|
|
270
|
+
const esperados = (0, verify_1.comandosDoManifesto)(daBranch.manifesto).length;
|
|
271
|
+
const contagem = head && baseRef ? git(raiz, ['rev-list', '--count', `${baseRef}..${head}`]) : null;
|
|
272
|
+
const comProduto = !!contagem?.ok && Number(contagem.stdout.trim()) > 0;
|
|
273
|
+
const check = conferirCheck(raiz, t, baseRef, head);
|
|
274
|
+
return {
|
|
275
|
+
t, eventos, branch, head, comProduto, conducao: (0, parado_no_condutor_1.conducaoAgora)(raiz, t, eventos, quando),
|
|
276
|
+
check: check.etapa, checkPassou: check.passou, verify: conferirVerify(raiz, eventos, head, esperados),
|
|
277
|
+
bundle: conferirBundle(raiz, t, branch, head, (0, ci_1.comandosDoBundle)(daBranch)),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/** A base de comparacao: a copia do remoto primeiro (a base local desta maquina pode estar parada). */
|
|
281
|
+
function refDaBase(refs, remoto, base) {
|
|
282
|
+
return [`refs/remotes/${remoto}/${base}`, `refs/heads/${base}`].find((r) => refs.has(r)) ?? null;
|
|
283
|
+
}
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// O remoto e a forja.
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
/**
|
|
288
|
+
* A ponta da branch no remoto pelo `ls-remote`: `null` quando ela nao existe la; `erro` quando o git nao respondeu. Vale
|
|
289
|
+
* so a linha da ref exata: o padrao do `ls-remote` casa por sufixo (`refs/heads/a/refs/heads/<branch>` tambem casaria).
|
|
290
|
+
*/
|
|
291
|
+
function pontaNoRemoto(raiz, remoto, branch) {
|
|
292
|
+
const r = git(raiz, ['ls-remote', '--', remoto, `refs/heads/${branch}`], PRAZO_DO_LS_REMOTE_MS);
|
|
293
|
+
if (!r.ok)
|
|
294
|
+
return { sha: null, erro: (0, texto_1.deFora)(r.stderr || r.stdout || `codigo ${r.code}`) };
|
|
295
|
+
const alvo = `refs/heads/${branch}`;
|
|
296
|
+
const linha = r.stdout.split('\n').map((l) => l.trim().split(/\s+/)).find((partes) => partes[1] === alvo);
|
|
297
|
+
const sha = linha?.[0] ?? '';
|
|
298
|
+
return { sha: SHA.test(sha) ? sha : null, erro: null };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* O sha do remoto esta contido no HEAD local? Sem o objeto nesta copia, a resposta tambem e nao: se ele fosse ancestral
|
|
302
|
+
* do HEAD, a copia o teria (A3 da revisao). `null` so quando o git nao respondeu.
|
|
303
|
+
*/
|
|
304
|
+
function remotoContido(raiz, remota, head) {
|
|
305
|
+
if (!git(raiz, ['cat-file', '-e', `${remota}^{commit}`]).ok)
|
|
306
|
+
return false;
|
|
307
|
+
const r = git(raiz, ['merge-base', '--is-ancestor', remota, head]);
|
|
308
|
+
return r.code === 0 ? true : r.code === 1 ? false : null;
|
|
309
|
+
}
|
|
310
|
+
/** As pontas de todas as branches do remoto numa chamada so. */
|
|
311
|
+
function pontasNoRemoto(raiz, remoto) {
|
|
312
|
+
const r = git(raiz, ['ls-remote', '--heads', '--', remoto], PRAZO_DO_LS_REMOTE_MS);
|
|
313
|
+
if (!r.ok)
|
|
314
|
+
return null;
|
|
315
|
+
const mapa = new Map();
|
|
316
|
+
for (const linha of r.stdout.split('\n')) {
|
|
317
|
+
const [sha, ref] = linha.trim().split(/\s+/);
|
|
318
|
+
if (sha && ref && SHA.test(sha) && ref.startsWith('refs/heads/'))
|
|
319
|
+
mapa.set(ref.slice('refs/heads/'.length), sha);
|
|
320
|
+
}
|
|
321
|
+
return mapa;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* O tipo da forja sem rede nem CLI, para o comando que o dono roda: o fixado, o bloco `forja:`, o host conhecido ou a
|
|
325
|
+
* sondagem que ja esta no cache de 24 h. Remoto sem host (caminho local) segue o GitHub de sempre; host proprio que
|
|
326
|
+
* nada disso resolve da `null`, e o comando do dono mostra as duas forjas.
|
|
327
|
+
*/
|
|
328
|
+
function tipoSemRede(carregado, remoto, fixado) {
|
|
329
|
+
if (fixado)
|
|
330
|
+
return fixado;
|
|
331
|
+
if (carregado.manifesto.forja?.tipo)
|
|
332
|
+
return carregado.manifesto.forja.tipo;
|
|
333
|
+
const endereco = (0, entrega_pr_1.enderecoDoRemotoDaRaiz)(carregado.raiz, remoto);
|
|
334
|
+
if (!endereco)
|
|
335
|
+
return 'github';
|
|
336
|
+
const r = (0, resolver_1.resolverForja)({ endereco, manifesto: carregado.manifesto.forja, sondas: {}, cache: (0, cache_1.dirDoCacheDaForja)(carregado.raiz) });
|
|
337
|
+
return r.ok ? r.valor.tipo : null;
|
|
338
|
+
}
|
|
339
|
+
function pedidosDoGithub(forja, executor) {
|
|
340
|
+
const gh = (0, registro_1.adaptadorDaForja)('github');
|
|
341
|
+
return {
|
|
342
|
+
tipo: 'github',
|
|
343
|
+
listar: (base, branch) => (0, registro_1.exigirCapacidade)(gh, 'pedidosDaBranch')({ ...forja, base, branch, executor, prazoMs: PRAZO_DO_GH_MS }),
|
|
344
|
+
abrir: (base, branch, titulo, corpo) => (0, registro_1.exigirCapacidade)(gh, 'abrirPedido')({ ...forja, base, branch, titulo, corpo, executor,
|
|
345
|
+
prazoMs: PRAZO_DO_GH_MS }),
|
|
346
|
+
passoDaLista: (branch) => `gh pr list --head ${branch} --state all`,
|
|
347
|
+
passoDaCriacao: (base, branch) => `gh pr create --base ${base} --head ${branch}`,
|
|
348
|
+
ensaioDaCriacao: (base, branch, titulo, corpo) => `gh pr create --base ${base} --head ${branch} --title "${titulo}" --body-file <${corpo}>`,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/** O GitLab pela API com a CLI logada; o gh nunca roda aqui. */
|
|
352
|
+
function pedidosDoGitlab(f, opcoes) {
|
|
353
|
+
const gl = (0, registro_1.adaptadorDaForja)('gitlab');
|
|
354
|
+
const semGh = () => ({ status: 1, stdout: '', stderr: 'o gh não fala com o GitLab' });
|
|
355
|
+
const comum = { host: (0, cli_1.hostDaApi)(f), repositorio: f.repo, executor: semGh, prazoMs: PRAZO_DO_GH_MS, api: (0, api_1.chamadorDaApi)(f, opcoes) };
|
|
356
|
+
const projeto = (0, pedidos_1.projetoNaApi)(f.repo);
|
|
357
|
+
return {
|
|
358
|
+
tipo: 'gitlab',
|
|
359
|
+
listar: (base, branch) => (0, registro_1.exigirCapacidade)(gl, 'pedidosDaBranch')({ ...comum, base, branch }),
|
|
360
|
+
abrir: (base, branch, titulo, corpo) => (0, registro_1.exigirCapacidade)(gl, 'abrirPedido')({ ...comum, base, branch, titulo, corpo }),
|
|
361
|
+
passoDaLista: (branch) => `glab api ${(0, pedidos_1.caminhoDosMrsDaBranch)(f.repo, branch)}`,
|
|
362
|
+
passoDaCriacao: (base, branch) => `glab api --method POST ${projeto}/merge_requests (source_branch=${branch}, target_branch=${base})`,
|
|
363
|
+
ensaioDaCriacao: (base, branch, titulo, corpo) => `glab api --method POST ${projeto}/merge_requests (source_branch=${branch}, target_branch=${base}, title="${titulo}", description <${corpo}>)`,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/** Os pedidos da entrega: o GitHub fixo dos testes, a forja fixada, ou a resolvida do remoto. */
|
|
367
|
+
function pedidosDaEntrega(carregado, remoto, opcoes) {
|
|
368
|
+
const executor = opcoes.executorGh ?? parado_no_condutor_1.ghPadrao;
|
|
369
|
+
if (opcoes.forja)
|
|
370
|
+
return { ok: true, pedidos: pedidosDoGithub(opcoes.forja, executor) };
|
|
371
|
+
const r = opcoes.forjaResolvida ? { ok: true, valor: opcoes.forjaResolvida } : (0, entrega_pr_1.forjaDaEntrega)(carregado, remoto, opcoes.sondas);
|
|
372
|
+
if (!r.ok)
|
|
373
|
+
return r;
|
|
374
|
+
return { ok: true, pedidos: r.valor.tipo === 'gitlab' ? pedidosDoGitlab(r.valor, opcoes.api ?? {})
|
|
375
|
+
: pedidosDoGithub({ host: r.valor.host, repositorio: r.valor.repo }, executor) };
|
|
376
|
+
}
|
|
377
|
+
// ---------------------------------------------------------------------------
|
|
378
|
+
// O corpo e o titulo do PR.
|
|
379
|
+
// ---------------------------------------------------------------------------
|
|
380
|
+
/** O `pr-body.md` da thread, quando e arquivo comum e cabe no teto. */
|
|
381
|
+
function corpoDaThread(raiz, threadId) {
|
|
382
|
+
const arquivo = path.join((0, thread_1.dirThread)(raiz, threadId), 'pr-body.md');
|
|
383
|
+
try {
|
|
384
|
+
const st = fs.lstatSync(arquivo);
|
|
385
|
+
if (!st.isFile() || st.size === 0 || st.size > TETO_DO_CORPO)
|
|
386
|
+
return null;
|
|
387
|
+
const texto = fs.readFileSync(arquivo, 'utf8');
|
|
388
|
+
// O corpo vai ao gh por um arquivo temporario 600, nunca pelo argv; com NUL ele nao e texto de PR, e vale o corpo padrao.
|
|
389
|
+
return texto.includes('\0') ? null : { arquivo, texto };
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/** O titulo do PR: `ship(<thread>): ` e o primeiro cabecalho do corpo, ou o nome da thread. */
|
|
396
|
+
function tituloDoPr(t, corpo) {
|
|
397
|
+
let titulo = null;
|
|
398
|
+
for (const linha of (corpo ?? '').split('\n')) {
|
|
399
|
+
const l = linha.trim();
|
|
400
|
+
if (!l)
|
|
401
|
+
continue;
|
|
402
|
+
const m = /^#{1,6}\s+(.+)$/.exec(l);
|
|
403
|
+
titulo = m ? (0, texto_1.umaLinha)(m[1], 120) : null;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
const prefixo = `ship(${t.id})`;
|
|
407
|
+
if (titulo?.startsWith(prefixo))
|
|
408
|
+
return titulo;
|
|
409
|
+
return `${prefixo}: ${titulo ?? (0, texto_1.umaLinha)(t.nome || t.id, 120)}`;
|
|
410
|
+
}
|
|
411
|
+
/** Uma palavra do shell entre aspas simples: nada dentro dela vira comando, nem `;`, `$`, crase ou barra. */
|
|
412
|
+
function entreAspas(s) {
|
|
413
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* O que o dono roda no proprio terminal quando o modo da thread nao autoriza o push. A branch e a base vem do estado e do
|
|
417
|
+
* manifesto, que podem ser do clone: cada parte vai entre aspas simples (A4 da revisao). No GitLab, a descricao vai pelo
|
|
418
|
+
* `--description-file` (ou o titulo, sem `pr-body.md`) e nunca pelo `--fill`, que empurra a branch e pode trocar o titulo;
|
|
419
|
+
* o `glab mr create` nao arma merge.
|
|
420
|
+
*/
|
|
421
|
+
function comandoDoDono(remoto, base, branch, titulo, comCorpo, tipo = 'github') {
|
|
422
|
+
if (tipo === null) {
|
|
423
|
+
const gh = comandoDoDono(remoto, base, branch, titulo, comCorpo, 'github'), glab = comandoDoDono(remoto, base, branch, titulo, comCorpo, 'gitlab');
|
|
424
|
+
return (0, locale_1.textoDoCatalogo)((m) => m.ship.publicar.comandoDasDuasForjas(gh, glab));
|
|
425
|
+
}
|
|
426
|
+
const push = `git push -u ${entreAspas(remoto)} ${entreAspas(branch)}`;
|
|
427
|
+
if (tipo === 'gitlab') {
|
|
428
|
+
return `${push} && glab mr create --source-branch ${entreAspas(branch)} --target-branch ${entreAspas(base)} --title ${entreAspas(titulo)} ` +
|
|
429
|
+
`${comCorpo ? `--description-file ${entreAspas(comCorpo)}` : `--description ${entreAspas(titulo)}`} --yes`;
|
|
430
|
+
}
|
|
431
|
+
return `${push} && gh pr create --base ${entreAspas(base)} --head ${entreAspas(branch)} ` +
|
|
432
|
+
`--title ${entreAspas(titulo)} ${comCorpo ? `--body-file ${entreAspas(comCorpo)}` : '--fill'}`;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* `ork ship publicar <thread>`: publica a branch da thread e abre (ou reaproveita) o PR, com prova, so no modo que
|
|
436
|
+
* ja autoriza push. Nunca lanca por reprovacao: a recusa antes de qualquer efeito volta tipada e nada vai ao ledger; o
|
|
437
|
+
* push que aconteceu vai sempre ao ledger, provado ou nao (B1 da revisao).
|
|
438
|
+
*/
|
|
439
|
+
function publicarEntrega(carregado, threadId, opcoes = {}) {
|
|
440
|
+
const raiz = carregado.raiz, base = carregado.manifesto.worktree.base_branch;
|
|
441
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
|
|
442
|
+
const quando = opcoes.quando ?? new Date().toISOString();
|
|
443
|
+
const dryRun = opcoes.dryRun === true;
|
|
444
|
+
const p = (m) => m.ship.publicar;
|
|
445
|
+
const r = {
|
|
446
|
+
contrato: exports.CONTRATO_DA_PUBLICACAO, thread: threadId, modo: null, tag: null, acao: 'recusada', motivo: null,
|
|
447
|
+
detalhe: '', correcao: '', branch: null, base, remoto, head: null, remotaAntes: null, remota: null, pushVerificado: false,
|
|
448
|
+
pr: null, corpo: null, passos: [], dryRun,
|
|
449
|
+
};
|
|
450
|
+
const recusar = (motivo, detalhe, correcao) => ({ ...r, acao: 'recusada', motivo, detalhe, correcao });
|
|
451
|
+
// 1. A thread que existe e esta aberta. S3 da revisao: a que nao se le tambem volta como recusa tipada, no contrato.
|
|
452
|
+
let lida;
|
|
453
|
+
try {
|
|
454
|
+
lida = (0, thread_1.lerThread)(raiz, threadId);
|
|
455
|
+
}
|
|
456
|
+
catch (e) {
|
|
457
|
+
return recusar('artifact.missing', (0, locale_1.textoDoCatalogo)((m) => p(m).threadInexistente((0, texto_1.umaLinha)(threadId, 80), (0, texto_1.deFora)(e.message))), (0, locale_1.textoDoCatalogo)((m) => p(m).threadInexistenteCorrecao));
|
|
458
|
+
}
|
|
459
|
+
const t = lida;
|
|
460
|
+
r.thread = t.id;
|
|
461
|
+
r.modo = t.modo;
|
|
462
|
+
r.tag = (0, modos_1.tagDoModo)(t.modo);
|
|
463
|
+
if (t.status === 'fechada') {
|
|
464
|
+
return recusar('artifact.missing', (0, locale_1.textoDoCatalogo)((m) => p(m).threadFechada(t.id)), (0, locale_1.textoDoCatalogo)((m) => p(m).threadFechadaCorrecao));
|
|
465
|
+
}
|
|
466
|
+
// RM-058, integração (T1.1, D3 da ork-rm058integra): a thread de um arco #Noctum que a guarda só é publicada pelo próprio
|
|
467
|
+
// arco (`doArco`). Antes de qualquer git, e sem ledger, como as outras recusas daqui.
|
|
468
|
+
const guarda = (0, noctum_guarda_1.guardaDaThread)(raiz, t.id, quando, { doArco: opcoes.doArco });
|
|
469
|
+
if (guarda)
|
|
470
|
+
return { ...recusar('policy.violation', guarda.detalhe, guarda.correcao), codigo: guarda.motivo };
|
|
471
|
+
const refs = (0, parado_no_condutor_1.refsLocais)(raiz, remoto);
|
|
472
|
+
const baseRef = refDaBase(refs, remoto, base);
|
|
473
|
+
const f = fatosDaThread(carregado, t, refs, baseRef, quando);
|
|
474
|
+
r.branch = f.branch;
|
|
475
|
+
r.head = f.head;
|
|
476
|
+
const corpo = corpoDaThread(raiz, t.id);
|
|
477
|
+
// 2. O modo que ja autoriza push (D1): fora dele, o push e do dono, e a correcao diz o comando dele.
|
|
478
|
+
if (!exports.MODOS_QUE_PUBLICAM.includes(t.modo)) {
|
|
479
|
+
const comando = comandoDoDono(remoto, base, f.branch, tituloDoPr(t, corpo?.texto ?? null), corpo ? path.relative(raiz, corpo.arquivo) : null, tipoSemRede(carregado, remoto, opcoes.forja ? 'github' : opcoes.forjaResolvida?.tipo));
|
|
480
|
+
return recusar('human.pending', (0, locale_1.textoDoCatalogo)((m) => p(m).modoSemPush((0, modos_1.tagDoModo)(t.modo))), (0, locale_1.textoDoCatalogo)((m) => p(m).modoSemPushCorrecao(comando)));
|
|
481
|
+
}
|
|
482
|
+
// 3. Ninguem conduz a thread agora: a branch pode mudar no meio da publicacao.
|
|
483
|
+
if (f.conducao) {
|
|
484
|
+
const sessao = f.conducao.sessao ? f.conducao.sessao.slice(0, 8) : f.conducao.canal;
|
|
485
|
+
return recusar('conducao.em-andamento', (0, locale_1.textoDoCatalogo)((m) => p(m).conduzida(sessao, f.conducao?.fase ?? '-')), (0, locale_1.textoDoCatalogo)((m) => p(m).conduzidaCorrecao(t.id)));
|
|
486
|
+
}
|
|
487
|
+
// 4. A branch com produto, que nao e a base.
|
|
488
|
+
if (!(0, branch_de_estado_1.branchValida)(f.branch) || !f.head) {
|
|
489
|
+
return recusar('artifact.missing', (0, locale_1.textoDoCatalogo)((m) => p(m).semBranch(f.branch)), (0, locale_1.textoDoCatalogo)((m) => p(m).semBranchCorrecao(t.id)));
|
|
490
|
+
}
|
|
491
|
+
const head = f.head;
|
|
492
|
+
if (f.branch === base) {
|
|
493
|
+
return recusar('policy.violation', (0, locale_1.textoDoCatalogo)((m) => p(m).branchEBase(base)), (0, locale_1.textoDoCatalogo)((m) => p(m).branchEBaseCorrecao));
|
|
494
|
+
}
|
|
495
|
+
if (!f.comProduto) {
|
|
496
|
+
return recusar('artifact.missing', (0, locale_1.textoDoCatalogo)((m) => p(m).semProduto(f.branch, base)), (0, locale_1.textoDoCatalogo)((m) => p(m).semProdutoCorrecao));
|
|
497
|
+
}
|
|
498
|
+
// 5 a 7. O CHECK, o verify e o bundle no HEAD.
|
|
499
|
+
if (f.check.estado === 'pendente')
|
|
500
|
+
return recusar('artifact.missing', f.check.texto, (0, locale_1.textoDoCatalogo)((m) => p(m).checkCorrecao(t.id)));
|
|
501
|
+
if (f.verify.estado === 'pendente')
|
|
502
|
+
return recusar('verify.failed', f.verify.texto, (0, locale_1.textoDoCatalogo)((m) => p(m).verifyCorrecao(t.id)));
|
|
503
|
+
if (f.bundle.estado === 'pendente')
|
|
504
|
+
return recusar('artifact.missing', f.bundle.texto, (0, locale_1.textoDoCatalogo)((m) => p(m).bundleCorrecao(t.id)));
|
|
505
|
+
// 8. O remoto e a forja. S3 da revisao: sem o remoto, a publicacao nao tem para onde ir (runtime.unavailable).
|
|
506
|
+
if (!git(raiz, ['remote', 'get-url', '--', remoto]).ok) {
|
|
507
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => p(m).semRemoto(remoto)), (0, locale_1.textoDoCatalogo)((m) => p(m).semRemotoCorrecao));
|
|
508
|
+
}
|
|
509
|
+
const daForja = pedidosDaEntrega(carregado, remoto, opcoes);
|
|
510
|
+
if (!daForja.ok) {
|
|
511
|
+
const erro = daForja.erro;
|
|
512
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => p(m).semForja(remoto, erro ? m.forja.motivo(erro, null) : null)), (0, locale_1.textoDoCatalogo)((m) => p(m).semForjaCorrecao));
|
|
513
|
+
}
|
|
514
|
+
const pedidos = daForja.pedidos;
|
|
515
|
+
const noGitlab = pedidos.tipo === 'gitlab';
|
|
516
|
+
const rede = (m) => (noGitlab ? p(m).redeCorrecaoGitlab : p(m).redeCorrecao);
|
|
517
|
+
// 9. A ponta no remoto e os PRs da branch, antes de qualquer efeito.
|
|
518
|
+
const provaDoPush = `git ls-remote ${remoto} refs/heads/${f.branch}`;
|
|
519
|
+
const antes = pontaNoRemoto(raiz, remoto, f.branch);
|
|
520
|
+
r.passos.push(provaDoPush);
|
|
521
|
+
if (antes.erro !== null) {
|
|
522
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => p(m).lsRemoteFalhou(remoto, antes.erro ?? '-')), (0, locale_1.textoDoCatalogo)(rede));
|
|
523
|
+
}
|
|
524
|
+
r.remotaAntes = antes.sha;
|
|
525
|
+
r.remota = antes.sha;
|
|
526
|
+
const lidos = pedidos.listar(base, f.branch);
|
|
527
|
+
r.passos.push(pedidos.passoDaLista(f.branch));
|
|
528
|
+
if (lidos.erro !== null) {
|
|
529
|
+
const erro = lidos.erro;
|
|
530
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => noGitlab ? p(m).prsFalharamGitlab(erro) : p(m).prsFalharam(erro)), (0, locale_1.textoDoCatalogo)(rede));
|
|
531
|
+
}
|
|
532
|
+
const aberto = lidos.prs.find((x) => x.estado === 'aberto') ?? null;
|
|
533
|
+
const mesclado = lidos.prs.find((x) => x.estado === 'mesclado' && x.head === head) ?? null;
|
|
534
|
+
const noRemoto = antes.sha === head;
|
|
535
|
+
r.pushVerificado = noRemoto;
|
|
536
|
+
// A2 da revisao: o PR mesclado no HEAD ja e a entrega, com ou sem a branch no remoto (o GitHub pode te-la apagado).
|
|
537
|
+
if (mesclado && !aberto) {
|
|
538
|
+
return { ...r, acao: 'ja-publicada', pr: { numero: mesclado.numero, url: mesclado.url, criado: false, head: mesclado.head },
|
|
539
|
+
detalhe: (0, locale_1.textoDoCatalogo)((m) => p(m).jaMesclado(mesclado.numero, noGitlab)), correcao: (0, locale_1.textoDoCatalogo)((m) => p(m).registreAEntrega(t.id)) };
|
|
540
|
+
}
|
|
541
|
+
if (noRemoto && aberto) {
|
|
542
|
+
return { ...r, acao: 'ja-publicada', pr: { numero: aberto.numero, url: aberto.url, criado: false, head: aberto.head },
|
|
543
|
+
detalhe: (0, locale_1.textoDoCatalogo)((m) => p(m).jaPublicada(aberto.numero, noGitlab)) };
|
|
544
|
+
}
|
|
545
|
+
// O remoto com commit que a branch local nao tem, ou que esta copia nem conhece (A3 da revisao): o push sem forca
|
|
546
|
+
// seria recusado. Nunca forcar.
|
|
547
|
+
if (antes.sha && !noRemoto && remotoContido(raiz, antes.sha, head) === false) {
|
|
548
|
+
return recusar('tree.blocked', (0, locale_1.textoDoCatalogo)((m) => p(m).remotoDivergiu(remoto, f.branch, curto(antes.sha))), (0, locale_1.textoDoCatalogo)((m) => p(m).remotoDivergiuCorrecao(remoto, f.branch)));
|
|
549
|
+
}
|
|
550
|
+
r.corpo = corpo ? 'pr-body.md' : 'padrao';
|
|
551
|
+
const titulo = tituloDoPr(t, corpo?.texto ?? null);
|
|
552
|
+
// A5 da revisao: o corpo e o texto lido agora, gravado num arquivo temporario 600 so para o `gh pr create`
|
|
553
|
+
// (`--body-file`); o gh nunca reabre o `pr-body.md`.
|
|
554
|
+
const textoDoCorpo = corpo?.texto ?? (0, locale_1.textoDoCatalogo)((m) => p(m).corpoPadrao((0, modos_1.tagDoModo)(t.modo), f.branch, curto(head), carregado.manifesto.ci.context || 'ork-verify', noGitlab));
|
|
555
|
+
// B1 da revisao: o push leva o sha conferido, e nao a ref: o commit que chegue a branch depois das conferencias fica
|
|
556
|
+
// fora desta publicacao.
|
|
557
|
+
const refspec = `${head}:refs/heads/${f.branch}`;
|
|
558
|
+
if (dryRun) {
|
|
559
|
+
const passos = [...r.passos];
|
|
560
|
+
if (!noRemoto)
|
|
561
|
+
passos.push(`git push -- ${remoto} ${refspec}`, provaDoPush);
|
|
562
|
+
passos.push(aberto ? (0, locale_1.textoDoCatalogo)((m) => p(m).passoReaproveita(aberto.numero, noGitlab))
|
|
563
|
+
: pedidos.ensaioDaCriacao(base, f.branch, titulo, corpo ? 'pr-body.md' : 'padrao'));
|
|
564
|
+
return { ...r, acao: 'publicaria', passos, pr: aberto ? { numero: aberto.numero, url: aberto.url, criado: false, head: aberto.head } : null,
|
|
565
|
+
detalhe: (0, locale_1.textoDoCatalogo)((m) => p(m).publicaria(curto(head), aberto?.numero ?? null, noGitlab)) };
|
|
566
|
+
}
|
|
567
|
+
// A evidencia de cada efeito, com a prova ou a falta dela.
|
|
568
|
+
let pushFeito = false;
|
|
569
|
+
const gravar = (extra) => (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, t.id), t.id, ledger_1.TIPOS_DE_EVENTO.shipPublicado, {
|
|
570
|
+
branch: f.branch, base, remoto, head, remotaAntes: r.remotaAntes, shaRemoto: r.remota, pushFeito, pushVerificado: r.pushVerificado,
|
|
571
|
+
fonteDaProva: provaDoPush, corpo: r.corpo, modo: t.modo, tag: (0, modos_1.tagDoModo)(t.modo),
|
|
572
|
+
autorizadoPor: (0, locale_1.textoDoCatalogo)((m) => m.ship.porTag((0, modos_1.tagDoModo)(t.modo))), tipoDeAutorizacao: 'modo', passos: r.passos, ...extra,
|
|
573
|
+
});
|
|
574
|
+
// Efeito 1: o push sem forca do sha conferido, provado pelo ls-remote.
|
|
575
|
+
if (!noRemoto) {
|
|
576
|
+
const conferido = opcoes.antesDoEfeito?.('push') ?? null;
|
|
577
|
+
if (conferido)
|
|
578
|
+
return recusar('policy.violation', conferido.recusa, conferido.correcao);
|
|
579
|
+
const argv = ['push', '--', remoto, refspec];
|
|
580
|
+
const push = (opcoes.executorGit ?? ((args, prazoMs) => git(raiz, args, prazoMs)))(argv, PRAZO_DO_PUSH_MS);
|
|
581
|
+
r.passos.push(`git ${argv.join(' ')}`);
|
|
582
|
+
const depois = pontaNoRemoto(raiz, remoto, f.branch);
|
|
583
|
+
r.passos.push(provaDoPush);
|
|
584
|
+
r.remota = depois.sha;
|
|
585
|
+
r.pushVerificado = depois.sha === head;
|
|
586
|
+
// O push que saiu com erro mas chegou (o prazo venceu depois da escrita no remoto) conta: quem decide e o ls-remote.
|
|
587
|
+
pushFeito = push.ok || r.pushVerificado;
|
|
588
|
+
if (!pushFeito) {
|
|
589
|
+
const erro = (0, texto_1.deFora)(push.stderr || push.stdout || `codigo ${push.code}`, 300);
|
|
590
|
+
const recusado = /rejected|non-fast-forward|fetch first|stale info|failed to update ref/i.test(erro);
|
|
591
|
+
return recusar(recusado ? 'tree.blocked' : 'runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => p(m).pushFalhou(remoto, f.branch, erro)), (0, locale_1.textoDoCatalogo)((m) => recusado ? p(m).remotoDivergiuCorrecao(remoto, f.branch) : rede(m)));
|
|
592
|
+
}
|
|
593
|
+
if (!r.pushVerificado) {
|
|
594
|
+
// B1 da revisao: o push aconteceu e o remoto nao mostra o HEAD; a tentativa vai ao ledger com o que ele respondeu.
|
|
595
|
+
gravar({ pr: null, ...(depois.erro !== null ? { erroDaProva: depois.erro } : {}) });
|
|
596
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => p(m).pushSemProva(depois.sha ? curto(depois.sha) : null, curto(head))), (0, locale_1.textoDoCatalogo)((m) => p(m).pushSemProvaCorrecao(t.id)));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// Efeito 2: o PR aberto da branch, ou um novo, provado pela releitura da lista.
|
|
600
|
+
let pr = aberto ? { numero: aberto.numero, url: aberto.url, criado: false, head: aberto.head } : null;
|
|
601
|
+
let erroDoPr = null;
|
|
602
|
+
if (!pr) {
|
|
603
|
+
const conferido = opcoes.antesDoEfeito?.('pr', { titulo, corpo: textoDoCorpo }) ?? null;
|
|
604
|
+
if (conferido) {
|
|
605
|
+
// O push desta chamada aconteceu: ele vai ao ledger com a prova, e o PR fica para depois (B1 da revisao).
|
|
606
|
+
if (pushFeito)
|
|
607
|
+
gravar({ pr: null, prRecusado: conferido.recusa.slice(0, 300) });
|
|
608
|
+
return recusar('policy.violation', conferido.recusa, conferido.correcao);
|
|
609
|
+
}
|
|
610
|
+
const criado = pedidos.abrir(base, f.branch, titulo, textoDoCorpo);
|
|
611
|
+
r.passos.push(pedidos.passoDaCriacao(base, f.branch));
|
|
612
|
+
const relidos = pedidos.listar(base, f.branch);
|
|
613
|
+
r.passos.push(`${pedidos.passoDaLista(f.branch)} (prova do PR)`);
|
|
614
|
+
const achado = relidos.prs.find((x) => x.estado === 'aberto') ?? null;
|
|
615
|
+
if (achado)
|
|
616
|
+
pr = { numero: achado.numero, url: achado.url, criado: criado.status === 0, head: achado.head };
|
|
617
|
+
else {
|
|
618
|
+
erroDoPr = criado.status !== 0 ? (0, texto_1.deFora)(criado.stderr || criado.stdout || `codigo ${criado.status ?? '-'}`)
|
|
619
|
+
: relidos.erro ?? (0, locale_1.textoDoCatalogo)((m) => noGitlab ? p(m).prSemReleituraGitlab : p(m).prSemReleitura);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
r.pr = pr;
|
|
623
|
+
// A evidencia: so com efeito (push ou PR novo), com a prova.
|
|
624
|
+
if (pushFeito || pr?.criado || erroDoPr) {
|
|
625
|
+
gravar({ pr: pr ? { numero: pr.numero, url: pr.url, criado: pr.criado, head: pr.head } : null,
|
|
626
|
+
...(pr ? { provaDoPr: pedidos.passoDaLista(f.branch) } : {}), ...(erroDoPr ? { erroDoPr } : {}) });
|
|
627
|
+
}
|
|
628
|
+
if (erroDoPr) {
|
|
629
|
+
const erro = erroDoPr;
|
|
630
|
+
return recusar('runtime.unavailable', (0, locale_1.textoDoCatalogo)((m) => noGitlab ? p(m).prFalhouGitlab(curto(head), erro) : p(m).prFalhou(curto(head), erro)), (0, locale_1.textoDoCatalogo)((m) => noGitlab ? p(m).prFalhouCorrecaoGitlab(t.id) : p(m).prFalhouCorrecao(t.id)));
|
|
631
|
+
}
|
|
632
|
+
// S7 da revisao: sem push e sem PR aberto por este processo, quem publicou foi outro; a entrega ja estava publicada.
|
|
633
|
+
if (!pushFeito && !pr?.criado) {
|
|
634
|
+
return { ...r, acao: 'ja-publicada', motivo: null, correcao: '', detalhe: (0, locale_1.textoDoCatalogo)((m) => p(m).jaPublicada(pr?.numero ?? 0, noGitlab)) };
|
|
635
|
+
}
|
|
636
|
+
return { ...r, acao: 'publicou', motivo: null, correcao: '',
|
|
637
|
+
detalhe: (0, locale_1.textoDoCatalogo)((m) => p(m).publicou(curto(head), pr?.numero ?? 0, pr?.criado === true, noGitlab)) };
|
|
638
|
+
}
|
|
639
|
+
/** As linhas da saida de texto do `ork ship publicar`, no locale ativo. */
|
|
640
|
+
function linhasDaPublicacao(r) {
|
|
641
|
+
const m = (0, locale_1.msg)().ship;
|
|
642
|
+
const p = m.publicar;
|
|
643
|
+
const curtoOuTraco = (sha) => (sha ? sha.slice(0, 7) : '-');
|
|
644
|
+
const linhas = [p.cabecalho(r.dryRun, r.thread, r.tag ?? '-')];
|
|
645
|
+
if (r.branch)
|
|
646
|
+
linhas.push(p.linhaBranch(r.branch, curtoOuTraco(r.head)));
|
|
647
|
+
if (r.passos.length) {
|
|
648
|
+
linhas.push(p.linhaRemoto(r.remoto, curtoOuTraco(r.remotaAntes), curtoOuTraco(r.remota)));
|
|
649
|
+
// O PR ja mesclado no HEAD com a branch apagada no remoto nao tem push a provar: a linha some.
|
|
650
|
+
if (!r.dryRun && r.acao !== 'recusada' && (r.pushVerificado || r.remota !== null)) {
|
|
651
|
+
linhas.push(r.pushVerificado ? p.linhaPushProvado : p.linhaPushSemProva);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
// O MR do GitLab se reconhece pelos passos, que dizem a CLI de cada forja.
|
|
655
|
+
if (r.pr)
|
|
656
|
+
linhas.push(p.linhaPr(r.pr.numero, r.pr.criado, r.pr.url ?? '', r.passos.some((x) => x.startsWith('glab '))));
|
|
657
|
+
if (r.corpo)
|
|
658
|
+
linhas.push(p.linhaCorpo(r.corpo));
|
|
659
|
+
if (r.acao === 'recusada')
|
|
660
|
+
linhas.push(m.bloqueado(r.motivo ?? '-'), m.detalhe((0, locale_1.remontar)(r.detalhe)));
|
|
661
|
+
else {
|
|
662
|
+
linhas.push(p.resultado(p.acoes[r.acao] ?? r.acao));
|
|
663
|
+
if (r.detalhe)
|
|
664
|
+
linhas.push(m.detalhe((0, locale_1.remontar)(r.detalhe)));
|
|
665
|
+
}
|
|
666
|
+
if (r.correcao)
|
|
667
|
+
linhas.push(m.correcao((0, locale_1.remontar)(r.correcao)));
|
|
668
|
+
if (r.passos.length) {
|
|
669
|
+
linhas.push(m.evidencia);
|
|
670
|
+
for (const passo of r.passos)
|
|
671
|
+
linhas.push(` ${(0, locale_1.remontar)(passo)}`);
|
|
672
|
+
}
|
|
673
|
+
return linhas;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* O PR que vale para a pista: o aberto mais novo, senao o mesclado no HEAD, senao o mais novo da branch quando ele foi
|
|
677
|
+
* fechado sem merge. O mesclado de outro head e de uma entrega anterior (A1 da revisao): nao vale para a ponta nova.
|
|
678
|
+
*/
|
|
679
|
+
function prDaBranchNaLista(prs, branch, head) {
|
|
680
|
+
const daBranch = prs.filter((x) => x.branch === branch).sort((a, b) => b.numero - a.numero);
|
|
681
|
+
const aberto = daBranch.find((x) => x.estado === 'aberto');
|
|
682
|
+
if (aberto)
|
|
683
|
+
return aberto;
|
|
684
|
+
const mesclado = daBranch.find((x) => x.estado === 'mesclado' && x.head === head);
|
|
685
|
+
if (mesclado)
|
|
686
|
+
return mesclado;
|
|
687
|
+
return daBranch[0]?.estado === 'fechado' ? daBranch[0] : null;
|
|
688
|
+
}
|
|
689
|
+
function entregaLocal(raiz, f, remotas, remoto, base) {
|
|
690
|
+
const remota = remotas?.get(f.branch) ?? null;
|
|
691
|
+
const ships = f.eventos.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido);
|
|
692
|
+
const entregue = (!!f.head && ships.some((e) => e.shaDe === f.head || e.mergeSha === f.head)) || (!f.comProduto && ships.length > 0);
|
|
693
|
+
const merge = f.head ? (0, entrega_pr_1.mergeDaEntrega)(raiz, f.t.id, remoto, base) : null;
|
|
694
|
+
const mergeSemRegistro = !!merge && !ships.some((e) => e.mergeSha === merge.mergeSha);
|
|
695
|
+
// So entra na pista quem ja esta na entrega: passou do CHECK (ciclo sem CHECK: o turno acabou) com produto, publicou,
|
|
696
|
+
// tem merge sem registro ou ja foi entregue e espera o MASTER.
|
|
697
|
+
const passouDoCheck = f.check.estado === 'nao-se-aplica' ? !f.conducao : f.checkPassou;
|
|
698
|
+
const naEntrega = (passouDoCheck && f.comProduto) || (!!remota && f.comProduto) || mergeSemRegistro || entregue;
|
|
699
|
+
return { remota, entregue, merge, mergeSemRegistro, naEntrega };
|
|
700
|
+
}
|
|
701
|
+
/** Quantas branches a pista confere uma a uma no GitLab por chamada; as outras ficam "sem conferir". */
|
|
702
|
+
const MRS_CONFERIDOS_POR_LEITURA = 20;
|
|
703
|
+
/** Os MRs das branches candidatas, uma leitura por branch; a primeira que falha deixa a lista sem leitura. */
|
|
704
|
+
function lerMrsDasCandidatas(pedidos, base, candidatas) {
|
|
705
|
+
const prs = [], semConferir = [];
|
|
706
|
+
for (const [i, branch] of [...new Set(candidatas)].entries()) {
|
|
707
|
+
if (i >= MRS_CONFERIDOS_POR_LEITURA) {
|
|
708
|
+
semConferir.push(branch);
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const lidos = pedidos.listar(base, branch);
|
|
712
|
+
if (lidos.erro !== null)
|
|
713
|
+
return { erro: lidos.erro };
|
|
714
|
+
prs.push(...lidos.prs);
|
|
715
|
+
}
|
|
716
|
+
return { prs, semConferir };
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* A etapa `ci` do MR aberto pela CI do head. O mesmo mapa do rollup do GitHub: `success` e `bloqueado` (`manual`,
|
|
720
|
+
* `skipped`) sao verdes, vermelho e falhou, pendente e ausente esperam, e a leitura que falhou nao e lida.
|
|
721
|
+
*/
|
|
722
|
+
function etapaDaCiNoHead(ci, contexto, pr) {
|
|
723
|
+
const c = (m) => m.ship.publicar;
|
|
724
|
+
if (ci.state === 'success' || (ci.state === 'failure' && ci.bloqueado)) {
|
|
725
|
+
return etapa('ci', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).ciVerde(contexto, curto(pr.head))));
|
|
726
|
+
}
|
|
727
|
+
if (ci.state === 'failure')
|
|
728
|
+
return etapa('ci', 'falhou', (0, locale_1.textoDoCatalogo)((m) => c(m).ciVermelho(contexto, pr.numero, true)));
|
|
729
|
+
if (ci.state === 'pending')
|
|
730
|
+
return etapa('ci', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).ciEsperando(contexto, pr.numero, true)));
|
|
731
|
+
if (ci.state === 'missing')
|
|
732
|
+
return etapa('ci', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).ciSemCheck(contexto, pr.numero, true)));
|
|
733
|
+
return etapa('ci', 'nao-lida', ci.detail);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* O GitLab do remoto, quando e ele; `null` deixa a pista no caminho do GitHub de sempre. `erro` quando o remoto e do
|
|
737
|
+
* GitLab (pelo bloco `forja:` ou pelo host conhecido) e a forja nao resolveu: a pista diz "sem leitura", nunca "sem MR".
|
|
738
|
+
*/
|
|
739
|
+
function gitlabDaPista(carregado, remoto, opcoes) {
|
|
740
|
+
if (opcoes.forja)
|
|
741
|
+
return null;
|
|
742
|
+
if (opcoes.forjaResolvida)
|
|
743
|
+
return opcoes.forjaResolvida.tipo === 'gitlab' ? opcoes.forjaResolvida : null;
|
|
744
|
+
// So o remoto que ja se sabe do GitLab, sem rede, passa pela resolucao aqui; o host proprio sem tipo e resolvido
|
|
745
|
+
// uma vez pela pista, como o pulse o resolveria, e o resto segue pelo caminho do GitHub.
|
|
746
|
+
if (tipoSemRede(carregado, remoto) !== 'gitlab')
|
|
747
|
+
return null;
|
|
748
|
+
const r = (0, entrega_pr_1.forjaDaEntrega)(carregado, remoto, opcoes.sondas);
|
|
749
|
+
if (r.ok)
|
|
750
|
+
return r.valor.tipo === 'gitlab' ? r.valor : null;
|
|
751
|
+
return r.erro ? { erro: r.erro } : null;
|
|
752
|
+
}
|
|
753
|
+
/** O que a pista de uma thread diz, das leituras ja feitas. */
|
|
754
|
+
function pistaDaThread(carregado, f, local, leitura) {
|
|
755
|
+
const { t } = f;
|
|
756
|
+
const gl = leitura.tipo === 'gitlab';
|
|
757
|
+
const raiz = carregado.raiz;
|
|
758
|
+
const { remota, entregue, merge, mergeSemRegistro } = local;
|
|
759
|
+
const pr = leitura.prs ? prDaBranchNaLista(leitura.prs, f.branch, f.head) : null;
|
|
760
|
+
const prMesclado = pr?.estado === 'mesclado' && pr.head === f.head;
|
|
761
|
+
if (!(local.naEntrega || !!pr) || !f.head)
|
|
762
|
+
return null;
|
|
763
|
+
const c = (m) => m.ship.publicar;
|
|
764
|
+
const publicavel = exports.MODOS_QUE_PUBLICAM.includes(t.modo);
|
|
765
|
+
// A branch no remoto. A3 da revisao: o sha do remoto que esta copia nem conhece tambem e divergencia.
|
|
766
|
+
let branchEtapa;
|
|
767
|
+
if (!leitura.remotasLidas)
|
|
768
|
+
branchEtapa = etapa('branch', 'nao-lida', (0, locale_1.textoDoCatalogo)((m) => c(m).remotoNaoLido(leitura.remoto)));
|
|
769
|
+
else if (remota === f.head)
|
|
770
|
+
branchEtapa = etapa('branch', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).branchPublicada(curto(f.head))));
|
|
771
|
+
else if (!remota)
|
|
772
|
+
branchEtapa = etapa('branch', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).branchNaoPublicada));
|
|
773
|
+
else if (remotoContido(raiz, remota, f.head) === false) {
|
|
774
|
+
branchEtapa = etapa('branch', 'falhou', (0, locale_1.textoDoCatalogo)((m) => c(m).remotoDivergiu(leitura.remoto, f.branch, curto(remota))));
|
|
775
|
+
}
|
|
776
|
+
else
|
|
777
|
+
branchEtapa = etapa('branch', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).commitsSemPush(curto(remota), curto(f.head))));
|
|
778
|
+
// O PR, o CI e o conflito.
|
|
779
|
+
const corte = leitura.corte(f.branch);
|
|
780
|
+
let prEtapa, ciEtapa, conflitoEtapa;
|
|
781
|
+
if (!leitura.prs) {
|
|
782
|
+
prEtapa = etapa('pr', 'nao-lida', (0, locale_1.textoDoCatalogo)((m) => c(m).prsNaoLidos(leitura.prsNaoLidos ?? '-')));
|
|
783
|
+
ciEtapa = etapa('ci', 'nao-lida', (0, locale_1.textoDoCatalogo)((m) => c(m).prsNaoLidos(leitura.prsNaoLidos ?? '-')));
|
|
784
|
+
conflitoEtapa = etapa('conflito', 'nao-lida', (0, locale_1.textoDoCatalogo)((m) => c(m).prsNaoLidos(leitura.prsNaoLidos ?? '-')));
|
|
785
|
+
}
|
|
786
|
+
else if ((!pr || pr.estado === 'fechado') && corte) {
|
|
787
|
+
// A7 da revisao: a lista dos abertos cortada, ou a branch sem conferir nesta leitura, nao diz "sem PR" (a R1 do pulse).
|
|
788
|
+
const texto = (0, locale_1.textoDoCatalogo)((m) => corte === 'parcial' ? c(m).prsCortados(parado_no_condutor_1.LIMITE_DE_PRS) : c(m).branchSemConferir);
|
|
789
|
+
prEtapa = etapa('pr', 'nao-lida', texto);
|
|
790
|
+
ciEtapa = etapa('ci', 'nao-lida', texto);
|
|
791
|
+
conflitoEtapa = etapa('conflito', 'nao-lida', texto);
|
|
792
|
+
}
|
|
793
|
+
else if (!pr || pr.estado === 'fechado') {
|
|
794
|
+
prEtapa = etapa('pr', 'pendente', pr ? (0, locale_1.textoDoCatalogo)((m) => c(m).prFechado(pr.numero, gl)) : (0, locale_1.textoDoCatalogo)((m) => c(m).semPr));
|
|
795
|
+
ciEtapa = etapa('ci', leitura.ciExigido ? 'pendente' : 'nao-se-aplica', (0, locale_1.textoDoCatalogo)((m) => leitura.ciExigido ? c(m).ciSemPr : c(m).ciNaoExigido));
|
|
796
|
+
conflitoEtapa = etapa('conflito', 'nao-se-aplica', (0, locale_1.textoDoCatalogo)((m) => c(m).conflitoSemPr));
|
|
797
|
+
}
|
|
798
|
+
else if (pr.estado === 'mesclado') {
|
|
799
|
+
prEtapa = etapa('pr', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).prMesclado(pr.numero, gl)));
|
|
800
|
+
ciEtapa = etapa('ci', 'nao-se-aplica', (0, locale_1.textoDoCatalogo)((m) => c(m).ciDoMesclado));
|
|
801
|
+
conflitoEtapa = etapa('conflito', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).prMesclado(pr.numero, gl)));
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
prEtapa = etapa('pr', 'feita', (0, locale_1.textoDoCatalogo)((m) => pr.rascunho ? c(m).prRascunho(pr.numero, gl) : c(m).prAberto(pr.numero, gl)));
|
|
805
|
+
const check = pr.checks.find((k) => k.nome === leitura.contexto);
|
|
806
|
+
ciEtapa = !leitura.ciExigido ? etapa('ci', 'nao-se-aplica', (0, locale_1.textoDoCatalogo)((m) => c(m).ciNaoExigido))
|
|
807
|
+
: leitura.ciDoPedido ? leitura.ciDoPedido(pr)
|
|
808
|
+
: !check ? etapa('ci', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).ciSemCheck(leitura.contexto, pr.numero, gl)))
|
|
809
|
+
: check.situacao === 'verde' ? etapa('ci', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).ciVerde(leitura.contexto, curto(pr.head))))
|
|
810
|
+
: check.situacao === 'vermelho' ? etapa('ci', 'falhou', (0, locale_1.textoDoCatalogo)((m) => c(m).ciVermelho(leitura.contexto, pr.numero, gl)))
|
|
811
|
+
: etapa('ci', 'pendente', (0, locale_1.textoDoCatalogo)((m) => c(m).ciEsperando(leitura.contexto, pr.numero, gl)));
|
|
812
|
+
conflitoEtapa = pr.conflito === true ? etapa('conflito', 'falhou', (0, locale_1.textoDoCatalogo)((m) => c(m).conflito(pr.numero, gl)))
|
|
813
|
+
: pr.conflito === false ? etapa('conflito', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).semConflito))
|
|
814
|
+
: etapa('conflito', 'nao-lida', (0, locale_1.textoDoCatalogo)((m) => c(m).conflitoNaoCalculado));
|
|
815
|
+
}
|
|
816
|
+
const entregaEtapa = entregue ? etapa('entrega', 'feita', (0, locale_1.textoDoCatalogo)((m) => c(m).entregue))
|
|
817
|
+
: etapa('entrega', 'pendente', (0, locale_1.textoDoCatalogo)((m) => mergeSemRegistro ? c(m).mergeSemRegistro(curto(merge?.mergeSha)) : c(m).semShipDone));
|
|
818
|
+
// O proximo passo, a primeira regra que vale.
|
|
819
|
+
const corpo = corpoDaThread(raiz, t.id);
|
|
820
|
+
const nada = (texto, comando = null) => ({ acao: null, disponivel: false, texto, comando });
|
|
821
|
+
let proximo;
|
|
822
|
+
if (entregue)
|
|
823
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => c(m).proximoEntregue));
|
|
824
|
+
else if (mergeSemRegistro || prMesclado) {
|
|
825
|
+
proximo = { acao: 'registrar', disponivel: true, texto: (0, locale_1.textoDoCatalogo)((m) => c(m).proximoRegistrar), comando: `ork ship registrar-pr ${t.id}` };
|
|
826
|
+
}
|
|
827
|
+
else if (f.conducao) {
|
|
828
|
+
const sessao = f.conducao.sessao ? f.conducao.sessao.slice(0, 8) : f.conducao.canal;
|
|
829
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => c(m).proximoConduzida(sessao)), `ork conducao status ${t.id}`);
|
|
830
|
+
}
|
|
831
|
+
else if (f.check.estado === 'pendente')
|
|
832
|
+
proximo = nada(f.check.texto, (0, locale_1.textoDoCatalogo)((m) => c(m).comandoDoCheck(t.id)));
|
|
833
|
+
else if (f.verify.estado === 'pendente')
|
|
834
|
+
proximo = nada(f.verify.texto, `ork verify ${t.id}`);
|
|
835
|
+
else if (f.bundle.estado === 'pendente')
|
|
836
|
+
proximo = nada(f.bundle.texto, `ork ci prepare ${t.id}`);
|
|
837
|
+
else if (branchEtapa.estado === 'falhou')
|
|
838
|
+
proximo = nada(branchEtapa.texto, null);
|
|
839
|
+
else if (branchEtapa.estado === 'nao-lida')
|
|
840
|
+
proximo = nada(branchEtapa.texto, `ork ship pista ${t.id}`);
|
|
841
|
+
else if (branchEtapa.estado === 'pendente' || (prEtapa.estado === 'pendente')) {
|
|
842
|
+
proximo = publicavel
|
|
843
|
+
? { acao: 'publicar', disponivel: true, comando: `ork ship publicar ${t.id}`,
|
|
844
|
+
texto: (0, locale_1.textoDoCatalogo)((m) => pr?.estado === 'aberto' ? c(m).proximoPublicarNoPr(pr.numero, gl) : c(m).proximoPublicar) }
|
|
845
|
+
: { acao: 'publicar', disponivel: false, texto: (0, locale_1.textoDoCatalogo)((m) => c(m).proximoDoDono(t.id, (0, modos_1.tagDoModo)(t.modo))),
|
|
846
|
+
comando: comandoDoDono(leitura.remoto, leitura.base, f.branch, tituloDoPr(t, corpo?.texto ?? null), corpo ? path.relative(raiz, corpo.arquivo) : null, leitura.tipo) };
|
|
847
|
+
}
|
|
848
|
+
else if (prEtapa.estado === 'nao-lida')
|
|
849
|
+
proximo = nada(prEtapa.texto, `ork ship pista ${t.id}`);
|
|
850
|
+
else if (conflitoEtapa.estado === 'falhou')
|
|
851
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => c(m).proximoConflito(pr?.numero ?? 0, gl)));
|
|
852
|
+
else if (ciEtapa.estado === 'falhou')
|
|
853
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => c(m).proximoCiVermelho(leitura.contexto, pr?.numero ?? 0, gl)));
|
|
854
|
+
else if (ciEtapa.estado === 'pendente' || ciEtapa.estado === 'nao-lida') {
|
|
855
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => c(m).proximoEsperandoCi(leitura.contexto, pr?.numero ?? 0, gl)), pr ? `ork ci status --sha ${pr.head}` : null);
|
|
856
|
+
}
|
|
857
|
+
else
|
|
858
|
+
proximo = nada((0, locale_1.textoDoCatalogo)((m) => pr?.rascunho ? c(m).proximoRascunho(pr.numero, gl) : c(m).proximoMerge(pr?.numero ?? 0, gl)));
|
|
859
|
+
return {
|
|
860
|
+
thread: t.id, nome: t.nome, modo: t.modo, tag: (0, modos_1.tagDoModo)(t.modo), publicavel, conduzida: !!f.conducao, branch: f.branch, head: f.head,
|
|
861
|
+
remota, pr: pr ? { numero: pr.numero, url: pr.url, estado: pr.estado, rascunho: pr.rascunho, head: pr.head } : null,
|
|
862
|
+
etapas: [f.check, f.verify, f.bundle, branchEtapa, prEtapa, ciEtapa, conflitoEtapa, entregaEtapa], proximo,
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
/** `ork ship pista [<thread>]`: as etapas e o proximo passo de cada thread aberta que ja esta na entrega. Nao grava nada. */
|
|
866
|
+
function pistaDeEntrega(carregado, opcoes = {}) {
|
|
867
|
+
const raiz = carregado.raiz, base = carregado.manifesto.worktree.base_branch;
|
|
868
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
|
|
869
|
+
const lidoEm = opcoes.quando ?? new Date().toISOString();
|
|
870
|
+
const contexto = carregado.manifesto.ci.context || 'ork-verify';
|
|
871
|
+
const ciExigido = carregado.manifesto.ci.required_for_ship === true;
|
|
872
|
+
const refs = (0, parado_no_condutor_1.refsLocais)(raiz, remoto);
|
|
873
|
+
const baseRef = refDaBase(refs, remoto, base);
|
|
874
|
+
const ids = opcoes.thread ? [opcoes.thread] : (0, thread_1.listarIds)(raiz);
|
|
875
|
+
const fatos = [];
|
|
876
|
+
for (const id of ids) {
|
|
877
|
+
let t;
|
|
878
|
+
try {
|
|
879
|
+
t = (0, thread_1.lerThread)(raiz, id);
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
if (opcoes.thread)
|
|
883
|
+
throw new Error(`ship.pista: a thread ${id} nao existe`);
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
if (t.status === 'fechada')
|
|
887
|
+
continue;
|
|
888
|
+
fatos.push(fatosDaThread(carregado, t, refs, baseRef, lidoEm));
|
|
889
|
+
}
|
|
890
|
+
const comBranch = fatos.filter((f) => f.head && (0, branch_de_estado_1.branchValida)(f.branch));
|
|
891
|
+
const remotas = comBranch.length ? pontasNoRemoto(raiz, remoto) : new Map();
|
|
892
|
+
const locais = new Map(fatos.map((f) => [f.t.id, entregaLocal(raiz, f, remotas, remoto, base)]));
|
|
893
|
+
// A7 da revisao: so a branch da thread que ja esta na entrega pelo que se le sem a forja vai a leitura dos PRs, que
|
|
894
|
+
// confere uma a uma a que nao aparece nas listas; sem nenhuma, a forja nem e lida.
|
|
895
|
+
const candidatas = comBranch.filter((f) => locais.get(f.t.id)?.naEntrega === true).map((f) => f.branch);
|
|
896
|
+
let prs = [];
|
|
897
|
+
let prsNaoLidos = null;
|
|
898
|
+
let parcial = false;
|
|
899
|
+
let semConferir = new Set();
|
|
900
|
+
let ciDoPedido;
|
|
901
|
+
let prsNaoLidosDoGitlab = false;
|
|
902
|
+
let doHostProprio;
|
|
903
|
+
if (candidatas.length) {
|
|
904
|
+
let gitlab = gitlabDaPista(carregado, remoto, opcoes);
|
|
905
|
+
// Host proprio sem o bloco `forja:` (um GitLab como o de um piloto, ou um GitHub Enterprise): a forja e resolvida uma
|
|
906
|
+
// vez, como o pulse a resolve, e a leitura segue pela forja certa, com o mesmo criterio do gate no GitLab.
|
|
907
|
+
let naoResolvida = null;
|
|
908
|
+
if (!gitlab && !opcoes.forja && !opcoes.forjaResolvida && tipoSemRede(carregado, remoto) === null) {
|
|
909
|
+
const lido = (0, parado_no_condutor_1.forjaDoRemotoDoPulse)(carregado, remoto, { executor: opcoes.executorGh, sondas: opcoes.sondas });
|
|
910
|
+
if (!lido.ok)
|
|
911
|
+
naoResolvida = lido.erro;
|
|
912
|
+
else if (lido.forja.tipo === 'gitlab')
|
|
913
|
+
gitlab = lido.forja;
|
|
914
|
+
else
|
|
915
|
+
doHostProprio = lido.forja;
|
|
916
|
+
}
|
|
917
|
+
if (naoResolvida !== null) {
|
|
918
|
+
prs = null;
|
|
919
|
+
prsNaoLidos = (0, texto_1.deFora)(naoResolvida);
|
|
920
|
+
}
|
|
921
|
+
else if (gitlab && 'erro' in gitlab) {
|
|
922
|
+
prs = null;
|
|
923
|
+
prsNaoLidos = (0, locale_1.textoDoCatalogo)((m) => m.forja.motivo(gitlab.erro, 'gitlab'));
|
|
924
|
+
prsNaoLidosDoGitlab = true;
|
|
925
|
+
}
|
|
926
|
+
else if (gitlab) {
|
|
927
|
+
const lidos = lerMrsDasCandidatas(pedidosDoGitlab(gitlab, opcoes.api ?? {}), base, candidatas);
|
|
928
|
+
if ('erro' in lidos) {
|
|
929
|
+
prs = null;
|
|
930
|
+
prsNaoLidos = (0, texto_1.deFora)(lidos.erro);
|
|
931
|
+
}
|
|
932
|
+
else {
|
|
933
|
+
prs = lidos.prs;
|
|
934
|
+
semConferir = new Set(lidos.semConferir);
|
|
935
|
+
}
|
|
936
|
+
const ciDoHead = opcoes.ciDoHead ?? ((sha) => (0, ci_1.consultarCi)(carregado, sha, remoto, undefined, undefined, opcoes.sondas, opcoes.api));
|
|
937
|
+
ciDoPedido = (pr) => etapaDaCiNoHead(ciDoHead(pr.head), contexto, pr);
|
|
938
|
+
}
|
|
939
|
+
else {
|
|
940
|
+
const fixada = opcoes.forja ?? (opcoes.forjaResolvida?.tipo === 'github'
|
|
941
|
+
? { host: (0, cli_1.hostDaApi)(opcoes.forjaResolvida), repositorio: opcoes.forjaResolvida.repo } : undefined);
|
|
942
|
+
const leitura = (0, parado_no_condutor_1.lerPrsDaForja)(carregado, { quando: lidoEm, executor: opcoes.executorGh, remoto, candidatas, forja: fixada,
|
|
943
|
+
resolvida: doHostProprio, sondas: opcoes.sondas });
|
|
944
|
+
if (leitura.ok) {
|
|
945
|
+
prs = leitura.retrato.prs;
|
|
946
|
+
parcial = leitura.retrato.parcial;
|
|
947
|
+
semConferir = new Set(leitura.retrato.semConferir ?? []);
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
prs = null;
|
|
951
|
+
prsNaoLidos = (0, texto_1.deFora)(leitura.erro);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
const tipo = ciDoPedido || prsNaoLidosDoGitlab ? 'gitlab' : doHostProprio ? 'github'
|
|
956
|
+
: tipoSemRede(carregado, remoto, opcoes.forja ? 'github' : opcoes.forjaResolvida?.tipo);
|
|
957
|
+
// S8 da revisao (rodada 2): a candidata sem nenhum PR na leitura foi conferida uma a uma pelo `--head`, que a lista
|
|
958
|
+
// cortada nao limita; so a que nao foi conferida, ou que so tem PR achado na lista cortada, fica em duvida.
|
|
959
|
+
const comPrNaLeitura = new Set((prs ?? []).map((x) => x.branch));
|
|
960
|
+
const conferida = (branch) => candidatas.includes(branch) && !comPrNaLeitura.has(branch);
|
|
961
|
+
const corte = (branch) => (semConferir.has(branch) ? 'sem-conferir'
|
|
962
|
+
: parcial && !conferida(branch) ? 'parcial' : null);
|
|
963
|
+
const pistas = fatos.flatMap((f) => {
|
|
964
|
+
const local = locais.get(f.t.id);
|
|
965
|
+
const x = local ? pistaDaThread(carregado, f, local, { remoto, base, remotasLidas: remotas !== null, prs, prsNaoLidos, corte, ciExigido, contexto, tipo, ciDoPedido })
|
|
966
|
+
: null;
|
|
967
|
+
return x ? [x] : [];
|
|
968
|
+
});
|
|
969
|
+
return { contrato: exports.CONTRATO_DA_PISTA, lidoEm, base, remoto, remotoLido: remotas !== null, prsLidos: prs !== null, prsNaoLidos,
|
|
970
|
+
ciExigido, contextoDoCi: contexto, pistas };
|
|
971
|
+
}
|