@orkastery/cli 0.6.0 → 0.6.2
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/claude-code/agents/ork-check.md +1 -1
- package/adapters/claude-code/agents/ork-go.md +1 -1
- package/adapters/claude-code/agents/ork-goal.md +1 -1
- package/adapters/claude-code/agents/ork-master.md +1 -1
- package/adapters/claude-code/agents/ork-plan.md +1 -1
- package/adapters/claude-code/agents/ork-ship.md +1 -1
- package/adapters/claude-code/commands/ork.md +1 -1
- package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +2 -0
- package/adapters/codex/skills/ork/SKILL.md +1 -1
- package/adapters/openclaw/openclaw.plugin.json +1 -1
- package/adapters/openclaw/package.json +1 -1
- package/assets/adapters-en/claude-code/agents/ork-check.md +1 -1
- package/assets/adapters-en/claude-code/agents/ork-go.md +1 -1
- package/assets/adapters-en/claude-code/agents/ork-goal.md +1 -1
- package/assets/adapters-en/claude-code/agents/ork-master.md +1 -1
- package/assets/adapters-en/claude-code/agents/ork-plan.md +1 -1
- package/assets/adapters-en/claude-code/agents/ork-ship.md +1 -1
- package/assets/adapters-en/claude-code/commands/ork.md +1 -1
- package/assets/adapters-en/codex/skills/ork/SKILL.md +1 -1
- package/assets/orkmind_fixture.py +4 -1
- package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +1 -1
- package/assets/skills-en/phases/check-quality/SKILL.md +1 -1
- package/assets/skills-en/phases/go-implementation/SKILL.md +1 -1
- package/dist/adapters/claude-bg.js +9 -7
- package/dist/adapters/grok-events.js +227 -0
- package/dist/adapters/grok-mcp-servidor.js +622 -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/branch-de-estado.js +7 -2
- package/dist/changelog-check.js +217 -0
- package/dist/check-agil.js +289 -25
- package/dist/check-paralelo.js +73 -18
- package/dist/ci.js +3 -2
- package/dist/claim-lint.js +29 -0
- package/dist/claims.js +4 -0
- package/dist/conducao.js +5 -0
- package/dist/docs.js +16 -16
- package/dist/doctor-forja.js +1 -3
- package/dist/doctor.js +1 -1
- package/dist/entrega-pr.js +10 -10
- package/dist/fabrica-estado.js +20 -11
- package/dist/fila-pesada.js +121 -11
- package/dist/hitl-classificacao.js +1 -0
- package/dist/horario.js +4 -1
- package/dist/index.js +63 -35
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +27 -9
- package/dist/locale-accounts.js +11 -3
- package/dist/locale-ajuda.js +10 -6
- package/dist/locale-claims.js +16 -2
- package/dist/locale-forja.js +2 -4
- package/dist/locale-grafo.js +56 -1
- package/dist/locale-maestro.js +38 -0
- package/dist/locale-network.js +8 -6
- package/dist/locale-onboarding.js +14 -0
- package/dist/locale-operacao-restante.js +2 -2
- package/dist/locale-preflight.js +80 -0
- package/dist/locale-projetos.js +6 -0
- package/dist/locale-prompts.js +8 -8
- package/dist/locale-pulse.js +4 -0
- package/dist/locale-retry.js +56 -2
- package/dist/locale-security-scan.js +35 -1
- package/dist/locale-ship.js +10 -2
- package/dist/locale-verify.js +15 -0
- package/dist/locale.js +24 -7
- package/dist/maestro-cli.js +12 -17
- package/dist/manifest.js +6 -1
- package/dist/mcp-install.js +24 -13
- package/dist/mcp-server.js +62 -33
- package/dist/mcp-verify-async.js +353 -0
- package/dist/mcp-verify-worker.js +17 -0
- package/dist/mcp-verify.js +10 -1
- package/dist/merge-da-entrega.js +85 -0
- package/dist/network-roadmap.js +18 -14
- package/dist/noctum-aceite.js +154 -14
- package/dist/noctum-cli.js +69 -12
- package/dist/noctum-entrega.js +55 -7
- package/dist/noctum-envelope.js +1 -1
- package/dist/noctum-execucao.js +5 -1
- package/dist/noctum-fechamento.js +18 -7
- package/dist/noctum-fila.js +6 -1
- package/dist/noctum-guarda.js +81 -4
- package/dist/noctum-maquinas.js +5 -1
- package/dist/noctum-modo.js +35 -7
- package/dist/noctum-reconciliacao.js +4 -1
- package/dist/noctum-rede.js +102 -0
- package/dist/noctum-relatorio.js +44 -10
- package/dist/noctum-retomada-rede.js +71 -0
- package/dist/noctum-vigia.js +49 -9
- package/dist/parado-no-condutor.js +14 -15
- package/dist/pedido-conducao.js +51 -0
- package/dist/phase.js +43 -15
- package/dist/postura-local.js +7 -3
- package/dist/preflight.js +27 -27
- package/dist/prompts.js +4 -2
- package/dist/pulse.js +4 -2
- package/dist/ratelimit.js +1 -0
- package/dist/rede.js +24 -12
- package/dist/retry.js +115 -10
- package/dist/runtime-context.js +165 -45
- package/dist/runtime-escada.js +7 -1
- package/dist/runtime-profiles.js +27 -17
- package/dist/runtimes.js +42 -5
- package/dist/security-scan/agil.js +18 -7
- package/dist/security-scan/cli.js +2 -2
- package/dist/security-scan/executor.js +8 -0
- package/dist/security-scan/report.js +1 -1
- package/dist/session-watcher-grok.js +425 -0
- package/dist/session-watcher.js +52 -11
- package/dist/sessoes-contas.js +33 -5
- package/dist/setup.js +11 -11
- package/dist/varredura-acoes.js +8 -15
- package/dist/verify.js +191 -43
- package/package.json +2 -2
- package/skills/core/orkastery-bootstrap/SKILL.md +1 -1
- package/skills/phases/check-quality/SKILL.md +1 -1
- package/skills/phases/go-implementation/SKILL.md +1 -1
package/dist/noctum-aceite.js
CHANGED
|
@@ -65,9 +65,11 @@ const branch_de_estado_1 = require("./branch-de-estado");
|
|
|
65
65
|
const ci_1 = require("./ci");
|
|
66
66
|
const horario_1 = require("./horario");
|
|
67
67
|
const ledger_1 = require("./ledger");
|
|
68
|
+
const maquina_1 = require("./maquina");
|
|
68
69
|
const master_1 = require("./master");
|
|
69
70
|
const noctum_arco_1 = require("./noctum-arco");
|
|
70
71
|
const noctum_envelope_1 = require("./noctum-envelope");
|
|
72
|
+
const noctum_coordenacao_1 = require("./noctum-coordenacao");
|
|
71
73
|
const noctum_fila_1 = require("./noctum-fila");
|
|
72
74
|
const noctum_medicao_1 = require("./noctum-medicao");
|
|
73
75
|
const noctum_registro_1 = require("./noctum-registro");
|
|
@@ -76,6 +78,8 @@ const noctum_supervisao_1 = require("./noctum-supervisao");
|
|
|
76
78
|
const parado_no_condutor_1 = require("./parado-no-condutor");
|
|
77
79
|
const estado_thread_1 = require("./estado-thread");
|
|
78
80
|
const thread_1 = require("./thread");
|
|
81
|
+
const noctum_coordenacao_2 = require("./noctum-coordenacao");
|
|
82
|
+
const noctum_transporte_1 = require("./noctum-transporte");
|
|
79
83
|
const util_1 = require("./util");
|
|
80
84
|
const worktree_1 = require("./worktree");
|
|
81
85
|
exports.CONTRATO_PILOTO = 'ork.noctum-piloto/v1';
|
|
@@ -128,8 +132,9 @@ function remotoLocal(url) {
|
|
|
128
132
|
return /^file:/i.test(url) || /^(\/|\.{1,2}\/|[A-Za-z]:[\\/])/.test(url) || (!/^[a-z][a-z0-9+.-]*:\/\//i.test(url) && !/^[^@\s]+@[^:\s]+:/.test(url));
|
|
129
133
|
}
|
|
130
134
|
/** Os limiares da proposta, pela janela do piloto. */
|
|
131
|
-
function limiaresDaProposta(horas) {
|
|
132
|
-
return { m1MinimoHoras: arred(horas), m5MaximoMin: 15, entregasMinimas: horas < 12 ? 2 : 4,
|
|
135
|
+
function limiaresDaProposta(horas, multimaquina = false) {
|
|
136
|
+
return { m1MinimoHoras: arred(horas), m5MaximoMin: multimaquina ? 25 : 15, entregasMinimas: horas < 12 ? 2 : 4,
|
|
137
|
+
margemDoTeto: 0, atrasoDoRelatorioMin: noctum_fila_1.CADENCIA_MS / MIN };
|
|
133
138
|
}
|
|
134
139
|
/** As chaves dos limiares do dono, no contrato `ork.noctum-limiares/v1`. */
|
|
135
140
|
exports.CHAVES_DOS_LIMIARES = ['m1MinimoHoras', 'm5MaximoMin', 'entregasMinimas', 'margemDoTeto', 'atrasoDoRelatorioMin'];
|
|
@@ -203,12 +208,29 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
203
208
|
if (!estado?.conteudo || !estado.autorizadoPor)
|
|
204
209
|
throw new RecusaDoAceite('noctum.aceite.sem-arco', `o arco ${arco} nunca foi autorizado pelo dono`);
|
|
205
210
|
const conteudo = estado.conteudo;
|
|
211
|
+
const multimaquina = (0, noctum_envelope_1.envelopeMultimaquina)(conteudo);
|
|
212
|
+
const maquinaAtual = (0, maquina_1.nomeDaMaquina)(opcoes.maquina);
|
|
213
|
+
let rede = null;
|
|
214
|
+
let erroDaRede = null;
|
|
215
|
+
if (multimaquina) {
|
|
216
|
+
try {
|
|
217
|
+
if (opcoes.rede)
|
|
218
|
+
rede = opcoes.rede;
|
|
219
|
+
else {
|
|
220
|
+
const leitura = (0, noctum_transporte_1.lerRamo)(carregado, arco, { remoto: opcoes.remoto, maquina: maquinaAtual }, noctum_coordenacao_2.conferirCoordenacao);
|
|
221
|
+
rede = { registros: leitura.registros.map(r => r.dados), estado: (0, noctum_coordenacao_1.derivarCoordenacao)(leitura) };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (e) {
|
|
225
|
+
erroDaRede = `a coordenação não se lê (${e instanceof noctum_envelope_1.RecusaDoArco ? e.motivo : e.message.slice(0, 120)})`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
206
228
|
const janela = conteudo.janela;
|
|
207
229
|
// A condução começa no início da janela ou na primeira autorização, o que vier depois; as autorizações seguintes, dentro
|
|
208
230
|
// da janela, são emendas do dono.
|
|
209
231
|
let autorizacoes = [];
|
|
210
232
|
try {
|
|
211
|
-
autorizacoes = (0, noctum_arco_1.versoesAutorizadas)(raiz, arco).map(v => ({ versao: v.versao, autorizadoEm: v.autorizadoEm }));
|
|
233
|
+
autorizacoes = (0, noctum_arco_1.versoesAutorizadas)(raiz, arco).map(v => ({ versao: v.versao, autorizadoEm: v.autorizadoEm, envelopeSha256: v.envelopeSha256 }));
|
|
212
234
|
}
|
|
213
235
|
catch (e) {
|
|
214
236
|
if (!(e instanceof noctum_envelope_1.RecusaDoArco))
|
|
@@ -221,6 +243,19 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
221
243
|
const horasDaJanela = (Date.parse(janela.fim) - Date.parse(janela.inicio)) / HORA;
|
|
222
244
|
const git = opcoes.git ?? gitDaRaiz(raiz);
|
|
223
245
|
const remoto = opcoes.remoto ?? carregado.manifesto.fabrica?.remoto ?? 'origin';
|
|
246
|
+
const outras = [];
|
|
247
|
+
for (const outra of opcoes.outrasMaquinas ?? []) {
|
|
248
|
+
const r = outra.resultado;
|
|
249
|
+
const envelope = objeto(r) && objeto(r.envelope) ? r.envelope : null;
|
|
250
|
+
const maquina = objeto(r) && typeof r.maquina === 'string' ? r.maquina : null;
|
|
251
|
+
const valida = objeto(r) && r.contrato === exports.CONTRATO_PILOTO && r.arco === arco && envelope && typeof envelope.sha256 === 'string' &&
|
|
252
|
+
autorizacoes.some(v => v.envelopeSha256 === envelope.sha256) && maquina && multimaquina && conteudo.maquinas.some(m => m.nome === maquina) &&
|
|
253
|
+
Array.isArray(r.medidas) && Array.isArray(r.criterios) && typeof r.veredito === 'string';
|
|
254
|
+
if (!valida) {
|
|
255
|
+
throw new RecusaDoAceite('noctum.aceite.outra-maquina-invalida', `${outra.fonte}: o arquivo precisa ser um ${exports.CONTRATO_PILOTO} completo do arco ${arco}, de uma máquina e envelope autorizados aqui`);
|
|
256
|
+
}
|
|
257
|
+
outras.push({ ...outra, resultado: r });
|
|
258
|
+
}
|
|
224
259
|
// As leituras: a supervisão, o relatório e os ledgers das threads do arco.
|
|
225
260
|
let supervisao = null;
|
|
226
261
|
let erroDaSupervisao = null;
|
|
@@ -300,6 +335,8 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
300
335
|
catch { /* sem transporte configurado: o relatório diz a lacuna */ }
|
|
301
336
|
const medidas = [];
|
|
302
337
|
const medida = (m) => { medidas.push(m); return m; };
|
|
338
|
+
const nomesDasMaquinas = multimaquina ? conteudo.maquinas.map(m => m.nome) : [maquinaAtual];
|
|
339
|
+
const porMaquina = (valor) => Object.fromEntries(nomesDasMaquinas.map(maquina => [maquina, valor(maquina)]));
|
|
303
340
|
/**
|
|
304
341
|
* I1 do CHECK 2: a entrega do arco é o `ship_done` que a entrega dele gravou (o arco na evidência), e não a reconciliação
|
|
305
342
|
* de um merge feito por fora (`incorporadaPor: 'outro-caminho'`) nem o ship do dono depois do arco.
|
|
@@ -443,7 +480,8 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
443
480
|
const semLeitura = entregas.some(e => e.provada === null) || ilegiveis.length > 0;
|
|
444
481
|
medida({ id: 'M2', nome: 'Entregas com prova', valor: semLeitura ? null : provadas.length, unidade: `entregas provadas de ${entregas.length} alegadas`,
|
|
445
482
|
fonte: 'ship_done dos ledgers, ponta da base pelo git ls-remote e ancestralidade do merge', lacunas: lacunasDaEntrega,
|
|
446
|
-
evidencia: { alegadas: entregas.length, entregas: entregas.map(e => ({ trabalho: e.trabalho, thread: e.thread, provada: e.provada, motivo: e.motivo }))
|
|
483
|
+
evidencia: { alegadas: entregas.length, entregas: entregas.map(e => ({ trabalho: e.trabalho, thread: e.thread, provada: e.provada, motivo: e.motivo })),
|
|
484
|
+
...(multimaquina ? { porMaquina: porMaquina(maquina => (rede?.registros ?? []).filter(r => r.tipo === 'entrega' && r.por === maquina).length) } : {}) } });
|
|
447
485
|
medida({ id: 'M3', nome: 'MASTER por omissão', valor: semLeitura ? null : provadas.filter(e => e.master).length, unidade: `entregas com MASTER de ${provadas.length} provadas`,
|
|
448
486
|
fonte: 'aceite_por_omissao com o arco na evidência, antes do fim do arco, e a thread fechada', lacunas: semLeitura ? ['as entregas não se provaram todas'] : [],
|
|
449
487
|
evidencia: { semMaster: provadas.filter(e => !e.master).map(e => e.thread) } });
|
|
@@ -456,6 +494,37 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
456
494
|
.map(l => ({ em: l.em, fonte: `supervisão: ${l.evento.tipo}`, alvos: alvosDe(l.evento) }));
|
|
457
495
|
const dosLedgers = (tipos) => eventosDasThreads.filter(e => tipos.includes(e.tipo))
|
|
458
496
|
.map(e => ({ em: e.ts, fonte: `ledger da ${e.threadDoArco}: ${e.tipo}`, alvos: [e.threadDoArco, ...[...porTrabalho].filter(([, t]) => t === e.threadDoArco).map(([w]) => w)] }));
|
|
497
|
+
const ordensDaRede = new Map((rede?.registros ?? []).filter(r => r.tipo === 'ordem' && typeof r.ordem === 'string')
|
|
498
|
+
.map(r => [String(r.ordem), { maquina: String(r.maquina), trabalho: String(r.trabalho) }]));
|
|
499
|
+
const vezesDaRede = new Map((rede?.registros ?? []).filter(r => r.tipo === 'vez' && typeof r.chave === 'string' && typeof r.n === 'number')
|
|
500
|
+
.map(r => [`${String(r.chave)}/${String(r.n)}`, { maquina: String(r.por), trabalho: ordensDaRede.get(String(r.ordem))?.trabalho ?? '' }]));
|
|
501
|
+
const daRede = (i, falha) => {
|
|
502
|
+
if (!i.alvo)
|
|
503
|
+
return `${falha} exige o alvo (a máquina afetada) na agenda`;
|
|
504
|
+
if (erroDaRede)
|
|
505
|
+
return erroDaRede;
|
|
506
|
+
if (!rede)
|
|
507
|
+
return 'a coordenação da rede não foi lida';
|
|
508
|
+
if (falha === 'F10') {
|
|
509
|
+
return rede.registros.filter(r => r.por === i.alvo)
|
|
510
|
+
.map(r => ({ em: r.em, fonte: `coordenação: ${r.tipo} assinado por ${r.por}`, alvos: [i.alvo], maquina: r.por }));
|
|
511
|
+
}
|
|
512
|
+
const isoladas = rede.ordensIsoladas?.filter(o => o.maquina === i.alvo) ??
|
|
513
|
+
[...(rede.estado?.ordens.values() ?? [])].filter(o => o.maquina === i.alvo && o.estado === 'isolada');
|
|
514
|
+
if (isoladas.length)
|
|
515
|
+
return [];
|
|
516
|
+
return rede.registros.filter(r => {
|
|
517
|
+
if (r.por === i.alvo)
|
|
518
|
+
return false;
|
|
519
|
+
if (r.tipo === 'autoridade' && r.modo === 'forcada')
|
|
520
|
+
return objeto(r.anterior) && r.anterior.maquina === i.alvo;
|
|
521
|
+
if (r.tipo === 'cancelamento')
|
|
522
|
+
return ordensDaRede.get(String(r.ordem))?.maquina === i.alvo;
|
|
523
|
+
if (r.tipo === 'vez-fim' && r.desfecho === 'abandonada')
|
|
524
|
+
return vezesDaRede.get(`${String(r.chave)}/${String(r.n)}`)?.maquina === i.alvo;
|
|
525
|
+
return false;
|
|
526
|
+
}).map(r => ({ em: r.em, fonte: `coordenação: ${r.tipo} de ${i.alvo} por ${r.por}`, alvos: [i.alvo], maquina: r.por }));
|
|
527
|
+
};
|
|
459
528
|
const SINAIS = {
|
|
460
529
|
F1: () => erroDaSupervisao ?? daSupervisao(['retomada_autorizada']),
|
|
461
530
|
F2: () => erroDaSupervisao ?? daSupervisao(['conducao_assumida']),
|
|
@@ -466,26 +535,33 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
466
535
|
F7: () => erroDoRelatorio ?? confirmacoesAutomaticas.map(l => ({ em: l.em, fonte: 'relatório: envio_confirmado', alvos: [] })),
|
|
467
536
|
F8: () => erroDaSupervisao ?? daSupervisao(['efeito_reconciliado']),
|
|
468
537
|
F9: () => erroDaSupervisao ?? daSupervisao(['tique_concluido']),
|
|
469
|
-
F10: () =>
|
|
470
|
-
F11: () =>
|
|
538
|
+
F10: (i) => daRede(i, 'F10'),
|
|
539
|
+
F11: (i) => daRede(i, 'F11'),
|
|
471
540
|
};
|
|
472
541
|
const injecoes = opcoes.injecoes ?? null;
|
|
473
542
|
const recuperacoes = (injecoes ?? []).map(i => {
|
|
474
|
-
const fontes = SINAIS[i.falha]?.() ?? `falha desconhecida: ${i.falha}`;
|
|
543
|
+
const fontes = SINAIS[i.falha]?.(i) ?? `falha desconhecida: ${i.falha}`;
|
|
475
544
|
if (typeof fontes === 'string')
|
|
476
545
|
return { ...i, lacuna: fontes, sinal: null };
|
|
477
546
|
const doAlvo = i.alvo ? fontes.filter(f => !f.alvos.length || f.alvos.includes(i.alvo)) : fontes;
|
|
478
547
|
const sinal = sinalDe(doAlvo, Date.parse(i.instante));
|
|
479
|
-
return { ...i, lacuna: null, sinal: sinal ? { em: sinal.em, fonte: sinal.fonte } : null };
|
|
548
|
+
return { ...i, lacuna: null, sinal: sinal ? { em: sinal.em, fonte: sinal.fonte, ...(sinal.maquina ? { maquina: sinal.maquina } : {}) } : null };
|
|
480
549
|
});
|
|
481
550
|
// A agenda vazia não prova recuperação nenhuma: é lacuna, como a agenda que falta.
|
|
482
551
|
const lacunasDaAgenda = injecoes === null ? ['sem a agenda de injeções (--injecoes)']
|
|
483
552
|
: !injecoes.length ? ['a agenda de injeções está vazia: nenhuma falha foi injetada']
|
|
484
553
|
: recuperacoes.filter(r => r.lacuna).map(r => `${r.falha}: ${r.lacuna}`);
|
|
485
554
|
const recuperadas = recuperacoes.filter(r => r.sinal);
|
|
555
|
+
const aguardamRecibo = (rede?.ordensIsoladas ?? [...(rede?.estado?.ordens.values() ?? [])]
|
|
556
|
+
.filter(o => o.estado === 'isolada').map(o => ({ maquina: o.maquina, trabalho: o.trabalho })))
|
|
557
|
+
.filter(o => (injecoes ?? []).some(i => i.falha === 'F11' && i.alvo === o.maquina));
|
|
558
|
+
const retomados = [...(rede?.estado?.trabalhos.values() ?? [])].filter(t => t.ordem && t.estado !== 'isolado' &&
|
|
559
|
+
(injecoes ?? []).some(i => i.falha === 'F11' && i.alvo && t.ordem.maquina !== i.alvo)).map(t => t.trabalho);
|
|
486
560
|
medida({ id: 'M4', nome: 'Falhas recuperadas', valor: lacunasDaAgenda.length ? null : recuperadas.length, unidade: `recuperadas de ${recuperacoes.length} injetadas`,
|
|
487
561
|
fonte: 'agenda de injeções, log da supervisão, registro do relatório e ledgers', lacunas: lacunasDaAgenda,
|
|
488
|
-
evidencia: { injecoes: recuperacoes.map(r => ({ falha: r.falha, instante: r.instante, sinal: r.sinal, lacuna: r.lacuna }))
|
|
562
|
+
evidencia: { injecoes: recuperacoes.map(r => ({ falha: r.falha, instante: r.instante, sinal: r.sinal, lacuna: r.lacuna })),
|
|
563
|
+
...(multimaquina ? { porMaquina: porMaquina(maquina => recuperadas.filter(r => r.sinal && 'maquina' in r.sinal && r.sinal.maquina === maquina).length),
|
|
564
|
+
retomados, aguardamRecibo } : {}) } });
|
|
489
565
|
// M5 é das falhas que o plano mede pelo tempo (a sessão morta, o condutor morto e a máquina perdida); as outras, como o
|
|
490
566
|
// tique parado de propósito por 20 min, contam só em M4.
|
|
491
567
|
const tempos = recuperadas.filter(r => exports.FALHAS_DO_M5.includes(r.falha)).map(r => (Date.parse(r.sinal.em) - Date.parse(r.instante)) / MIN)
|
|
@@ -494,7 +570,12 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
494
570
|
medida({ id: 'M5', nome: 'Tempo de recuperação', valor: lacunasDaAgenda.length || !tempos.length ? null : arred(tempos.at(-1)), unidade: 'min (máximo)',
|
|
495
571
|
fonte: 'da injeção ao primeiro sinal de retomada no log', lacunas: lacunasDaAgenda.length ? lacunasDaAgenda : tempos.length ? []
|
|
496
572
|
: [`nenhuma falha recuperada de ${exports.FALHAS_DO_M5.join(', ')} para medir`],
|
|
497
|
-
evidencia: { mediana: mediana === null ? null : arred(mediana), maximo: tempos.length ? arred(tempos.at(-1)) : null
|
|
573
|
+
evidencia: { mediana: mediana === null ? null : arred(mediana), maximo: tempos.length ? arred(tempos.at(-1)) : null,
|
|
574
|
+
...(multimaquina ? { porMaquina: porMaquina(maquina => {
|
|
575
|
+
const t = recuperadas.filter(r => exports.FALHAS_DO_M5.includes(r.falha) && r.sinal && 'maquina' in r.sinal && r.sinal.maquina === maquina)
|
|
576
|
+
.map(r => arred((Date.parse(r.sinal.em) - Date.parse(r.instante)) / MIN));
|
|
577
|
+
return t.length ? Math.max(...t) : null;
|
|
578
|
+
}) } : {}) } });
|
|
498
579
|
// M6: violações do envelope.
|
|
499
580
|
const contas = new Set([...conteudo.orcamento.porConta.map(c => c.conta), ...(comTrabalhos ? conteudo.capacidade.porConta.map(c => c.conta) : [])]);
|
|
500
581
|
const bases = new Set(conteudo.destinos.map(d => d.base));
|
|
@@ -549,6 +630,22 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
549
630
|
for (const [chave, n] of paginas)
|
|
550
631
|
if (n > 1)
|
|
551
632
|
duplicados.push(`${n} envios confirmados da ${chave}`);
|
|
633
|
+
const vagasSobrepostas = [];
|
|
634
|
+
const vagasDaRede = rede?.vagas ?? rede?.estado?.vagas ?? [];
|
|
635
|
+
for (let i = 0; i < vagasDaRede.length; i++) {
|
|
636
|
+
for (let j = i + 1; j < vagasDaRede.length; j++) {
|
|
637
|
+
const a = vagasDaRede[i], b = vagasDaRede[j];
|
|
638
|
+
if (a.trabalho !== b.trabalho || a.maquina === b.maquina)
|
|
639
|
+
continue;
|
|
640
|
+
const inicio = Math.max(Date.parse(a.desde), Date.parse(b.desde));
|
|
641
|
+
const fimA = a.solta ? Date.parse(a.solta.em) : Number.POSITIVE_INFINITY;
|
|
642
|
+
const fimB = b.solta ? Date.parse(b.solta.em) : Number.POSITIVE_INFINITY;
|
|
643
|
+
if (inicio < Math.min(fimA, fimB)) {
|
|
644
|
+
vagasSobrepostas.push({ trabalho: a.trabalho, maquinas: [a.maquina, b.maquina], vagas: [a.vaga, b.vaga] });
|
|
645
|
+
duplicados.push(`o trabalho ${a.trabalho} teve vagas ativas ao mesmo tempo em ${a.maquina} e ${b.maquina}`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
552
649
|
const lacunasDaForja = [];
|
|
553
650
|
const repositorio = urlDoRemoto && !remotoLocal(urlDoRemoto) ? (0, ci_1.repositorioGitHub)(urlDoRemoto) : null;
|
|
554
651
|
if (repositorio) {
|
|
@@ -583,7 +680,8 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
583
680
|
}
|
|
584
681
|
const lacunasDoM7 = [...(erroDoRelatorio ? [erroDoRelatorio] : []), ...lacunasDaForja, ...ilegiveis];
|
|
585
682
|
medida({ id: 'M7', nome: 'Efeitos duplicados', valor: lacunasDoM7.length && !duplicados.length ? null : duplicados.length, unidade: 'efeitos duplicados',
|
|
586
|
-
fonte: 'ledgers (ship_done e ship_published), log do arco, registro do relatório e PRs da forja', lacunas: lacunasDoM7,
|
|
683
|
+
fonte: 'ledgers (ship_done e ship_published), log do arco, registro do relatório, coordenação e PRs da forja', lacunas: lacunasDoM7,
|
|
684
|
+
evidencia: { duplicados, ...(multimaquina ? { vagasSobrepostas, porMaquina: porMaquina(maquina => vagasSobrepostas.filter(v => v.maquinas.includes(maquina)).length) } : {}) } });
|
|
587
685
|
// M8: evidência perdida.
|
|
588
686
|
const perdidas = [...ilegiveis, ...(erroDaSupervisao ? [erroDaSupervisao] : []), ...(erroDoRelatorio ? [erroDoRelatorio] : [])];
|
|
589
687
|
for (const e of entregas)
|
|
@@ -625,7 +723,9 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
625
723
|
const lacunasDoTeto = tetos.filter(t => t.lacuna).map(t => `${t.escopo}: ${t.lacuna}`);
|
|
626
724
|
const acima = tetos.filter(t => t.consumo !== null && t.consumo > t.teto);
|
|
627
725
|
medida({ id: 'M9', nome: 'Consumo contra o teto', valor: lacunasDoTeto.length ? null : acima.length, unidade: 'escopos acima do teto',
|
|
628
|
-
fonte: 'consumo do log do arco e a medição das unidades', lacunas: lacunasDoTeto,
|
|
726
|
+
fonte: 'consumo do log do arco, da coordenação e a medição das unidades', lacunas: lacunasDoTeto,
|
|
727
|
+
evidencia: { tetos, ...(multimaquina ? { porMaquina: porMaquina(maquina => (rede?.vagas ?? rede?.estado?.vagas ?? [])
|
|
728
|
+
.filter(v => v.maquina === maquina && (!v.solta || v.solta.consumiu)).length) } : {}) } });
|
|
629
729
|
// M10: o relatório da manhã.
|
|
630
730
|
const lacunasDoRelatorio = erroDoRelatorio ? [erroDoRelatorio] : [];
|
|
631
731
|
const vencimento = (0, noctum_relatorio_1.vencimentoDoRelatorio)(conteudo);
|
|
@@ -666,8 +766,39 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
666
766
|
medida({ id: 'M10', nome: 'Relatório da manhã', valor: lacunasDoRelatorio.length ? null : falhasDoRelatorio.length ? 0 : 1, unidade: '1 no horário com recibo, 0 fora',
|
|
667
767
|
fonte: 'registro do relatório do arco', lacunas: lacunasDoRelatorio,
|
|
668
768
|
evidencia: { vencimento, versao1: v1 ? { compostoEm: v1.em, paginas: paginasDaV1, recibos: recibos.size } : null, falhas: falhasDoRelatorio } });
|
|
769
|
+
// No v3, cinco medidas são a composição dos aceites completos de todas as máquinas. A ausência de uma fonte é lacuna,
|
|
770
|
+
// nunca zero. As demais já trazem em `evidencia.porMaquina` a divisão derivada do ramo conferido.
|
|
771
|
+
const porFonte = new Map([[maquinaAtual, medidas]]);
|
|
772
|
+
for (const outra of outras) {
|
|
773
|
+
if (porFonte.has(outra.resultado.maquina)) {
|
|
774
|
+
throw new RecusaDoAceite('noctum.aceite.outra-maquina-invalida', `${outra.fonte}: a máquina ${outra.resultado.maquina} apareceu mais de uma vez`);
|
|
775
|
+
}
|
|
776
|
+
porFonte.set(outra.resultado.maquina, outra.resultado.medidas);
|
|
777
|
+
}
|
|
778
|
+
if (multimaquina) {
|
|
779
|
+
const ausentes = conteudo.maquinas.map(m => m.nome).filter(m => !porFonte.has(m));
|
|
780
|
+
const combinadas = new Set(['M1', 'M3', 'M6', 'M8', 'M10']);
|
|
781
|
+
for (const medidaLocal of medidas.filter(m => combinadas.has(m.id))) {
|
|
782
|
+
const valores = Object.fromEntries(conteudo.maquinas.map(({ nome }) => [nome,
|
|
783
|
+
porFonte.get(nome)?.find(m => m.id === medidaLocal.id)?.valor ?? null]));
|
|
784
|
+
medidaLocal.evidencia = { ...medidaLocal.evidencia, porMaquina: valores };
|
|
785
|
+
if (ausentes.length) {
|
|
786
|
+
medidaLocal.valor = null;
|
|
787
|
+
medidaLocal.lacunas.push(`sem o aceite completo da(s) máquina(s): ${ausentes.join(', ')}`);
|
|
788
|
+
}
|
|
789
|
+
else if (Object.values(valores).some(v => v === null)) {
|
|
790
|
+
medidaLocal.valor = null;
|
|
791
|
+
medidaLocal.lacunas.push('ao menos uma máquina deixou a medida como lacuna');
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
const vs = Object.values(valores);
|
|
795
|
+
medidaLocal.valor = medidaLocal.id === 'M1' ? Math.min(...vs) : medidaLocal.id === 'M10' ? (vs.every(v => v === 1) ? 1 : 0)
|
|
796
|
+
: vs.reduce((a, b) => a + b, 0);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
669
800
|
// Os critérios.
|
|
670
|
-
const proposta = limiaresDaProposta(horasDaJanela);
|
|
801
|
+
const proposta = limiaresDaProposta(horasDaJanela, multimaquina);
|
|
671
802
|
const doDono = opcoes.limiares ?? {};
|
|
672
803
|
const limiar = (k) => doDono[k] !== undefined ? { valor: doDono[k], origem: 'dono' } : { valor: proposta[k], origem: 'proposta' };
|
|
673
804
|
const m = (id) => medidas.find(x => x.id === id);
|
|
@@ -700,11 +831,17 @@ function aceiteDoPiloto(carregado, arco, opcoes = {}) {
|
|
|
700
831
|
: 'sem revogação');
|
|
701
832
|
const veredito = marcas.length ? 'simulado' : criterios.some(c => c.veredito === 'reprovado') ? 'reprovado'
|
|
702
833
|
: criterios.some(c => c.veredito === 'incompleto') ? 'incompleto' : 'aprovado';
|
|
834
|
+
const maquinasDoResultado = [
|
|
835
|
+
{ maquina: maquinaAtual, fonte: 'estado local', sha256: sha256(JSON.stringify({ arco, maquina: maquinaAtual, medidas })), veredito },
|
|
836
|
+
...outras.map(o => ({ maquina: o.resultado.maquina, fonte: o.fonte, sha256: o.sha256, veredito: o.resultado.veredito })),
|
|
837
|
+
];
|
|
703
838
|
return {
|
|
704
839
|
contrato: exports.CONTRATO_PILOTO, arco,
|
|
705
840
|
envelope: { contrato: conteudo.contrato ?? null, versao: estado.versao, sha256: estado.envelopeSha256 },
|
|
706
841
|
janela: { inicio: janela.inicio, fim: janela.fim, fuso: janela.fuso, horas: arred(horasDaJanela) },
|
|
707
842
|
encerramento: estado.encerramento ? { motivo: estado.encerramento.motivo, em: estado.encerramento.em } : null,
|
|
843
|
+
maquina: maquinaAtual,
|
|
844
|
+
maquinas: maquinasDoResultado,
|
|
708
845
|
simulacao: { simulado: marcas.length > 0, marcas },
|
|
709
846
|
medidas, criterios, veredito,
|
|
710
847
|
lacunas: medidas.flatMap(x => x.lacunas.map(l => `${x.id}: ${l}`)),
|
|
@@ -756,7 +893,7 @@ function publicavel(r, sha256DoCompleto, sensiveis) {
|
|
|
756
893
|
return x;
|
|
757
894
|
};
|
|
758
895
|
const andar = (v) => typeof v === 'string' ? limpar(v) : Array.isArray(v) ? v.map(andar)
|
|
759
|
-
: objeto(v) ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, andar(x)])) : v;
|
|
896
|
+
: objeto(v) ? Object.fromEntries(Object.entries(v).map(([k, x]) => [limpar(k), andar(x)])) : v;
|
|
760
897
|
return { ...andar(r), publicavel: true, sha256DoCompleto };
|
|
761
898
|
}
|
|
762
899
|
/** As contas, as máquinas e os repositórios que o arco conhece: o que o publicável troca por rótulos. */
|
|
@@ -768,6 +905,9 @@ function sensiveisDoArco(carregado, arco) {
|
|
|
768
905
|
const repositorios = new Set();
|
|
769
906
|
for (const c of conteudo?.orcamento.porConta ?? [])
|
|
770
907
|
contas.add(c.conta);
|
|
908
|
+
if (conteudo && (0, noctum_envelope_1.envelopeMultimaquina)(conteudo))
|
|
909
|
+
for (const m of conteudo.maquinas)
|
|
910
|
+
maquinas.add(m.nome);
|
|
771
911
|
for (const d of estado?.despachos ?? [])
|
|
772
912
|
contas.add(d.conta);
|
|
773
913
|
for (const d of conteudo?.destinos ?? []) {
|
package/dist/noctum-cli.js
CHANGED
|
@@ -41,6 +41,8 @@ exports.comandoNoctum = comandoNoctum;
|
|
|
41
41
|
* RM-058, fatia N6 (D1, D12 e D13 da ork-rm058n6): o comando `ork noctum`, a porta do CLI para o arco.
|
|
42
42
|
*
|
|
43
43
|
* ork noctum propor --arquivo <envelope.json> [--json] o pedido de abertura vira proposta e pergunta ao dono; nada é autorizado
|
|
44
|
+
* ork noctum maquina [--json] a entrada desta máquina em `maquinas` do envelope `v3`: o nome, a
|
|
45
|
+
* chave pública e a impressão (RM-058, bloco B, D5)
|
|
44
46
|
* ork noctum revogar <arco> [--json] a pergunta de revogação ao dono (RM-057); nada é revogado
|
|
45
47
|
* ork noctum responder <arco> --resposta-stdin ... o envelope assinado do gateway (autorizar ou revogar)
|
|
46
48
|
* ork noctum terminal --hook-stdin o ingresso do terminal, que o hook UserPromptSubmit chama (RM-057);
|
|
@@ -57,6 +59,7 @@ exports.comandoNoctum = comandoNoctum;
|
|
|
57
59
|
* aqui pelo `responder`, ou o diálogo nativo do host pelo MCP). Recusa tipada sai na saída de erro, com código 2.
|
|
58
60
|
*/
|
|
59
61
|
const fs = __importStar(require("node:fs"));
|
|
62
|
+
const node_crypto_1 = require("node:crypto");
|
|
60
63
|
const fila_pesada_1 = require("./fila-pesada");
|
|
61
64
|
const hitl_gates_1 = require("./hitl-gates");
|
|
62
65
|
const hitl_public_receipt_1 = require("./hitl-public-receipt");
|
|
@@ -73,14 +76,17 @@ const noctum_modo_1 = require("./noctum-modo");
|
|
|
73
76
|
const noctum_relatorio_1 = require("./noctum-relatorio");
|
|
74
77
|
const noctum_registro_1 = require("./noctum-registro");
|
|
75
78
|
const noctum_supervisao_1 = require("./noctum-supervisao");
|
|
79
|
+
const noctum_transporte_1 = require("./noctum-transporte");
|
|
76
80
|
const noctum_vigia_1 = require("./noctum-vigia");
|
|
81
|
+
const maquina_1 = require("./maquina");
|
|
77
82
|
const runtime_profiles_1 = require("./runtime-profiles");
|
|
78
83
|
const noctum_terminal_1 = require("./noctum-terminal");
|
|
79
84
|
const transporte_do_canal_1 = require("./transporte-do-canal");
|
|
80
|
-
exports.USO_DO_NOCTUM = 'uso: ork noctum propor --arquivo <envelope.json> |
|
|
85
|
+
exports.USO_DO_NOCTUM = 'uso: ork noctum propor --arquivo <envelope.json> | maquina [--json] | revogar <arco> [--json] | ' +
|
|
86
|
+
'responder <arco> --resposta-stdin ' +
|
|
81
87
|
'--origem O --canal C --por P --mensagem M [--conta X] | terminal --hook-stdin | status [<arco>] [--json] | tique <arco> [--json] | ' +
|
|
82
88
|
'relatorio <arco> [--json] [--reenviar <canal>] | conduzir <arco> [--json] | aceite <arco> [--json] [--injecoes <arquivo>] ' +
|
|
83
|
-
'[--limiares <arquivo>] [--publicar <arquivo>]';
|
|
89
|
+
'[--limiares <arquivo>] [--outra-maquina <arquivo>[,<arquivo>]] [--publicar <arquivo>]';
|
|
84
90
|
/** A linha da entrega da pergunta ao canal do dono, sem caminho de máquina. */
|
|
85
91
|
function linhaDaEntrega(e) {
|
|
86
92
|
if (e.entregue)
|
|
@@ -115,13 +121,31 @@ function lerEntradaDoHookStdin() {
|
|
|
115
121
|
const TETO_DO_ARQUIVO_DO_ENVELOPE = 64 * 1024;
|
|
116
122
|
const texto = (v) => typeof v === 'string' ? v : undefined;
|
|
117
123
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
124
|
+
* RM-058, bloco B (D22): no `v3`, esta máquina só entra no arco se está em `maquinas` com o nome e a chave desta raiz,
|
|
125
|
+
* a mesma conferência do `euNaVersaoVigente`. O aviso só antecipa a recusa: a proposta segue.
|
|
126
|
+
*/
|
|
127
|
+
function avisosDaMaquina(maquinas, eu) {
|
|
128
|
+
const listada = maquinas.find(m => m.nome === eu.nome);
|
|
129
|
+
const correcao = 'rode ork noctum maquina --json nesta máquina e ponha a saída em maquinas do envelope';
|
|
130
|
+
if (!listada) {
|
|
131
|
+
return [{ motivo: 'noctum.proposta.maquina-ausente', correcao,
|
|
132
|
+
detalhe: `esta máquina (${eu.nome}) não está em maquinas do envelope v3: fica fora do arco, sem ordem, despacho nem entrega` }];
|
|
133
|
+
}
|
|
134
|
+
if (listada.chave === eu.chave)
|
|
135
|
+
return [];
|
|
136
|
+
return [{ motivo: 'noctum.proposta.maquina-outra-chave', correcao,
|
|
137
|
+
detalhe: `o envelope dá à máquina ${eu.nome} a chave de impressão ${(0, noctum_envelope_1.impressaoDaChave)(listada.chave)}, e a desta raiz é ` +
|
|
138
|
+
`${(0, noctum_envelope_1.impressaoDaChave)(eu.chave)}: a máquina fica fora do arco` }];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Pré-voo informativo da proposta: antecipa as causas que fariam o arco esperar, mas não autoriza nem bloqueia nada.
|
|
142
|
+
* As dependências opcionais deixam os testes usar perfis, trust e a identidade da máquina simulados sem ler contas reais.
|
|
120
143
|
*/
|
|
121
144
|
function avisosDaProposta(carregado, conteudo, opcoes = {}) {
|
|
122
145
|
if (!(0, noctum_envelope_1.envelopeComTrabalhos)(conteudo))
|
|
123
146
|
return [];
|
|
124
|
-
const avisos =
|
|
147
|
+
const avisos = (0, noctum_envelope_1.envelopeMultimaquina)(conteudo)
|
|
148
|
+
? avisosDaMaquina(conteudo.maquinas, (opcoes.identidade ?? (() => (0, noctum_transporte_1.identidadeDaMaquina)(carregado.raiz)))()) : [];
|
|
125
149
|
let store = null;
|
|
126
150
|
try {
|
|
127
151
|
store = opcoes.store ?? (0, runtime_profiles_1.lerPerfisComContas)(carregado.raiz);
|
|
@@ -130,7 +154,7 @@ function avisosDaProposta(carregado, conteudo, opcoes = {}) {
|
|
|
130
154
|
avisos.push({ motivo: 'noctum.proposta.contas-sem-leitura', detalhe: 'as contas do envelope não puderam ser conferidas',
|
|
131
155
|
correcao: 'rode ork accounts check e proponha de novo depois de corrigir a leitura' });
|
|
132
156
|
}
|
|
133
|
-
const confiar = opcoes.confianca ?? ((raiz, p) => (0, impedimento_1.impedimentoResolvido)('runtime.workspace-untrusted', { cwd: raiz, runtime: p.runtime, configDir:
|
|
157
|
+
const confiar = opcoes.confianca ?? ((raiz, p) => (0, impedimento_1.impedimentoResolvido)('runtime.workspace-untrusted', { cwd: raiz, runtime: p.runtime, configDir: (0, runtime_profiles_1.diretorioDoPerfil)(p) }));
|
|
134
158
|
if (store) {
|
|
135
159
|
for (const { conta } of conteudo.capacidade.porConta) {
|
|
136
160
|
const p = store.perfis.find(x => x.id === conta);
|
|
@@ -267,9 +291,11 @@ function comandoNoctum(args) {
|
|
|
267
291
|
const { raiz } = carregado;
|
|
268
292
|
const quando = new Date().toISOString();
|
|
269
293
|
const r = (0, noctum_arco_1.proporEnvelope)(raiz, pedido, quando, (0, pulse_resposta_1.codigosEmUso)(raiz));
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const
|
|
294
|
+
// Os avisos olham o envelope que o dono vai autorizar, já validado pelo proporEnvelope: o vigente (lerArco) só
|
|
295
|
+
// existe depois da autorização, e na primeira proposta os avisos sumiam (RM-058, bloco B).
|
|
296
|
+
const proposto = (0, noctum_envelope_1.validarPedidoDeAbertura)(pedido);
|
|
297
|
+
const fuso = proposto.janela.fuso;
|
|
298
|
+
const avisos = avisosDaProposta(carregado, proposto);
|
|
273
299
|
// RM-057 (resposta curta, D4 e D9): a proposta é a pergunta ao dono, que sai também pelo canal dele quando ele tem um.
|
|
274
300
|
const q = r.codigo ? (0, noctum_arco_1.perguntasDoArco)(raiz, r.arco, quando).find(x => x.codigo === r.codigo && x.situacao === 'pendente') : undefined;
|
|
275
301
|
const entrega = q ? (0, noctum_pergunta_canal_1.entregarPerguntaDoArco)(raiz, q, { quando }) : null;
|
|
@@ -288,6 +314,32 @@ function comandoNoctum(args) {
|
|
|
288
314
|
}
|
|
289
315
|
return 0;
|
|
290
316
|
}
|
|
317
|
+
if (sub === 'maquina') {
|
|
318
|
+
// RM-058, bloco B (B4, D5): o que o dono copia de cada máquina para `maquinas` do envelope `v3`. O nome vem antes da
|
|
319
|
+
// chave: o recusado não cria a chave local. A chave privada nunca sai desta raiz.
|
|
320
|
+
if (args.posicionais.length !== 2) {
|
|
321
|
+
console.error(exports.USO_DO_NOCTUM);
|
|
322
|
+
return 2;
|
|
323
|
+
}
|
|
324
|
+
const { raiz } = (0, manifest_1.exigirManifesto)();
|
|
325
|
+
const nome = (0, maquina_1.nomeDaMaquina)();
|
|
326
|
+
if (!noctum_transporte_1.NOME_DE_MAQUINA.test(nome)) {
|
|
327
|
+
console.error(`noctum.maquina.nome-invalido: o nome desta máquina ("${nome}") não serve no envelope v3: letras, dígitos, ` +
|
|
328
|
+
'ponto, _ ou -, até 64, começando por letra ou dígito. Correção: grave um nome válido em ~/.orkastery/maquina.json ' +
|
|
329
|
+
'(o campo nome) ou defina ORK_MAQUINA em todo processo do ork desta máquina, o cron e os gateways inclusive');
|
|
330
|
+
return 2;
|
|
331
|
+
}
|
|
332
|
+
const { chave } = (0, noctum_transporte_1.identidadeDaMaquina)(raiz, nome);
|
|
333
|
+
const impressao = (0, noctum_envelope_1.impressaoDaChave)(chave);
|
|
334
|
+
if (json)
|
|
335
|
+
console.log(JSON.stringify({ nome, chave, impressao }, null, 2));
|
|
336
|
+
else {
|
|
337
|
+
console.log(['Esta máquina no envelope v3:', ` nome ${nome}`, ` chave ${chave}`, ` impressão ${impressao}`, '',
|
|
338
|
+
'A entrada para maquinas do envelope:', JSON.stringify({ nome, chave }), '',
|
|
339
|
+
'A chave privada não sai desta raiz; o dono confere a impressão no resumo da proposta.'].join('\n'));
|
|
340
|
+
}
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
291
343
|
if (sub === 'revogar') {
|
|
292
344
|
// RM-057 (resposta curta, D10): abre a pergunta de revogação e a entrega; quem revoga é a resposta do dono.
|
|
293
345
|
const arco = args.posicionais[2];
|
|
@@ -443,17 +495,22 @@ function comandoNoctum(args) {
|
|
|
443
495
|
if (sub === 'aceite') {
|
|
444
496
|
const arco = args.posicionais[2];
|
|
445
497
|
const arquivo = (nome) => args.opcoes[nome] === undefined ? null : texto(args.opcoes[nome]) ?? false;
|
|
446
|
-
const [injecoes, limiares, publicar] = [arquivo('injecoes'), arquivo('limiares'), arquivo('publicar')];
|
|
447
|
-
if (!arco || args.posicionais.length !== 3 || injecoes === false || limiares === false || publicar === false) {
|
|
498
|
+
const [injecoes, limiares, outraMaquina, publicar] = [arquivo('injecoes'), arquivo('limiares'), arquivo('outra-maquina'), arquivo('publicar')];
|
|
499
|
+
if (!arco || args.posicionais.length !== 3 || injecoes === false || limiares === false || outraMaquina === false || publicar === false) {
|
|
448
500
|
console.error(exports.USO_DO_NOCTUM);
|
|
449
501
|
return 2;
|
|
450
502
|
}
|
|
451
503
|
let agenda = null, doDono = null;
|
|
504
|
+
const outrasMaquinas = [];
|
|
452
505
|
try {
|
|
453
506
|
if (injecoes)
|
|
454
507
|
agenda = (0, noctum_aceite_1.lerInjecoes)(fs.readFileSync(injecoes, 'utf8'));
|
|
455
508
|
if (limiares)
|
|
456
509
|
doDono = (0, noctum_aceite_1.lerLimiares)(JSON.parse(fs.readFileSync(limiares, 'utf8')));
|
|
510
|
+
for (const fonte of (outraMaquina ? outraMaquina.split(',') : []).map(x => x.trim()).filter(Boolean)) {
|
|
511
|
+
const bruto = fs.readFileSync(fonte, 'utf8');
|
|
512
|
+
outrasMaquinas.push({ fonte, sha256: (0, node_crypto_1.createHash)('sha256').update(bruto).digest('hex'), resultado: JSON.parse(bruto) });
|
|
513
|
+
}
|
|
457
514
|
}
|
|
458
515
|
catch (e) {
|
|
459
516
|
if (e instanceof noctum_aceite_1.RecusaDoAceite)
|
|
@@ -463,7 +520,7 @@ function comandoNoctum(args) {
|
|
|
463
520
|
}
|
|
464
521
|
const carregado = (0, manifest_1.exigirManifesto)();
|
|
465
522
|
// RM-058, integração (T8, D12): o arquivo completo fica no estado; o publicável vai aonde o dono pedir.
|
|
466
|
-
const r = (0, noctum_aceite_1.aceiteDoPiloto)(carregado, arco, { injecoes: agenda, limiares: doDono });
|
|
523
|
+
const r = (0, noctum_aceite_1.aceiteDoPiloto)(carregado, arco, { injecoes: agenda, limiares: doDono, outrasMaquinas });
|
|
467
524
|
const gravado = (0, noctum_aceite_1.gravarAceite)(carregado.raiz, r);
|
|
468
525
|
if (publicar)
|
|
469
526
|
fs.writeFileSync(publicar, `${JSON.stringify((0, noctum_aceite_1.publicavel)(r, gravado.sha256, (0, noctum_aceite_1.sensiveisDoArco)(carregado, arco)), null, 2)}\n`);
|
package/dist/noctum-entrega.js
CHANGED
|
@@ -97,6 +97,8 @@ const ship_publicar_1 = require("./ship-publicar");
|
|
|
97
97
|
const thread_1 = require("./thread");
|
|
98
98
|
const verify_1 = require("./verify");
|
|
99
99
|
const worktree_1 = require("./worktree");
|
|
100
|
+
const noctum_integracao_1 = require("./noctum-integracao");
|
|
101
|
+
const noctum_rede_1 = require("./noctum-rede");
|
|
100
102
|
exports.CONTRATO_DA_ENTREGA = 'ork.noctum-entrega/v1';
|
|
101
103
|
/** D2: quantas vezes o arco despacha o CHECK independente de um trabalho antes de bloquear. */
|
|
102
104
|
exports.LIMITE_DE_REVISOES = 4;
|
|
@@ -374,8 +376,15 @@ function passoDaEntrega(carregado, arco, opcoes = {}) {
|
|
|
374
376
|
}
|
|
375
377
|
if (sup.parada)
|
|
376
378
|
return { acao: 'nada', motivo: 'arco-encerrado', detalhe: `a supervisão parou o arco (${sup.parada.motivo}): nenhum efeito novo` };
|
|
379
|
+
const multimaquina = (0, noctum_envelope_1.envelopeMultimaquina)(conteudo);
|
|
380
|
+
const rede = multimaquina ? opcoes.projecaoDaRede ?? (0, noctum_rede_1.lerRede)(carregado, arco, { quando, maquina: opcoes.maquina, remoto, rede: opcoes.redeDaCoordenacao }) : null;
|
|
381
|
+
if (rede?.lacuna) {
|
|
382
|
+
return { acao: 'aguardar', trabalho: null, thread: null, motivo: rede.lacuna.motivo, detalhe: rede.lacuna.detalhe,
|
|
383
|
+
ate: depoisDe(quando, exports.ESPERA_DO_CI_MS) };
|
|
384
|
+
}
|
|
385
|
+
const coordenacao = rede ? (0, noctum_rede_1.coordenacaoDaFila)(rede) : null;
|
|
377
386
|
const fila = (0, noctum_fila_1.montarFila)((0, noctum_fila_1.fatosDaFila)(carregado, arco, { quando, maquina: opcoes.maquina, lerReservas: opcoes.lerReservas,
|
|
378
|
-
supervisao: decisoesDaEntrega(sup) }));
|
|
387
|
+
...(coordenacao ? { coordenacao } : {}), supervisao: decisoesDaEntrega(sup) }));
|
|
379
388
|
const naEntrega = fila.trabalhos.filter(t => t.thread && (t.estado === 'aguardando-entrega' || t.estado === 'entregue'))
|
|
380
389
|
.sort((a, b) => a.prioridade - b.prioridade || a.posicao - b.posicao);
|
|
381
390
|
if (!naEntrega.length)
|
|
@@ -392,11 +401,14 @@ function passoDaEntrega(carregado, arco, opcoes = {}) {
|
|
|
392
401
|
detalhe: `o trabalho ${trabalho.id} foi isolado pela supervisão (${isoladoDepois.motivo}): ${isoladoDepois.detalhe}` });
|
|
393
402
|
continue;
|
|
394
403
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
404
|
+
if (multimaquina && rede?.trabalhos.find(t => t.id === trabalho.id)?.estado === 'entregue') {
|
|
405
|
+
let entregueAqui = false;
|
|
406
|
+
try {
|
|
407
|
+
entregueAqui = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, trabalho.thread)).some(e => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido);
|
|
408
|
+
}
|
|
409
|
+
catch { /* a leitura normal abaixo dará a lacuna se este trabalho ainda couber aqui */ }
|
|
410
|
+
if (!entregueAqui)
|
|
411
|
+
continue;
|
|
400
412
|
}
|
|
401
413
|
let lido;
|
|
402
414
|
try {
|
|
@@ -421,7 +433,41 @@ function passoDaEntrega(carregado, arco, opcoes = {}) {
|
|
|
421
433
|
bloqueios.push({ ...ids, motivo: decisao.motivo, detalhe: decisao.porque });
|
|
422
434
|
continue;
|
|
423
435
|
}
|
|
424
|
-
|
|
436
|
+
let executado;
|
|
437
|
+
if (multimaquina && decisao.acao === 'integrar') {
|
|
438
|
+
const ordem = coordenacao?.ordens?.get(trabalho.id);
|
|
439
|
+
const candidato = lido.entrada.provas ? candidatoDaEntrega(lido.entrada.provas) : null;
|
|
440
|
+
if (!ordem || !candidato || !lido.destino) {
|
|
441
|
+
bloqueios.push({ trabalho: trabalho.id, thread: trabalho.thread, motivo: 'noctum.coordenacao.ordem-vencida',
|
|
442
|
+
detalhe: `o trabalho ${trabalho.id} não tem ordem aceita desta máquina e candidato provado para a vez` });
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const feita = (opcoes.integrarPelaRede ?? noctum_integracao_1.integrarComVez)(carregado, arco, { ordem: ordem.ordem,
|
|
447
|
+
destino: { repositorio: lido.destino.repositorio, base: lido.destino.base }, candidato }, integradorDaEntrega(carregado, arco, lido.t.id, opcoes), { quando, maquina: opcoes.maquina, remoto, rede: opcoes.redeDaCoordenacao });
|
|
448
|
+
executado = { resultado: { acao: 'integrou', trabalho: trabalho.id, thread: lido.t.id, mergeSha: feita.merge,
|
|
449
|
+
pontaDaBase: feita.merge, docs: null, provas: candidato.provas }, efeito: true };
|
|
450
|
+
}
|
|
451
|
+
catch (e) {
|
|
452
|
+
if (!(e instanceof noctum_envelope_1.RecusaDoArco))
|
|
453
|
+
throw e;
|
|
454
|
+
const ids = { trabalho: trabalho.id, thread: lido.t.id };
|
|
455
|
+
if (['noctum.integracao.ja-entregue', 'noctum.coordenacao.ordem-vencida'].includes(e.motivo)) {
|
|
456
|
+
executado = { resultado: { acao: 'nada', motivo: 'sem-entrega', detalhe: e.message }, efeito: false };
|
|
457
|
+
}
|
|
458
|
+
else if (e.motivo === 'noctum.integracao.base-nao-provada') {
|
|
459
|
+
executado = { resultado: { acao: 'bloqueado', ...ids, motivo: e.motivo, detalhe: e.message, outros: [] }, efeito: false };
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
executado = { resultado: { acao: 'aguardar', ...ids, motivo: e.motivo, detalhe: e.message,
|
|
463
|
+
ate: depoisDe(quando, exports.ESPERA_DO_CI_MS) }, efeito: false };
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
executado = executar(carregado, arco, estado, trabalho, lido, decisao.acao, opcoes, remoto, quando);
|
|
469
|
+
}
|
|
470
|
+
const { resultado, efeito } = executado;
|
|
425
471
|
// Um efeito por chamada (A1 da rodada 1): o efeito feito, ou de resultado incerto, encerra o passo; a recusa de antes de
|
|
426
472
|
// qualquer efeito deixa o trabalho seguinte tentar, e o trabalho travado não prende a fila.
|
|
427
473
|
if (efeito)
|
|
@@ -434,6 +480,8 @@ function passoDaEntrega(carregado, arco, opcoes = {}) {
|
|
|
434
480
|
bloqueios.push({ trabalho: resultado.trabalho, thread: resultado.thread, motivo: resultado.motivo, detalhe: resultado.detalhe });
|
|
435
481
|
continue;
|
|
436
482
|
}
|
|
483
|
+
if (resultado.acao === 'nada')
|
|
484
|
+
continue;
|
|
437
485
|
return resultado;
|
|
438
486
|
}
|
|
439
487
|
if (espera)
|
package/dist/noctum-envelope.js
CHANGED
|
@@ -377,7 +377,7 @@ function lerOrcamento(v, p) {
|
|
|
377
377
|
chavesConhecidas(v, ['arco', 'porConta', 'porRuntime'], 'orcamento', p);
|
|
378
378
|
const arco = lerTeto(v.arco, 'orcamento.arco', p);
|
|
379
379
|
const porConta = lerSubtetos(v.porConta, 'conta', 'orcamento.porConta', x => ID_DE_CONTA.test(x), 'id de perfil de conta já autenticado', p);
|
|
380
|
-
const porRuntime = lerSubtetos(v.porRuntime, 'runtime', 'orcamento.porRuntime', x => runtime_profiles_1.
|
|
380
|
+
const porRuntime = lerSubtetos(v.porRuntime, 'runtime', 'orcamento.porRuntime', x => runtime_profiles_1.RUNTIMES_COM_INVENTARIO.includes(x), `runtime de assinatura: ${runtime_profiles_1.RUNTIMES_COM_INVENTARIO.join(', ')}`, p);
|
|
381
381
|
// Subteto acima do teto do arco, na mesma unidade, não limita nada: é teto do arco disfarçado.
|
|
382
382
|
for (const [nome, teto] of [...(porConta ?? []).map(s => [`conta ${s.conta}`, s.teto]),
|
|
383
383
|
...(porRuntime ?? []).map(s => [`runtime ${s.runtime}`, s.teto])]) {
|
package/dist/noctum-execucao.js
CHANGED
|
@@ -326,7 +326,11 @@ function despacharCandidato(carregado, arco, fila, c, opcoes) {
|
|
|
326
326
|
if (!c.pedido)
|
|
327
327
|
return { ...recusar('noctum.despacho.pedido-ausente', `o trabalho ${c.trabalho} não traz pedido para abrir a thread`, null), seguir: true };
|
|
328
328
|
// RM-037 (CHECK 3 da ork-rm037defeit2): sob a trava de despacho, o preparo das dependências só fica pendente.
|
|
329
|
-
|
|
329
|
+
const base = `${c.item.toLowerCase()} ${c.trabalho}`;
|
|
330
|
+
const numero = opcoes.coordenacao?.ordens?.get(c.trabalho)?.numero;
|
|
331
|
+
const sufixo = numero === undefined ? '' : ` o${numero}`;
|
|
332
|
+
const nome = sufixo ? `${base.slice(0, Math.max(1, 12 - sufixo.length)).trimEnd()}${sufixo}` : base;
|
|
333
|
+
thread = (opcoes.abrirThread ?? ((k, o) => (0, thread_1.novaThread)(k, o).thread))(carregado, { nome,
|
|
330
334
|
modo: 'auto', roadmap: c.item, pedido: c.pedido, criarWorktree: true, adiarDependencias: true });
|
|
331
335
|
}
|
|
332
336
|
pedido = (0, thread_1.pedidoDaThread)(raiz, thread);
|