@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,420 @@
|
|
|
1
|
+
// O cálculo do Radar de Colisão (RM-059, fatia F3; ficha M10 do plano dos mods). Módulo puro: escolhe as threads
|
|
2
|
+
// da rodada, monta o argv e o ambiente de cada comando, lê as saídas do git, cruza os conflitos com os leases e
|
|
3
|
+
// acha as colisões novas. Nenhum `$` passa por aqui; as chamadas ficam no register.tsx. Do git, só `ls-remote`
|
|
4
|
+
// e `merge-tree` com diretório de objetos temporário (D6 do dono e D2 da thread); o `fetch` fica com o núcleo.
|
|
5
|
+
import type { RadarArquivo, RadarBase, RadarCelula, RadarLease, RadarMapa, RadarThread } from '../types'
|
|
6
|
+
|
|
7
|
+
/** O lado da base nos pares; `@` não cabe em id de thread, então não colide com nenhuma. */
|
|
8
|
+
export const BASE = '@main'
|
|
9
|
+
export const NOME_DA_BASE = 'origin/main'
|
|
10
|
+
/** D7: a `origin/main` local, conferida contra a `main` do `origin`. */
|
|
11
|
+
export const REF_DA_BASE = 'refs/remotes/origin/main'
|
|
12
|
+
export const REMOTO = 'origin'
|
|
13
|
+
export const REF_REMOTA = 'refs/heads/main'
|
|
14
|
+
/** D7: no máximo 12 threads por rodada, na ordem das fases mais perto do SHIP; a fase MASTER fica fora. */
|
|
15
|
+
export const TETO_DE_THREADS = 12
|
|
16
|
+
export const ORDEM_DAS_FASES: readonly string[] = ['SHIP', 'CHECK', 'GO', 'PLAN', 'GOAL']
|
|
17
|
+
export const FASES_FORA = ['MASTER']
|
|
18
|
+
/** A rodada do relógio, a cada 10 min (ficha M10). */
|
|
19
|
+
export const PERIODO_DA_RODADA_MS = 600000
|
|
20
|
+
/** D12: os tetos de cada comando, o orçamento de `merge-tree` por rodada e o tamanho do cache. */
|
|
21
|
+
export const PRAZO_LOCAL_MS = 5000
|
|
22
|
+
export const PRAZO_DO_REMOTO_MS = 15000
|
|
23
|
+
export const PRAZO_DO_MERGE_MS = 20000
|
|
24
|
+
export const ORCAMENTO_DO_MERGE_MS = 60000
|
|
25
|
+
export const TETO_DO_CACHE = 256
|
|
26
|
+
/** Quantas leituras de `thread.status` saem ao mesmo tempo, e até quantas páginas da seção `leases` a rodada lê. */
|
|
27
|
+
export const LEITURAS_EM_PARALELO = 4
|
|
28
|
+
export const TETO_DE_PAGINAS_DE_LEASES = 10
|
|
29
|
+
/** D5: o temporário fica no `/tmp`, com o nome do Radar e 8 caracteres do `mktemp`. */
|
|
30
|
+
export const MODELO_DO_TEMPORARIO = '/tmp/ork-radar.XXXXXXXX'
|
|
31
|
+
/** Quantos arquivos de um par a linha do conflito mostra antes de resumir. */
|
|
32
|
+
export const ARQUIVOS_POR_LINHA = 5
|
|
33
|
+
|
|
34
|
+
const ROTULOS = '123456789abcdefghijklmnopqrstuvwxyz'
|
|
35
|
+
const ID_DE_THREAD = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/
|
|
36
|
+
const SLUG = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,159}$/
|
|
37
|
+
const BRANCH_DO_ORK = /^ork\/[a-zA-Z0-9][a-zA-Z0-9._/-]{0,199}$/
|
|
38
|
+
/** SHA de commit ou de árvore, em SHA-1 ou SHA-256. */
|
|
39
|
+
const SHA = /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/
|
|
40
|
+
const TEMPORARIO = /^\/tmp\/ork-radar\.[A-Za-z0-9]{8}$/
|
|
41
|
+
const NUL = String.fromCharCode(0)
|
|
42
|
+
/** O ambiente de todo git do Radar: nunca pergunta credencial no terminal. */
|
|
43
|
+
export const AMBIENTE_DO_GIT: Readonly<Record<string, string>> = { GIT_TERMINAL_PROMPT: '0' }
|
|
44
|
+
|
|
45
|
+
export type ThreadDaLista = { id: string; slug: string; fase: string }
|
|
46
|
+
export type Escolha = { threads: ThreadDaLista[]; omitidas: number }
|
|
47
|
+
|
|
48
|
+
function posicaoDaFase(fase: string): number {
|
|
49
|
+
const i = ORDEM_DAS_FASES.indexOf(fase)
|
|
50
|
+
return i < 0 ? ORDEM_DAS_FASES.length : i
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** As threads abertas da consulta `thread.list`, na ordem da rodada e até o teto; a fase MASTER fica fora (D7). */
|
|
54
|
+
export function threadsDaLista(json: unknown, teto = TETO_DE_THREADS): Escolha {
|
|
55
|
+
const lista = (json as { threads?: unknown } | null)?.threads
|
|
56
|
+
if (!Array.isArray(lista)) throw new Error('a lista das threads abertas veio sem threads')
|
|
57
|
+
const validas: ThreadDaLista[] = []
|
|
58
|
+
const vistas = new Set<string>()
|
|
59
|
+
for (const bruto of lista) {
|
|
60
|
+
const t = (bruto ?? {}) as { id?: unknown; slug?: unknown; fase?: unknown; status?: unknown }
|
|
61
|
+
if (typeof t.id !== 'string' || !ID_DE_THREAD.test(t.id) || vistas.has(t.id)) continue
|
|
62
|
+
if (typeof t.slug !== 'string' || !SLUG.test(t.slug) || t.slug.includes('..')) continue
|
|
63
|
+
if (t.status === 'fechada') continue
|
|
64
|
+
const fase = typeof t.fase === 'string' ? t.fase : ''
|
|
65
|
+
if (FASES_FORA.includes(fase)) continue
|
|
66
|
+
vistas.add(t.id)
|
|
67
|
+
validas.push({ id: t.id, slug: t.slug, fase })
|
|
68
|
+
}
|
|
69
|
+
validas.sort((x, y) => posicaoDaFase(x.fase) - posicaoDaFase(y.fase) || (x.id < y.id ? -1 : x.id > y.id ? 1 : 0))
|
|
70
|
+
return { threads: validas.slice(0, teto), omitidas: Math.max(0, validas.length - teto) }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** O nome curto da thread no mapa: de 1 a 9, depois letras. */
|
|
74
|
+
export function rotuloDe(i: number): string {
|
|
75
|
+
return ROTULOS[i] ?? '?'
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A branch canônica da thread pelo slug, como o núcleo a cria (`ork/<slug>`). */
|
|
79
|
+
export function refDaThread(slug: string): string {
|
|
80
|
+
return `refs/heads/ork/${slug}`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** A branch pelo `base.branch` da consulta `thread.status`, só quando começa com `ork/` (`branchDaWorktree` do núcleo). */
|
|
84
|
+
export function refDoStatus(json: unknown): string | null {
|
|
85
|
+
const b = (json as { base?: { branch?: unknown } } | null)?.base?.branch
|
|
86
|
+
if (typeof b !== 'string' || !BRANCH_DO_ORK.test(b) || b.includes('..') || b.includes('//') || b.endsWith('/') || b.endsWith('.lock')) return null
|
|
87
|
+
return `refs/heads/${b}`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A branch canônica da thread, com a regra do núcleo (`branchDaWorktree` de `core/src/worktree.ts`): a ref do
|
|
92
|
+
* `base.branch` quando ele começa com `ork/` (`refDoStatus`), senão `ork/<slug>`.
|
|
93
|
+
*/
|
|
94
|
+
export function branchCanonica(refPeloStatus: string | null, slug: string): string {
|
|
95
|
+
return refPeloStatus ?? refDaThread(slug)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** O `ls-remote` no próprio repositório: o SHA da base e o de cada branch pedida, sem escrever nada. */
|
|
99
|
+
export function argvDoLsRemoteLocal(refs: readonly string[]): string[] {
|
|
100
|
+
return ['git', 'ls-remote', '.', REF_DA_BASE, ...refs]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** O `ls-remote` no `origin`: só o SHA da `main` remota, para saber se a base local ficou para trás (D4). */
|
|
104
|
+
export function argvDoLsRemoteRemoto(): string[] {
|
|
105
|
+
return ['git', 'ls-remote', REMOTO, REF_REMOTA]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** As linhas `<sha> <ref>` do `ls-remote`; linha que não tem essa forma fica de fora. */
|
|
109
|
+
export function lerLsRemote(stdout: string): Record<string, string> {
|
|
110
|
+
const shas: Record<string, string> = {}
|
|
111
|
+
for (const linha of stdout.split('\n')) {
|
|
112
|
+
const [sha, ref, sobra] = linha.trim().split(/\s+/)
|
|
113
|
+
if (sha && ref && sobra === undefined && SHA.test(sha) && ref.startsWith('refs/')) shas[ref] = sha
|
|
114
|
+
}
|
|
115
|
+
return shas
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** O diretório de objetos temporário da rodada (D5). */
|
|
119
|
+
export function argvDoTemporario(): string[] {
|
|
120
|
+
return ['mktemp', '-d', MODELO_DO_TEMPORARIO]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** O caminho que o `mktemp` devolveu, só quando é um temporário do Radar; senão null. */
|
|
124
|
+
export function temporarioValido(saida: unknown): string | null {
|
|
125
|
+
if (typeof saida !== 'string') return null
|
|
126
|
+
const caminho = saida.trim()
|
|
127
|
+
return TEMPORARIO.test(caminho) ? caminho : null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** O `rm` do temporário da rodada; recusa qualquer outro caminho. */
|
|
131
|
+
export function argvDeApagar(temporario: string): string[] {
|
|
132
|
+
if (temporarioValido(temporario) !== temporario) throw new Error('o Radar só apaga o próprio temporário')
|
|
133
|
+
return ['rm', '-rf', '--', temporario]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Junta pasta e nome com uma barra só. */
|
|
137
|
+
export function juntar(pasta: string, nome: string): string {
|
|
138
|
+
return pasta.replace(/\/+$/, '') + '/' + nome.replace(/^\/+/, '')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Resolve `.` e `..` de um caminho absoluto, sem tocar o disco. */
|
|
142
|
+
export function normalizar(caminho: string): string {
|
|
143
|
+
const partes: string[] = []
|
|
144
|
+
for (const p of caminho.split('/')) {
|
|
145
|
+
if (p === '' || p === '.') continue
|
|
146
|
+
if (p === '..') partes.pop()
|
|
147
|
+
else partes.push(p)
|
|
148
|
+
}
|
|
149
|
+
return '/' + partes.join('/')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** O `gitdir:` do arquivo `.git` de uma worktree vinculada, absoluto; null se o texto não tem essa linha. */
|
|
153
|
+
export function gitdirDoArquivo(texto: string, raiz: string): string | null {
|
|
154
|
+
const linha = texto.split('\n').map(l => l.trim()).find(l => l.startsWith('gitdir:'))
|
|
155
|
+
const alvo = linha?.slice('gitdir:'.length).trim()
|
|
156
|
+
if (!alvo) return null
|
|
157
|
+
return normalizar(alvo.startsWith('/') ? alvo : juntar(raiz, alvo))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Os objetos do repositório: o `commondir` da worktree vinculada (relativo ao gitdir) ou o próprio gitdir. */
|
|
161
|
+
export function objetosDoComum(gitdir: string, commondir: string | null): string {
|
|
162
|
+
const comum = commondir?.trim()
|
|
163
|
+
const base = !comum ? gitdir : comum.startsWith('/') ? comum : juntar(gitdir, comum)
|
|
164
|
+
return juntar(normalizar(base), 'objects')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** O `merge-tree` de um par, só com SHAs: sem worktree e com os arquivos em conflito pelo nome. */
|
|
168
|
+
export function argvDoMergeTree(a: string, b: string): string[] {
|
|
169
|
+
if (!SHA.test(a) || !SHA.test(b)) throw new Error('o merge-tree do Radar só recebe SHA')
|
|
170
|
+
return ['git', 'merge-tree', '--write-tree', '--name-only', '-z', '--no-messages', a, b]
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Um caminho na lista do `GIT_ALTERNATE_OBJECT_DIRECTORIES`, que o git separa por `:`: com `:`, aspas, barra
|
|
175
|
+
* invertida ou quebra de linha, vai entre aspas no estilo C, que o git desfaz (entrada que começa com aspas).
|
|
176
|
+
*/
|
|
177
|
+
export function caminhoDoAlternativo(caminho: string): string {
|
|
178
|
+
if (!/[:"\\\n]/.test(caminho)) return caminho
|
|
179
|
+
return '"' + caminho.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* O ambiente do `merge-tree`: objetos novos no temporário, os do repositório só como alternativo (D2 e D3), e
|
|
184
|
+
* nenhum fetch preguiçoso de clone parcial (`GIT_NO_LAZY_FETCH`): o `fetch` fica com o núcleo.
|
|
185
|
+
*/
|
|
186
|
+
export function ambienteDoMerge(temporario: string, objetos: string): Record<string, string> {
|
|
187
|
+
return {
|
|
188
|
+
...AMBIENTE_DO_GIT, GIT_NO_LAZY_FETCH: '1', GIT_OBJECT_DIRECTORY: temporario,
|
|
189
|
+
GIT_ALTERNATE_OBJECT_DIRECTORIES: caminhoDoAlternativo(objetos),
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type Resultado = { estado: 'limpa' } | { estado: 'conflito'; arquivos: string[] } | { estado: 'erro'; erro: string }
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* A saída do `merge-tree`: 0 com a árvore no começo é par limpo; 1 com a árvore no começo é conflito, com os
|
|
197
|
+
* arquivos depois dela; o resto é erro. A saída 1 sozinha não basta: ref que não existe também sai 1, sem árvore.
|
|
198
|
+
*/
|
|
199
|
+
export function lerMergeTree(r: { exitCode: number; stdout: string; stderr: string }): Resultado {
|
|
200
|
+
const partes = String(r.stdout ?? '').split(NUL)
|
|
201
|
+
const temArvore = SHA.test(partes[0] ?? '')
|
|
202
|
+
if (temArvore && r.exitCode === 0) return { estado: 'limpa' }
|
|
203
|
+
if (temArvore && r.exitCode === 1) {
|
|
204
|
+
const arquivos = [...new Set(partes.slice(1).filter(p => p !== ''))].sort()
|
|
205
|
+
if (arquivos.length > 0) return { estado: 'conflito', arquivos }
|
|
206
|
+
return { estado: 'erro', erro: 'o merge-tree acusou conflito sem arquivo' }
|
|
207
|
+
}
|
|
208
|
+
const primeira = String(r.stderr ?? '').trim().split('\n')[0]?.trim().slice(0, 200)
|
|
209
|
+
return { estado: 'erro', erro: primeira || `o merge-tree saiu ${r.exitCode}` }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A chave de um par ou de um par de SHAs: os dois lados em ordem. */
|
|
213
|
+
export function chaveDoPar(a: string, b: string): string {
|
|
214
|
+
return a < b ? `${a}|${b}` : `${b}|${a}`
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export type Par = { a: string; b: string; shaA: string; shaB: string }
|
|
218
|
+
|
|
219
|
+
/** Os pares da rodada: cada thread com SHA contra a base, depois cada par de threads com SHA, na ordem do mapa. */
|
|
220
|
+
export function paresDaRodada(threads: readonly RadarThread[], shaDaBase: string | null): Par[] {
|
|
221
|
+
const com = threads.filter(t => t.sha !== null)
|
|
222
|
+
const pares: Par[] = []
|
|
223
|
+
if (shaDaBase !== null) for (const t of com) pares.push({ a: t.id, b: BASE, shaA: t.sha as string, shaB: shaDaBase })
|
|
224
|
+
for (let i = 0; i < com.length; i++) {
|
|
225
|
+
for (let j = i + 1; j < com.length; j++) {
|
|
226
|
+
const x = com[i] as RadarThread
|
|
227
|
+
const y = com[j] as RadarThread
|
|
228
|
+
pares.push({ a: x.id, b: y.id, shaA: x.sha as string, shaB: y.sha as string })
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return pares
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Guarda um resultado no cache pelo par de SHAs; acima do teto sai o mais antigo (D12). Erro não entra. */
|
|
235
|
+
export function guardarNoCache(cache: Map<string, Resultado>, chave: string, r: Resultado, teto = TETO_DO_CACHE): void {
|
|
236
|
+
if (r.estado === 'erro') return
|
|
237
|
+
cache.delete(chave)
|
|
238
|
+
cache.set(chave, r)
|
|
239
|
+
while (cache.size > teto) {
|
|
240
|
+
const primeira = cache.keys().next()
|
|
241
|
+
if (primeira.done) break
|
|
242
|
+
cache.delete(primeira.value)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export type LeaseDePath = { glob: string; thread: string }
|
|
247
|
+
|
|
248
|
+
/** Os leases `path:<glob>` ativos da seção `leases` do retrato, com a thread que segura cada um (D1 e D10). */
|
|
249
|
+
export function leasesDoRetrato(retrato: unknown): LeaseDePath[] {
|
|
250
|
+
const itens = (retrato as { sections?: { leases?: { items?: unknown } } } | null)?.sections?.leases?.items
|
|
251
|
+
if (!Array.isArray(itens)) throw new Error('o retrato veio sem a seção leases')
|
|
252
|
+
const leases: LeaseDePath[] = []
|
|
253
|
+
for (const bruto of itens) {
|
|
254
|
+
const x = (bruto ?? {}) as { id?: unknown; status?: unknown; refs?: unknown }
|
|
255
|
+
if (typeof x.id !== 'string' || !x.id.startsWith('path:') || x.status !== 'active') continue
|
|
256
|
+
const refs = Array.isArray(x.refs) ? x.refs as Array<{ kind?: unknown; id?: unknown }> : []
|
|
257
|
+
const thread = refs.find(r => r && r.kind === 'thread' && typeof r.id === 'string' && ID_DE_THREAD.test(r.id))?.id
|
|
258
|
+
const glob = x.id.slice('path:'.length).trim()
|
|
259
|
+
if (typeof thread === 'string' && glob !== '') leases.push({ glob, thread })
|
|
260
|
+
}
|
|
261
|
+
return leases
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export type PaginaDeLeases = { leases: LeaseDePath[]; proximo: number | null; lacuna: string | null }
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Uma página da seção `leases` do retrato (até 50 itens): os leases `path:` ativos, o offset da página seguinte
|
|
268
|
+
* (`coverage.nextOffset`) e o que veio faltando. Seção indisponível não traz lease nenhum, e isso vira lacuna.
|
|
269
|
+
*/
|
|
270
|
+
export function paginaDosLeases(retrato: unknown): PaginaDeLeases {
|
|
271
|
+
type Secao = { state?: unknown; gaps?: unknown; coverage?: { nextOffset?: unknown } }
|
|
272
|
+
const secao = (retrato as { sections?: { leases?: Secao } } | null)?.sections?.leases
|
|
273
|
+
if (!secao || typeof secao !== 'object') throw new Error('o retrato veio sem a seção leases')
|
|
274
|
+
const faltas = Array.isArray(secao.gaps) ? secao.gaps.filter((g): g is string => typeof g === 'string') : []
|
|
275
|
+
const detalhe = faltas.length > 0 ? ` (${faltas.join(', ')})` : ''
|
|
276
|
+
if (secao.state === 'unavailable') return { leases: [], proximo: null, lacuna: `a seção leases veio indisponível${detalhe}` }
|
|
277
|
+
const seguinte = secao.coverage?.nextOffset
|
|
278
|
+
const proximo = typeof seguinte === 'number' && Number.isInteger(seguinte) && seguinte > 0 ? seguinte : null
|
|
279
|
+
return { leases: leasesDoRetrato(retrato), proximo, lacuna: faltas.length > 0 ? `a seção leases veio com lacunas${detalhe}` : null }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** O glob de um lease `path:` como regex, com a mesma regra do núcleo (`globParaRegex` de `core/src/leases.ts`). */
|
|
283
|
+
export function globParaRegex(glob: string): RegExp {
|
|
284
|
+
let re = ''
|
|
285
|
+
for (let i = 0; i < glob.length; i++) {
|
|
286
|
+
const c = glob[i] as string
|
|
287
|
+
if (c === '*') {
|
|
288
|
+
if (glob[i + 1] === '*') {
|
|
289
|
+
re += '.*'
|
|
290
|
+
i++
|
|
291
|
+
if (glob[i + 1] === '/') i++
|
|
292
|
+
} else re += '[^/]*'
|
|
293
|
+
} else if (c === '?') re += '[^/]'
|
|
294
|
+
else re += c.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
295
|
+
}
|
|
296
|
+
return new RegExp(`^${re}$`)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Os leases que cobrem um arquivo em conflito. */
|
|
300
|
+
export function leasesDoArquivo(caminho: string, leases: readonly LeaseDePath[]): RadarLease[] {
|
|
301
|
+
return leases.filter(l => globParaRegex(l.glob).test(caminho)).map(l => ({ lease: `path:${l.glob}`, thread: l.thread }))
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** A célula de um par: o resultado do `merge-tree` (null quando ficou para a próxima rodada) e os leases de cada arquivo. */
|
|
305
|
+
export function celulaDoPar(par: { a: string; b: string }, r: Resultado | null, leases: readonly LeaseDePath[], motivo?: string): RadarCelula {
|
|
306
|
+
const base = { par: chaveDoPar(par.a, par.b), a: par.a, b: par.b }
|
|
307
|
+
if (r === null) return { ...base, estado: 'pendente', arquivos: [], erro: motivo ?? 'não calculado nesta rodada' }
|
|
308
|
+
if (r.estado === 'erro') return { ...base, estado: 'erro', arquivos: [], erro: r.erro }
|
|
309
|
+
if (r.estado === 'limpa') return { ...base, estado: 'limpa', arquivos: [], erro: null }
|
|
310
|
+
const arquivos: RadarArquivo[] = r.arquivos.map(caminho => ({ caminho, leases: leasesDoArquivo(caminho, leases) }))
|
|
311
|
+
return { ...base, estado: 'conflito', arquivos, erro: null }
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** A base do mapa: o SHA local e o que o remoto disse (D4: sem `fetch`, só os dois SHAs). */
|
|
315
|
+
export function baseDoMapa(shaLocal: string | null, remoto: { sha: string | null; erro: string | null }): RadarBase {
|
|
316
|
+
const situacao = remoto.sha === null ? 'nao-conferida' : remoto.sha === shaLocal ? 'igual' : 'diferente'
|
|
317
|
+
return { ref: REF_DA_BASE, sha: shaLocal, remoto: remoto.sha, situacao, erroRemoto: remoto.erro }
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** As colisões de um mapa, uma por par e arquivo. */
|
|
321
|
+
export function colisoesDoMapa(m: RadarMapa): string[] {
|
|
322
|
+
return m.celulas.flatMap(c => (c.estado === 'conflito' ? c.arquivos.map(a => `${c.par}|${a.caminho}`) : []))
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** As colisões da rodada anterior pelo mapa guardado (depois de uma recarga do módulo); null sem rodada anterior. */
|
|
326
|
+
export function anterioresDoMapa(m: RadarMapa): Set<string> | null {
|
|
327
|
+
return m.lidoEm === null ? null : new Set(colisoesDoMapa(m))
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Os pares com colisão nova (D6): par com algum arquivo em conflito que não estava na rodada anterior da sessão.
|
|
332
|
+
* Na primeira rodada (`anteriores` null), toda colisão é nova.
|
|
333
|
+
*/
|
|
334
|
+
export function paresComColisaoNova(anteriores: ReadonlySet<string> | null, m: RadarMapa): string[] {
|
|
335
|
+
const pares: string[] = []
|
|
336
|
+
for (const c of m.celulas) {
|
|
337
|
+
if (c.estado !== 'conflito') continue
|
|
338
|
+
if (anteriores === null || c.arquivos.some(a => !anteriores.has(`${c.par}|${a.caminho}`))) pares.push(c.par)
|
|
339
|
+
}
|
|
340
|
+
return pares
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Como um lado do par aparece para o dono. */
|
|
344
|
+
export function nomeDoLado(id: string): string {
|
|
345
|
+
return id === BASE ? NOME_DA_BASE : id
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** O comando que resolve um conflito, como texto (D10): o Radar nunca o roda. */
|
|
349
|
+
export function comandoQueResolve(c: Pick<RadarCelula, 'a' | 'b'>): string {
|
|
350
|
+
if (c.b === BASE) return `ork worktree sync ${c.a} --dry-run`
|
|
351
|
+
if (c.a === BASE) return `ork worktree sync ${c.b} --dry-run`
|
|
352
|
+
return `a que entregar depois roda: ork worktree sync <${c.a} ou ${c.b}> --dry-run`
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Um arquivo em conflito com os leases que o cobrem. */
|
|
356
|
+
export function textoDoArquivo(a: RadarArquivo): string {
|
|
357
|
+
if (a.leases.length === 0) return a.caminho
|
|
358
|
+
return `${a.caminho} (${a.leases.map(l => `lease ${l.lease} de ${l.thread}`).join(', ')})`
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** Os arquivos de um par, os primeiros 5 por inteiro e o resto contado. */
|
|
362
|
+
export function textoDosArquivos(c: Pick<RadarCelula, 'arquivos'>): string {
|
|
363
|
+
const mostrados = c.arquivos.slice(0, ARQUIVOS_POR_LINHA).map(textoDoArquivo).join(', ')
|
|
364
|
+
const resto = c.arquivos.length - ARQUIVOS_POR_LINHA
|
|
365
|
+
return resto > 0 ? `${mostrados} e mais ${resto}` : mostrados
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Uma contagem com o substantivo no número certo. */
|
|
369
|
+
export function contar(n: number, singular: string, plural: string): string {
|
|
370
|
+
return `${n} ${n === 1 ? singular : plural}`
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** O SHA curto, como o git mostra. */
|
|
374
|
+
export function curto(sha: string | null): string {
|
|
375
|
+
return sha === null ? '?' : sha.slice(0, 7)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** A situação da base numa frase (D4). */
|
|
379
|
+
export function textoDaBase(b: RadarBase): string {
|
|
380
|
+
if (b.sha === null) return `sem ${NOME_DA_BASE} local`
|
|
381
|
+
if (b.situacao === 'igual') return `${NOME_DA_BASE} ${curto(b.sha)}, igual ao remoto`
|
|
382
|
+
if (b.situacao === 'diferente') return `${NOME_DA_BASE} ${curto(b.sha)}, diferente do remoto (${curto(b.remoto)}): a conta vale até o fetch do núcleo`
|
|
383
|
+
return `${NOME_DA_BASE} ${curto(b.sha)}, remoto não conferido${b.erroRemoto ? ` (${b.erroRemoto})` : ''}`
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* A linha de quando nenhum par está em conflito: "nenhuma colisão" sozinho só quando todo par foi calculado; com
|
|
388
|
+
* par em erro ou que ficou para a próxima rodada, diz quantos foram calculados.
|
|
389
|
+
*/
|
|
390
|
+
export function textoSemColisao(m: Pick<RadarMapa, 'celulas'>): string {
|
|
391
|
+
const total = m.celulas.length
|
|
392
|
+
const limpas = m.celulas.filter(c => c.estado === 'limpa').length
|
|
393
|
+
if (total === 0) return 'Nenhum par para calcular'
|
|
394
|
+
if (limpas === total) return `Nenhuma colisão: ${contar(limpas, 'par limpo', 'pares limpos')}`
|
|
395
|
+
if (limpas === 0) return 'Nenhum par calculado nesta rodada'
|
|
396
|
+
return `Nenhuma colisão entre os pares calculados (${limpas} de ${total})`
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** O resumo do mapa que o `/radar` devolve: base, colisões com arquivos e comando, e o que ficou de fora. */
|
|
400
|
+
export function resumoDoMapa(m: RadarMapa): string {
|
|
401
|
+
if (m.lidoEm === null) return `Radar de Colisão: ainda sem rodada${m.erro ? ` (${m.erro})` : ''}.`
|
|
402
|
+
const linhas: string[] = []
|
|
403
|
+
const omitidas = m.omitidas > 0 ? ` (mais ${m.omitidas} fora do teto)` : ''
|
|
404
|
+
linhas.push(`Radar de Colisão: ${contar(m.threads.length, 'thread aberta', 'threads abertas')}${omitidas}; base ${textoDaBase(m.base)}.`)
|
|
405
|
+
if (m.erro) linhas.push(`A rodada parou: ${m.erro}.`)
|
|
406
|
+
const conflitos = m.celulas.filter(c => c.estado === 'conflito')
|
|
407
|
+
for (const c of conflitos) {
|
|
408
|
+
linhas.push(`- ${nomeDoLado(c.a)} × ${nomeDoLado(c.b)}: ${textoDosArquivos(c)}; resolve: ${comandoQueResolve(c)}`)
|
|
409
|
+
}
|
|
410
|
+
const limpas = m.celulas.filter(c => c.estado === 'limpa').length
|
|
411
|
+
if (conflitos.length === 0 && !m.erro) linhas.push(`${textoSemColisao(m)}.`)
|
|
412
|
+
else if (!m.erro) linhas.push(`${contar(conflitos.length, 'par em conflito', 'pares em conflito')} e ${contar(limpas, 'limpo', 'limpos')}.`)
|
|
413
|
+
for (const c of m.celulas.filter(x => x.estado === 'erro')) linhas.push(`Erro em ${nomeDoLado(c.a)} × ${nomeDoLado(c.b)}: ${c.erro}`)
|
|
414
|
+
const pendentes = m.celulas.filter(c => c.estado === 'pendente').length
|
|
415
|
+
if (pendentes > 0) linhas.push(`${pendentes === 1 ? '1 par ficou' : `${pendentes} pares ficaram`} para a próxima rodada.`)
|
|
416
|
+
const semBranch = m.threads.filter(t => t.sha === null).map(t => t.id)
|
|
417
|
+
if (semBranch.length > 0) linhas.push(`Sem branch local: ${semBranch.join(', ')}.`)
|
|
418
|
+
for (const l of m.lacunas) linhas.push(`Lacuna: ${l}.`)
|
|
419
|
+
return linhas.join('\n')
|
|
420
|
+
}
|