@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,270 @@
|
|
|
1
|
+
// Os arquivos tocados num lote e as claims que eles afetam (RM-059, F2, T2.2). Modulo puro: le a saida do
|
|
2
|
+
// `git status`, compara fotos, junta os caminhos das ferramentas de escrita do lote e casa os caminhos com as
|
|
3
|
+
// claims e com os `touch_paths` do plano. As chamadas ao `$` ficam no register.ts.
|
|
4
|
+
import type { FreioClaim, FreioFoto, FreioPedido, FreioVigia } from '../types'
|
|
5
|
+
|
|
6
|
+
/** O `git status` da foto (D4): HEAD, sem renomeacao (vira saida e entrada) e com cada arquivo novo listado. */
|
|
7
|
+
export const ARGV_DO_STATUS: readonly string[] = ['git', 'status', '--porcelain=v2', '--branch', '-z', '--no-renames', '--untracked-files=all']
|
|
8
|
+
export const TETO_DO_STATUS_MS = 10000
|
|
9
|
+
/** Caminhos sujos com `stat` por foto; acima disso, so o codigo XY entra na assinatura. */
|
|
10
|
+
export const TETO_DE_STAT = 300
|
|
11
|
+
/** Nome-base menor que isto nao casa com comando (D5). */
|
|
12
|
+
export const MINIMO_DO_NOME_BASE = 3
|
|
13
|
+
|
|
14
|
+
/** As ferramentas que escrevem um arquivo e o campo do caminho no `tool_input`. */
|
|
15
|
+
const ESCRITA: Readonly<Record<string, string>> = { Edit: 'file_path', Write: 'file_path', MultiEdit: 'file_path', NotebookEdit: 'notebook_path' }
|
|
16
|
+
/** Ferramentas que so leem: o lote feito so delas nao roda o `git status` (D4). */
|
|
17
|
+
export const FERRAMENTAS_DE_LEITURA: readonly string[] = [
|
|
18
|
+
'Read', 'Grep', 'Glob', 'LS', 'NotebookRead', 'WebFetch', 'WebSearch', 'ToolSearch',
|
|
19
|
+
'TaskCreate', 'TaskGet', 'TaskList', 'TaskUpdate', 'TaskOutput',
|
|
20
|
+
'mcp__orkastery__ork_thread_status', 'mcp__orkastery__ork_artifact_read', 'mcp__orkastery__ork_claims_list',
|
|
21
|
+
'mcp__orkastery__ork_git_status', 'mcp__orkastery__ork_phase_list', 'mcp__orkastery__ork_hitl_pending',
|
|
22
|
+
'mcp__orkastery__ork_observe',
|
|
23
|
+
]
|
|
24
|
+
const EXTENSOES_DE_CODIGO = new Set(['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'mts', 'cts'])
|
|
25
|
+
/** O CLI de claims dentro de um comando do `Bash` (pelo `ork` ou pelo `index.js` do CLI): o lote mexeu nas claims. */
|
|
26
|
+
const CLI_DE_CLAIMS = /(?:\bork|\bindex\.js)\s+claims\s+(?:add|retirar|verificar)\b/
|
|
27
|
+
/** Caminhos fora dos `touch_paths` citados por extenso num aviso; o resto vai pela contagem (D8). */
|
|
28
|
+
export const TETO_DE_CAMINHOS_NO_AVISO = 20
|
|
29
|
+
|
|
30
|
+
/** Uma chamada do lote como o `classic.PostToolBatch` a entrega. */
|
|
31
|
+
export type Chamada = { tool_name?: unknown; tool_input?: unknown }
|
|
32
|
+
export type EntradaDoStatus = { caminho: string; xy: string }
|
|
33
|
+
|
|
34
|
+
/** Pasta e caminho relativo com uma barra so. */
|
|
35
|
+
export function juntar(pasta: string, rel: string): string {
|
|
36
|
+
return pasta.replace(/\/+$/, '') + '/' + rel.replace(/^\/+/, '')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A saida de `git status --porcelain=v2 --branch -z`: o HEAD (`# branch.oid`, `null` antes do primeiro commit)
|
|
41
|
+
* e cada caminho sujo com o codigo XY. Entrada renomeada (`2`) pula o caminho de origem; nova vem como `??`.
|
|
42
|
+
*/
|
|
43
|
+
export function lerStatus(saida: string): { head: string | null; entradas: EntradaDoStatus[] } {
|
|
44
|
+
let head: string | null = null
|
|
45
|
+
const entradas: EntradaDoStatus[] = []
|
|
46
|
+
const registros = saida.split('\0')
|
|
47
|
+
for (let i = 0; i < registros.length; i++) {
|
|
48
|
+
const r = registros[i] as string
|
|
49
|
+
if (r.startsWith('# branch.oid ')) {
|
|
50
|
+
const oid = r.slice('# branch.oid '.length).trim()
|
|
51
|
+
head = /^[0-9a-f]{7,64}$/.test(oid) ? oid : null
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
const campos = r.split(' ')
|
|
55
|
+
const xy = campos[1] ?? ''
|
|
56
|
+
if (r.startsWith('1 ') && campos.length >= 9) entradas.push({ caminho: campos.slice(8).join(' '), xy })
|
|
57
|
+
else if (r.startsWith('2 ') && campos.length >= 10) { entradas.push({ caminho: campos.slice(9).join(' '), xy }); i++ }
|
|
58
|
+
else if (r.startsWith('u ') && campos.length >= 11) entradas.push({ caminho: campos.slice(10).join(' '), xy })
|
|
59
|
+
else if (r.startsWith('? ') && r.length > 2) entradas.push({ caminho: r.slice(2), xy: '??' })
|
|
60
|
+
}
|
|
61
|
+
return { head, entradas }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A assinatura de um caminho sujo: o XY e, com `stat`, o tamanho e o `mtimeMs` (D4). */
|
|
65
|
+
export function assinatura(xy: string, stat: { size?: unknown; mtimeMs?: unknown } | null | undefined, comStat: boolean): string {
|
|
66
|
+
if (!comStat) return xy
|
|
67
|
+
return stat && typeof stat.size === 'number' && typeof stat.mtimeMs === 'number' ? `${xy}|${stat.size}|${stat.mtimeMs}` : `${xy}|ausente`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Duas assinaturas do mesmo caminho dizem mudanca. A que ficou so com o XY (acima do teto de `stat`) nao se
|
|
72
|
+
* compara pelo `stat` da outra: o caminho que passa a borda do teto sem mudar nao vira tocado.
|
|
73
|
+
*/
|
|
74
|
+
export function mudou(antes: string | undefined, agora: string): boolean {
|
|
75
|
+
if (antes === undefined) return true
|
|
76
|
+
if (antes === agora) return false
|
|
77
|
+
const [xyAntes, ...statAntes] = antes.split('|')
|
|
78
|
+
const [xyAgora, ...statAgora] = agora.split('|')
|
|
79
|
+
return xyAntes !== xyAgora || (statAntes.length > 0 && statAgora.length > 0)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Os caminhos que mudaram entre duas fotos (D4): novo na lista, com assinatura diferente, ou que saiu da lista
|
|
84
|
+
* com o HEAD parado (reversao). Saida da lista com HEAD novo foi commit e nao conta. Sem foto anterior, nada.
|
|
85
|
+
*/
|
|
86
|
+
export function diferenca(antes: FreioFoto | null, agora: FreioFoto): string[] {
|
|
87
|
+
if (!antes) return []
|
|
88
|
+
const tocados = new Set<string>()
|
|
89
|
+
for (const [caminho, sig] of Object.entries(agora.caminhos)) if (mudou(antes.caminhos[caminho], sig)) tocados.add(caminho)
|
|
90
|
+
if (antes.head === agora.head) for (const caminho of Object.keys(antes.caminhos)) if (!(caminho in agora.caminhos)) tocados.add(caminho)
|
|
91
|
+
return [...tocados].sort()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** O caminho relativo a raiz da sessao, ou `null` quando ele fica fora dela ou nao e caminho. */
|
|
95
|
+
export function relativo(caminho: unknown, raiz: string): string | null {
|
|
96
|
+
if (typeof caminho !== 'string' || caminho.trim() === '') return null
|
|
97
|
+
const base = raiz.replace(/\/+$/, '')
|
|
98
|
+
let rel = caminho.trim()
|
|
99
|
+
if (rel.startsWith('/')) {
|
|
100
|
+
if (!rel.startsWith(base + '/')) return null
|
|
101
|
+
rel = rel.slice(base.length + 1)
|
|
102
|
+
}
|
|
103
|
+
rel = rel.replace(/^(?:\.\/)+/, '')
|
|
104
|
+
const partes = rel.split('/')
|
|
105
|
+
return rel !== '' && !partes.some(p => p === '' || p === '.' || p === '..') ? rel : null
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const nomeDa = (c: Chamada) => (typeof c?.tool_name === 'string' ? c.tool_name : '')
|
|
109
|
+
|
|
110
|
+
/** Os caminhos que as ferramentas de escrita do lote citam, dentro da raiz, sem repeticao. */
|
|
111
|
+
export function caminhosDoLote(chamadas: readonly Chamada[], raiz: string): string[] {
|
|
112
|
+
const achados = new Set<string>()
|
|
113
|
+
for (const c of chamadas) {
|
|
114
|
+
const campo = ESCRITA[nomeDa(c)]
|
|
115
|
+
if (!campo) continue
|
|
116
|
+
const rel = relativo((c.tool_input as Record<string, unknown> | null)?.[campo], raiz)
|
|
117
|
+
if (rel) achados.add(rel)
|
|
118
|
+
}
|
|
119
|
+
return [...achados].sort()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** O lote so tem ferramentas de leitura (ou nenhuma chamada): nao ha o que fotografar. */
|
|
123
|
+
export function soLeitura(chamadas: readonly Chamada[]): boolean {
|
|
124
|
+
return chamadas.every(c => FERRAMENTAS_DE_LEITURA.includes(nomeDa(c)))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** O lote registrou, retirou ou mudou claim: a lista do nucleo precisa ser relida. */
|
|
128
|
+
export function mexeuNasClaims(chamadas: readonly Chamada[]): boolean {
|
|
129
|
+
return chamadas.some(c => nomeDa(c) === 'mcp__orkastery__ork_claim_add'
|
|
130
|
+
|| (nomeDa(c) === 'Bash' && CLI_DE_CLAIMS.test(String((c.tool_input as { command?: unknown } | null)?.command ?? ''))))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** O lote regravou um artefato de fase: o plano precisa ser relido. */
|
|
134
|
+
export function mexeuNoPlano(chamadas: readonly Chamada[]): boolean {
|
|
135
|
+
return chamadas.some(c => nomeDa(c) === 'mcp__orkastery__ork_artifact_write')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const fronteira = (c: string) => c === '' || /[\s'"=:(),;|&<>]/.test(c)
|
|
139
|
+
|
|
140
|
+
/** O texto cita `alvo` com fronteira dos dois lados. */
|
|
141
|
+
function cita(texto: string, alvo: string, antes: (c: string) => boolean): boolean {
|
|
142
|
+
for (let i = texto.indexOf(alvo); i >= 0; i = texto.indexOf(alvo, i + 1)) {
|
|
143
|
+
if (antes(i === 0 ? '' : (texto[i - 1] as string)) && fronteira(texto[i + alvo.length] ?? '')) return true
|
|
144
|
+
}
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** O comando cita o caminho inteiro, com ou sem `./` na frente (D5, forca 2). */
|
|
149
|
+
export function citaCaminho(comando: string, caminho: string): boolean {
|
|
150
|
+
return cita(comando, caminho, fronteira) || cita(comando, './' + caminho, fronteira)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* O comando cita o mesmo nome-base de um fonte TS ou JS, com extensao de codigo (D5, forca 1): pega o teste
|
|
155
|
+
* compilado (`core/test/x.test.ts` contra `core/dist-test/test/x.test.js`). Nome-base curto nao casa.
|
|
156
|
+
*/
|
|
157
|
+
export function citaNomeBase(comando: string, caminho: string): boolean {
|
|
158
|
+
const base = caminho.slice(caminho.lastIndexOf('/') + 1)
|
|
159
|
+
const ponto = base.lastIndexOf('.')
|
|
160
|
+
if (ponto <= 0 || !EXTENSOES_DE_CODIGO.has(base.slice(ponto + 1))) return false
|
|
161
|
+
const nome = base.slice(0, ponto)
|
|
162
|
+
if (nome.length < MINIMO_DO_NOME_BASE) return false
|
|
163
|
+
const alvo = nome + '.'
|
|
164
|
+
for (let i = comando.indexOf(alvo); i >= 0; i = comando.indexOf(alvo, i + 1)) {
|
|
165
|
+
const antes = i === 0 ? '' : (comando[i - 1] as string)
|
|
166
|
+
if (antes !== '/' && !fronteira(antes)) continue
|
|
167
|
+
let j = i + alvo.length
|
|
168
|
+
while (j < comando.length && /[a-z]/.test(comando[j] as string)) j++
|
|
169
|
+
if (EXTENSOES_DE_CODIGO.has(comando.slice(i + alvo.length, j)) && fronteira(comando[j] ?? '')) return true
|
|
170
|
+
}
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const numero = (id: string) => Number(id.slice(1)) || 0
|
|
175
|
+
|
|
176
|
+
/** Ordem da fila: a forca maior antes; na mesma forca, a claim mais nova antes. */
|
|
177
|
+
function ordenar(pedidos: FreioPedido[]): FreioPedido[] {
|
|
178
|
+
return pedidos.sort((a, b) => b.forca - a.forca || numero(b.id) - numero(a.id))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* As claims que os caminhos tocados afetam, com a forca e os caminhos de cada uma (D5). Claim sem comando fica de
|
|
183
|
+
* fora: a conferencia so diria que ela nao tem como ser verificada.
|
|
184
|
+
*/
|
|
185
|
+
export function claimsAfetadas(claims: readonly FreioClaim[], tocados: readonly string[]): FreioPedido[] {
|
|
186
|
+
const afetadas: FreioPedido[] = []
|
|
187
|
+
for (const c of claims) {
|
|
188
|
+
if (c.comandos.length === 0) continue
|
|
189
|
+
let forca = 0
|
|
190
|
+
const caminhos: string[] = []
|
|
191
|
+
for (const t of tocados) {
|
|
192
|
+
const f = c.arquivo === t ? 3 : c.comandos.some(cmd => citaCaminho(cmd, t)) ? 2 : c.comandos.some(cmd => citaNomeBase(cmd, t)) ? 1 : 0
|
|
193
|
+
if (f > 0) { caminhos.push(t); forca = Math.max(forca, f) }
|
|
194
|
+
}
|
|
195
|
+
if (forca > 0) afetadas.push({ id: c.id, forca, caminhos })
|
|
196
|
+
}
|
|
197
|
+
return ordenar(afetadas)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** A fila com as claims novas, sem repeticao: a claim que ja esta nela junta os caminhos e fica com a forca maior. */
|
|
201
|
+
export function enfileirar(fila: readonly FreioPedido[], afetadas: readonly FreioPedido[]): FreioPedido[] {
|
|
202
|
+
const porId = new Map(fila.map(p => [p.id, { ...p, caminhos: [...p.caminhos] }]))
|
|
203
|
+
for (const a of afetadas) {
|
|
204
|
+
const ja = porId.get(a.id)
|
|
205
|
+
if (!ja) { porId.set(a.id, { ...a, caminhos: [...a.caminhos] }); continue }
|
|
206
|
+
ja.forca = Math.max(ja.forca, a.forca)
|
|
207
|
+
for (const c of a.caminhos) if (!ja.caminhos.includes(c)) ja.caminhos.push(c)
|
|
208
|
+
}
|
|
209
|
+
return ordenar([...porId.values()])
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** O caminho casa com um `touch_path`: caminho exato ou pasta (com ou sem barra no fim), `*` sem barra e `**` (D9). */
|
|
213
|
+
export function casaTouchPath(caminho: string, padrao: string): boolean {
|
|
214
|
+
const p = padrao.replace(/\/+$/, '')
|
|
215
|
+
if (p === '') return false
|
|
216
|
+
if (!p.includes('*')) return caminho === p || caminho.startsWith(p + '/')
|
|
217
|
+
let fonte = '^'
|
|
218
|
+
for (let i = 0; i < p.length; i++) {
|
|
219
|
+
const c = p[i] as string
|
|
220
|
+
if (c === '*') {
|
|
221
|
+
if (p[i + 1] === '*') { fonte += '.*'; i++ } else fonte += '[^/]*'
|
|
222
|
+
} else fonte += /[.+?^${}()|[\]\\]/.test(c) ? '\\' + c : c
|
|
223
|
+
}
|
|
224
|
+
return new RegExp(fonte + '$').test(caminho)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Os caminhos tocados fora da uniao dos `touch_paths` do plano; plano sem `touch_paths` nao avisa nada (D9). */
|
|
228
|
+
export function foraDosTouchPaths(tocados: readonly string[], touchPaths: readonly string[] | null): string[] {
|
|
229
|
+
if (!touchPaths || touchPaths.length === 0) return []
|
|
230
|
+
return tocados.filter(t => !touchPaths.some(p => casaTouchPath(t, p)))
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A vigia de uma thread antes da primeira foto. */
|
|
234
|
+
export function vigiaVazia(thread: string): FreioVigia {
|
|
235
|
+
return { thread, foto: null, seq: 0, toques: {}, fila: [], avisadosFora: [], foraPendentes: [] }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* O que um lote faz na vigia: foto nova, toques, claims afetadas na fila e os caminhos novos fora dos `touch_paths`,
|
|
240
|
+
* guardados uma vez cada para o aviso do laco principal (o lote de subagente toca, mas nao recebe o aviso).
|
|
241
|
+
*/
|
|
242
|
+
export function aplicarLote(v: FreioVigia, lote: { foto: FreioFoto | null; doLote: readonly string[]; claims: readonly FreioClaim[] | null; touchPaths: readonly string[] | null }):
|
|
243
|
+
{ vigia: FreioVigia; tocados: string[]; afetadas: FreioPedido[]; fora: string[] } {
|
|
244
|
+
const tocados = [...new Set([...lote.doLote, ...(lote.foto ? diferenca(v.foto, lote.foto) : [])])].sort()
|
|
245
|
+
const seq = v.seq + 1
|
|
246
|
+
const toques = { ...v.toques }
|
|
247
|
+
for (const t of tocados) toques[t] = seq
|
|
248
|
+
const afetadas = lote.claims ? claimsAfetadas(lote.claims, tocados) : []
|
|
249
|
+
const fora = foraDosTouchPaths(tocados, lote.touchPaths).filter(c => !v.avisadosFora.includes(c))
|
|
250
|
+
return {
|
|
251
|
+
vigia: {
|
|
252
|
+
...v, foto: lote.foto ?? v.foto, seq, toques, fila: enfileirar(v.fila, afetadas),
|
|
253
|
+
avisadosFora: [...v.avisadosFora, ...fora], foraPendentes: [...(v.foraPendentes ?? []), ...fora],
|
|
254
|
+
},
|
|
255
|
+
tocados, afetadas, fora,
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Tira os caminhos fora dos `touch_paths` ainda nao avisados, para o lote do laco principal devolver. */
|
|
260
|
+
export function tomarFora(v: FreioVigia): { vigia: FreioVigia; fora: string[] } {
|
|
261
|
+
return { vigia: { ...v, foraPendentes: [] }, fora: v.foraPendentes ?? [] }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** O aviso de `touch_paths` para o modelo, com teto de caminhos; sem caminho novo fora do plano, nenhum texto. */
|
|
265
|
+
export function textoDoFora(fora: readonly string[]): string {
|
|
266
|
+
if (fora.length === 0) return ''
|
|
267
|
+
const citados = fora.slice(0, TETO_DE_CAMINHOS_NO_AVISO).join(', ')
|
|
268
|
+
const resto = fora.length > TETO_DE_CAMINHOS_NO_AVISO ? ` e mais ${fora.length - TETO_DE_CAMINHOS_NO_AVISO}` : ''
|
|
269
|
+
return `Freio de Lote: o lote mexeu fora dos touch_paths do plano: ${citados}${resto}.`
|
|
270
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// O Freio de Lote (RM-059, fatia F2). Na sessao de fase, acha as claims que o lote de ferramentas mexeu, pede
|
|
2
|
+
// ao nucleo a conferencia delas no sandbox do verify (`ork claims conferir`) e devolve o que quebrou no lote
|
|
3
|
+
// seguinte. Nunca para o laco agentico, nunca roda comando de claim, nunca grava estado de claim e nunca fala
|
|
4
|
+
// pelo dono. A logica fica nos modulos puros ao lado; aqui so as chamadas ao `$`, sempre escritas como
|
|
5
|
+
// `x.noun.metodo(...)`, como o validador exige.
|
|
6
|
+
import type { EngineInterface, Register } from 'claude-code'
|
|
7
|
+
import type { FreioCarga, FreioFoto, FreioVigia } from '../types'
|
|
8
|
+
import {
|
|
9
|
+
argsDaFerramenta, cargaVazia, claimsDoNucleo, claimsVelhas, FERRAMENTA_DAS_CLAIMS, FERRAMENTA_DO_PLANO, jsonDoMcp,
|
|
10
|
+
maiorNumeroDeClaim, planoVelho, SERVIDOR, statusNoRetrato, textoDoPlano, threadAtiva, touchPathsDoPlano,
|
|
11
|
+
} from './carga'
|
|
12
|
+
import {
|
|
13
|
+
aplicarLote, ARGV_DO_STATUS, assinatura, caminhosDoLote, diferenca, juntar, lerStatus, mexeuNasClaims, mexeuNoPlano,
|
|
14
|
+
soLeitura, TETO_DE_STAT, TETO_DO_STATUS_MS, textoDoFora, tomarFora, vigiaVazia,
|
|
15
|
+
} from './lote'
|
|
16
|
+
import type { Chamada } from './lote'
|
|
17
|
+
import {
|
|
18
|
+
acumular, argvDaConferencia, ESPERA_DO_FIM_MS, fecharRodada, indisponivelSemRodada, iniciarRodada, lerConferencia, limitarTexto,
|
|
19
|
+
MOTIVO_PROCESSO_ABERTO, precisaDeLaco, TETO_POR_RODADA, textoDaEntrega, textoDoStatus, tomarEntrega, VIGIA_DA_CONFERENCIA_MS,
|
|
20
|
+
} from './conferencia'
|
|
21
|
+
import type { Leitura } from './conferencia'
|
|
22
|
+
|
|
23
|
+
const CARGA = { plugin: 'ork-freio', key: 'carga' } as const
|
|
24
|
+
const VIGIA = { plugin: 'ork-freio', key: 'vigia' } as const
|
|
25
|
+
const TENTATIVAS_DE_ESCRITA = 5
|
|
26
|
+
/**
|
|
27
|
+
* O laco de conferencia desta carga do modulo esta rodando (D10). Fica no modulo, nao no `$.state`: uma troca do
|
|
28
|
+
* worker mata o laco junto com a marca, e a rodada que ficou aberta no estado e retomada pelo laco seguinte.
|
|
29
|
+
*/
|
|
30
|
+
let rodando = false
|
|
31
|
+
/**
|
|
32
|
+
* O processo da ultima rodada ainda nao fechou (o vigia venceu e o `return` nao chegou a ele, como num processo que
|
|
33
|
+
* nao escreve nada). Enquanto ele existir, nenhuma rodada nova abre: duas conferencias nunca correm juntas.
|
|
34
|
+
*/
|
|
35
|
+
let fluxoAberto: Promise<unknown> | null = null
|
|
36
|
+
|
|
37
|
+
/** A sessao de fase com thread, pelo contexto da ponte; qualquer outra sessao fica sem Freio (D10). */
|
|
38
|
+
type ContextoDeFase = { thread: string; raiz: string }
|
|
39
|
+
|
|
40
|
+
const mensagem = (erro: unknown) => (erro instanceof Error ? erro.message : String(erro)).slice(0, 300)
|
|
41
|
+
|
|
42
|
+
async function contextoDeFase($: EngineInterface): Promise<ContextoDeFase | null> {
|
|
43
|
+
const ctx = await $.ork.contexto()
|
|
44
|
+
return ctx.papel === 'fase' && ctx.thread ? { thread: ctx.thread, raiz: ctx.raiz } : null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Grava a carga com `ifVersion`, aplicando `mudar` sobre a versao mais nova (como a ponte faz com a faixa). */
|
|
48
|
+
async function atualizarCarga($: EngineInterface, thread: string, mudar: (atual: FreioCarga) => FreioCarga): Promise<FreioCarga> {
|
|
49
|
+
for (let i = 0; i < TENTATIVAS_DE_ESCRITA; i++) {
|
|
50
|
+
const lida = await $.state.get(CARGA)
|
|
51
|
+
const atual = lida.value && lida.value.thread === thread ? lida.value : cargaVazia(thread)
|
|
52
|
+
const nova = mudar(atual)
|
|
53
|
+
const escrita = await $.state.set(CARGA, nova, { ifVersion: lida.version })
|
|
54
|
+
if (escrita.isSet) return nova
|
|
55
|
+
}
|
|
56
|
+
throw new Error('ork-freio: a carga nao foi guardada')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Grava a vigia do mesmo jeito; `mudar` e pura e pode rodar de novo quando outra escrita passou na frente. */
|
|
60
|
+
async function atualizarVigia<T>($: EngineInterface, thread: string, mudar: (atual: FreioVigia) => { vigia: FreioVigia; extra: T }): Promise<{ vigia: FreioVigia; extra: T }> {
|
|
61
|
+
for (let i = 0; i < TENTATIVAS_DE_ESCRITA; i++) {
|
|
62
|
+
const lida = await $.state.get(VIGIA)
|
|
63
|
+
const atual = lida.value && lida.value.thread === thread ? lida.value : vigiaVazia(thread)
|
|
64
|
+
const r = mudar(atual)
|
|
65
|
+
const escrita = await $.state.set(VIGIA, r.vigia, { ifVersion: lida.version })
|
|
66
|
+
if (escrita.isSet) return r
|
|
67
|
+
}
|
|
68
|
+
throw new Error('ork-freio: a vigia nao foi guardada')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A carga (T2.1): o estado da thread pelo retrato da ponte, as claims e o plano pelas duas ferramentas de
|
|
73
|
+
* leitura do nucleo (D2). Cada parte falha sozinha e fica para a proxima leitura.
|
|
74
|
+
*/
|
|
75
|
+
async function carregar($: EngineInterface, ctx: ContextoDeFase, partes: { retrato: boolean; claims: boolean; plano: boolean }): Promise<FreioCarga> {
|
|
76
|
+
const agora = await $.clock.now()
|
|
77
|
+
const erros: string[] = []
|
|
78
|
+
let status: string | null | undefined
|
|
79
|
+
let claims: FreioCarga['claims'] | undefined
|
|
80
|
+
let maiorClaim = 0
|
|
81
|
+
let touchPaths: string[] | null = null
|
|
82
|
+
let planoLido = false
|
|
83
|
+
if (partes.retrato) {
|
|
84
|
+
try {
|
|
85
|
+
status = statusNoRetrato((await $.ork.retrato({ thread: ctx.thread })).retrato, ctx.thread)
|
|
86
|
+
} catch (erro) { erros.push(`retrato: ${mensagem(erro)}`) }
|
|
87
|
+
}
|
|
88
|
+
if (partes.claims) {
|
|
89
|
+
try {
|
|
90
|
+
const r = await $.mcp.call(SERVIDOR, FERRAMENTA_DAS_CLAIMS, argsDaFerramenta(FERRAMENTA_DAS_CLAIMS, ctx.thread))
|
|
91
|
+
const lista = jsonDoMcp(r, FERRAMENTA_DAS_CLAIMS)
|
|
92
|
+
claims = claimsDoNucleo(lista)
|
|
93
|
+
maiorClaim = maiorNumeroDeClaim(lista)
|
|
94
|
+
} catch (erro) { erros.push(`claims: ${mensagem(erro)}`) }
|
|
95
|
+
}
|
|
96
|
+
if (partes.plano) {
|
|
97
|
+
try {
|
|
98
|
+
const r = await $.mcp.call(SERVIDOR, FERRAMENTA_DO_PLANO, argsDaFerramenta(FERRAMENTA_DO_PLANO, ctx.thread))
|
|
99
|
+
touchPaths = touchPathsDoPlano(textoDoPlano(jsonDoMcp(r, FERRAMENTA_DO_PLANO)))
|
|
100
|
+
planoLido = true
|
|
101
|
+
} catch (erro) { erros.push(`plano: ${mensagem(erro)}`) }
|
|
102
|
+
}
|
|
103
|
+
// Uma leitura mais velha nunca sobrescreve outra mais nova que gravou antes dela (duas cargas ao mesmo tempo).
|
|
104
|
+
return atualizarCarga($, ctx.thread, atual => ({
|
|
105
|
+
...atual,
|
|
106
|
+
...(status !== undefined ? { statusDaThread: status } : {}),
|
|
107
|
+
...(claims !== undefined && agora >= atual.claimsEm ? { claims, claimsEm: agora, maiorClaim } : {}),
|
|
108
|
+
...(planoLido && agora >= atual.planoEm ? { touchPaths, planoLido: true, planoEm: agora } : {}),
|
|
109
|
+
erros,
|
|
110
|
+
}))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** A foto do `git status` da worktree (D4), com o `stat` de cada caminho sujo ate o teto; `null` se o git falhar. */
|
|
114
|
+
async function fotografar($: EngineInterface, raiz: string): Promise<FreioFoto | null> {
|
|
115
|
+
let r
|
|
116
|
+
try {
|
|
117
|
+
// Sem lock opcional: o `git status` do Freio nunca segura o `index.lock` que um commit do modelo precisa.
|
|
118
|
+
r = await $.process.run(ARGV_DO_STATUS, { cwd: raiz, timeoutMs: TETO_DO_STATUS_MS, env: { GIT_OPTIONAL_LOCKS: '0' } })
|
|
119
|
+
} catch { return null }
|
|
120
|
+
if (r.exitCode !== 0) return null
|
|
121
|
+
const lido = lerStatus(r.stdout)
|
|
122
|
+
const caminhos: Record<string, string> = {}
|
|
123
|
+
for (let i = 0; i < lido.entradas.length; i++) {
|
|
124
|
+
const entrada = lido.entradas[i] as { caminho: string; xy: string }
|
|
125
|
+
const comStat = i < TETO_DE_STAT
|
|
126
|
+
const stat = comStat ? await $.fs.stat(juntar(raiz, entrada.caminho)).catch(() => null) : null
|
|
127
|
+
caminhos[entrada.caminho] = assinatura(entrada.xy, stat, comStat)
|
|
128
|
+
}
|
|
129
|
+
return { head: lido.head, caminhos }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** A primeira foto, guardada so quando ainda nao ha foto (o reload nao apaga o que o lote anterior viu). */
|
|
133
|
+
async function primeiraFoto($: EngineInterface, ctx: ContextoDeFase): Promise<void> {
|
|
134
|
+
const foto = await fotografar($, ctx.raiz)
|
|
135
|
+
if (!foto) return
|
|
136
|
+
await atualizarVigia($, ctx.thread, v => ({ vigia: v.foto ? v : { ...v, foto }, extra: null }))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Uma rodada no nucleo (D6): `ork claims conferir` por `$.process.spawn`, na raiz da sessao, com o vigia do mod.
|
|
141
|
+
* O processo que nao abre e a saida fora do formato viram conferencia indisponivel (D7).
|
|
142
|
+
*/
|
|
143
|
+
async function rodarConferencia($: EngineInterface, ctx: ContextoDeFase, ids: readonly string[]): Promise<Leitura> {
|
|
144
|
+
let stdout = ''
|
|
145
|
+
let stderr = ''
|
|
146
|
+
let vigia: { cancel: () => void } | undefined
|
|
147
|
+
try {
|
|
148
|
+
const fluxo = $.process.spawn({ argv: argvDaConferencia(ctx.thread, ids), cwd: ctx.raiz })
|
|
149
|
+
const lido = (async () => {
|
|
150
|
+
for await (const pedaco of fluxo) {
|
|
151
|
+
if (pedaco.stream === 'stdout') stdout = acumular(stdout, pedaco.text, false)
|
|
152
|
+
else stderr = acumular(stderr, pedaco.text, true)
|
|
153
|
+
}
|
|
154
|
+
return fluxo.result
|
|
155
|
+
})()
|
|
156
|
+
lido.catch(() => undefined)
|
|
157
|
+
fluxoAberto = lido
|
|
158
|
+
void lido.catch(() => undefined).then(() => { if (fluxoAberto === lido) fluxoAberto = null })
|
|
159
|
+
const vencido = new Promise<'vencido'>(resolver => { vigia = $.clock.after(VIGIA_DA_CONFERENCIA_MS, () => resolver('vencido')) })
|
|
160
|
+
const fim = await Promise.race([lido, vencido])
|
|
161
|
+
if (fim === 'vencido') {
|
|
162
|
+
// Pede o fim do processo; a volta seguinte do laco espera ele fechar (uma espera so, com teto) antes de abrir
|
|
163
|
+
// rodada nova, e com ele aberto a conferencia fica indisponivel.
|
|
164
|
+
void fluxo.return(undefined as never).catch(() => undefined)
|
|
165
|
+
return { tipo: 'prazo' }
|
|
166
|
+
}
|
|
167
|
+
return lerConferencia(stdout, fim.code, stderr)
|
|
168
|
+
} catch (erro) {
|
|
169
|
+
return { tipo: 'indisponivel', motivo: `ork claims conferir nao rodou: ${mensagem(erro)}` }
|
|
170
|
+
} finally {
|
|
171
|
+
vigia?.cancel()
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** As claims ativas da carga e o maior numero ja dado, para a rodada nao levar claim retirada; `null` sem lista lida. */
|
|
176
|
+
async function claimsAtivas($: EngineInterface, ctx: ContextoDeFase): Promise<{ ids: string[]; maior: number } | null> {
|
|
177
|
+
const carga = (await $.state.get(CARGA)).value
|
|
178
|
+
return carga && carga.thread === ctx.thread && carga.claims ? { ids: carga.claims.map(c => c.id), maior: carga.maiorClaim ?? 0 } : null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* O laco de fundo (T2.3): uma rodada por vez, ate a fila acabar, a pausa chegar ou a conferencia faltar. A recusa
|
|
183
|
+
* de uma claim so rele as claims e segue com as outras; a conducao alheia pausa um minuto.
|
|
184
|
+
*/
|
|
185
|
+
async function conferirEmLaco($: EngineInterface, ctx: ContextoDeFase): Promise<void> {
|
|
186
|
+
if (rodando) return
|
|
187
|
+
rodando = true
|
|
188
|
+
try {
|
|
189
|
+
for (;;) {
|
|
190
|
+
if (fluxoAberto) {
|
|
191
|
+
const aberto = fluxoAberto
|
|
192
|
+
await Promise.race([aberto.catch(() => undefined), new Promise(resolver => { $.clock.after(ESPERA_DO_FIM_MS, () => resolver(undefined)) })])
|
|
193
|
+
if (fluxoAberto === aberto) {
|
|
194
|
+
const quando = await $.clock.now()
|
|
195
|
+
const parada = await atualizarVigia($, ctx.thread, v => ({ vigia: indisponivelSemRodada(v, MOTIVO_PROCESSO_ABERTO, quando), extra: null }))
|
|
196
|
+
$.ui.status(textoDoStatus(parada.vigia, quando))
|
|
197
|
+
break
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const agora = await $.clock.now()
|
|
201
|
+
const ativas = await claimsAtivas($, ctx)
|
|
202
|
+
const { vigia } = await atualizarVigia($, ctx.thread, v => ({ vigia: iniciarRodada(v, agora, TETO_POR_RODADA, ativas), extra: null }))
|
|
203
|
+
if (!vigia.rodada) break
|
|
204
|
+
$.ui.status(textoDoStatus(vigia, agora))
|
|
205
|
+
const leitura = await rodarConferencia($, ctx, vigia.rodada.ids)
|
|
206
|
+
const depois = await $.clock.now()
|
|
207
|
+
const fechada = await atualizarVigia($, ctx.thread, v => ({ vigia: fecharRodada(v, leitura, depois), extra: null }))
|
|
208
|
+
$.ui.status(textoDoStatus(fechada.vigia, depois))
|
|
209
|
+
if (leitura.tipo === 'recusada') await carregar($, ctx, { retrato: false, claims: true, plano: false })
|
|
210
|
+
if (leitura.tipo === 'indisponivel' || leitura.tipo === 'ocupada') break
|
|
211
|
+
}
|
|
212
|
+
} finally {
|
|
213
|
+
rodando = false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Abre o laco fora do despacho do lote, por `$.clock.after`; o laco que ja roda pega a fila nova. */
|
|
218
|
+
function pedirConferencia($: EngineInterface, ctx: ContextoDeFase): void {
|
|
219
|
+
if (rodando) return
|
|
220
|
+
$.clock.after(0, () => { void conferirEmLaco($, ctx).catch(() => undefined) })
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export const register: Register = on => {
|
|
224
|
+
// A carga roda fora do inicio da sessao: o MCP pode ainda estar conectando, e o inicio nao espera por ela.
|
|
225
|
+
// O `session.start` dispara de novo num reload, e a carga refaz a leitura do mesmo jeito (D10).
|
|
226
|
+
on('session.start', async ($, e, next) => {
|
|
227
|
+
const iniciada = await next(e)
|
|
228
|
+
try {
|
|
229
|
+
const ctx = await contextoDeFase($)
|
|
230
|
+
if (ctx) {
|
|
231
|
+
$.clock.after(0, () => {
|
|
232
|
+
void (async () => {
|
|
233
|
+
await carregar($, ctx, { retrato: true, claims: true, plano: true }).catch(() => undefined)
|
|
234
|
+
await primeiraFoto($, ctx).catch(() => undefined)
|
|
235
|
+
})()
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
} catch { /* sem a ponte, o Freio fica dormente */ }
|
|
239
|
+
return iniciada
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// O lote (T2.2 e T2.3): devolve o que a conferencia apurou desde o lote anterior, acha os arquivos tocados e as
|
|
243
|
+
// claims afetadas, pede a conferencia ao nucleo e avisa os `touch_paths`. Responde so com `additionalContext` e
|
|
244
|
+
// nunca para o laco: na sessao de fundo nao ha quem o retome. Falha deixa o lote passar. O lote de subagente
|
|
245
|
+
// (`agent_id`) conta os toques, mas a entrega e o aviso ficam para o lote do laco principal, que e quem os le.
|
|
246
|
+
on('classic.PostToolBatch', async ($, e, next) => {
|
|
247
|
+
const resultado = await next(e)
|
|
248
|
+
const ctx = await contextoDeFase($)
|
|
249
|
+
if (!ctx) return resultado
|
|
250
|
+
let carga = (await $.state.get(CARGA)).value
|
|
251
|
+
if (carga && carga.thread === ctx.thread && !threadAtiva(carga.statusDaThread)) return resultado
|
|
252
|
+
const chamadas: Chamada[] = Array.isArray(e.tool_calls) ? e.tool_calls : []
|
|
253
|
+
const doSubagente = typeof e.agent_id === 'string' && e.agent_id !== ''
|
|
254
|
+
const doLote = caminhosDoLote(chamadas, ctx.raiz)
|
|
255
|
+
const foto = soLeitura(chamadas) ? null : await fotografar($, ctx.raiz)
|
|
256
|
+
const mexeu = doLote.length > 0 || foto !== null
|
|
257
|
+
// O lote que mexeu nas claims ou no plano rele na hora; a lista velha so e relida quando ha caminho para casar.
|
|
258
|
+
const lida = (await $.state.get(VIGIA)).value
|
|
259
|
+
const anterior = lida && lida.thread === ctx.thread ? lida.foto : null
|
|
260
|
+
const previstos = doLote.length + (foto ? diferenca(anterior, foto).length : 0)
|
|
261
|
+
const nasClaims = mexeuNasClaims(chamadas)
|
|
262
|
+
const noPlano = mexeuNoPlano(chamadas)
|
|
263
|
+
if (previstos > 0 || nasClaims || noPlano) {
|
|
264
|
+
const agora = await $.clock.now()
|
|
265
|
+
const atual = carga && carga.thread === ctx.thread ? carga : cargaVazia(ctx.thread)
|
|
266
|
+
const relerClaims = nasClaims || (previstos > 0 && claimsVelhas(atual, agora, false))
|
|
267
|
+
const relerPlano = noPlano || (previstos > 0 && planoVelho(atual, agora, false))
|
|
268
|
+
if (relerClaims || relerPlano) carga = await carregar($, ctx, { retrato: false, claims: relerClaims, plano: relerPlano })
|
|
269
|
+
}
|
|
270
|
+
const lote = { foto, doLote, claims: carga?.thread === ctx.thread ? carga.claims : null, touchPaths: carga?.thread === ctx.thread ? carga.touchPaths : null }
|
|
271
|
+
const { vigia, extra } = await atualizarVigia($, ctx.thread, v => {
|
|
272
|
+
const aplicada = mexeu ? aplicarLote(v, lote).vigia : v
|
|
273
|
+
if (doSubagente) return { vigia: aplicada, extra: { entrega: null, fora: [] as string[] } }
|
|
274
|
+
const f = tomarFora(aplicada)
|
|
275
|
+
const t = tomarEntrega(f.vigia)
|
|
276
|
+
return { vigia: t.vigia, extra: { entrega: t.entrega, fora: f.fora } }
|
|
277
|
+
})
|
|
278
|
+
// A rodada que ficou aberta no estado (o laco morreu com o worker) e retomada como a fila.
|
|
279
|
+
if (precisaDeLaco(vigia)) pedirConferencia($, ctx)
|
|
280
|
+
$.ui.status(textoDoStatus(vigia, await $.clock.now()))
|
|
281
|
+
const partes = [extra.entrega ? textoDaEntrega(extra.entrega) : '', textoDoFora(extra.fora)].filter(t => t !== '')
|
|
282
|
+
const texto = limitarTexto(partes.join('\n'))
|
|
283
|
+
return texto ? { ...resultado, additionalContext: [...(resultado.additionalContext ?? []), texto] } : resultado
|
|
284
|
+
}).catch(($, e, next) => next(e))
|
|
285
|
+
}
|