@orkastery/cli 0.2.0 → 0.4.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/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/check.md +4 -3
- package/adapters/claude-code/commands/goal.md +3 -2
- package/adapters/claude-code/commands/master.md +3 -2
- 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-guard.js +1 -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 +161 -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-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +24 -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 +136 -27
- 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 +460 -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 +12 -9
- package/dist/auditrun.js +5 -4
- package/dist/board.js +174 -23
- 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 +223 -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 +184 -25
- 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 +22 -1
- package/dist/gates.js +59 -11
- 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 +1741 -94
- 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 +109 -2
- package/dist/licoes.js +221 -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 +612 -151
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/policies.js +72 -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 +640 -118
- 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 +700 -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 +168 -19
- 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 +5 -1
- package/eval/casos/master-metrics.json +1 -1
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +37 -3
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +3 -3
- 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 +28 -7
- package/references/definition-of-done.md +2 -2
- 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/README.md +3 -3
- 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/decision-triage/SKILL.md +4 -4
- package/skills/governance/narrative-guardian/SKILL.md +1 -1
- package/skills/governance/roadmap-keeper/SKILL.md +1 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
- package/skills/observability/thread-tracing/SKILL.md +1 -1
- package/skills/phases/check-quality/SKILL.md +2 -2
- package/skills/phases/goal-definition/SKILL.md +1 -1
- package/skills/phases/master-metrics/SKILL.md +9 -7
- package/skills/phases/plan-specification/SKILL.md +1 -1
- package/skills/phases/ship-release/SKILL.md +1 -1
package/dist/manifest.js
CHANGED
|
@@ -40,14 +40,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
40
40
|
exports.LIMITE_MANIFESTO_BYTES = exports.DIR_ESTADO = exports.NOME_MANIFESTO_LEGADO = exports.NOME_MANIFESTO = void 0;
|
|
41
41
|
exports.acharRaiz = acharRaiz;
|
|
42
42
|
exports.dirEstado = dirEstado;
|
|
43
|
+
exports.validarOptInPlaybook = validarOptInPlaybook;
|
|
43
44
|
exports.carregarManifesto = carregarManifesto;
|
|
44
45
|
exports.exigirManifesto = exigirManifesto;
|
|
45
46
|
const fs = __importStar(require("node:fs"));
|
|
46
47
|
const path = __importStar(require("node:path"));
|
|
47
48
|
const yaml_1 = require("./yaml");
|
|
48
49
|
const modos_1 = require("./modos");
|
|
50
|
+
const runtimes_1 = require("./runtimes");
|
|
51
|
+
const codex_1 = require("./adapters/codex");
|
|
49
52
|
const slug_1 = require("./slug");
|
|
50
53
|
const util_1 = require("./util");
|
|
54
|
+
const delegation_1 = require("./delegation");
|
|
55
|
+
const horario_1 = require("./horario");
|
|
51
56
|
exports.NOME_MANIFESTO = 'orkastery.yaml';
|
|
52
57
|
exports.NOME_MANIFESTO_LEGADO = 'devmaster.yaml';
|
|
53
58
|
exports.DIR_ESTADO = '.orkastery';
|
|
@@ -76,12 +81,70 @@ function texto(v, padrao) {
|
|
|
76
81
|
function numero(v, padrao) {
|
|
77
82
|
return typeof v === 'number' ? v : typeof v === 'string' && v.trim() !== '' && !isNaN(Number(v)) ? Number(v) : padrao;
|
|
78
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* I-37 (D2): `verify.timeout_ms` e `verify.timeout_ms_por_comando`. Prazo so vale inteiro
|
|
86
|
+
* positivo em milissegundos, entre 1 s e 24 h; o resto e erro do manifesto, porque um prazo
|
|
87
|
+
* mal escrito que caisse no default em silencio mudaria o veredito sem ninguem saber.
|
|
88
|
+
*/
|
|
89
|
+
function prazosDoVerify(verify, erros) {
|
|
90
|
+
const prazo = (chave, v) => {
|
|
91
|
+
if (v === undefined || v === null)
|
|
92
|
+
return undefined;
|
|
93
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' && v.trim() !== '' ? Number(v) : NaN;
|
|
94
|
+
if (!Number.isInteger(n) || n < 1_000 || n > 86_400_000) {
|
|
95
|
+
erros.push(`${chave} precisa ser um inteiro em ms entre 1000 e 86400000 (recebido ${JSON.stringify(v)})`);
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return n;
|
|
99
|
+
};
|
|
100
|
+
const saida = {};
|
|
101
|
+
const geral = prazo('verify.timeout_ms', verify.timeout_ms);
|
|
102
|
+
if (geral !== undefined)
|
|
103
|
+
saida.timeout_ms = geral;
|
|
104
|
+
const brutos = mapa(verify.timeout_ms_por_comando);
|
|
105
|
+
const porComando = {};
|
|
106
|
+
for (const nome of Object.keys(brutos)) {
|
|
107
|
+
if (!['build', 'test', 'typecheck'].includes(nome)) {
|
|
108
|
+
erros.push(`verify.timeout_ms_por_comando.${nome}: so build, test e typecheck tem prazo proprio`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const n = prazo(`verify.timeout_ms_por_comando.${nome}`, brutos[nome]);
|
|
112
|
+
if (n !== undefined)
|
|
113
|
+
porComando[nome] = n;
|
|
114
|
+
}
|
|
115
|
+
if (Object.keys(porComando).length > 0)
|
|
116
|
+
saida.timeout_ms_por_comando = porComando;
|
|
117
|
+
return saida;
|
|
118
|
+
}
|
|
79
119
|
function booleano(v, padrao) {
|
|
80
120
|
return typeof v === 'boolean' ? v : padrao;
|
|
81
121
|
}
|
|
82
122
|
function mapa(v) {
|
|
83
123
|
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
84
124
|
}
|
|
125
|
+
/** Mesmo contrato na leitura do YAML e nos consumidores de manifesto em memoria. */
|
|
126
|
+
function validarOptInPlaybook(valor) {
|
|
127
|
+
if (valor === undefined)
|
|
128
|
+
return false;
|
|
129
|
+
if (!valor || typeof valor !== 'object' || Array.isArray(valor) ||
|
|
130
|
+
Object.keys(valor).length !== 1 || !Object.hasOwn(valor, 'ativo') ||
|
|
131
|
+
typeof valor.ativo !== 'boolean') {
|
|
132
|
+
throw new Error('playbook deve conter somente ativo booleano explicito');
|
|
133
|
+
}
|
|
134
|
+
return valor.ativo;
|
|
135
|
+
}
|
|
136
|
+
/** I-33 (N2): texto e numero que dizem sim ou nao sem ambiguidade; o resto nao e reconhecido. */
|
|
137
|
+
const BOOLEANOS_RECONHECIVEIS = new Map([
|
|
138
|
+
['true', true], ['yes', true], ['on', true], ['sim', true], ['1', true],
|
|
139
|
+
['false', false], ['no', false], ['off', false], ['nao', false], ['n\u00e3o', false], ['0', false],
|
|
140
|
+
]);
|
|
141
|
+
function booleanoReconhecivel(v) {
|
|
142
|
+
if (typeof v === 'number')
|
|
143
|
+
return v === 1 ? true : v === 0 ? false : null;
|
|
144
|
+
if (typeof v !== 'string')
|
|
145
|
+
return null;
|
|
146
|
+
return BOOLEANOS_RECONHECIVEIS.get(v.trim().toLowerCase()) ?? null;
|
|
147
|
+
}
|
|
85
148
|
/** Le e valida o manifesto. Nunca lanca: erros e avisos voltam na estrutura. */
|
|
86
149
|
function carregarManifesto(dirInicial = process.cwd()) {
|
|
87
150
|
const raiz = acharRaiz(dirInicial);
|
|
@@ -103,16 +166,56 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
103
166
|
erros.push(e.message);
|
|
104
167
|
}
|
|
105
168
|
const project = mapa(dados.project);
|
|
169
|
+
// I-35: fonte unica do fuso do dono. Valor invalido nao reprova o manifesto: avisa e cai
|
|
170
|
+
// no fuso do sistema, porque um horario com rotulo certo vale mais que um comando parado.
|
|
171
|
+
const fusoDoDono = (0, horario_1.lerFusoDoDono)(mapa(dados.owner).timezone);
|
|
172
|
+
if (fusoDoDono.aviso)
|
|
173
|
+
avisos.push(fusoDoDono.aviso);
|
|
106
174
|
const board = mapa(dados.board);
|
|
107
175
|
const runtime = mapa(dados.runtime);
|
|
108
176
|
const conduction = mapa(dados.conduction);
|
|
177
|
+
if (conduction.delegation !== undefined && !(0, delegation_1.validarDelegacao)(conduction.delegation)) {
|
|
178
|
+
erros.push('conduction.delegation exige thread, escopo premissas, prazo ISO, evidencia e delegado');
|
|
179
|
+
}
|
|
109
180
|
const worktree = mapa(dados.worktree);
|
|
110
181
|
const verify = mapa(dados.verify);
|
|
182
|
+
const ci = mapa(dados.ci);
|
|
111
183
|
const concurrency = mapa(dados.concurrency);
|
|
112
184
|
const handoff = mapa(dados.handoff);
|
|
113
185
|
const retry = mapa(dados.retry);
|
|
186
|
+
// I-33 (D14, N2): so booleano liga ou desliga a troca. Texto ou numero reconhecivel (`off`, "false", 0,
|
|
187
|
+
// "no") vale o booleano que diz, com aviso; o resto vale o padrao documentado, tambem com aviso.
|
|
188
|
+
const perfisDeRuntime = mapa(dados.runtime_profiles);
|
|
189
|
+
const chaveDeRotacao = (nome, padrao) => {
|
|
190
|
+
const v = perfisDeRuntime[nome];
|
|
191
|
+
if (v === undefined || v === null)
|
|
192
|
+
return padrao;
|
|
193
|
+
if (typeof v === 'boolean')
|
|
194
|
+
return v;
|
|
195
|
+
const lido = booleanoReconhecivel(v);
|
|
196
|
+
if (lido !== null) {
|
|
197
|
+
avisos.push(`runtime_profiles.${nome} deve ser true ou false; ${JSON.stringify(v)} lido como ${lido}`);
|
|
198
|
+
return lido;
|
|
199
|
+
}
|
|
200
|
+
avisos.push(`runtime_profiles.${nome} deve ser true ou false; vale o padrao ${padrao} (${JSON.stringify(v)} nao reconhecido)`);
|
|
201
|
+
return padrao;
|
|
202
|
+
};
|
|
203
|
+
const liveness = mapa(dados.liveness);
|
|
204
|
+
const silencioMaxMin = numero(liveness.silencio_max_min, 10);
|
|
205
|
+
if (!Number.isFinite(silencioMaxMin) || silencioMaxMin <= 0)
|
|
206
|
+
erros.push('liveness.silencio_max_min deve ser positivo e finito');
|
|
114
207
|
const memory = mapa(dados.memory);
|
|
115
208
|
const audit = mapa(dados.audit);
|
|
209
|
+
const fabrica = mapa(dados.fabrica);
|
|
210
|
+
let playbook;
|
|
211
|
+
try {
|
|
212
|
+
const ativo = validarOptInPlaybook(dados.playbook);
|
|
213
|
+
if (dados.playbook !== undefined)
|
|
214
|
+
playbook = { ativo };
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
erros.push(e.message);
|
|
218
|
+
}
|
|
116
219
|
const abbrev = texto(project.abbrev, '');
|
|
117
220
|
const checkAbbrev = (0, slug_1.validarAbbrev)(abbrev);
|
|
118
221
|
if (!checkAbbrev.ok)
|
|
@@ -120,9 +223,26 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
120
223
|
const nomeProjeto = texto(project.name, '');
|
|
121
224
|
if (!nomeProjeto)
|
|
122
225
|
erros.push('project.name ausente no manifesto');
|
|
123
|
-
|
|
226
|
+
/**
|
|
227
|
+
* I-43 (D6): o manifesto e a unica peca com motivo para DISTINGUIR modo aposentado
|
|
228
|
+
* de modo inexistente, e por isso a distincao mora so aqui.
|
|
229
|
+
*
|
|
230
|
+
* `parseModo` continua estrito de proposito: ele e o portao de ESCRITA, e afrouxa-lo
|
|
231
|
+
* deixaria `#Look` ser escrito de novo. Mas um `orkastery.yaml` que lista `look` estava
|
|
232
|
+
* CERTO quando foi escrito, e existe assim nos quatro arquivos deste VPS. Tratar isso
|
|
233
|
+
* como erro pintaria `ork doctor` de vermelho nos tres projetos no dia um, com uma
|
|
234
|
+
* mensagem que culpa o usuario por um arquivo que ele nao errou.
|
|
235
|
+
*
|
|
236
|
+
* Entao: modo aposentado vira AVISO e sai da lista de permitidos; so valor
|
|
237
|
+
* genuinamente desconhecido continua ERRO.
|
|
238
|
+
*/
|
|
239
|
+
const brutoDefault = texto(conduction.default_mode, 'classic');
|
|
240
|
+
const defaultModo = (0, modos_1.parseModo)(brutoDefault);
|
|
124
241
|
if (!defaultModo) {
|
|
125
|
-
|
|
242
|
+
const substitutos = (0, modos_1.substitutosVivos)().join(' ou ');
|
|
243
|
+
erros.push((0, modos_1.modoAposentado)(brutoDefault.trim().toLowerCase())
|
|
244
|
+
? `conduction.default_mode aposentado: "${brutoDefault}" (use ${substitutos})`
|
|
245
|
+
: `conduction.default_mode invalido: "${brutoDefault}"`);
|
|
126
246
|
}
|
|
127
247
|
const brutosPermitidos = Array.isArray(conduction.allowed_modes)
|
|
128
248
|
? conduction.allowed_modes.map((m) => texto(m, ''))
|
|
@@ -130,10 +250,15 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
130
250
|
const permitidos = [];
|
|
131
251
|
for (const b of brutosPermitidos) {
|
|
132
252
|
const m = (0, modos_1.parseModo)(b);
|
|
133
|
-
if (
|
|
134
|
-
erros.push(`conduction.allowed_modes contem modo invalido: "${b}"`);
|
|
135
|
-
else
|
|
253
|
+
if (m) {
|
|
136
254
|
permitidos.push(m);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if ((0, modos_1.modoAposentado)(b.trim().toLowerCase())) {
|
|
258
|
+
avisos.push(`conduction.allowed_modes ignora modo aposentado "${b}"; use ${(0, modos_1.substitutosVivos)().join(' ou ')}`);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
erros.push(`conduction.allowed_modes contem modo invalido: "${b}"`);
|
|
137
262
|
}
|
|
138
263
|
if (permitidos.length === 0)
|
|
139
264
|
permitidos.push(...modos_1.ORDEM_DOS_MODOS);
|
|
@@ -144,6 +269,16 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
144
269
|
if (providerPolicy !== 'subscription-only' && providerPolicy !== 'any') {
|
|
145
270
|
avisos.push(`runtime.provider_policy desconhecida: "${providerPolicy}"`);
|
|
146
271
|
}
|
|
272
|
+
// Runtime de despacho: so os homologados passam. Um typo aqui viraria erro apenas na
|
|
273
|
+
// hora do despacho, com a thread ja aberta; reprovar no manifesto e mais barato.
|
|
274
|
+
const adapterDeRuntime = texto(runtime.adapter, runtimes_1.RUNTIME_PADRAO);
|
|
275
|
+
if (!(0, runtimes_1.runtimeConhecido)(adapterDeRuntime)) {
|
|
276
|
+
erros.push(`runtime.adapter desconhecido: "${adapterDeRuntime}" (homologados: ${runtimes_1.ORDEM_DOS_RUNTIMES.join(', ')})`);
|
|
277
|
+
}
|
|
278
|
+
const sandboxDoRuntime = texto(runtime.sandbox, codex_1.SANDBOX_PADRAO);
|
|
279
|
+
if (!codex_1.SANDBOXES_DO_CODEX.includes(sandboxDoRuntime)) {
|
|
280
|
+
erros.push(`runtime.sandbox invalido: "${sandboxDoRuntime}" (aceitos: ${codex_1.SANDBOXES_DO_CODEX.join(', ')})`);
|
|
281
|
+
}
|
|
147
282
|
// Bloco B6, isolamento por tenant (precedente do incidente memory-orkmind):
|
|
148
283
|
// `database_url_env` recebe o NOME da variavel de ambiente, nunca a string de conexao.
|
|
149
284
|
// Uma DSN colada aqui e exatamente o defeito que fez a memoria de um produto escrever
|
|
@@ -178,20 +313,24 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
178
313
|
stage: texto(project.stage, 'nascente') ?? 'nascente',
|
|
179
314
|
repo_root: texto(project.repo_root, raiz),
|
|
180
315
|
},
|
|
316
|
+
...(fusoDoDono.origem === 'manifesto' ? { owner: { timezone: fusoDoDono.fuso } } : {}),
|
|
181
317
|
board: {
|
|
182
318
|
adapter: texto(board.adapter, 'hermes-kanban'),
|
|
183
319
|
default: texto(board.default, 'default'),
|
|
184
320
|
},
|
|
185
321
|
runtime: {
|
|
186
|
-
adapter:
|
|
322
|
+
adapter: adapterDeRuntime,
|
|
187
323
|
model: texto(runtime.model, 'opus'),
|
|
188
324
|
effort: texto(runtime.effort, 'high'),
|
|
189
325
|
provider_policy: providerPolicy,
|
|
326
|
+
sandbox: sandboxDoRuntime,
|
|
190
327
|
},
|
|
191
328
|
conduction: {
|
|
192
329
|
default_mode: defaultModo ?? 'classic',
|
|
193
330
|
allowed_modes: permitidos,
|
|
331
|
+
...((0, delegation_1.validarDelegacao)(conduction.delegation) ? { delegation: conduction.delegation } : {}),
|
|
194
332
|
},
|
|
333
|
+
...(playbook === undefined ? {} : { playbook }),
|
|
195
334
|
worktree: {
|
|
196
335
|
base_branch: texto(worktree.base_branch, 'main'),
|
|
197
336
|
dir: texto(worktree.dir, '.claude/worktrees'),
|
|
@@ -200,17 +339,32 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
200
339
|
verify: {
|
|
201
340
|
build: verify.build === null || verify.build === undefined ? undefined : texto(verify.build, ''),
|
|
202
341
|
test: verify.test === null || verify.test === undefined ? undefined : texto(verify.test, ''),
|
|
342
|
+
...prazosDoVerify(verify, erros),
|
|
203
343
|
typecheck: verify.typecheck === null || verify.typecheck === undefined
|
|
204
344
|
? undefined
|
|
205
345
|
: texto(verify.typecheck, ''),
|
|
346
|
+
// I-54 (RM-037, D10): o preparo unico da rodada de verify, quando declarado.
|
|
347
|
+
...(typeof verify.preparo === 'string' && verify.preparo.trim() ? { preparo: verify.preparo.trim() } : {}),
|
|
348
|
+
},
|
|
349
|
+
ci: {
|
|
350
|
+
required_for_ship: booleano(ci.required_for_ship, false),
|
|
351
|
+
context: texto(ci.context, 'ork-verify'),
|
|
352
|
+
command: ci.command === null || ci.command === undefined ? undefined : texto(ci.command, ''),
|
|
206
353
|
},
|
|
207
354
|
concurrency: {
|
|
208
355
|
max_parallel_threads: numero(concurrency.max_parallel_threads, 3),
|
|
356
|
+
stale_after_min: Math.max(1, Math.trunc(numero(concurrency.stale_after_min, 240))),
|
|
209
357
|
},
|
|
358
|
+
liveness: { silencio_max_min: silencioMaxMin },
|
|
210
359
|
handoff: {
|
|
211
360
|
rotate_above: numero(handoff.rotate_above, 0.7),
|
|
212
361
|
force_rotate_above: numero(handoff.force_rotate_above, 0.85),
|
|
213
362
|
},
|
|
363
|
+
// I-33 (D16): troca por cota ligada por padrao, decisao do dono em 19/09/2026; o operador desliga aqui.
|
|
364
|
+
runtime_profiles: {
|
|
365
|
+
rotate_same_runtime_on_quota: chaveDeRotacao('rotate_same_runtime_on_quota', true),
|
|
366
|
+
rotate_same_runtime_on_auth: chaveDeRotacao('rotate_same_runtime_on_auth', true),
|
|
367
|
+
},
|
|
214
368
|
// Bloco B3: o limite de escalacao tem padrao, e o padrao e conservador. Manifesto
|
|
215
369
|
// sem bloco `retry:` continua andando com 3 tentativas e janela estimada de 60 min,
|
|
216
370
|
// que e exatamente o que o B3 promete, nao um "sem limite" implicito.
|
|
@@ -238,6 +392,11 @@ function carregarManifesto(dirInicial = process.cwd()) {
|
|
|
238
392
|
since_padrao: texto(audit.since_padrao, '7d'),
|
|
239
393
|
graphify: texto(audit.graphify, 'auto'),
|
|
240
394
|
},
|
|
395
|
+
// I-51 (RM-047): publicar o estado da fabrica empurra para o remoto, entao so com opt-in.
|
|
396
|
+
fabrica: {
|
|
397
|
+
compartilhada: booleano(fabrica.compartilhada, false),
|
|
398
|
+
remoto: texto(fabrica.remoto, 'origin'),
|
|
399
|
+
},
|
|
241
400
|
policies: Object.fromEntries(Object.entries(mapa(dados.policies)).map(([k, v]) => [k, texto(v, '')])),
|
|
242
401
|
};
|
|
243
402
|
return { caminho: achado.caminho, raiz, legado: achado.legado, bytes, manifesto, erros, avisos };
|
package/dist/maquina.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
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.CONTRATO_CONFIG_DA_MAQUINA = void 0;
|
|
37
|
+
exports.pastaDoUsuario = pastaDoUsuario;
|
|
38
|
+
exports.lerConfigDaMaquina = lerConfigDaMaquina;
|
|
39
|
+
exports.gravarConfigDaMaquina = gravarConfigDaMaquina;
|
|
40
|
+
exports.nomeDaMaquina = nomeDaMaquina;
|
|
41
|
+
exports.fabricaCompartilhada = fabricaCompartilhada;
|
|
42
|
+
/**
|
|
43
|
+
* I-51 (RM-047): esta maquina na fabrica.
|
|
44
|
+
*
|
|
45
|
+
* O nome e a adesao a fabrica compartilhada sao da MAQUINA, nao do projeto: o repositorio vai a
|
|
46
|
+
* outras pessoas, e o clone de um contribuidor nao pode sair publicando estado no remoto. Por isso
|
|
47
|
+
* os dois moram num arquivo do usuario, `~/.orkastery/maquina.json` (contrato `ork.maquina/v1`),
|
|
48
|
+
* gravado por `ork fabrica entrar`. Arquivo e nao variavel de ambiente porque o cron e os gateways
|
|
49
|
+
* nao carregam o perfil do shell, e a mesma maquina apareceria com dois nomes.
|
|
50
|
+
*
|
|
51
|
+
* Precedencia do nome: `--maquina`, `ORK_MAQUINA`, o arquivo, o hostname.
|
|
52
|
+
* Precedencia da adesao: `ORK_FABRICA_COMPARTILHADA` (1 liga, 0 desliga), senao o manifesto do
|
|
53
|
+
* projeto (`fabrica.compartilhada`, para o time que quer em todas as maquinas) ou o arquivo.
|
|
54
|
+
*/
|
|
55
|
+
const fs = __importStar(require("node:fs"));
|
|
56
|
+
const os = __importStar(require("node:os"));
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
58
|
+
exports.CONTRATO_CONFIG_DA_MAQUINA = 'ork.maquina/v1';
|
|
59
|
+
const ARQUIVO = 'maquina.json';
|
|
60
|
+
/** A pasta do usuario (`~/.orkastery`). `ORK_USUARIO_DIR` isola testes e `ork eval`. */
|
|
61
|
+
function pastaDoUsuario() {
|
|
62
|
+
return (process.env.ORK_USUARIO_DIR ?? '').trim() || path.join(os.homedir(), '.orkastery');
|
|
63
|
+
}
|
|
64
|
+
function lerConfigDaMaquina() {
|
|
65
|
+
try {
|
|
66
|
+
const bruto = JSON.parse(fs.readFileSync(path.join(pastaDoUsuario(), ARQUIVO), 'utf8'));
|
|
67
|
+
if (bruto.contrato !== exports.CONTRATO_CONFIG_DA_MAQUINA)
|
|
68
|
+
return null;
|
|
69
|
+
return { ...bruto, nome: typeof bruto.nome === 'string' && bruto.nome.trim() ? bruto.nome.trim() : null,
|
|
70
|
+
fabricaCompartilhada: bruto.fabricaCompartilhada === true };
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function gravarConfigDaMaquina(mudanca) {
|
|
77
|
+
const atual = lerConfigDaMaquina();
|
|
78
|
+
const nome = mudanca.nome !== undefined ? (mudanca.nome ?? '').trim() || null : atual?.nome ?? null;
|
|
79
|
+
if (nome !== null && !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(nome)) {
|
|
80
|
+
throw new Error(`fabrica.maquina: nome de maquina invalido ("${nome}"); use letras, numeros, ponto, _ ou -`);
|
|
81
|
+
}
|
|
82
|
+
const config = { contrato: exports.CONTRATO_CONFIG_DA_MAQUINA, nome,
|
|
83
|
+
fabricaCompartilhada: mudanca.fabricaCompartilhada ?? atual?.fabricaCompartilhada ?? false, atualizadoEm: new Date().toISOString() };
|
|
84
|
+
const dir = pastaDoUsuario();
|
|
85
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
86
|
+
const temp = path.join(dir, `.${ARQUIVO}.${process.pid}.tmp`);
|
|
87
|
+
fs.writeFileSync(temp, JSON.stringify(config, null, 2) + '\n', { mode: 0o644 });
|
|
88
|
+
fs.renameSync(temp, path.join(dir, ARQUIVO));
|
|
89
|
+
return config;
|
|
90
|
+
}
|
|
91
|
+
function nomeDaMaquina(explicito) {
|
|
92
|
+
return (explicito ?? '').trim() || (process.env.ORK_MAQUINA ?? '').trim() || lerConfigDaMaquina()?.nome || os.hostname();
|
|
93
|
+
}
|
|
94
|
+
/** Esta maquina publica o estado da fabrica deste projeto? */
|
|
95
|
+
function fabricaCompartilhada(manifesto) {
|
|
96
|
+
const env = (process.env.ORK_FABRICA_COMPARTILHADA ?? '').trim();
|
|
97
|
+
if (env === '1')
|
|
98
|
+
return true;
|
|
99
|
+
if (env === '0')
|
|
100
|
+
return false;
|
|
101
|
+
return manifesto.fabrica?.compartilhada === true || lerConfigDaMaquina()?.fabricaCompartilhada === true;
|
|
102
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
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.reciboSemanalValido = reciboSemanalValido;
|
|
37
|
+
exports.auditarMaster = auditarMaster;
|
|
38
|
+
/** Indicadores operacionais: ausência de evidência nunca conta como aprovação. */
|
|
39
|
+
const fs = __importStar(require("node:fs"));
|
|
40
|
+
const node_crypto_1 = require("node:crypto");
|
|
41
|
+
const thread_1 = require("./thread");
|
|
42
|
+
const ledger_1 = require("./ledger");
|
|
43
|
+
const master_1 = require("./master");
|
|
44
|
+
const master_digest_1 = require("./master-digest");
|
|
45
|
+
function reciboSemanalValido(job) {
|
|
46
|
+
if (!job.concluidoEm || (0, master_digest_1.sextaLocal)(job.concluidoEm) !== job.semana || !job.paginas.length ||
|
|
47
|
+
job.recibos.length !== job.paginas.length || new Set(job.recibos.map(r => r.pagina)).size !== job.paginas.length)
|
|
48
|
+
return false;
|
|
49
|
+
return job.paginas.every((p, pagina) => {
|
|
50
|
+
const r = job.recibos.find(r => r.pagina === pagina);
|
|
51
|
+
return !!r && r.sha256 === (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(p)).digest('hex') &&
|
|
52
|
+
r.host.success === true && Number.isInteger(r.host.message_id) && r.host.message_id > 0 &&
|
|
53
|
+
typeof r.host.platform === 'string' && !!r.host.platform.trim() &&
|
|
54
|
+
Number.isFinite(Date.parse(r.confirmadoEm)) && Date.parse(r.confirmadoEm) >= Date.parse(job.criadoEm) &&
|
|
55
|
+
Date.parse(r.confirmadoEm) <= Date.parse(job.concluidoEm);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function auditarMaster(raiz, quando = new Date().toISOString()) {
|
|
59
|
+
const fim = Date.parse(quando), inicio = fim - 30 * 86400000;
|
|
60
|
+
if (!Number.isFinite(fim))
|
|
61
|
+
throw new Error('data de auditoria inválida');
|
|
62
|
+
const fechadas = [], classes = new Set();
|
|
63
|
+
for (const id of (0, thread_1.listarIds)(raiz)) {
|
|
64
|
+
const t = (0, thread_1.lerThread)(raiz, id);
|
|
65
|
+
if (t.status !== 'fechada')
|
|
66
|
+
continue;
|
|
67
|
+
const data = Date.parse(t.atualizadaEm);
|
|
68
|
+
if (Number.isFinite(data) && (data < inicio || data > fim))
|
|
69
|
+
continue;
|
|
70
|
+
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
|
|
71
|
+
const admin = t.fechamentoAdmin && !t.score && eventos.some(e => e.tipo === 'thread_closed_admin' &&
|
|
72
|
+
e.motivo === t.fechamentoAdmin.motivo && e.por === t.fechamentoAdmin.por && e.fechadoEm === t.fechamentoAdmin.fechadoEm);
|
|
73
|
+
const log = (0, master_1.masterRatificado)(raiz, id) ? (0, master_1.lerMasterLog)(raiz, id) : null;
|
|
74
|
+
const ok = Number.isFinite(data) && !!(admin || log);
|
|
75
|
+
fechadas.push({ thread: id, ok, tipo: admin ? 'administrativo' : log ? 'ratificado' : 'sem-prova' });
|
|
76
|
+
if (ok && log)
|
|
77
|
+
log.classesDeFalha.forEach(c => classes.add(c));
|
|
78
|
+
}
|
|
79
|
+
let sexta = null, referencia = fim;
|
|
80
|
+
for (let n = 0; n < 7 && !sexta; n++, referencia -= 86400000)
|
|
81
|
+
sexta = (0, master_digest_1.sextaLocal)(new Date(referencia).toISOString());
|
|
82
|
+
const semanas = [21, 14, 7, 0].map(dias => new Date(Date.parse(`${sexta}T12:00:00Z`) - dias * 86400000).toISOString().slice(0, 10));
|
|
83
|
+
const recibos = semanas.map(semana => {
|
|
84
|
+
try {
|
|
85
|
+
const job = (0, master_digest_1.lerDigest)(raiz, semana);
|
|
86
|
+
return { semana, ok: reciboSemanalValido(job) && Date.parse(job.concluidoEm) <= fim, paginas: job.paginas.length };
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return { semana, ok: false, paginas: 0 };
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
const conformes = fechadas.filter(f => f.ok).length;
|
|
93
|
+
const cobertura = { ok: fechadas.length > 0 && conformes === fechadas.length, total: fechadas.length, conformes,
|
|
94
|
+
percentual: fechadas.length ? 100 * conformes / fechadas.length : null, threads: fechadas };
|
|
95
|
+
const distribuicao = { ok: classes.size >= 3, minimo: 3, classes: [...classes].sort() };
|
|
96
|
+
const digest = { ok: recibos.every(r => r.ok), semanas: recibos,
|
|
97
|
+
arquivosObservados: fs.existsSync((0, master_digest_1.dirDigest)(raiz)) ? fs.readdirSync((0, master_digest_1.dirDigest)(raiz)).filter(f => /^\d{4}-\d{2}-\d{2}\.json$/.test(f)).length : 0 };
|
|
98
|
+
return { contrato: 'ork.master-audit/v1', consultadoEm: quando, janelaDias: 30,
|
|
99
|
+
ok: cobertura.ok && distribuicao.ok && digest.ok, cobertura, distribuicao, digest,
|
|
100
|
+
limite: 'Testes controlados provam o mecanismo; somente estado e recibos operacionais satisfazem estes KPIs.' };
|
|
101
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assinaturaProposta = assinaturaProposta;
|
|
4
|
+
exports.listarBatch = listarBatch;
|
|
5
|
+
exports.ratificarBatch = ratificarBatch;
|
|
6
|
+
/**
|
|
7
|
+
* Seleção humana vinculada ao conteúdo exato da proposta apresentada.
|
|
8
|
+
*
|
|
9
|
+
* I-43 (T8): a FILA saiu daqui. O que era `textoDoBatch` ("Fila de score: N esperando
|
|
10
|
+
* o humano") deixou de existir, porque era exatamente o mecanismo que acumulava e não
|
|
11
|
+
* convertia: 13 entradas esperando nota que ninguém dava.
|
|
12
|
+
*
|
|
13
|
+
* O que FICA é outra coisa, e a distinção importa: ratificar uma PROPOSTA explícita de
|
|
14
|
+
* agente (`score_proposto`), com assinatura do conteúdo apresentado, é o caminho que o
|
|
15
|
+
* digest semanal e o HITL usam quando o dono responde. Isso não é fila, é resposta a
|
|
16
|
+
* um pedido específico, e a I-43 não mexe nele.
|
|
17
|
+
*/
|
|
18
|
+
const node_crypto_1 = require("node:crypto");
|
|
19
|
+
const master_1 = require("./master");
|
|
20
|
+
function assinaturaProposta(p) {
|
|
21
|
+
return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(p)).digest('hex');
|
|
22
|
+
}
|
|
23
|
+
function listarBatch(raiz, todas = false) {
|
|
24
|
+
return (0, master_1.pendentesDeScore)(raiz, todas).map(p => ({ thread: p.thread.id, nome: p.thread.nome, entregue: p.entregou,
|
|
25
|
+
proposta: p.thread.score_proposto ?? null, assinatura: p.thread.score_proposto ? assinaturaProposta(p.thread.score_proposto) : null }));
|
|
26
|
+
}
|
|
27
|
+
function ratificarBatch(raiz, selecao, por) {
|
|
28
|
+
(0, master_1.exigirAutoriaHumana)(por);
|
|
29
|
+
if (!selecao.length || new Set(selecao.map(s => s.thread)).size !== selecao.length)
|
|
30
|
+
throw new Error('selecione threads distintas explicitamente');
|
|
31
|
+
const disponiveis = listarBatch(raiz);
|
|
32
|
+
const planos = selecao.map(s => {
|
|
33
|
+
const item = disponiveis.find(i => i.thread === s.thread);
|
|
34
|
+
if (!item?.proposta || item.assinatura !== s.assinatura)
|
|
35
|
+
throw new Error(`proposta ausente ou alterada: ${s.thread}; revise o batch`);
|
|
36
|
+
const p = item.proposta;
|
|
37
|
+
const opcoes = { score: p.valor, justificativa: p.justificativa, classes: s.classe ? [s.classe] : p.classes, resumo: p.resumo, por };
|
|
38
|
+
(0, master_1.preflightMaster)(raiz, s.thread, opcoes);
|
|
39
|
+
return { id: s.thread, opcoes };
|
|
40
|
+
});
|
|
41
|
+
// Todo erro de seleção, prova, autoria, score e classe foi verificado antes de gravar.
|
|
42
|
+
return planos.map(p => (0, master_1.registrarMaster)(raiz, p.id, p.opcoes));
|
|
43
|
+
}
|