@orkastery/cli 0.5.6 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/README.md +18 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
- package/adapters/claude-code/README.md +37 -5
- package/adapters/claude-code/agents/ork-check.md +1 -0
- package/adapters/claude-code/agents/ork-go.md +1 -0
- package/adapters/claude-code/agents/ork-goal.md +1 -0
- package/adapters/claude-code/agents/ork-master.md +1 -0
- package/adapters/claude-code/agents/ork-plan.md +1 -0
- package/adapters/claude-code/agents/ork-ship.md +1 -0
- package/adapters/claude-code/hooks/hooks.json +2 -1
- package/adapters/claude-code/hooks/ork-guard.js +15 -1
- package/adapters/claude-code/hooks/ork-resposta.js +91 -0
- package/adapters/claude-code/hooks/ork-sensor.js +18 -2
- package/adapters/claude-code/hooks/quota-signal.js +14 -0
- package/adapters/claude-code/mods/ork-mensageiro/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
- package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +9 -5
- package/adapters/claude-code/mods/ork-ritual/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
- package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +1 -1
- package/adapters/codex/skills/ork/SKILL.md +2 -0
- package/adapters/hermes/README.md +64 -1
- package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
- package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
- package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
- package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
- package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
- package/adapters/hermes/hermes.plugin.json +4 -0
- package/adapters/hermes/hitl-ingress/__init__.py +101 -8
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +2 -2
- package/adapters/openclaw/README.md +81 -9
- package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
- package/adapters/openclaw/dist/hitl-ingress.js +106 -9
- package/adapters/openclaw/dist/index.js +86 -0
- package/adapters/openclaw/openclaw.plugin.json +34 -4
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +103 -9
- package/adapters/openclaw/src/index.ts +94 -0
- package/assets/adapters-en/claude-code/README.md +403 -0
- package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
- package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
- package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
- package/assets/adapters-en/claude-code/commands/check.md +46 -0
- package/assets/adapters-en/claude-code/commands/go.md +46 -0
- package/assets/adapters-en/claude-code/commands/goal.md +55 -0
- package/assets/adapters-en/claude-code/commands/master.md +54 -0
- package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
- package/assets/adapters-en/claude-code/commands/ork.md +126 -0
- package/assets/adapters-en/claude-code/commands/plan.md +47 -0
- package/assets/adapters-en/claude-code/commands/ship.md +45 -0
- package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
- package/assets/adapters-en/hermes/README.md +273 -0
- package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
- package/assets/references-en/README.md +25 -0
- package/assets/references-en/code-review-axes.md +82 -0
- package/assets/references-en/definition-of-done.md +74 -0
- package/assets/references-en/performance-checklist.md +53 -0
- package/assets/references-en/security-checklist.md +101 -0
- package/assets/references-en/testing-patterns.md +51 -0
- package/assets/security-scan/defaults/.golangci.yml +2 -0
- package/assets/security-scan/defaults/eslint.config.mjs +11 -0
- package/assets/security-scan/defaults/gitleaks.toml +3 -0
- package/assets/security-scan/defaults/ruff.toml +1 -0
- package/assets/security-scan/tools-agil.json +87 -0
- package/assets/security-scan/tools.json +625 -0
- package/assets/skills-en/core/onboarding/SKILL.md +58 -0
- package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
- package/assets/skills-en/core/thread-state/SKILL.md +88 -0
- package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
- package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
- package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
- package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
- package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
- package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
- package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
- package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
- package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
- package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
- package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
- package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
- package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
- package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
- package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
- package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
- package/dist/adapters/claude-bg.js +123 -9
- package/dist/adapters/codex-controller-worker.js +12 -5
- package/dist/adapters/codex-events.js +16 -4
- package/dist/adapters/codex.js +3 -1
- package/dist/adapters/grok-events.js +227 -0
- package/dist/adapters/grok-mcp-servidor.js +612 -0
- package/dist/adapters/grok-mcp.js +178 -0
- package/dist/adapters/grok.js +686 -0
- package/dist/agendador-cpu.js +92 -0
- package/dist/atualizar-branch.js +245 -0
- package/dist/auditoria.js +13 -11
- package/dist/auditrun.js +51 -46
- package/dist/autorizacao-duravel.js +327 -0
- package/dist/board.js +94 -40
- package/dist/branch-de-estado.js +23 -10
- package/dist/busca-semantica.js +7 -5
- package/dist/catalogo.js +2 -1
- package/dist/changelog-reconciliacao.js +290 -0
- package/dist/check-agil.js +528 -0
- package/dist/check-modo.js +41 -0
- package/dist/check-paralelo.js +238 -0
- package/dist/ci.js +248 -45
- package/dist/ciclos.js +8 -6
- package/dist/claim-lint.js +12 -8
- package/dist/claims-conferir.js +47 -39
- package/dist/claims.js +10 -9
- package/dist/company-brain-client.js +10 -3
- package/dist/company-brain-migration.js +11 -5
- package/dist/conducao-batida.js +759 -0
- package/dist/conducao-sentinela.js +25 -8
- package/dist/conducao.js +89 -29
- package/dist/conhecimento-consulta.js +270 -0
- package/dist/conhecimento.js +111 -87
- package/dist/conta-esgotada.js +127 -0
- package/dist/dado-privado.js +816 -0
- package/dist/decisao-autonoma.js +5 -4
- package/dist/demo.js +14 -12
- package/dist/dependencias-da-worktree.js +25 -0
- package/dist/divida.js +38 -36
- package/dist/docs.js +89 -89
- package/dist/doctor-forja.js +343 -0
- package/dist/doctor-pulse-cron.js +113 -1
- package/dist/doctor.js +164 -6
- package/dist/dsn-da-memoria.js +417 -0
- package/dist/entrega-por-mod.js +503 -0
- package/dist/entrega-pr.js +154 -54
- package/dist/esgotamentos.js +13 -11
- package/dist/estado-thread.js +21 -18
- package/dist/evalrunner.js +35 -32
- package/dist/fabrica-batida.js +34 -21
- package/dist/fabrica-estado.js +33 -21
- package/dist/fix.js +21 -19
- package/dist/forja/adaptador.js +6 -0
- package/dist/forja/ambiente-de-ci.js +27 -0
- package/dist/forja/api.js +256 -0
- package/dist/forja/cache.js +89 -0
- package/dist/forja/cli.js +60 -0
- package/dist/forja/contrato.js +9 -0
- package/dist/forja/endereco.js +43 -0
- package/dist/forja/estado.js +22 -0
- package/dist/forja/executor.js +73 -0
- package/dist/forja/github/ci.js +95 -0
- package/dist/forja/github/dono-da-rede.js +18 -0
- package/dist/forja/github/metadados.js +15 -0
- package/dist/forja/github/pedidos.js +200 -0
- package/dist/forja/gitlab/ci.js +141 -0
- package/dist/forja/gitlab/consultas.js +59 -0
- package/dist/forja/gitlab/dono-da-rede.js +43 -0
- package/dist/forja/gitlab/metadados.js +15 -0
- package/dist/forja/gitlab/pedidos-abertos.js +158 -0
- package/dist/forja/gitlab/pedidos.js +141 -0
- package/dist/forja/produtor.js +32 -0
- package/dist/forja/registro.js +31 -0
- package/dist/forja/resolver.js +121 -0
- package/dist/forja/texto.js +13 -0
- package/dist/forja/versao.js +71 -0
- package/dist/forja.js +123 -80
- package/dist/handoff.js +23 -13
- package/dist/hitl-contract.js +46 -43
- package/dist/hitl-curto.js +37 -25
- package/dist/hitl-gates.js +13 -11
- package/dist/hitl-local-receipt.js +51 -0
- package/dist/hitl-local.js +11 -2
- package/dist/hitl-lock.js +5 -11
- package/dist/hitl-public-receipt.js +11 -0
- package/dist/hitl-resumo.js +44 -1
- package/dist/hitl-sessions.js +62 -9
- package/dist/hitl-texto-livre.js +7 -4
- package/dist/hitl.js +34 -31
- package/dist/horario.js +20 -1
- package/dist/hosts.js +104 -134
- package/dist/index.js +864 -554
- package/dist/indice-vetorial.js +14 -12
- package/dist/init.js +11 -2
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +123 -69
- package/dist/intelligence-graph-query.js +37 -22
- package/dist/leases.js +19 -18
- package/dist/ledger-stats.js +17 -16
- package/dist/ledger.js +31 -1
- package/dist/licoes.js +12 -11
- package/dist/locale-accounts.js +228 -0
- package/dist/locale-adapter.js +291 -0
- package/dist/locale-ajuda.js +86 -10
- 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 +288 -0
- package/dist/locale-gerados.js +5 -0
- package/dist/locale-grafo.js +129 -0
- package/dist/locale-master.js +83 -0
- package/dist/locale-network.js +524 -0
- package/dist/locale-operacao-restante.js +931 -0
- package/dist/locale-projetos.js +100 -0
- package/dist/locale-prompts.js +194 -0
- package/dist/locale-pulse.js +140 -2
- package/dist/locale-reservas.js +87 -0
- package/dist/locale-retry.js +183 -6
- package/dist/locale-security-scan.js +69 -0
- package/dist/locale-setup.js +192 -0
- package/dist/locale-ship.js +177 -66
- package/dist/locale-thread.js +149 -5
- package/dist/locale-verify.js +80 -4
- package/dist/locale-worktree.js +246 -0
- package/dist/locale.js +553 -9
- package/dist/maestro-runtime.js +22 -3
- package/dist/manifest.js +293 -12
- package/dist/maquina-ociosa.js +211 -0
- package/dist/maquina.js +10 -5
- package/dist/master-nota-local.js +200 -0
- package/dist/master-nota.js +10 -2
- package/dist/master.js +118 -41
- package/dist/mcp-conhecimento.js +52 -0
- package/dist/mcp-experiencia.js +26 -5
- package/dist/mcp-install.js +90 -15
- package/dist/mcp-noctum.js +101 -0
- package/dist/mcp-server.js +116 -22
- package/dist/mcp-ship-transporte.js +977 -0
- package/dist/mcp-ship.js +68 -24
- package/dist/mcp-transportes.js +17 -0
- package/dist/memoria.js +63 -58
- package/dist/merge-da-entrega.js +85 -0
- package/dist/modos-migracao.js +8 -6
- package/dist/modos.js +17 -18
- package/dist/network-roadmap.js +94 -54
- package/dist/noctum-aceite.js +929 -0
- package/dist/noctum-arco.js +540 -33
- package/dist/noctum-capacidade.js +3 -3
- package/dist/noctum-changelog.js +399 -0
- package/dist/noctum-cli.js +539 -0
- package/dist/noctum-coordenacao.js +1225 -0
- package/dist/noctum-entrega.js +1217 -0
- package/dist/noctum-envelope.js +253 -17
- package/dist/noctum-execucao.js +100 -24
- package/dist/noctum-fechamento.js +416 -0
- package/dist/noctum-fila.js +49 -10
- package/dist/noctum-guarda.js +333 -0
- package/dist/noctum-integracao.js +507 -0
- package/dist/noctum-maquinas.js +387 -0
- package/dist/noctum-medicao.js +450 -0
- package/dist/noctum-modo.js +390 -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 +594 -0
- package/dist/noctum-rede.js +102 -0
- package/dist/noctum-registro.js +215 -0
- package/dist/noctum-relatorio.js +861 -0
- package/dist/noctum-resposta.js +207 -0
- package/dist/noctum-retomada-rede.js +71 -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 +679 -0
- package/dist/ocupacao.js +3 -1
- package/dist/onboarding.js +16 -5
- package/dist/orkmind.js +39 -23
- package/dist/orquestracao.js +31 -35
- package/dist/parado-no-condutor.js +160 -139
- package/dist/phase.js +96 -42
- package/dist/policies.js +33 -0
- package/dist/postura-local.js +11 -6
- package/dist/preflight.js +2 -1
- package/dist/procedencia.js +9 -14
- package/dist/projeto-alvo.js +59 -20
- package/dist/prompts.js +136 -42
- package/dist/prova-minima.js +5 -6
- package/dist/pulse-cadencia.js +5 -4
- package/dist/pulse-consentimento.js +53 -1
- package/dist/pulse-delivery.js +143 -27
- package/dist/pulse-resposta.js +368 -4
- package/dist/pulse.js +136 -3
- package/dist/ratelimit.js +13 -4
- package/dist/recall.js +14 -13
- package/dist/rede-adesao.js +13 -8
- package/dist/rede-forja.js +108 -24
- package/dist/rede-status.js +63 -45
- package/dist/rede.js +86 -46
- package/dist/retomada-checkpoint.js +101 -0
- package/dist/retry.js +326 -78
- package/dist/roadmap-reservas.js +32 -32
- package/dist/runtime-ambiente.js +5 -0
- package/dist/runtime-context.js +279 -85
- package/dist/runtime-escada.js +429 -0
- package/dist/runtime-profiles.js +130 -63
- package/dist/runtimes.js +42 -5
- package/dist/saida-segura.js +3 -2
- package/dist/security-scan/agil.js +366 -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 +196 -0
- package/dist/security-scan/guard.js +180 -0
- package/dist/security-scan/imagem-de-lint.js +96 -0
- package/dist/security-scan/normalize/actionlint.js +12 -0
- package/dist/security-scan/normalize/eslint.js +12 -0
- package/dist/security-scan/normalize/gitleaks.js +13 -0
- package/dist/security-scan/normalize/golangci-lint.js +13 -0
- package/dist/security-scan/normalize/govulncheck.js +36 -0
- package/dist/security-scan/normalize/index.js +25 -0
- package/dist/security-scan/normalize/npm-audit.js +30 -0
- package/dist/security-scan/normalize/osv-scanner.js +32 -0
- package/dist/security-scan/normalize/oxlint.js +51 -0
- package/dist/security-scan/normalize/pip-audit.js +16 -0
- package/dist/security-scan/normalize/ruff.js +12 -0
- package/dist/security-scan/normalize/semgrep.js +20 -0
- package/dist/security-scan/normalize/trivy.js +33 -0
- package/dist/security-scan/normalize/util.js +204 -0
- package/dist/security-scan/normalize/zizmor.js +19 -0
- package/dist/security-scan/report.js +156 -0
- package/dist/security-scan/run.js +448 -0
- package/dist/security-scan/tools.js +62 -0
- package/dist/security-scan/trabalhador.js +74 -0
- package/dist/security-scan/types.js +15 -0
- package/dist/session-events.js +19 -2
- package/dist/session-watcher-claude.js +74 -19
- package/dist/session-watcher-grok.js +425 -0
- package/dist/session-watcher.js +174 -13
- package/dist/sessoes-contas.js +42 -5
- package/dist/sessoes-inventario.js +1 -1
- package/dist/sessoes.js +25 -23
- package/dist/setup.js +67 -66
- package/dist/ship-publicar.js +263 -92
- package/dist/ship.js +160 -17
- package/dist/superficie.js +14 -11
- package/dist/thread-close.js +9 -9
- package/dist/thread.js +121 -18
- package/dist/tokens.js +15 -11
- package/dist/trabalho-thread.js +297 -0
- package/dist/transporte-do-canal.js +189 -0
- package/dist/types.js +12 -1
- package/dist/util.js +5 -2
- package/dist/varredura-acoes.js +500 -0
- package/dist/verify.js +491 -32
- package/dist/worktree-local.js +12 -10
- package/dist/worktree.js +81 -85
- package/eval/casos/check-quality.json +77 -0
- package/eval/casos/security-auditor.json +148 -0
- package/eval/casos/security-remediation.json +161 -0
- package/eval/fixtures/security-scan/README.md +8 -0
- package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/go/Dockerfile +4 -0
- package/eval/fixtures/security-scan/go/README.md +4 -0
- package/eval/fixtures/security-scan/go/config.go +4 -0
- package/eval/fixtures/security-scan/go/go.mod +5 -0
- package/eval/fixtures/security-scan/go/go.sum +2 -0
- package/eval/fixtures/security-scan/go/main.go +31 -0
- package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/js/Dockerfile +3 -0
- package/eval/fixtures/security-scan/js/README.md +4 -0
- package/eval/fixtures/security-scan/js/package-lock.json +844 -0
- package/eval/fixtures/security-scan/js/package.json +10 -0
- package/eval/fixtures/security-scan/js/src/config.js +4 -0
- package/eval/fixtures/security-scan/js/src/server.js +17 -0
- package/eval/fixtures/security-scan/js/src/util.ts +4 -0
- package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
- package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/python/Dockerfile +3 -0
- package/eval/fixtures/security-scan/python/README.md +4 -0
- package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
- package/eval/fixtures/security-scan/python/app/config.py +2 -0
- package/eval/fixtures/security-scan/python/app/main.py +19 -0
- package/eval/fixtures/security-scan/python/requirements.txt +1 -0
- package/package.json +10 -5
- package/references/security-checklist.md +3 -3
- package/skills/README.md +1 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/check-quality/SKILL.md +16 -0
- package/skills/phases/go-implementation/SKILL.md +6 -0
- package/skills/phases/security-remediation/SKILL.md +70 -0
- package/skills/reviewers/security-auditor/SKILL.md +25 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TETO_DO_ARQUIVO_MEDIDO = exports.UNIDADES_MEDIDAS = exports.CONTRATO_MEDICAO = void 0;
|
|
37
|
+
exports.fontesDoDisco = fontesDoDisco;
|
|
38
|
+
exports.tokensDasTranscricoes = tokensDasTranscricoes;
|
|
39
|
+
exports.leituraDoRollout = leituraDoRollout;
|
|
40
|
+
exports.cotaDasLeituras = cotaDasLeituras;
|
|
41
|
+
exports.medirArco = medirArco;
|
|
42
|
+
exports.consumoDoEscopoNaUnidade = consumoDoEscopoNaUnidade;
|
|
43
|
+
exports.precisaMedir = precisaMedir;
|
|
44
|
+
exports.medidoParaReserva = medidoParaReserva;
|
|
45
|
+
exports.textoDoConsumo = textoDoConsumo;
|
|
46
|
+
/**
|
|
47
|
+
* RM-058, fatia N6 (D4, D5 e D9 da ork-rm058n6): a medição do consumo do arco nas unidades do orçamento.
|
|
48
|
+
*
|
|
49
|
+
* A N2 mediu só `sessoes` (as reservas não recusadas). Aqui entram as outras três, sempre a partir do que o núcleo e o
|
|
50
|
+
* runtime gravaram, nunca de estimativa:
|
|
51
|
+
*
|
|
52
|
+
* - `minutos-de-sessao`: do `phase_dispatch` da sessão ao primeiro resultado dela no ledger da thread (`phase_result`,
|
|
53
|
+
* `sessao_morta` ou `session_superseded`), arredondado para cima por sessão. A latência do observador fica dentro:
|
|
54
|
+
* a medida é sempre a maior. A sessão em voo conta até o instante da leitura e sai marcada como parcial.
|
|
55
|
+
* - `tokens`: o que o runtime diz ter processado, sem conversão. No Claude Code, o `message.usage` da transcrição da
|
|
56
|
+
* sessão e dos subagentes, uma vez por `message.id` (a transcrição repete o mesmo uso em cada bloco da resposta):
|
|
57
|
+
* entrada, criação de cache, leitura de cache e saída. No codex, o `total_tokens` do último `token_count` do rollout.
|
|
58
|
+
* - `percentual-da-cota`: só o codex grava a cota fora da sessão (`rate_limits` do rollout). O valor é o `used_percent`
|
|
59
|
+
* mais alto da janela, que inclui o uso de antes do arco e o de outros projetos na mesma janela: teto superior, nunca
|
|
60
|
+
* menos que o consumo real. Janela que renovou no meio do arco perde o uso de antes da renovação, e vira lacuna. O
|
|
61
|
+
* Claude Code só mostra a cota aos mods dentro da sessão: conta claude-bg em percentual é sempre lacuna.
|
|
62
|
+
*
|
|
63
|
+
* Consumo desconhecido nunca é zero: reserva pendente (a sessão pode ter aberto sem id), ledger ilegível, transcrição ou
|
|
64
|
+
* rollout ausente, linha ilegível no meio do arquivo e sessão sem leitura ainda viram lacuna tipada, e a lacuna de uma
|
|
65
|
+
* sessão contamina o escopo inteiro dela. Zero só é medido quando nenhuma sessão do arco caiu no escopo.
|
|
66
|
+
*
|
|
67
|
+
* Nada aqui grava. `fontes` é dependência dos testes; em produção, o ledger, o store de perfis, a transcrição e o rollout.
|
|
68
|
+
*/
|
|
69
|
+
const fs = __importStar(require("node:fs"));
|
|
70
|
+
const path = __importStar(require("node:path"));
|
|
71
|
+
const codex_1 = require("./adapters/codex");
|
|
72
|
+
const ledger_1 = require("./ledger");
|
|
73
|
+
const noctum_envelope_1 = require("./noctum-envelope");
|
|
74
|
+
const runtime_profiles_1 = require("./runtime-profiles");
|
|
75
|
+
const session_watcher_claude_1 = require("./session-watcher-claude");
|
|
76
|
+
const thread_1 = require("./thread");
|
|
77
|
+
exports.CONTRATO_MEDICAO = 'ork.noctum-medicao/v1';
|
|
78
|
+
exports.UNIDADES_MEDIDAS = ['minutos-de-sessao', 'tokens', 'percentual-da-cota'];
|
|
79
|
+
/** Arquivo de transcrição ou rollout acima disto não é lido inteiro: vira lacuna, nunca leitura parcial. */
|
|
80
|
+
exports.TETO_DO_ARQUIVO_MEDIDO = 256 * 1024 * 1024;
|
|
81
|
+
/** Duas leituras da mesma janela com renovações a menos disto são a mesma janela (o arredondamento do runtime). */
|
|
82
|
+
const TOLERANCIA_DA_RENOVACAO_MS = 120_000;
|
|
83
|
+
function lerArquivoLimitado(arquivo) {
|
|
84
|
+
let fd;
|
|
85
|
+
try {
|
|
86
|
+
fd = fs.openSync(arquivo, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const st = fs.fstatSync(fd);
|
|
93
|
+
if (!st.isFile() || st.size > exports.TETO_DO_ARQUIVO_MEDIDO)
|
|
94
|
+
return null;
|
|
95
|
+
return fs.readFileSync(fd);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
fs.closeSync(fd);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** As fontes de produção para a raiz de estado dada. */
|
|
105
|
+
function fontesDoDisco(raiz) {
|
|
106
|
+
let perfis;
|
|
107
|
+
return {
|
|
108
|
+
eventos: (thread) => { try {
|
|
109
|
+
return (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, thread));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return null;
|
|
113
|
+
} },
|
|
114
|
+
cwd: (thread) => { try {
|
|
115
|
+
return (0, thread_1.lerThread)(raiz, thread).worktree ?? null;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
} },
|
|
120
|
+
perfil: (conta) => {
|
|
121
|
+
if (perfis === undefined) {
|
|
122
|
+
try {
|
|
123
|
+
perfis = (0, runtime_profiles_1.lerPerfis)(raiz);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
perfis = null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (perfis === null)
|
|
130
|
+
return undefined;
|
|
131
|
+
const p = perfis.perfis.find(x => x.id === conta);
|
|
132
|
+
return p ? (0, runtime_profiles_1.perfilDeDespacho)(p) : null;
|
|
133
|
+
},
|
|
134
|
+
transcricoes: (perfil, cwd, sessionId) => {
|
|
135
|
+
const principal = (0, session_watcher_claude_1.arquivoDaTranscricao)(perfil, cwd, sessionId);
|
|
136
|
+
if (!principal)
|
|
137
|
+
return null;
|
|
138
|
+
try {
|
|
139
|
+
if (!fs.lstatSync(principal).isFile())
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const dir = path.join(path.dirname(principal), sessionId, 'subagents');
|
|
146
|
+
let subagentes = [];
|
|
147
|
+
try {
|
|
148
|
+
subagentes = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort().map(f => path.join(dir, f));
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
subagentes = [];
|
|
152
|
+
}
|
|
153
|
+
return [principal, ...subagentes];
|
|
154
|
+
},
|
|
155
|
+
rollout: (perfil, sessionId) => { try {
|
|
156
|
+
return (0, codex_1.acharRollout)(sessionId, 3, (0, codex_1.casaDoCodex)(perfil));
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
} },
|
|
161
|
+
ler: lerArquivoLimitado,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** O primeiro destes eventos da sessão no ledger da thread é o fim dela. */
|
|
165
|
+
const FIM_DA_SESSAO = ['phase_result', 'sessao_morta', 'session_superseded'];
|
|
166
|
+
const numero = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
167
|
+
/** As linhas JSON de um arquivo de acréscimo; a última sem quebra está sendo gravada e fica de fora. */
|
|
168
|
+
function linhasJson(bruto) {
|
|
169
|
+
const fim = bruto.lastIndexOf(0x0a) + 1;
|
|
170
|
+
const textos = bruto.subarray(0, fim).toString('utf8').split('\n').slice(0, -1);
|
|
171
|
+
const linhas = [];
|
|
172
|
+
let ilegivel = 0;
|
|
173
|
+
for (const t of textos) {
|
|
174
|
+
if (!t.trim())
|
|
175
|
+
continue;
|
|
176
|
+
try {
|
|
177
|
+
linhas.push(JSON.parse(t));
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
ilegivel += 1;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { linhas, ilegivel };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Os tokens das transcrições do Claude Code: um uso por `message.id`, somando entrada, criação de cache, leitura de
|
|
187
|
+
* cache e saída. Linha ilegível no meio (não a cauda em gravação) é lacuna: ela poderia esconder uso.
|
|
188
|
+
*/
|
|
189
|
+
function tokensDasTranscricoes(conteudos) {
|
|
190
|
+
const vistos = new Set();
|
|
191
|
+
let total = 0;
|
|
192
|
+
for (const bruto of conteudos) {
|
|
193
|
+
const lido = linhasJson(bruto);
|
|
194
|
+
if (!lido)
|
|
195
|
+
return { lacuna: 'transcrição ilegível' };
|
|
196
|
+
if (lido.ilegivel)
|
|
197
|
+
return { lacuna: `transcrição com ${lido.ilegivel} linha(s) ilegível(is) no meio` };
|
|
198
|
+
for (const l of lido.linhas) {
|
|
199
|
+
const e = l;
|
|
200
|
+
if (e?.type !== 'assistant' || !e.message || typeof e.message !== 'object' || !e.message.usage)
|
|
201
|
+
continue;
|
|
202
|
+
const u = e.message.usage;
|
|
203
|
+
const partes = [u.input_tokens, u.cache_creation_input_tokens ?? 0, u.cache_read_input_tokens ?? 0, u.output_tokens];
|
|
204
|
+
if (!partes.every(numero))
|
|
205
|
+
return { lacuna: 'transcrição com uso de tokens fora do formato' };
|
|
206
|
+
// Sem id, a linha conta sozinha: duplicar superestima, nunca subestima.
|
|
207
|
+
const chave = typeof e.message.id === 'string' && e.message.id ? e.message.id : `linha:${vistos.size}:${String(e.uuid)}`;
|
|
208
|
+
if (vistos.has(chave))
|
|
209
|
+
continue;
|
|
210
|
+
vistos.add(chave);
|
|
211
|
+
total += partes.reduce((a, b) => a + b, 0);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { valor: total, parcial: false, tetoSuperior: false, fonte: 'message.usage da transcrição do Claude Code' };
|
|
215
|
+
}
|
|
216
|
+
/** Os tokens e as leituras da cota do rollout do codex: o último `token_count` e cada `rate_limits` dele. */
|
|
217
|
+
function leituraDoRollout(bruto) {
|
|
218
|
+
const lido = linhasJson(bruto);
|
|
219
|
+
if (!lido || lido.ilegivel)
|
|
220
|
+
return { tokens: { lacuna: 'rollout com linha ilegível no meio' }, cota: { lacuna: 'rollout com linha ilegível no meio' } };
|
|
221
|
+
let total = null;
|
|
222
|
+
const cota = [];
|
|
223
|
+
for (const l of lido.linhas) {
|
|
224
|
+
const e = l;
|
|
225
|
+
const p = e?.type === 'event_msg' ? e.payload : e;
|
|
226
|
+
if (!p || p.type !== 'token_count')
|
|
227
|
+
continue;
|
|
228
|
+
const info = p.info;
|
|
229
|
+
const uso = info?.total_token_usage;
|
|
230
|
+
if (uso && typeof uso === 'object') {
|
|
231
|
+
const t = uso.total_tokens ?? (numero(uso.input_tokens) && numero(uso.output_tokens) ? Number(uso.input_tokens) + Number(uso.output_tokens) : undefined);
|
|
232
|
+
if (numero(t))
|
|
233
|
+
total = t;
|
|
234
|
+
}
|
|
235
|
+
const limites = p.rate_limits;
|
|
236
|
+
const lidaEm = typeof e.timestamp === 'string' && Number.isFinite(Date.parse(e.timestamp)) ? new Date(Date.parse(e.timestamp)).toISOString() : null;
|
|
237
|
+
if (!limites || typeof limites !== 'object' || !lidaEm)
|
|
238
|
+
continue;
|
|
239
|
+
for (const nome of ['primary', 'secondary']) {
|
|
240
|
+
const j = limites[nome];
|
|
241
|
+
if (!j || typeof j !== 'object' || !numero(j.used_percent) || !numero(j.window_minutes))
|
|
242
|
+
continue;
|
|
243
|
+
const renovaEm = numero(j.resets_at) ? Number(j.resets_at) * 1000
|
|
244
|
+
: numero(j.resets_in_seconds) ? Date.parse(lidaEm) + Number(j.resets_in_seconds) * 1000 : null;
|
|
245
|
+
cota.push({ janelaMin: Number(j.window_minutes), usado: Number(j.used_percent), renovaEm, lidaEm });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return { tokens: total === null ? { lacuna: 'rollout sem contagem de tokens ainda' }
|
|
249
|
+
: { valor: total, parcial: false, tetoSuperior: false, fonte: 'token_count do rollout do codex' }, cota };
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A cota do codex de uma conta pelas leituras das sessões do arco: o `used_percent` mais alto de cada janela, e a janela
|
|
253
|
+
* que mais subiu manda. A janela que renovou entre leituras é lacuna (o uso de antes da renovação não se prova).
|
|
254
|
+
*/
|
|
255
|
+
function cotaDasLeituras(leituras) {
|
|
256
|
+
if (!leituras.length)
|
|
257
|
+
return { lacuna: 'nenhuma leitura da cota no rollout das sessões do arco' };
|
|
258
|
+
let maior = 0;
|
|
259
|
+
const porJanela = new Map();
|
|
260
|
+
for (const l of leituras)
|
|
261
|
+
porJanela.set(l.janelaMin, [...(porJanela.get(l.janelaMin) ?? []), l]);
|
|
262
|
+
for (const [janela, lista] of porJanela) {
|
|
263
|
+
const renovacoes = lista.map(l => l.renovaEm).filter((x) => x !== null);
|
|
264
|
+
if (renovacoes.length && Math.max(...renovacoes) - Math.min(...renovacoes) > TOLERANCIA_DA_RENOVACAO_MS) {
|
|
265
|
+
return { lacuna: `a janela de ${janela} min renovou no meio do arco; o uso de antes da renovação não se prova` };
|
|
266
|
+
}
|
|
267
|
+
maior = Math.max(maior, ...lista.map(l => l.usado));
|
|
268
|
+
}
|
|
269
|
+
return { valor: maior, parcial: false, tetoSuperior: true,
|
|
270
|
+
fonte: 'rate_limits do rollout do codex (inclui o uso de antes do arco e de outros projetos na janela)' };
|
|
271
|
+
}
|
|
272
|
+
function medirSessao(d, quando, fontes) {
|
|
273
|
+
const base = { seq: d.seq, trabalho: d.trabalho, thread: d.threadDespachada ?? d.thread, sessionId: d.sessionId, runtime: d.runtime,
|
|
274
|
+
conta: d.conta, inicio: null, fim: null, emVoo: false };
|
|
275
|
+
const lacuna = (motivo) => ({ ...base, emVoo: true, minutos: { lacuna: motivo }, tokens: { lacuna: motivo },
|
|
276
|
+
cota: { lacuna: motivo } });
|
|
277
|
+
if (d.desfecho === 'pendente')
|
|
278
|
+
return lacuna('reserva pendente: a sessão pode ter aberto sem id, e o consumo fica desconhecido até a reconciliação');
|
|
279
|
+
if (!d.sessionId || !base.thread) {
|
|
280
|
+
// O despacho idempotente sem sessão nova não abriu nada: zero provado para esta reserva.
|
|
281
|
+
const zero = { valor: 0, parcial: false, tetoSuperior: false, fonte: 'despacho idempotente: a sessão em curso já atendia' };
|
|
282
|
+
return { ...base, minutos: zero, tokens: zero, cota: [] };
|
|
283
|
+
}
|
|
284
|
+
const thread = base.thread, sessionId = d.sessionId;
|
|
285
|
+
const eventos = fontes.eventos(thread);
|
|
286
|
+
if (eventos === null)
|
|
287
|
+
return lacuna(`o ledger da thread ${thread} não se lê`);
|
|
288
|
+
const inicio = eventos.find(e => e.tipo === ledger_1.TIPOS_DE_EVENTO.faseDespachada && e.sessionId === sessionId)?.ts ?? null;
|
|
289
|
+
const fim = inicio ? eventos.find(e => FIM_DA_SESSAO.includes(e.tipo) && e.sessionId === sessionId && e.ts >= inicio)?.ts ?? null : null;
|
|
290
|
+
const emVoo = fim === null;
|
|
291
|
+
const duracao = inicio ? Math.ceil((Date.parse(fim ?? quando) - Date.parse(inicio)) / 60_000) : Number.NaN;
|
|
292
|
+
const minutos = !inicio ? { lacuna: `sem o phase_dispatch da sessão ${sessionId} no ledger da thread ${thread}` }
|
|
293
|
+
// Instante que não é data (linha emendada à mão) não vira NaN abaixo do teto: é lacuna.
|
|
294
|
+
: !Number.isFinite(duracao) ? { lacuna: `instante ilegível no ledger da thread ${thread} para a sessão ${sessionId}` }
|
|
295
|
+
: { valor: Math.max(0, duracao), parcial: emVoo, tetoSuperior: false,
|
|
296
|
+
fonte: emVoo ? 'do phase_dispatch até a leitura (sessão em voo)' : 'do phase_dispatch ao resultado gravado no ledger' };
|
|
297
|
+
const perfil = fontes.perfil(d.conta);
|
|
298
|
+
let tokens;
|
|
299
|
+
let cota;
|
|
300
|
+
if (perfil === undefined) {
|
|
301
|
+
tokens = { lacuna: 'o store de perfis não se lê' };
|
|
302
|
+
cota = { lacuna: 'o store de perfis não se lê' };
|
|
303
|
+
}
|
|
304
|
+
else if (d.runtime === 'claude-bg') {
|
|
305
|
+
cota = { lacuna: 'o Claude Code só mostra a cota aos mods dentro da sessão, fora do alcance do núcleo' };
|
|
306
|
+
const cwd = fontes.cwd(thread);
|
|
307
|
+
const arquivos = cwd ? fontes.transcricoes(perfil, cwd, sessionId) : null;
|
|
308
|
+
if (!cwd)
|
|
309
|
+
tokens = { lacuna: `a thread ${thread} não diz onde a sessão rodou` };
|
|
310
|
+
else if (!arquivos)
|
|
311
|
+
tokens = { lacuna: `sem a transcrição da sessão ${sessionId}` };
|
|
312
|
+
else {
|
|
313
|
+
// Um arquivo por vez na memória: a sessão com muitos subagentes não junta todas as transcrições de uma vez.
|
|
314
|
+
let ilegivel = false;
|
|
315
|
+
const lidas = function* () {
|
|
316
|
+
for (const a of arquivos) {
|
|
317
|
+
const c = fontes.ler(a);
|
|
318
|
+
if (c === null) {
|
|
319
|
+
ilegivel = true;
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
yield c;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
const medida = tokensDasTranscricoes(lidas());
|
|
326
|
+
tokens = ilegivel ? { lacuna: 'transcrição que não se lê' } : medida;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else if (d.runtime === 'codex') {
|
|
330
|
+
const arquivo = fontes.rollout(perfil, sessionId);
|
|
331
|
+
const bruto = arquivo ? fontes.ler(arquivo) : null;
|
|
332
|
+
if (!bruto) {
|
|
333
|
+
tokens = { lacuna: `sem o rollout da sessão ${sessionId}` };
|
|
334
|
+
cota = { lacuna: `sem o rollout da sessão ${sessionId}` };
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
const r = leituraDoRollout(bruto);
|
|
338
|
+
tokens = r.tokens;
|
|
339
|
+
cota = r.cota;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
tokens = { lacuna: `runtime ${d.runtime} sem fonte de medição` };
|
|
344
|
+
cota = { lacuna: `runtime ${d.runtime} sem fonte de medição` };
|
|
345
|
+
}
|
|
346
|
+
if ('valor' in tokens)
|
|
347
|
+
tokens = { ...tokens, parcial: emVoo };
|
|
348
|
+
return { ...base, inicio, fim, emVoo, minutos, tokens, cota };
|
|
349
|
+
}
|
|
350
|
+
function vazio(unidade) {
|
|
351
|
+
return { unidade, valor: 0, lacunas: [], parcial: false, tetoSuperior: false, sessoes: 0 };
|
|
352
|
+
}
|
|
353
|
+
function somar(alvo, m, origem) {
|
|
354
|
+
alvo.sessoes += 1;
|
|
355
|
+
if ('lacuna' in m || !Number.isFinite(m.valor)) {
|
|
356
|
+
alvo.lacunas.push(`${origem}: ${'lacuna' in m ? m.lacuna : 'medida que não é número'}`);
|
|
357
|
+
alvo.valor = null;
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (alvo.valor !== null)
|
|
361
|
+
alvo.valor += m.valor;
|
|
362
|
+
alvo.parcial = alvo.parcial || m.parcial;
|
|
363
|
+
alvo.tetoSuperior = alvo.tetoSuperior || m.tetoSuperior;
|
|
364
|
+
}
|
|
365
|
+
/** As sessões do escopo, somadas em cada unidade; a cota é somada por conta (cada conta com a medida da cota dela). */
|
|
366
|
+
function consumoDoEscopo(sessoes, sessoesNaUnidade) {
|
|
367
|
+
const r = Object.fromEntries(noctum_envelope_1.UNIDADES.map(u => [u, vazio(u)]));
|
|
368
|
+
r.sessoes.valor = sessoesNaUnidade;
|
|
369
|
+
r.sessoes.sessoes = sessoesNaUnidade;
|
|
370
|
+
for (const s of sessoes) {
|
|
371
|
+
const origem = `sessão ${s.sessionId ?? `da reserva ${s.seq}`} (${s.trabalho})`;
|
|
372
|
+
somar(r['minutos-de-sessao'], s.minutos, origem);
|
|
373
|
+
somar(r.tokens, s.tokens, origem);
|
|
374
|
+
}
|
|
375
|
+
for (const conta of [...new Set(sessoes.map(s => s.conta))].sort()) {
|
|
376
|
+
const daConta = sessoes.filter(s => s.conta === conta);
|
|
377
|
+
const comLacuna = daConta.find(s => !Array.isArray(s.cota));
|
|
378
|
+
const medida = comLacuna ? { lacuna: comLacuna.cota.lacuna }
|
|
379
|
+
: cotaDasLeituras(daConta.flatMap(s => s.cota));
|
|
380
|
+
somar(r['percentual-da-cota'], medida, `conta ${conta}`);
|
|
381
|
+
}
|
|
382
|
+
r['percentual-da-cota'].sessoes = sessoes.length;
|
|
383
|
+
return r;
|
|
384
|
+
}
|
|
385
|
+
/** Mede o consumo do arco no instante dado. Sem gravar nada; a sessão repetida (o mesmo id) conta uma vez. */
|
|
386
|
+
function medirArco(raiz, estado, opcoes = {}) {
|
|
387
|
+
const quando = opcoes.quando ?? new Date().toISOString();
|
|
388
|
+
const base = { ...fontesDoDisco(raiz), ...opcoes.fontes };
|
|
389
|
+
// O ledger de cada thread é lido uma vez por medição, e não uma vez por sessão.
|
|
390
|
+
const ledgers = new Map();
|
|
391
|
+
const fontes = { ...base, eventos: (thread) => {
|
|
392
|
+
if (!ledgers.has(thread))
|
|
393
|
+
ledgers.set(thread, base.eventos(thread));
|
|
394
|
+
return ledgers.get(thread);
|
|
395
|
+
} };
|
|
396
|
+
const vistas = new Set();
|
|
397
|
+
const sessoes = [];
|
|
398
|
+
for (const d of estado.despachos) {
|
|
399
|
+
if (d.desfecho === 'recusado')
|
|
400
|
+
continue;
|
|
401
|
+
if (d.sessionId) {
|
|
402
|
+
if (vistas.has(d.sessionId))
|
|
403
|
+
continue;
|
|
404
|
+
vistas.add(d.sessionId);
|
|
405
|
+
}
|
|
406
|
+
sessoes.push(medirSessao(d, quando, fontes));
|
|
407
|
+
}
|
|
408
|
+
const contas = [...new Set(sessoes.map(s => s.conta))].sort(), runtimes = [...new Set(sessoes.map(s => s.runtime))].sort();
|
|
409
|
+
return {
|
|
410
|
+
contrato: exports.CONTRATO_MEDICAO, arco: estado.arco, quando, sessoes,
|
|
411
|
+
doArco: consumoDoEscopo(sessoes, estado.consumo.arco),
|
|
412
|
+
porConta: Object.fromEntries(contas.map(c => [c, consumoDoEscopo(sessoes.filter(s => s.conta === c), estado.consumo.porConta[c] ?? 0)])),
|
|
413
|
+
porRuntime: Object.fromEntries(runtimes.map(r => [r, consumoDoEscopo(sessoes.filter(s => s.runtime === r), estado.consumo.porRuntime[r] ?? 0)])),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/** O consumo de um escopo numa unidade; escopo sem sessão do arco mede zero (provado: nenhuma sessão caiu nele). */
|
|
417
|
+
function consumoDoEscopoNaUnidade(medicao, escopo, unidade) {
|
|
418
|
+
const porUnidade = escopo === 'arco' ? medicao.doArco : 'conta' in escopo ? medicao.porConta[escopo.conta] : medicao.porRuntime[escopo.runtime];
|
|
419
|
+
return porUnidade?.[unidade] ?? vazio(unidade);
|
|
420
|
+
}
|
|
421
|
+
/** Algum teto do envelope está numa unidade que não é `sessoes`? Só então o passo precisa medir. */
|
|
422
|
+
function precisaMedir(conteudo) {
|
|
423
|
+
const o = conteudo.orcamento;
|
|
424
|
+
return [o.arco, ...o.porConta.map(s => s.teto), ...o.porRuntime.map(s => s.teto)].some(t => t.unidade !== 'sessoes');
|
|
425
|
+
}
|
|
426
|
+
const valorMedido = (c) => c.valor === null
|
|
427
|
+
? { unidade: c.unidade, lacuna: c.lacunas.join('; ') || 'consumo desconhecido' }
|
|
428
|
+
: { unidade: c.unidade, valor: c.valor, ...(c.tetoSuperior ? { tetoSuperior: true } : {}) };
|
|
429
|
+
/** O consumo medido dos três tetos de um despacho (arco, conta e runtime), cada um na unidade dele. */
|
|
430
|
+
function medidoParaReserva(medicao, conteudo, conta, runtime) {
|
|
431
|
+
const o = conteudo.orcamento;
|
|
432
|
+
const daConta = o.porConta.find(s => s.conta === conta)?.teto, doRuntime = o.porRuntime.find(s => s.runtime === runtime)?.teto;
|
|
433
|
+
// A sessão do claude-bg nunca terá a cota medida fora dela: o teto em percentual não se garante para ela, nem com o
|
|
434
|
+
// zero provado de um escopo ainda sem sessão (runtime sem medição suficiente não é elegível para o regime).
|
|
435
|
+
const medido = (c) => c.unidade === 'percentual-da-cota' && runtime === 'claude-bg'
|
|
436
|
+
? { unidade: c.unidade, lacuna: 'o Claude Code só mostra a cota dentro da sessão, e o teto em percentual não se garante para ele' }
|
|
437
|
+
: valorMedido(c);
|
|
438
|
+
return {
|
|
439
|
+
arco: medido(consumoDoEscopoNaUnidade(medicao, 'arco', o.arco.unidade)),
|
|
440
|
+
...(daConta ? { conta: medido(consumoDoEscopoNaUnidade(medicao, { conta }, daConta.unidade)) } : {}),
|
|
441
|
+
...(doRuntime ? { runtime: medido(consumoDoEscopoNaUnidade(medicao, { runtime }, doRuntime.unidade)) } : {}),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
/** Uma medida em texto para pessoa: o valor com a unidade e o rótulo, ou a lacuna. */
|
|
445
|
+
function textoDoConsumo(c) {
|
|
446
|
+
if (c.valor === null)
|
|
447
|
+
return `lacuna (${c.lacunas.join('; ') || 'consumo desconhecido'})`;
|
|
448
|
+
const valor = c.unidade === 'percentual-da-cota' ? `${Math.round(c.valor * 10) / 10}%` : `${c.valor} ${c.unidade}`;
|
|
449
|
+
return `${c.tetoSuperior ? 'até ' : ''}${valor}${c.parcial ? ' até agora (sessão em voo)' : ''}${c.tetoSuperior ? ' (teto superior)' : ''}`;
|
|
450
|
+
}
|