@orkastery/cli 0.2.0 → 0.3.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/LICENSE +1 -1
- package/README.md +86 -65
- package/adapters/README.md +30 -15
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
- package/adapters/claude-code/README.md +110 -8
- package/adapters/claude-code/commands/onboarding.md +21 -0
- package/adapters/claude-code/commands/ork.md +99 -27
- package/adapters/claude-code/hooks/hooks.json +6 -1
- package/adapters/claude-code/hooks/ork-sensor.js +66 -0
- package/adapters/codex/skills/ork/SKILL.md +57 -0
- package/adapters/hermes/README.md +163 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
- package/adapters/hermes/bin/ork-brain.sh +4 -0
- package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
- package/adapters/hermes/bin/ork-maestro.sh +6 -0
- package/adapters/hermes/bin/ork-master-enviar.py +84 -0
- package/adapters/hermes/bin/ork-objective-message.sh +17 -0
- package/adapters/hermes/bin/ork-objective-status.sh +12 -0
- package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +26 -4
- package/adapters/hermes/hitl-ingress/__init__.py +356 -0
- package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
- package/adapters/openclaw/README.md +135 -26
- package/adapters/openclaw/bin/ork-brain.sh +4 -0
- package/adapters/openclaw/construir.sh +19 -0
- package/adapters/openclaw/dist/hitl-ingress.js +199 -0
- package/adapters/openclaw/dist/index.js +437 -0
- package/adapters/openclaw/openclaw.plugin.json +39 -134
- package/adapters/openclaw/package.json +26 -0
- package/adapters/openclaw/src/hitl-ingress.ts +180 -0
- package/adapters/openclaw/src/index.ts +458 -0
- package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
- package/adapters/openclaw/tsconfig.json +15 -0
- package/assets/docs/markdownlint-cli2.jsonc +22 -0
- package/assets/docs/padroes/documentacao-de-produto.md +133 -0
- package/assets/docs/padroes/roadmap-de-produto.md +98 -0
- package/assets/docs/produto/README.md +14 -0
- package/assets/docs/produto/_modelo-feature.md +59 -0
- package/assets/docs/roadmap/README.md +14 -0
- package/assets/docs/roadmap/_modelo-item.md +73 -0
- package/assets/orkmind-native-schema.json +32 -0
- package/assets/orkmind_bridge.py +357 -0
- package/assets/orkmind_fixture.py +67 -0
- package/assets/orkmind_prospective.py +138 -0
- package/assets/reference-tariffs-i07.json +23 -0
- package/dist/adapters/claude-bg.js +488 -39
- package/dist/adapters/codex-controller-sensor.js +449 -0
- package/dist/adapters/codex-controller-worker.js +361 -0
- package/dist/adapters/codex-controller.js +252 -0
- package/dist/adapters/codex-events.js +205 -0
- package/dist/adapters/codex-question.js +26 -0
- package/dist/adapters/codex-runner.js +133 -0
- package/dist/adapters/codex.js +394 -0
- package/dist/agents-md.js +84 -0
- package/dist/auditoria.js +11 -8
- package/dist/auditrun.js +5 -4
- package/dist/board.js +173 -22
- package/dist/branch-de-estado.js +136 -0
- package/dist/canarios-hitl.js +177 -0
- package/dist/canarios-i43.js +543 -0
- package/dist/canarios-pulse.js +147 -0
- package/dist/canarios-sensores.js +129 -0
- package/dist/canarios.js +111 -2
- package/dist/catalogo.js +9 -0
- package/dist/ci.js +216 -0
- package/dist/ciclos.js +2 -1
- package/dist/claim-lint.js +64 -0
- package/dist/claims.js +60 -0
- package/dist/company-brain-capture.js +195 -0
- package/dist/company-brain-cli.js +123 -0
- package/dist/company-brain-client.js +61 -0
- package/dist/company-brain-contract.js +166 -0
- package/dist/company-brain-journal.js +192 -0
- package/dist/company-brain-mcp.js +33 -0
- package/dist/company-brain-migration.js +60 -0
- package/dist/company-brain-source.js +177 -0
- package/dist/company-brain-worker.js +18 -0
- package/dist/conducao-texto.js +61 -0
- package/dist/conducao.js +876 -0
- package/dist/contrato-publico.js +39 -0
- package/dist/creation-operation-store.js +251 -0
- package/dist/creation-operation.js +148 -0
- package/dist/decisao-autonoma.js +183 -0
- package/dist/delegation.js +79 -0
- package/dist/demo.js +120 -0
- package/dist/docs.js +828 -0
- package/dist/doctor.js +183 -24
- package/dist/entrega-pr.js +117 -0
- package/dist/escopo-escrita.js +71 -0
- package/dist/estado-thread.js +222 -0
- package/dist/evalrunner.js +12 -0
- package/dist/fabrica-estado.js +329 -0
- package/dist/fabrica-publicar.js +76 -0
- package/dist/fix.js +21 -0
- package/dist/gates.js +55 -9
- package/dist/handoff.js +39 -23
- package/dist/hitl-canais.js +333 -0
- package/dist/hitl-classificacao.js +131 -0
- package/dist/hitl-contract.js +465 -0
- package/dist/hitl-estado.js +136 -0
- package/dist/hitl-gates.js +554 -0
- package/dist/hitl-ingress-receipt.js +382 -0
- package/dist/hitl-local-atestado.js +57 -0
- package/dist/hitl-local-receipt.js +328 -0
- package/dist/hitl-local.js +143 -0
- package/dist/hitl-lock.js +139 -0
- package/dist/hitl-lote.js +223 -0
- package/dist/hitl-native-offer.js +97 -0
- package/dist/hitl-native.js +65 -0
- package/dist/hitl-presentation.js +209 -0
- package/dist/hitl-public-receipt.js +176 -0
- package/dist/hitl-resumo.js +209 -0
- package/dist/hitl-sessions.js +475 -0
- package/dist/hitl.js +711 -0
- package/dist/horario.js +269 -0
- package/dist/hosts.js +198 -22
- package/dist/index.js +1736 -93
- package/dist/indice.js +99 -0
- package/dist/init.js +28 -3
- package/dist/integracoes-locais.js +17 -0
- package/dist/leases.js +65 -21
- package/dist/ledger-stats.js +272 -0
- package/dist/ledger.js +107 -2
- package/dist/licoes.js +215 -0
- package/dist/liveness.js +218 -0
- package/dist/maestro-actions.js +51 -0
- package/dist/maestro-authority.js +152 -0
- package/dist/maestro-cli.js +97 -0
- package/dist/maestro-contract.js +55 -0
- package/dist/maestro-discovery.js +132 -0
- package/dist/maestro-runtime.js +268 -0
- package/dist/maestro-snapshot.js +86 -0
- package/dist/maestro-sources.js +224 -0
- package/dist/manifest.js +165 -6
- package/dist/maquina.js +102 -0
- package/dist/master-audit.js +101 -0
- package/dist/master-batch.js +43 -0
- package/dist/master-digest.js +149 -0
- package/dist/master-migracao.js +155 -0
- package/dist/master.js +361 -77
- package/dist/mcp-artifacts.js +234 -0
- package/dist/mcp-git.js +433 -0
- package/dist/mcp-install.js +310 -0
- package/dist/mcp-maestro.js +25 -0
- package/dist/mcp-server.js +469 -0
- package/dist/mcp-ship.js +436 -0
- package/dist/mcp-verify.js +173 -0
- package/dist/memoria-humana.js +207 -0
- package/dist/memoria.js +314 -78
- package/dist/memory-migration.js +279 -0
- package/dist/memory-prospective.js +148 -0
- package/dist/modos-migracao.js +191 -0
- package/dist/modos.js +151 -15
- package/dist/monitor-lock.js +110 -0
- package/dist/objective.js +449 -0
- package/dist/ocupacao.js +267 -0
- package/dist/onboarding.js +303 -0
- package/dist/orkmind.js +389 -90
- package/dist/orquestracao.js +96 -69
- package/dist/phase.js +596 -150
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/portfolio-context.js +61 -0
- package/dist/portfolio.js +180 -0
- package/dist/preflight.js +207 -0
- package/dist/process-audit.js +112 -0
- package/dist/project-state.js +93 -0
- package/dist/prompts.js +25 -5
- package/dist/prova-minima.js +112 -0
- package/dist/pulse-cadencia.js +163 -0
- package/dist/pulse-consentimento.js +260 -0
- package/dist/pulse-delivery.js +323 -0
- package/dist/pulse-resposta.js +542 -0
- package/dist/pulse.js +262 -0
- package/dist/ratelimit.js +35 -2
- package/dist/recall.js +80 -3
- package/dist/redacao-saida.js +45 -0
- package/dist/redacao-url.js +66 -0
- package/dist/retry.js +637 -115
- package/dist/roadmap-reservas.js +243 -0
- package/dist/runtime-ambiente.js +38 -0
- package/dist/runtime-context.js +215 -0
- package/dist/runtime-profiles.js +869 -0
- package/dist/runtimes.js +103 -0
- package/dist/sandbox.js +9 -0
- package/dist/session-events.js +203 -0
- package/dist/session-watcher-claude.js +637 -0
- package/dist/session-watcher.js +683 -0
- package/dist/sessoes-adopt.js +154 -0
- package/dist/sessoes-inventario.js +159 -0
- package/dist/sessoes.js +16 -35
- package/dist/setup.js +691 -0
- package/dist/ship.js +150 -15
- package/dist/slug.js +1 -1
- package/dist/thread-close.js +115 -0
- package/dist/thread.js +142 -28
- package/dist/tokens.js +1 -1
- package/dist/util.js +4 -2
- package/dist/verify-sandbox.js +265 -0
- package/dist/verify.js +270 -25
- package/dist/versao.js +60 -0
- package/dist/worktree.js +31 -2
- package/dist/write-activation.js +291 -0
- package/dist/yaml.js +2 -0
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +35 -1
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +2 -2
- package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
- package/eval/fixtures/b2-master-log/caso.json +1 -1
- package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
- package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
- package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
- package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
- package/eval/fixtures/fx-codex-dry/caso.json +18 -0
- package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
- package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
- package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
- package/eval/fixtures/fx-happy/caso.json +6 -4
- package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
- package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
- package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
- package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
- package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
- package/eval/fixtures/fx-omnicanal/caso.json +17 -0
- package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
- package/monitor/company-brain.cjs +17 -0
- package/monitor/pulse-scope.cjs +45 -0
- package/monitor/pulse.cron +18 -0
- package/monitor/varredura-pulse.sh +27 -0
- package/package.json +25 -4
- package/schemas/claims.schema.json +25 -0
- package/schemas/company-brain.schema.json +1158 -0
- package/schemas/creation-operation.schema.json +365 -0
- package/schemas/maestro-snapshot.schema.json +2716 -0
- package/skills/core/onboarding/SKILL.md +50 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
- package/skills/core/thread-state/SKILL.md +3 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/indice.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* O indice automatico de qualidade da entrega (I-43, D3).
|
|
4
|
+
*
|
|
5
|
+
* Ele existe para substituir a fila de ratificacao de score, e o problema que a fila
|
|
6
|
+
* tinha nao era falta de lembrete: eram 13 entradas esperando nota humana justamente
|
|
7
|
+
* porque lembrete nao converte em nota. A saida e ACEITACAO POR DEFAULT com registro:
|
|
8
|
+
* entregue e aceito, a menos que o dono diga o contrario, e a nota humana passa a
|
|
9
|
+
* existir so quando ele reclamar, e ai vale.
|
|
10
|
+
*
|
|
11
|
+
* DUAS REGRAS DURAS, e elas explicam quase todo o resto deste arquivo.
|
|
12
|
+
*
|
|
13
|
+
* 1. So entra fato que tem ESCRITOR no nucleo e entrada no catalogo `TIPOS_DE_EVENTO`.
|
|
14
|
+
* A medida que motivou isso: os 137 ledgers do projeto trazem mais de 200 valores
|
|
15
|
+
* distintos de `tipo`, muitos com uma ocorrencia so, com variantes do mesmo fato
|
|
16
|
+
* (`lease_acquire` x `lease_acquired`, `claim_novo` x `claim_added`) e ate lixo
|
|
17
|
+
* literal (`B`, `path`, `commit`). Um indice que case string livre no ledger e um
|
|
18
|
+
* indice que mente: `verify_result` tem 122 ocorrencias e ZERO escritor no nucleo.
|
|
19
|
+
*
|
|
20
|
+
* 2. O indice e DERIVADO, nunca digitado. Nao existe caminho que aceite um numero de
|
|
21
|
+
* fora. E a diferenca entre este campo e o `score`, que hoje mistura tres coisas:
|
|
22
|
+
* das 19 notas em disco, 9 nao sao juizo humano de qualidade (3 sao carimbo cujo
|
|
23
|
+
* proprio texto diz "ratificacao pendente", 3 comecam com "Proponho" e sao proposta
|
|
24
|
+
* de agente, e 3 sao `valor: 0` de encerramento administrativo).
|
|
25
|
+
*
|
|
26
|
+
* RESERVA HONESTA, que precisa estar escrita aqui e nao so no PLAN: o indice NAO
|
|
27
|
+
* classifica o passado. Com os insumos que hoje tem escritor, 23 das 29 threads
|
|
28
|
+
* entregues ficariam coladas no teto, porque `rollback_done` tinha ZERO ocorrencias.
|
|
29
|
+
* Ele comeca a discriminar a partir do momento em que o escritor de reversao existir
|
|
30
|
+
* (T7, em `ship.ts`). Cobrar do indice um veredito sobre o historico seria cobrar um
|
|
31
|
+
* numero que ele nao tem como produzir.
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.INSUMOS_DO_INDICE = exports.INDICE_MINIMO = exports.INDICE_BASE = void 0;
|
|
35
|
+
exports.calcularIndice = calcularIndice;
|
|
36
|
+
exports.textoDoIndice = textoDoIndice;
|
|
37
|
+
const ledger_1 = require("./ledger");
|
|
38
|
+
/** Nota maxima, e o ponto de partida: entregue e aceito ate prova em contrario. */
|
|
39
|
+
exports.INDICE_BASE = 5;
|
|
40
|
+
exports.INDICE_MINIMO = 0;
|
|
41
|
+
/**
|
|
42
|
+
* Os pesos de D3. Reversao pesa sozinha mais que tudo junto, e e de proposito:
|
|
43
|
+
* ela e o unico fato que diz, sem interpretacao, que a entrega nao servia.
|
|
44
|
+
*/
|
|
45
|
+
exports.INSUMOS_DO_INDICE = [
|
|
46
|
+
{ evento: ledger_1.TIPOS_DE_EVENTO.rollbackConcluido, peso: -3, piso: -3,
|
|
47
|
+
sobre: 'a entrega foi revertida depois do ship' },
|
|
48
|
+
{ evento: ledger_1.TIPOS_DE_EVENTO.fixAberto, peso: -0.5, piso: -1.5,
|
|
49
|
+
sobre: 'rodadas de GO-FIX: o CHECK reprovou e a entrega precisou de correcao' },
|
|
50
|
+
{ evento: ledger_1.TIPOS_DE_EVENTO.reverifyConcluido, peso: -0.5, piso: -1,
|
|
51
|
+
sobre: 'CHECK refeito: a verificacao precisou de uma segunda rodada' },
|
|
52
|
+
{ evento: ledger_1.TIPOS_DE_EVENTO.shipBloqueado, peso: -0.25, piso: -0.5,
|
|
53
|
+
sobre: 'ship barrado antes de entregar' },
|
|
54
|
+
];
|
|
55
|
+
/**
|
|
56
|
+
* Calcula o indice de uma thread a partir do ledger dela.
|
|
57
|
+
*
|
|
58
|
+
* PURA: le eventos, devolve numero, nao escreve nada e nao toca em git. Quem detecta
|
|
59
|
+
* reversao e `ship.ts`, que e quem sabe de merge e de base; aqui so se conta o evento
|
|
60
|
+
* que ele gravou.
|
|
61
|
+
*/
|
|
62
|
+
function calcularIndice(eventos) {
|
|
63
|
+
const parcelas = [];
|
|
64
|
+
let valor = exports.INDICE_BASE;
|
|
65
|
+
for (const insumo of exports.INSUMOS_DO_INDICE) {
|
|
66
|
+
const ocorrencias = eventos.filter((e) => e.tipo === insumo.evento).length;
|
|
67
|
+
if (ocorrencias === 0)
|
|
68
|
+
continue;
|
|
69
|
+
const bruto = insumo.peso * ocorrencias;
|
|
70
|
+
const desconto = Math.max(bruto, insumo.piso);
|
|
71
|
+
parcelas.push({
|
|
72
|
+
evento: insumo.evento,
|
|
73
|
+
sobre: insumo.sobre,
|
|
74
|
+
ocorrencias,
|
|
75
|
+
desconto,
|
|
76
|
+
noPiso: bruto < insumo.piso,
|
|
77
|
+
});
|
|
78
|
+
valor += desconto;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
valor: Math.max(exports.INDICE_MINIMO, Math.min(exports.INDICE_BASE, Number(valor.toFixed(2)))),
|
|
82
|
+
base: exports.INDICE_BASE,
|
|
83
|
+
parcelas,
|
|
84
|
+
derivado: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Texto de uma linha por parcela, para `ork master` mostrar de onde o numero veio. */
|
|
88
|
+
function textoDoIndice(indice) {
|
|
89
|
+
const linhas = [`indice ${indice.valor} de ${indice.base} (derivado do ledger, nunca digitado)`];
|
|
90
|
+
if (indice.parcelas.length === 0) {
|
|
91
|
+
linhas.push(' nenhum insumo: a entrega nao registrou reversao, GO-FIX, CHECK refeito nem ship barrado');
|
|
92
|
+
return linhas.join('\n');
|
|
93
|
+
}
|
|
94
|
+
for (const p of indice.parcelas) {
|
|
95
|
+
linhas.push(` ${p.desconto.toFixed(2).padStart(6)} ${p.evento} x${p.ocorrencias}${p.noPiso ? ' (no piso)' : ''}`);
|
|
96
|
+
linhas.push(` ${p.sobre}`);
|
|
97
|
+
}
|
|
98
|
+
return linhas.join('\n');
|
|
99
|
+
}
|
package/dist/init.js
CHANGED
|
@@ -39,6 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.PROXIMO_PASSO_INIT = void 0;
|
|
42
43
|
exports.raizDoRepo = raizDoRepo;
|
|
43
44
|
exports.nomeDetectado = nomeDetectado;
|
|
44
45
|
exports.baseBranchDetectada = baseBranchDetectada;
|
|
@@ -51,6 +52,9 @@ const path = __importStar(require("node:path"));
|
|
|
51
52
|
const manifest_1 = require("./manifest");
|
|
52
53
|
const slug_1 = require("./slug");
|
|
53
54
|
const util_1 = require("./util");
|
|
55
|
+
const horario_1 = require("./horario");
|
|
56
|
+
const modos_1 = require("./modos");
|
|
57
|
+
exports.PROXIMO_PASSO_INIT = 'Proximo passo: ork doctor; depois ork onboarding para conduzir a entrevista do projeto.';
|
|
54
58
|
/** Raiz do repositorio git, resolvendo tambem o caso de worktree. */
|
|
55
59
|
function raizDoRepo(dirInicial) {
|
|
56
60
|
const r = (0, util_1.exec)('git', ['rev-parse', '--show-toplevel'], dirInicial);
|
|
@@ -148,22 +152,34 @@ project:
|
|
|
148
152
|
abbrev: "${d.abbrev}"
|
|
149
153
|
stage: nascente
|
|
150
154
|
|
|
155
|
+
owner:
|
|
156
|
+
# fuso do dono (nome IANA): todo horario mostrado a pessoas usa este fuso.
|
|
157
|
+
# Ausente: fuso do sistema. Exemplo:
|
|
158
|
+
# timezone: "${horario_1.FUSO_DE_BRASILIA}"
|
|
159
|
+
|
|
151
160
|
board:
|
|
152
161
|
adapter: hermes-kanban
|
|
153
162
|
default: default
|
|
154
163
|
|
|
155
164
|
runtime:
|
|
156
|
-
#
|
|
165
|
+
# Runtimes homologados:
|
|
166
|
+
# claude-bg (padrao, mais maduro): despacha \`claude --bg\`, sessao visivel no app
|
|
167
|
+
# e em \`claude agents --json\`
|
|
168
|
+
# codex: despacha \`codex exec\` headless na sessao autenticada do Codex CLI,
|
|
169
|
+
# verificado no rollout de $CODEX_HOME/sessions (requer \`codex login\`)
|
|
157
170
|
adapter: claude-bg
|
|
158
171
|
model: opus
|
|
159
172
|
effort: high
|
|
160
|
-
# subscription-only: proibido despachar por provider pago (
|
|
173
|
+
# subscription-only: proibido despachar por provider pago (cobra por token, fora da assinatura)
|
|
161
174
|
provider_policy: subscription-only
|
|
175
|
+
# sandbox do runtime codex: read-only | workspace-write | danger-full-access
|
|
176
|
+
# (danger-full-access SO onde o bubblewrap nao roda; \`ork doctor\` tem a sonda)
|
|
177
|
+
sandbox: workspace-write
|
|
162
178
|
|
|
163
179
|
conduction:
|
|
164
180
|
# modo usado quando o pedido do builder nao traz #TAG
|
|
165
181
|
default_mode: classic
|
|
166
|
-
allowed_modes: [
|
|
182
|
+
allowed_modes: [${modos_1.ORDEM_DOS_MODOS.join(', ')}]
|
|
167
183
|
|
|
168
184
|
worktree:
|
|
169
185
|
base_branch: "${d.baseBranch}"
|
|
@@ -175,8 +191,17 @@ ${linhaVerify('build', d.verify.build)}
|
|
|
175
191
|
${linhaVerify('test', d.verify.test)}
|
|
176
192
|
${linhaVerify('typecheck', d.verify.typecheck)}
|
|
177
193
|
|
|
194
|
+
ci:
|
|
195
|
+
# Ative depois de publicar o workflow e tornar ork-verify um check obrigatório.
|
|
196
|
+
required_for_ship: false
|
|
197
|
+
context: ork-verify
|
|
198
|
+
# command: "npm test" # perfil hermético opcional do runner; sem ele, usa verify acima
|
|
199
|
+
|
|
178
200
|
concurrency:
|
|
179
201
|
max_parallel_threads: 3
|
|
202
|
+
# thread despachada sem atividade (ledger parado, sessao nao-working) por mais que
|
|
203
|
+
# isto NAO ocupa vaga do escalonador: a vaga volta para quem esta pronto para rodar
|
|
204
|
+
stale_after_min: 240
|
|
180
205
|
|
|
181
206
|
handoff:
|
|
182
207
|
# gate de tokens (bloco B1): rotaciona a sessao acima destas ocupacoes de janela
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TESTES_DE_INTEGRACAO_LOCAL = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* I-53 (RM-037, D17): a lista unica dos testes que exigem integracao local.
|
|
6
|
+
*
|
|
7
|
+
* Sao os arquivos que dependem de recurso deliberadamente ausente no runner hospedado do GitHub
|
|
8
|
+
* (Docker, OrkMind instalado, sessao de runtime). Antes a lista vivia duplicada em `ci.ts` e em
|
|
9
|
+
* `scripts/test-ci.js`, e as duas copias podiam divergir sem ninguem ver. Agora `ci.ts` importa
|
|
10
|
+
* daqui, e o script le o mesmo modulo ja compilado em `dist/` (o `test:ci` compila antes).
|
|
11
|
+
*/
|
|
12
|
+
exports.TESTES_DE_INTEGRACAO_LOCAL = new Set([
|
|
13
|
+
'codex-controller-sensor.test.js', 'consulta-restrita-nativa.test.js', 'decision-identity.test.js',
|
|
14
|
+
'mcp-git.test.js', 'mcp-server.test.js', 'mcp-ship.test.js', 'mcp-verify.test.js',
|
|
15
|
+
'memory-native-preparation.test.js', 'memory-native-schema.test.js', 'memory-prospective.test.js',
|
|
16
|
+
'memory-publication-profile.test.js', 'native-fixture.test.js', 'orkmind-transport.test.js', 'verify-sandbox.test.js',
|
|
17
|
+
]);
|
package/dist/leases.js
CHANGED
|
@@ -48,12 +48,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
48
48
|
};
|
|
49
49
|
})();
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.NOME_ARQUIVO_FILA = exports.FAMILIAS_DE_LEASE = exports.TTL_PADRAO_MS = exports.LEASE_MAIN_TREE = void 0;
|
|
51
|
+
exports.NOME_ARQUIVO_FILA = exports.PREFIXO_EXEC = exports.FAMILIAS_DE_LEASE = exports.TTL_PADRAO_MS = exports.LEASE_MAIN_TREE = void 0;
|
|
52
52
|
exports.dirLeases = dirLeases;
|
|
53
|
+
exports.dirLeasesDeExecucao = dirLeasesDeExecucao;
|
|
53
54
|
exports.nomeDeLease = nomeDeLease;
|
|
54
55
|
exports.tipoDoLease = tipoDoLease;
|
|
55
56
|
exports.alvoDoLease = alvoDoLease;
|
|
56
57
|
exports.caminhoLease = caminhoLease;
|
|
58
|
+
exports.regravarLease = regravarLease;
|
|
57
59
|
exports.lerLease = lerLease;
|
|
58
60
|
exports.expirado = expirado;
|
|
59
61
|
exports.globParaRegex = globParaRegex;
|
|
@@ -77,7 +79,10 @@ exports.tabelaDeLeases = tabelaDeLeases;
|
|
|
77
79
|
const fs = __importStar(require("node:fs"));
|
|
78
80
|
const path = __importStar(require("node:path"));
|
|
79
81
|
const manifest_1 = require("./manifest");
|
|
82
|
+
const estado_thread_1 = require("./estado-thread");
|
|
80
83
|
const util_1 = require("./util");
|
|
84
|
+
const horario_1 = require("./horario");
|
|
85
|
+
const conducao_texto_1 = require("./conducao-texto");
|
|
81
86
|
/** Nome do lease que serializa o merge na base (visao, paridade 5). */
|
|
82
87
|
exports.LEASE_MAIN_TREE = 'main-tree';
|
|
83
88
|
/** TTL padrao de 30 minutos: um SHIP que passe disso deixou de existir. */
|
|
@@ -89,11 +94,22 @@ exports.FAMILIAS_DE_LEASE = {
|
|
|
89
94
|
path: 'uma regiao de arquivos por glob (colisao entre threads paralelas)',
|
|
90
95
|
board: 'um card do board, para duas threads nao pegarem o mesmo cartao',
|
|
91
96
|
service: 'uma porta de servico local, para dois runs nao subirem no mesmo lugar',
|
|
97
|
+
exec: 'a EXECUCAO na worktree de uma thread (I-36): um condutor por vez, em qualquer canal',
|
|
92
98
|
};
|
|
99
|
+
/** I-36 (D1): prefixo da familia de execucao, `exec:<thread>`. */
|
|
100
|
+
exports.PREFIXO_EXEC = 'exec';
|
|
93
101
|
/** Diretorio dos leases do projeto. */
|
|
94
102
|
function dirLeases(raiz) {
|
|
95
103
|
return path.join((0, manifest_1.dirEstado)(raiz), 'leases');
|
|
96
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* I-36: o lease de execucao mora no estado CANONICO do projeto (o mesmo das threads), nunca no
|
|
107
|
+
* checkout de quem chamou. Um canal que roda da raiz e outro que roda de uma worktree disputam o
|
|
108
|
+
* mesmo arquivo; com o diretorio do checkout, cada um teria o seu e os dois executariam juntos.
|
|
109
|
+
*/
|
|
110
|
+
function dirLeasesDeExecucao(raiz) {
|
|
111
|
+
return path.join((0, manifest_1.dirEstado)((0, estado_thread_1.raizDoEstado)(raiz)), 'leases');
|
|
112
|
+
}
|
|
97
113
|
/**
|
|
98
114
|
* Nome canonico de um lease de familia tipada: `path:core/src/**`, `service:5173`.
|
|
99
115
|
* `main-tree` nao tem alvo: e um so no projeto.
|
|
@@ -111,7 +127,8 @@ function tipoDoLease(nome) {
|
|
|
111
127
|
if (nome === exports.LEASE_MAIN_TREE)
|
|
112
128
|
return 'main-tree';
|
|
113
129
|
const prefixo = nome.split(':')[0];
|
|
114
|
-
if (prefixo === 'worktree-write' || prefixo === 'path' || prefixo === 'board' || prefixo === 'service'
|
|
130
|
+
if (prefixo === 'worktree-write' || prefixo === 'path' || prefixo === 'board' || prefixo === 'service' ||
|
|
131
|
+
prefixo === exports.PREFIXO_EXEC) {
|
|
115
132
|
return prefixo;
|
|
116
133
|
}
|
|
117
134
|
return 'path';
|
|
@@ -127,7 +144,19 @@ function alvoDoLease(nome) {
|
|
|
127
144
|
* inalterado, o que preserva os leases gravados pelo bloco B1.
|
|
128
145
|
*/
|
|
129
146
|
function caminhoLease(raiz, nome) {
|
|
130
|
-
|
|
147
|
+
const dir = tipoDoLease(nome) === 'exec' ? dirLeasesDeExecucao(raiz) : dirLeases(raiz);
|
|
148
|
+
return path.join(dir, `${encodeURIComponent(nome)}.json`);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* I-36 (D3): regrava um lease que a propria operacao segura (renovacao do prazo e conversao do
|
|
152
|
+
* dono), por arquivo temporario e rename: quem le nunca ve o arquivo pela metade.
|
|
153
|
+
*/
|
|
154
|
+
function regravarLease(raiz, lease) {
|
|
155
|
+
const caminho = caminhoLease(raiz, lease.nome);
|
|
156
|
+
fs.mkdirSync(path.dirname(caminho), { recursive: true });
|
|
157
|
+
const temporario = `${caminho}.${process.pid}.tmp`;
|
|
158
|
+
fs.writeFileSync(temporario, JSON.stringify(lease, null, 2) + '\n', { encoding: 'utf8', mode: 0o644 });
|
|
159
|
+
fs.renameSync(temporario, caminho);
|
|
131
160
|
}
|
|
132
161
|
/** Le o lease em disco. Arquivo corrompido conta como lease ausente. */
|
|
133
162
|
function lerLease(raiz, nome) {
|
|
@@ -253,7 +282,7 @@ function adquirir(raiz, nome, opcoes) {
|
|
|
253
282
|
if (e.code !== 'EEXIST')
|
|
254
283
|
throw e;
|
|
255
284
|
const atual = lerLease(raiz, nome);
|
|
256
|
-
if (atual && !expirado(atual)) {
|
|
285
|
+
if (opcoes.retomarVencido === false || (atual && !expirado(atual))) {
|
|
257
286
|
return { ok: false, lease: null, ocupadoPor: atual, tomadoDeVencido: false };
|
|
258
287
|
}
|
|
259
288
|
// Lease vencido ou corrompido: remove e tenta uma unica vez mais.
|
|
@@ -292,23 +321,32 @@ function liberar(raiz, nome, thread, forcar = false) {
|
|
|
292
321
|
}
|
|
293
322
|
/** Todos os leases existentes no projeto, pelo nome canonico gravado no arquivo. */
|
|
294
323
|
function listarLeases(raiz) {
|
|
295
|
-
const dir = dirLeases(raiz);
|
|
296
|
-
if (!fs.existsSync(dir))
|
|
297
|
-
return [];
|
|
298
324
|
const leases = [];
|
|
299
|
-
|
|
300
|
-
if (!
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
325
|
+
const ler = (dir, soExecucao) => {
|
|
326
|
+
if (!fs.existsSync(dir))
|
|
327
|
+
return;
|
|
328
|
+
for (const arquivo of fs.readdirSync(dir)) {
|
|
329
|
+
if (!arquivo.endsWith('.json') || arquivo === exports.NOME_ARQUIVO_FILA)
|
|
330
|
+
continue;
|
|
331
|
+
try {
|
|
332
|
+
const lease = JSON.parse(fs.readFileSync(path.join(dir, arquivo), 'utf8'));
|
|
333
|
+
if (!lease || typeof lease.nome !== 'string')
|
|
334
|
+
continue;
|
|
335
|
+
if (soExecucao && tipoDoLease(lease.nome) !== 'exec')
|
|
336
|
+
continue;
|
|
306
337
|
leases.push(lease);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
/* arquivo corrompido conta como lease ausente */
|
|
341
|
+
}
|
|
307
342
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
343
|
+
};
|
|
344
|
+
// I-36: os do checkout, mais os de execucao do estado canonico quando ele e outro diretorio.
|
|
345
|
+
const local = dirLeases(raiz), canonico = dirLeasesDeExecucao(raiz);
|
|
346
|
+
const real = (dir) => (fs.existsSync(dir) ? fs.realpathSync(dir) : path.resolve(dir));
|
|
347
|
+
ler(local, false);
|
|
348
|
+
if (real(local) !== real(canonico))
|
|
349
|
+
ler(canonico, true);
|
|
312
350
|
return leases.sort((a, b) => a.nome.localeCompare(b.nome));
|
|
313
351
|
}
|
|
314
352
|
/** Leases ativos (nao vencidos) que colidem com o nome pedido. */
|
|
@@ -488,8 +526,12 @@ function tabelaDeLeases(raiz) {
|
|
|
488
526
|
for (const l of leases) {
|
|
489
527
|
const situacao = expirado(l) ? 'VENCIDO (tomavel)' : 'ativo';
|
|
490
528
|
linhas.push(` ${l.nome.padEnd(28)} [${tipoDoLease(l.nome)}] thread ${l.thread.padEnd(18)} ${situacao}`);
|
|
491
|
-
linhas.push(` desde ${l.adquiridoEm} ate ${l.expiraEm} (pid ${l.pid})`);
|
|
529
|
+
linhas.push(` desde ${(0, horario_1.formatarDataHora)(l.adquiridoEm)} ate ${(0, horario_1.formatarDataHora)(l.expiraEm)} (pid ${l.pid})`);
|
|
492
530
|
linhas.push(` motivo: ${l.motivo}`);
|
|
531
|
+
// I-36: o lease de execucao diz quem conduz, com a mesma linha das outras superficies.
|
|
532
|
+
const conducao = (0, conducao_texto_1.conducaoDoLease)(l);
|
|
533
|
+
if (conducao)
|
|
534
|
+
linhas.push(` ${(0, conducao_texto_1.linhaDeConducao)(conducao)}`);
|
|
493
535
|
}
|
|
494
536
|
}
|
|
495
537
|
linhas.push('');
|
|
@@ -497,12 +539,14 @@ function tabelaDeLeases(raiz) {
|
|
|
497
539
|
const regiao = fila.filter((p) => p.tipo !== 'main-tree');
|
|
498
540
|
linhas.push(`Fila de merge (lease ${exports.LEASE_MAIN_TREE}): ${merge.length === 0 ? 'vazia' : `${merge.length} na espera`}`);
|
|
499
541
|
merge.forEach((p, i) => {
|
|
500
|
-
linhas.push(` ${i + 1}. thread ${p.thread} desde ${p.desdeEm} (bloqueada por ${p.bloqueadaPor})`);
|
|
542
|
+
linhas.push(` ${i + 1}. thread ${p.thread} desde ${(0, horario_1.formatarDesde)(p.desdeEm)} (bloqueada por ${p.bloqueadaPor})`);
|
|
501
543
|
});
|
|
502
544
|
linhas.push(`Fila por colisao de regiao: ${regiao.length === 0 ? 'vazia' : `${regiao.length} na espera`}`);
|
|
503
545
|
regiao.forEach((p, i) => {
|
|
504
546
|
linhas.push(` ${i + 1}. thread ${p.thread} quer ${p.nome}, colide com ${p.colidiuCom} ` +
|
|
505
|
-
`(thread ${p.bloqueadaPor}) desde ${p.desdeEm}`);
|
|
547
|
+
`(thread ${p.bloqueadaPor}) desde ${(0, horario_1.formatarDesde)(p.desdeEm)}`);
|
|
506
548
|
});
|
|
549
|
+
if (leases.length > 0 || fila.length > 0)
|
|
550
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
507
551
|
return linhas.join('\n');
|
|
508
552
|
}
|
|
@@ -0,0 +1,272 @@
|
|
|
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.parsePeriodo = parsePeriodo;
|
|
37
|
+
exports.coletarEstatisticas = coletarEstatisticas;
|
|
38
|
+
exports.registrarEstimativaPlano = registrarEstimativaPlano;
|
|
39
|
+
exports.textoDasEstatisticas = textoDasEstatisticas;
|
|
40
|
+
const fs = __importStar(require("node:fs"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const thread_1 = require("./thread");
|
|
43
|
+
const ledger_1 = require("./ledger");
|
|
44
|
+
const util_1 = require("./util");
|
|
45
|
+
const horario_1 = require("./horario");
|
|
46
|
+
const MOTIVOS_PREVENTIVOS = new Set([
|
|
47
|
+
'policy.violation', 'cost.violation', 'verify.regression', 'claims.failed', 'claims.unverifiable',
|
|
48
|
+
]);
|
|
49
|
+
function numero(valor) {
|
|
50
|
+
return typeof valor === 'number' && Number.isFinite(valor) && valor >= 0 ? valor : null;
|
|
51
|
+
}
|
|
52
|
+
function parsePeriodo(valor, agoraMs = Date.now()) {
|
|
53
|
+
if (typeof valor === 'number') {
|
|
54
|
+
if (!Number.isFinite(valor))
|
|
55
|
+
throw Error('ledger.period.invalid');
|
|
56
|
+
return valor;
|
|
57
|
+
}
|
|
58
|
+
const relativo = /^(\d+(?:\.\d+)?)(m|h|d)$/.exec(valor.trim());
|
|
59
|
+
if (relativo) {
|
|
60
|
+
const fator = relativo[2] === 'm' ? 60_000 : relativo[2] === 'h' ? 3_600_000 : 86_400_000;
|
|
61
|
+
return agoraMs - Number(relativo[1]) * fator;
|
|
62
|
+
}
|
|
63
|
+
const absoluto = Date.parse(valor);
|
|
64
|
+
if (!Number.isFinite(absoluto))
|
|
65
|
+
throw Error(`ledger.period.invalid: ${valor}`);
|
|
66
|
+
return absoluto;
|
|
67
|
+
}
|
|
68
|
+
function lerTarifas() {
|
|
69
|
+
const candidatos = [
|
|
70
|
+
path.resolve(__dirname, '..', 'assets', 'reference-tariffs-i07.json'),
|
|
71
|
+
path.resolve(__dirname, '..', '..', 'assets', 'reference-tariffs-i07.json'),
|
|
72
|
+
];
|
|
73
|
+
const arquivo = candidatos.find(fs.existsSync);
|
|
74
|
+
if (!arquivo)
|
|
75
|
+
throw Error('ledger.tariffs.unavailable');
|
|
76
|
+
return JSON.parse(fs.readFileSync(arquivo, 'utf8'));
|
|
77
|
+
}
|
|
78
|
+
function instante(evento) {
|
|
79
|
+
const valor = Date.parse(evento.ts);
|
|
80
|
+
return Number.isFinite(valor) ? valor : null;
|
|
81
|
+
}
|
|
82
|
+
function chaveResultado(e, indice) {
|
|
83
|
+
const sensor = typeof e.sensorResultId === 'string' ? e.sensorResultId : null;
|
|
84
|
+
const sessao = typeof e.sessionId === 'string' ? e.sessionId : null;
|
|
85
|
+
return sensor ?? (sessao ? `${sessao}:${String(e.fase ?? '')}` : `linha:${indice}`);
|
|
86
|
+
}
|
|
87
|
+
function modeloDoEvento(e, despachos) {
|
|
88
|
+
if (typeof e.model === 'string')
|
|
89
|
+
return e.model;
|
|
90
|
+
const sessao = typeof e.sessionId === 'string' ? e.sessionId : '';
|
|
91
|
+
const d = despachos.get(sessao);
|
|
92
|
+
return typeof d?.model === 'string' ? d.model : null;
|
|
93
|
+
}
|
|
94
|
+
/** Agrega somente fatos observados no ledger; ausencia aparece como cobertura, nunca como zero inventado. */
|
|
95
|
+
function coletarEstatisticas(raiz, filtros) {
|
|
96
|
+
const agoraMs = filtros.agoraMs ?? Date.now();
|
|
97
|
+
const desdeMs = parsePeriodo(filtros.desde, agoraMs);
|
|
98
|
+
const ateMs = filtros.ate === undefined ? agoraMs : parsePeriodo(filtros.ate, agoraMs);
|
|
99
|
+
if (desdeMs >= ateMs)
|
|
100
|
+
throw Error('ledger.period.order');
|
|
101
|
+
if (filtros.thread && !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(filtros.thread))
|
|
102
|
+
throw Error('ledger.thread.invalid');
|
|
103
|
+
const tarifas = lerTarifas();
|
|
104
|
+
const candidatas = (0, thread_1.listarIds)(raiz).map(id => (0, thread_1.lerThread)(raiz, id)).filter(t => !filtros.thread || t.id === filtros.thread);
|
|
105
|
+
if (filtros.thread && candidatas.length === 0)
|
|
106
|
+
throw Error(`thread nao encontrada: ${filtros.thread}`);
|
|
107
|
+
const eventosPorThread = candidatas.map(t => ({ thread: t, eventos: (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)) }));
|
|
108
|
+
const selecionadas = eventosPorThread.filter(({ thread, eventos }) => {
|
|
109
|
+
const criada = eventos.find(e => e.tipo === 'thread_created');
|
|
110
|
+
const modo = typeof criada?.modo === 'string' ? criada.modo : thread.modo;
|
|
111
|
+
return !filtros.modo || modo === filtros.modo;
|
|
112
|
+
});
|
|
113
|
+
let despachadas = 0, concluidas = 0, retries = 0, ships = 0, duracao = 0;
|
|
114
|
+
let duracaoMedida = 0, duracaoAusente = 0, tokenMedido = 0, tokenAusente = 0;
|
|
115
|
+
let input = 0, cachedInput = 0, output = 0, total = 0, custo = 0, precificadas = 0, semTarifa = 0;
|
|
116
|
+
let esperaMs = 0, esperasFechadas = 0, esperasAbertas = 0, corrompidos = 0;
|
|
117
|
+
let estimativas = 0, semIaHoras = 0, iaSemOrkHoras = 0;
|
|
118
|
+
const riscos = {};
|
|
119
|
+
const leads = [];
|
|
120
|
+
const fontes = new Set();
|
|
121
|
+
for (const { eventos } of selecionadas) {
|
|
122
|
+
corrompidos += eventos.filter(e => e.tipo === 'ledger_corrupted').length;
|
|
123
|
+
const despachos = new Map();
|
|
124
|
+
for (const e of eventos)
|
|
125
|
+
if (e.tipo === 'phase_dispatch' && typeof e.sessionId === 'string')
|
|
126
|
+
despachos.set(e.sessionId, e);
|
|
127
|
+
const dentro = (e) => { const t = instante(e); return t !== null && t >= desdeMs && t < ateMs; };
|
|
128
|
+
const runtimeOk = (e) => {
|
|
129
|
+
if (!filtros.runtime)
|
|
130
|
+
return true;
|
|
131
|
+
if (e.runtime === filtros.runtime)
|
|
132
|
+
return true;
|
|
133
|
+
const sessao = typeof e.sessionId === 'string' ? e.sessionId : '';
|
|
134
|
+
return despachos.get(sessao)?.runtime === filtros.runtime;
|
|
135
|
+
};
|
|
136
|
+
despachadas += eventos.filter(e => e.tipo === 'phase_dispatch' && dentro(e) && runtimeOk(e)).length;
|
|
137
|
+
retries += eventos.filter(e => e.tipo === 'retry_attempt' && dentro(e)).length;
|
|
138
|
+
ships += eventos.filter(e => e.tipo === 'ship_done' && dentro(e)).length;
|
|
139
|
+
const resultados = new Map();
|
|
140
|
+
eventos.forEach((e, i) => {
|
|
141
|
+
if (e.tipo === 'phase_result' && dentro(e) && runtimeOk(e))
|
|
142
|
+
resultados.set(chaveResultado(e, i), e);
|
|
143
|
+
});
|
|
144
|
+
for (const e of resultados.values()) {
|
|
145
|
+
concluidas++;
|
|
146
|
+
const ms = numero(e.duracaoMs);
|
|
147
|
+
if (ms === null)
|
|
148
|
+
duracaoAusente++;
|
|
149
|
+
else {
|
|
150
|
+
duracao += ms;
|
|
151
|
+
duracaoMedida++;
|
|
152
|
+
}
|
|
153
|
+
const t = e.tokens && typeof e.tokens === 'object' ? e.tokens : null;
|
|
154
|
+
const tin = numero(t?.input), tcached = numero(t?.cachedInput), tout = numero(t?.output), ttotal = numero(t?.total);
|
|
155
|
+
if (!t || t.disponivel === false || tin === null || tcached === null || tout === null) {
|
|
156
|
+
tokenAusente++;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
tokenMedido++;
|
|
160
|
+
input += tin;
|
|
161
|
+
cachedInput += Math.min(tcached, tin);
|
|
162
|
+
output += tout;
|
|
163
|
+
total += ttotal ?? tin + tout;
|
|
164
|
+
const modelo = modeloDoEvento(e, despachos);
|
|
165
|
+
const tarifa = modelo ? tarifas.models[modelo] : undefined;
|
|
166
|
+
if (!tarifa) {
|
|
167
|
+
semTarifa++;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
custo += ((tin - Math.min(tcached, tin)) * tarifa.input + Math.min(tcached, tin) * tarifa.cachedInput + tout * tarifa.output) / tarifas.unitTokens;
|
|
171
|
+
precificadas++;
|
|
172
|
+
fontes.add(tarifa.source);
|
|
173
|
+
}
|
|
174
|
+
const criada = eventos.find(e => e.tipo === 'thread_created');
|
|
175
|
+
const criadaMs = criada ? instante(criada) : null;
|
|
176
|
+
for (const e of eventos.filter(e => e.tipo === 'ship_done' && dentro(e))) {
|
|
177
|
+
const fim = instante(e);
|
|
178
|
+
if (criadaMs !== null && fim !== null && fim >= criadaMs)
|
|
179
|
+
leads.push(fim - criadaMs);
|
|
180
|
+
}
|
|
181
|
+
const pedidos = new Map();
|
|
182
|
+
for (const e of eventos) {
|
|
183
|
+
if (e.tipo === 'gate_blocked' && e.motivo === 'human.pending') {
|
|
184
|
+
const chave = typeof e.pedidoId === 'string' ? e.pedidoId : `${String(e.fase ?? '')}:legacy`;
|
|
185
|
+
const t = instante(e);
|
|
186
|
+
if (t !== null)
|
|
187
|
+
(pedidos.get(chave) ?? (pedidos.set(chave, []), pedidos.get(chave))).push(t);
|
|
188
|
+
}
|
|
189
|
+
if (e.tipo === 'human_gate') {
|
|
190
|
+
const chave = typeof e.pedidoId === 'string' ? e.pedidoId : `${String(e.fase ?? '')}:legacy`;
|
|
191
|
+
const inicio = pedidos.get(chave)?.shift();
|
|
192
|
+
const fim = instante(e);
|
|
193
|
+
if (inicio !== undefined && fim !== null && fim >= inicio) {
|
|
194
|
+
const a = Math.max(inicio, desdeMs), b = Math.min(fim, ateMs);
|
|
195
|
+
if (b > a)
|
|
196
|
+
esperaMs += b - a;
|
|
197
|
+
if (fim >= desdeMs && fim < ateMs)
|
|
198
|
+
esperasFechadas++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const aberturas of pedidos.values())
|
|
203
|
+
for (const inicio of aberturas) {
|
|
204
|
+
const a = Math.max(inicio, desdeMs);
|
|
205
|
+
if (ateMs > a)
|
|
206
|
+
esperaMs += ateMs - a;
|
|
207
|
+
if (inicio < ateMs)
|
|
208
|
+
esperasAbertas++;
|
|
209
|
+
}
|
|
210
|
+
for (const e of eventos.filter(e => e.tipo === 'gate_blocked' && dentro(e))) {
|
|
211
|
+
const motivo = typeof e.motivo === 'string' ? e.motivo : '';
|
|
212
|
+
if (MOTIVOS_PREVENTIVOS.has(motivo))
|
|
213
|
+
riscos[motivo] = (riscos[motivo] ?? 0) + 1;
|
|
214
|
+
}
|
|
215
|
+
for (const e of eventos.filter(e => e.tipo === 'plan_estimate' && dentro(e))) {
|
|
216
|
+
const a = numero(e.semIaHoras), b = numero(e.iaSemOrkHoras);
|
|
217
|
+
if (a !== null && b !== null) {
|
|
218
|
+
estimativas++;
|
|
219
|
+
semIaHoras += a;
|
|
220
|
+
iaSemOrkHoras += b;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const observacoes = [];
|
|
225
|
+
if (tokenAusente)
|
|
226
|
+
observacoes.push(`${tokenAusente} sessao(oes) sem medicao de tokens`);
|
|
227
|
+
if (semTarifa)
|
|
228
|
+
observacoes.push(`${semTarifa} sessao(oes) com tokens, mas sem tarifa de referencia`);
|
|
229
|
+
if (corrompidos)
|
|
230
|
+
observacoes.push(`${corrompidos} linha(s) de ledger corrompida(s) ignorada(s)`);
|
|
231
|
+
return {
|
|
232
|
+
schema: 'ork.ledger-stats/v1', periodo: { desde: new Date(desdeMs).toISOString(), ate: new Date(ateMs).toISOString(), intervalo: '[desde,ate)' },
|
|
233
|
+
filtros: { thread: filtros.thread ?? null, modo: filtros.modo ?? null, runtime: filtros.runtime ?? null }, threads: selecionadas.length,
|
|
234
|
+
sessoes: { despachadas, concluidas, retries }, throughput: { ships },
|
|
235
|
+
execucao: { milissegundos: duracao, horas: duracao / 3_600_000, cobertura: { medidas: duracaoMedida, semMedida: duracaoAusente } },
|
|
236
|
+
tokens: { input, cachedInput, uncachedInput: input - cachedInput, output, total, cobertura: { medidas: tokenMedido, semMedida: tokenAusente } },
|
|
237
|
+
custoReferencia: { natureza: tarifas.nature, moeda: tarifas.currency, valor: precificadas ? Number(custo.toFixed(6)) : null, sessoesPrecificadas: precificadas, sessoesSemTarifa: semTarifa, tarifasVerificadasEm: tarifas.verifiedAt, fontes: [...fontes].sort() },
|
|
238
|
+
leadTime: { mediaMs: leads.length ? leads.reduce((a, b) => a + b, 0) / leads.length : null, amostras: leads.length },
|
|
239
|
+
esperaHumana: { milissegundos: esperaMs, fechadas: esperasFechadas, abertas: esperasAbertas },
|
|
240
|
+
riscosPreventivos: { total: Object.values(riscos).reduce((a, b) => a + b, 0), porMotivo: riscos },
|
|
241
|
+
estimativasPlano: { amostras: estimativas, semIaHoras, iaSemOrkHoras },
|
|
242
|
+
qualidade: { ledgersCorrompidos: corrompidos, observacoes },
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function registrarEstimativaPlano(raiz, threadId, dados) {
|
|
246
|
+
if (![dados.semIaHoras, dados.iaSemOrkHoras].every(v => Number.isFinite(v) && v > 0))
|
|
247
|
+
throw Error('ledger.estimate.hours-positive');
|
|
248
|
+
if (![dados.por, dados.metodo, dados.premissas].every(v => v.trim() !== ''))
|
|
249
|
+
throw Error('ledger.estimate.provenance-required');
|
|
250
|
+
const thread = (0, thread_1.listarIds)(raiz).map(id => (0, thread_1.lerThread)(raiz, id)).find(t => t.id === threadId);
|
|
251
|
+
if (!thread)
|
|
252
|
+
throw Error(`thread nao encontrada: ${threadId}`);
|
|
253
|
+
const head = (0, util_1.exec)('git', ['rev-parse', 'HEAD'], raiz);
|
|
254
|
+
if (!head.ok)
|
|
255
|
+
throw Error('ledger.estimate.head-unavailable');
|
|
256
|
+
return (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, threadId), threadId, 'plan_estimate', { fase: 'PLAN', unidade: 'hours', semIaHoras: dados.semIaHoras, iaSemOrkHoras: dados.iaSemOrkHoras, por: dados.por, metodo: dados.metodo, premissas: dados.premissas, incerteza: dados.incerteza ?? 'nao informada', head: head.stdout.trim() });
|
|
257
|
+
}
|
|
258
|
+
function textoDasEstatisticas(r) {
|
|
259
|
+
const dinheiro = r.custoReferencia.valor === null ? 'sem cobertura' : `USD ${r.custoReferencia.valor.toFixed(6)}`;
|
|
260
|
+
return [
|
|
261
|
+
`Ledger stats ${(0, horario_1.formatarDataHora)(r.periodo.desde)} ate ${(0, horario_1.formatarDataHoraRotulada)(r.periodo.ate)} ${r.periodo.intervalo}`,
|
|
262
|
+
` threads/sessoes ${r.threads} / ${r.sessoes.concluidas} concluidas (${r.sessoes.despachadas} despachos)`,
|
|
263
|
+
` throughput ${r.throughput.ships} ship(s); ${r.sessoes.retries} retry(ies)`,
|
|
264
|
+
` execucao ${r.execucao.horas.toFixed(2)} h (${r.execucao.cobertura.medidas} medidas; ${r.execucao.cobertura.semMedida} ausentes)`,
|
|
265
|
+
` tokens ${r.tokens.total} total; input ${r.tokens.input} (cached ${r.tokens.cachedInput}); output ${r.tokens.output}`,
|
|
266
|
+
` custo referencia ${dinheiro} — estimativa por tarifa publica, nao gasto/fatura`,
|
|
267
|
+
` espera humana ${(r.esperaHumana.milissegundos / 3_600_000).toFixed(2)} h; ${r.esperaHumana.abertas} aberta(s)`,
|
|
268
|
+
` riscos evitados ${r.riscosPreventivos.total} gate(s) preventivo(s)`,
|
|
269
|
+
` estimativas PLAN ${r.estimativasPlano.amostras} amostra(s)`,
|
|
270
|
+
...r.qualidade.observacoes.map(o => ` cobertura ${o}`),
|
|
271
|
+
].join('\n');
|
|
272
|
+
}
|