@orkastery/cli 0.6.4 → 0.6.6
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/openclaw/openclaw.plugin.json +1 -1
- package/adapters/openclaw/package.json +1 -1
- package/dist/adapters/codex-controller-sensor.js +21 -2
- package/dist/adapters/codex-events.js +15 -6
- package/dist/adapters/grok-events.js +43 -2
- package/dist/adapters/grok.js +28 -5
- package/dist/agendador-cpu.js +82 -28
- package/dist/check-agil.js +85 -9
- package/dist/check-paralelo.js +77 -15
- package/dist/check-selecao.js +149 -0
- package/dist/codex-task-complete.js +95 -0
- package/dist/junit.js +546 -0
- package/dist/locale-verify.js +37 -0
- package/dist/manifest.js +237 -13
- package/dist/retry.js +35 -0
- package/dist/session-watcher-claude.js +38 -22
- package/dist/session-watcher-grok.js +10 -0
- package/dist/session-watcher.js +141 -41
- package/dist/ship.js +9 -3
- package/dist/verify.js +215 -52
- package/package.json +1 -1
package/dist/session-watcher.js
CHANGED
|
@@ -39,6 +39,8 @@ exports.reconciliarSessaoSemWatcher = reconciliarSessaoSemWatcher;
|
|
|
39
39
|
exports.validarRegistroWatcher = validarRegistroWatcher;
|
|
40
40
|
exports.validarFonteWatcher = validarFonteWatcher;
|
|
41
41
|
exports.prepararFonteWatcher = prepararFonteWatcher;
|
|
42
|
+
exports.esperarProntidaoWatcher = esperarProntidaoWatcher;
|
|
43
|
+
exports.esperarConfirmacaoDoPaiWatcher = esperarConfirmacaoDoPaiWatcher;
|
|
42
44
|
exports.iniciarWatcher = iniciarWatcher;
|
|
43
45
|
exports.acompanharSessao = acompanharSessao;
|
|
44
46
|
/** D6: observador restrito a uma sessão, cursor canônico e resultados idempotentes. */
|
|
@@ -62,6 +64,7 @@ const session_watcher_grok_1 = require("./session-watcher-grok");
|
|
|
62
64
|
const conta_esgotada_1 = require("./conta-esgotada");
|
|
63
65
|
const trabalho_thread_1 = require("./trabalho-thread");
|
|
64
66
|
const pedido_conducao_1 = require("./pedido-conducao");
|
|
67
|
+
const codex_task_complete_1 = require("./codex-task-complete");
|
|
65
68
|
/** O gate estreito da própria sessão vence diagnósticos genéricos do watcher. */
|
|
66
69
|
function pedidoDaConducao(eventos, sessionId, despachoEm) {
|
|
67
70
|
const evento = eventos.filter(e => e.tipo === 'gate_blocked' && e.origem === 'mcp.request_conduction' &&
|
|
@@ -389,6 +392,16 @@ function observarSessao(carregado, sessionId, opcoes = {}) {
|
|
|
389
392
|
return observarSessaoResolvida(carregado, sessionId, resolvida, opcoes);
|
|
390
393
|
}
|
|
391
394
|
catch (e) {
|
|
395
|
+
if (e.code === 'SESSION_STATE_SPLIT' && threadId) {
|
|
396
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, threadId);
|
|
397
|
+
const registrada = thread.sessoes.find(s => s.sessionId === sessionId);
|
|
398
|
+
if (registrada) {
|
|
399
|
+
const sessao = (0, session_events_1.exigirSessaoDespachada)(registrada, sessionId);
|
|
400
|
+
const prova = (0, codex_task_complete_1.taskCompleteFixadoDaSessao)(carregado.raiz, thread, sessao, (0, ledger_1.lerLedger)((0, thread_1.dirThread)(carregado.raiz, threadId)), opcoes.agoraMs ?? Date.now());
|
|
401
|
+
if (prova)
|
|
402
|
+
return observarSessaoResolvida(carregado, sessionId, { thread, sessao }, { ...opcoes, taskCompleteFixado: prova });
|
|
403
|
+
}
|
|
404
|
+
}
|
|
392
405
|
if (threadId)
|
|
393
406
|
tentarRegistrarErroWatcher(carregado.raiz, threadId, sessionId, e);
|
|
394
407
|
throw e;
|
|
@@ -542,7 +555,8 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
542
555
|
return desfazer();
|
|
543
556
|
if (sessao.runtime === 'claude-bg') {
|
|
544
557
|
const r = comLockWatcher(pasta, () => (0, session_watcher_claude_1.observarClaudeSobLock)({ raiz: carregado.raiz,
|
|
545
|
-
thread, sessao, dir, pasta, chave, agoraMs: now, limiteMs: exports.LIMITE_MORTE_MS, consulta: opcoes.consultaClaude,
|
|
558
|
+
thread, sessao, dir, pasta, chave, agoraMs: now, limiteMs: exports.LIMITE_MORTE_MS, consulta: opcoes.consultaClaude,
|
|
559
|
+
tela: opcoes.telaClaude, carregado })) ?? { ...base, ocupado: true };
|
|
546
560
|
return (0, ledger_1.threadPresente)(dir) ? r : desfazer();
|
|
547
561
|
}
|
|
548
562
|
// RM-067 (F2): o grok tem observador próprio (stream, recibo do supervisor e pasta da sessão), no mesmo lock.
|
|
@@ -565,6 +579,7 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
565
579
|
const perfil = (0, runtime_profiles_1.perfilDoRegistro)(eventos, sessao);
|
|
566
580
|
// Fonte do controller validada ANTES de ler rollout ou escrever cursor.
|
|
567
581
|
let fonteControlador = null, snapshot = null;
|
|
582
|
+
let taskCompleteFixado = opcoes.taskCompleteFixado ?? null;
|
|
568
583
|
let cwdDespacho;
|
|
569
584
|
if (registro?.controlador) {
|
|
570
585
|
const despacho = eventos.filter(e => e.tipo === 'phase_dispatch' && e.sessionId === sessionId).at(-1);
|
|
@@ -580,7 +595,16 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
580
595
|
vinculo: { thread: thread.id, fase: sessao.fase, promptSha256: sessao.promptSha256 }
|
|
581
596
|
});
|
|
582
597
|
// Relógio injetado vale como está; o real é lido pelo sensor depois do state.json.
|
|
583
|
-
|
|
598
|
+
try {
|
|
599
|
+
snapshot = (0, codex_controller_sensor_1.lerSnapshotController)(fonteControlador, opcoes.agoraMs === undefined ? {} : { agoraMs: now });
|
|
600
|
+
}
|
|
601
|
+
catch (e) {
|
|
602
|
+
// A varredura integral e excepcional: no fluxo saudável o cursor incremental
|
|
603
|
+
// reconhece task_complete sem reler todo o rollout a cada polling.
|
|
604
|
+
taskCompleteFixado ??= (0, codex_task_complete_1.taskCompleteFixadoDaFonte)(fonteControlador, now);
|
|
605
|
+
if (!taskCompleteFixado)
|
|
606
|
+
throw e;
|
|
607
|
+
}
|
|
584
608
|
}
|
|
585
609
|
const file = path.join(pasta, 'cursor.json');
|
|
586
610
|
const cursor = lerJson(file) ?? { schema: 'ork.session-cursor/v1', sessionId,
|
|
@@ -590,7 +614,7 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
590
614
|
// Cursor anterior media bytes, nao progresso: migracao conservadora desde o despacho.
|
|
591
615
|
cursor.progressoEm ??= Date.parse(sessao.despachadaEm);
|
|
592
616
|
// Transporte do controller não admite descoberta nem override de rollout.
|
|
593
|
-
const fontes = { stream: registro?.logPath, rollout:
|
|
617
|
+
const fontes = { stream: registro?.logPath, rollout: fonteControlador ? fonteControlador.rollout
|
|
594
618
|
: opcoes.rollout === undefined ? (0, codex_1.acharRollout)(sessionId, 3, (0, codex_1.casaDoCodex)(perfil)) : opcoes.rollout };
|
|
595
619
|
let bytesLidos = 0, temMais = false, cresceu = false;
|
|
596
620
|
for (const [nome, fonte] of Object.entries(fontes)) {
|
|
@@ -673,7 +697,10 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
673
697
|
return tempo || (y.numeroTurno ?? 0) - (x.numeroTurno ?? 0) ||
|
|
674
698
|
ordem[x.classificacao] - ordem[y.classificacao] || a.nome.localeCompare(b.nome);
|
|
675
699
|
});
|
|
676
|
-
|
|
700
|
+
const taskCompleteDoCursor = fonteControlador ? terminais.find(({ nome, terminal: atual }) => nome === 'rollout' && atual.fonte === 'rollout.task_complete')?.terminal : undefined;
|
|
701
|
+
let terminal = taskCompleteFixado?.terminal ?? taskCompleteDoCursor ?? terminais[0]?.terminal;
|
|
702
|
+
const taskCompleteAutenticado = terminal !== undefined &&
|
|
703
|
+
(terminal === taskCompleteFixado?.terminal || terminal === taskCompleteDoCursor);
|
|
677
704
|
const fontesAtuais = Object.values(cursor.fontes);
|
|
678
705
|
const aberto = fontesAtuais.some(f => {
|
|
679
706
|
if (!f.parser.turnoAberto)
|
|
@@ -700,22 +727,23 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
700
727
|
const invalido = fontesAtuais.some(f => f.parser.invalido);
|
|
701
728
|
// Conclusão nativa é medida em todo terminal, independente da política de retry:
|
|
702
729
|
// bloqueio sem retry preserva o motivo, mas não prova que o turno do runtime terminou.
|
|
703
|
-
const provaNativa = snapshot && terminal
|
|
730
|
+
const provaNativa = taskCompleteAutenticado ? null : snapshot && terminal
|
|
704
731
|
? semProvaNativa(snapshot, terminal, terminais[0]?.nome, fechamento, sessionId, cwdDespacho)
|
|
705
732
|
: 'terminal nativo do controller ausente';
|
|
706
733
|
// Parecer negativo também exige conclusão nativa inteira: texto claims.failed de
|
|
707
734
|
// turno interrompido não pode virar rejeição autenticada de um objetivo.
|
|
708
|
-
const semProva = snapshot && terminal && terminal.classificacao !== 'human.pending' && !bloqueioPreservado(terminal)
|
|
735
|
+
const semProva = !taskCompleteAutenticado && snapshot && terminal && terminal.classificacao !== 'human.pending' && !bloqueioPreservado(terminal)
|
|
709
736
|
? provaNativa : null;
|
|
710
737
|
const descorrelacionado = !!semProva;
|
|
711
|
-
const
|
|
738
|
+
const observacaoInvalida = !taskCompleteAutenticado && (invalido || aberto || descorrelacionado);
|
|
739
|
+
const incompleto = !taskCompleteAutenticado && (semCloseNoLimite && (!!terminal || estado !== 'ausente' || aberto || parcial || invalido) || !backlog && (((parcial || aberto || invalido || descorrelacionado || !terminal) && !!fechamento) ||
|
|
712
740
|
(estavel && (parcial || (aberto && estado === 'ausente') ||
|
|
713
|
-
(supervisionado && estado === 'desconhecido'))));
|
|
741
|
+
(supervisionado && estado === 'desconhecido')))));
|
|
714
742
|
const morte = estado === 'ausente' && estavel && !temMais;
|
|
715
743
|
// Fechamento supervisionado precisa existir antes de associar o código de saída ao turno.
|
|
716
|
-
const podeTerminar = !esperaHumana && (incompleto || (!temMais && !aberto &&
|
|
744
|
+
const podeTerminar = taskCompleteAutenticado || !esperaHumana && (incompleto || (!temMais && !aberto &&
|
|
717
745
|
((terminal && (fechamento || !supervisionado)) || morte)));
|
|
718
|
-
const conta = falhaDeContaDoTerminal(terminal, !invalido && !aberto, snapshot, now);
|
|
746
|
+
const conta = falhaDeContaDoTerminal(terminal, taskCompleteAutenticado || !invalido && !aberto, snapshot, now);
|
|
719
747
|
(0, codex_runner_1.gravarAtomico)(file, cursor);
|
|
720
748
|
return (0, session_events_1.comLockDeSessao)(dir, () => {
|
|
721
749
|
const atuais = (0, ledger_1.lerLedger)(dir);
|
|
@@ -735,9 +763,9 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
735
763
|
const pedido = pedidoDaConducao(atuais, sessionId, sessao.despachadaEm);
|
|
736
764
|
const semTerminal = !terminal;
|
|
737
765
|
// Fato registrado para a autoridade de revisão: `null` só com terminal nativo correlacionado.
|
|
738
|
-
const conclusaoNativa = incompleto ||
|
|
766
|
+
const conclusaoNativa = incompleto || observacaoInvalida
|
|
739
767
|
? provaNativa ?? 'observação incompleta ou inválida' : provaNativa;
|
|
740
|
-
if (incompleto ||
|
|
768
|
+
if (incompleto || observacaoInvalida)
|
|
741
769
|
terminal = { classificacao: 'gate_blocked', motivo: 'runtime.unavailable',
|
|
742
770
|
timestamp: new Date(now).toISOString(), turnId: null, fonte: semProva ?? 'observação incompleta ou inválida',
|
|
743
771
|
tokens: new codex_events_1.ParserCodex().estado.tokens, duracaoMs: null };
|
|
@@ -745,12 +773,12 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
745
773
|
terminal = { classificacao: 'gate_blocked', motivo: 'runtime.silencio',
|
|
746
774
|
timestamp: new Date(now).toISOString(), turnId: null, fonte: 'processo ausente e arquivos estáveis',
|
|
747
775
|
tokens: new codex_events_1.ParserCodex().estado.tokens, duracaoMs: null };
|
|
748
|
-
if (pedido && (terminal.classificacao === 'fase_concluida' ||
|
|
776
|
+
if (pedido && (taskCompleteAutenticado || terminal.classificacao === 'fase_concluida' ||
|
|
749
777
|
terminal.classificacao === 'gate_blocked' && ['runtime.unavailable', 'runtime.silencio'].includes(terminal.motivo ?? ''))) {
|
|
750
778
|
terminal = { ...terminal, classificacao: 'gate_blocked', motivo: pedido.motivo,
|
|
751
779
|
fonte: `mcp.request_conduction: ${pedido.detalhe}` };
|
|
752
780
|
}
|
|
753
|
-
if (fechamento && (fechamento.exitCode !== 0 || fechamento.signal || fechamento.erro) &&
|
|
781
|
+
if (!taskCompleteAutenticado && fechamento && (fechamento.exitCode !== 0 || fechamento.signal || fechamento.erro) &&
|
|
754
782
|
terminal.classificacao !== 'human.pending' && !bloqueioPreservado(terminal)) {
|
|
755
783
|
terminal = { ...terminal, classificacao: 'gate_blocked', motivo: 'runtime.unavailable' };
|
|
756
784
|
}
|
|
@@ -761,16 +789,19 @@ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registr
|
|
|
761
789
|
fonte: `${conta.fonte}: ${conta.falha.motivo} (${conta.falha.trecho})` };
|
|
762
790
|
const respostaFinal = terminal.respostaFinal
|
|
763
791
|
? (0, trabalho_thread_1.gravarRespostaFinalDaSessao)(carregado.raiz, thread.id, sessionId, terminal.respostaFinal) : null;
|
|
792
|
+
const taskCompleteBloqueado = taskCompleteAutenticado && terminal.classificacao !== 'fase_concluida';
|
|
764
793
|
const dados = { fase: sessao.fase, sessionId, despachoEm: sessao.despachadaEm, sensorResultId: resultadoId,
|
|
765
794
|
classificacao: terminal.classificacao, motivo: terminal.motivo, runtime: 'codex', fonte: terminal.fonte,
|
|
766
|
-
fonteVencedora: pedido
|
|
795
|
+
fonteVencedora: pedido ? null : taskCompleteAutenticado ? 'rollout'
|
|
796
|
+
: incompleto || invalido || aberto || descorrelacionado ? null : terminais[0]?.nome ?? null,
|
|
767
797
|
turnId: terminal.turnId, numeroTurno: terminal.numeroTurno ?? null,
|
|
768
798
|
tokens: terminal.tokens, exitCode: fechamento?.exitCode ?? null, exitCodeFonte: fechamento?.fonte ?? 'unavailable',
|
|
769
799
|
signal: fechamento?.signal ?? null, duracaoMs: fechamento?.duracaoMs ?? terminal.duracaoMs,
|
|
770
800
|
duracaoFonte: fechamento?.fonte ?? (terminal.duracaoMs === null ? 'unavailable' : terminal.fonte),
|
|
771
|
-
ok: terminal.classificacao === 'fase_concluida' && fechamento?.exitCode === 0,
|
|
772
|
-
conclusaoNativa: conclusaoNativa === null,
|
|
773
|
-
conclusaoNativaAusente:
|
|
801
|
+
ok: terminal.classificacao === 'fase_concluida' && (taskCompleteAutenticado || fechamento?.exitCode === 0),
|
|
802
|
+
conclusaoNativa: conclusaoNativa === null && !taskCompleteBloqueado,
|
|
803
|
+
conclusaoNativaAusente: taskCompleteBloqueado
|
|
804
|
+
? 'task_complete encerrou o turno com resultado bloqueado' : conclusaoNativa,
|
|
774
805
|
estado: terminal.classificacao === 'fase_concluida' ? 'concluida' : 'bloqueada',
|
|
775
806
|
observadoEm: terminal.timestamp, gate: 'phase.dispatch', origem: 'sessions.watch',
|
|
776
807
|
morteLatenciaMs: morte ? now - cursor.progressoEm : null, ...(perfil ? { perfil } : {}),
|
|
@@ -877,6 +908,61 @@ function prepararFonteWatcher(raiz, sessionId, fonte) {
|
|
|
877
908
|
throw e;
|
|
878
909
|
}
|
|
879
910
|
}
|
|
911
|
+
class ErroDoApertoWatcher extends Error {
|
|
912
|
+
encerrarOutro;
|
|
913
|
+
constructor(message, encerrarOutro) {
|
|
914
|
+
super(message);
|
|
915
|
+
this.encerrarOutro = encerrarOutro;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
const TETO_ABSOLUTO_APERTO_WATCHER_MS = 60000;
|
|
919
|
+
const PAUSA_APERTO_WATCHER = new Int32Array(new SharedArrayBuffer(4));
|
|
920
|
+
function conferirTetoDoAperto(tetoMs) {
|
|
921
|
+
if (!Number.isFinite(tetoMs) || tetoMs <= 0)
|
|
922
|
+
throw new Error('teto invalido para o aperto de mao do watcher');
|
|
923
|
+
}
|
|
924
|
+
/** Lado do dispatcher: lentidao nao encerra um watcher cuja identidade continua viva. */
|
|
925
|
+
function esperarProntidaoWatcher(lerSinal, identidade, opcoes = {}) {
|
|
926
|
+
const agora = opcoes.agora ?? Date.now;
|
|
927
|
+
const estado = opcoes.estado ?? codex_runner_1.estadoProcesso;
|
|
928
|
+
const pausar = opcoes.pausar ?? ((ms) => { Atomics.wait(PAUSA_APERTO_WATCHER, 0, 0, ms); });
|
|
929
|
+
const tetoProntidaoMs = opcoes.tetoMs ?? TETO_ABSOLUTO_APERTO_WATCHER_MS;
|
|
930
|
+
conferirTetoDoAperto(tetoProntidaoMs);
|
|
931
|
+
const inicio = agora();
|
|
932
|
+
for (;;) {
|
|
933
|
+
if (agora() - inicio >= tetoProntidaoMs)
|
|
934
|
+
throw new ErroDoApertoWatcher('watcher sem prontidao confirmada', true);
|
|
935
|
+
const sinal = lerSinal();
|
|
936
|
+
if (sinal === 'confirmado')
|
|
937
|
+
return;
|
|
938
|
+
if (sinal === 'invalido')
|
|
939
|
+
throw new ErroDoApertoWatcher('watcher com prontidao invalida', true);
|
|
940
|
+
if (estado(identidade) === 'ausente')
|
|
941
|
+
throw new ErroDoApertoWatcher('watcher sem prontidao confirmada', false);
|
|
942
|
+
const restante = tetoProntidaoMs - (agora() - inicio);
|
|
943
|
+
pausar(Math.min(10, Math.max(1, restante)));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
/** Lado do watcher: o ack continua pendente somente enquanto o pai capturado na partida nao saiu. */
|
|
947
|
+
async function esperarConfirmacaoDoPaiWatcher(lerSinal, identidadePai, opcoes = {}) {
|
|
948
|
+
const agora = opcoes.agora ?? Date.now;
|
|
949
|
+
const estado = opcoes.estado ?? codex_runner_1.estadoProcesso;
|
|
950
|
+
const pausar = opcoes.pausar ?? ((ms) => new Promise(resolve => setTimeout(resolve, ms)));
|
|
951
|
+
const tetoConfirmacaoMs = opcoes.tetoMs ?? TETO_ABSOLUTO_APERTO_WATCHER_MS;
|
|
952
|
+
conferirTetoDoAperto(tetoConfirmacaoMs);
|
|
953
|
+
const inicio = agora();
|
|
954
|
+
for (;;) {
|
|
955
|
+
if (agora() - inicio >= tetoConfirmacaoMs)
|
|
956
|
+
throw new ErroDoApertoWatcher('watcher sem confirmacao do pai', false);
|
|
957
|
+
const sinal = lerSinal();
|
|
958
|
+
if (sinal === 'confirmado')
|
|
959
|
+
return;
|
|
960
|
+
if (sinal === 'invalido' || estado(identidadePai) === 'ausente')
|
|
961
|
+
throw new ErroDoApertoWatcher('watcher sem confirmacao do pai', false);
|
|
962
|
+
const restante = tetoConfirmacaoMs - (agora() - inicio);
|
|
963
|
+
await pausar(Math.min(10, Math.max(1, restante)));
|
|
964
|
+
}
|
|
965
|
+
}
|
|
880
966
|
function iniciarWatcher(raiz, sessionId) {
|
|
881
967
|
const { thread, sessao: registrada } = (0, session_events_1.resolverSessao)(raiz, sessionId);
|
|
882
968
|
const sessao = (0, session_events_1.exigirSessaoDespachada)(registrada, sessionId);
|
|
@@ -918,27 +1004,29 @@ function iniciarWatcher(raiz, sessionId) {
|
|
|
918
1004
|
try {
|
|
919
1005
|
if (!identidade)
|
|
920
1006
|
throw new Error('watcher sem identidade de processo');
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
(0, ledger_1.registrar)(dir, thread.id, 'session_watcher_started', { fase: sessao.fase, sessionId,
|
|
928
|
-
despachoEm: sessao.despachadaEm, pid: identidade.pid, identidade, readyPath, token });
|
|
929
|
-
(0, codex_runner_1.gravarAtomico)(ackPath, { token });
|
|
930
|
-
return identidade.pid;
|
|
1007
|
+
esperarProntidaoWatcher(() => {
|
|
1008
|
+
if (!fs.existsSync(readyPath))
|
|
1009
|
+
return 'pendente';
|
|
1010
|
+
let ready;
|
|
1011
|
+
try {
|
|
1012
|
+
ready = lerJson(readyPath);
|
|
931
1013
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1014
|
+
catch {
|
|
1015
|
+
return 'invalido';
|
|
1016
|
+
}
|
|
1017
|
+
return ready && ready.token === token && ready.sessionId === sessionId && ready.despachoEm === sessao.despachadaEm &&
|
|
1018
|
+
JSON.stringify(ready.identidade) === JSON.stringify(identidade) && (0, codex_runner_1.estadoProcesso)(identidade) === 'vivo'
|
|
1019
|
+
? 'confirmado' : 'invalido';
|
|
1020
|
+
}, identidade);
|
|
1021
|
+
(0, ledger_1.registrar)(dir, thread.id, 'session_watcher_started', { fase: sessao.fase, sessionId,
|
|
1022
|
+
despachoEm: sessao.despachadaEm, pid: identidade.pid, identidade, readyPath, token });
|
|
1023
|
+
(0, codex_runner_1.gravarAtomico)(ackPath, { token });
|
|
1024
|
+
return identidade.pid;
|
|
937
1025
|
}
|
|
938
1026
|
catch (e) {
|
|
939
1027
|
falha();
|
|
940
|
-
//
|
|
941
|
-
if (identidade && (0, codex_runner_1.estadoProcesso)(identidade) === 'vivo')
|
|
1028
|
+
// Lentidao dentro do teto nao encerra o filho; so teto ou prontidao invalida autorizam o sinal.
|
|
1029
|
+
if (e instanceof ErroDoApertoWatcher && e.encerrarOutro && identidade && (0, codex_runner_1.estadoProcesso)(identidade) === 'vivo')
|
|
942
1030
|
child.kill('SIGTERM');
|
|
943
1031
|
throw e;
|
|
944
1032
|
}
|
|
@@ -949,18 +1037,30 @@ async function acompanhar() {
|
|
|
949
1037
|
try {
|
|
950
1038
|
const readyPath = process.argv[5], token = process.argv[6];
|
|
951
1039
|
if (readyPath && token) {
|
|
1040
|
+
const identidadePai = (0, codex_runner_1.identidadeProcesso)(process.ppid);
|
|
1041
|
+
if (!identidadePai)
|
|
1042
|
+
throw new Error('watcher sem confirmacao do pai');
|
|
952
1043
|
validarRegistroWatcher(carregado.raiz, sessionId);
|
|
953
1044
|
const sessao = (0, session_events_1.exigirSessaoDespachada)((0, session_events_1.resolverSessao)(carregado.raiz, sessionId, threadId).sessao, sessionId);
|
|
954
1045
|
const identidade = (0, codex_runner_1.identidadeProcesso)(process.pid);
|
|
955
1046
|
if (!identidade)
|
|
956
1047
|
throw new Error('watcher sem identidade propria');
|
|
957
1048
|
(0, codex_runner_1.gravarAtomico)(readyPath, { token, sessionId, despachoEm: sessao.despachadaEm, identidade });
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1049
|
+
await esperarConfirmacaoDoPaiWatcher(() => {
|
|
1050
|
+
if (!(0, ledger_1.threadPresente)((0, thread_1.dirThread)(carregado.raiz, threadId)))
|
|
1051
|
+
return 'invalido';
|
|
1052
|
+
const ackPath = readyPath + '.ack';
|
|
1053
|
+
if (!fs.existsSync(ackPath))
|
|
1054
|
+
return 'pendente';
|
|
1055
|
+
let ack;
|
|
1056
|
+
try {
|
|
1057
|
+
ack = lerJson(ackPath);
|
|
1058
|
+
}
|
|
1059
|
+
catch {
|
|
1060
|
+
return 'invalido';
|
|
1061
|
+
}
|
|
1062
|
+
return ack?.token === token ? 'confirmado' : 'invalido';
|
|
1063
|
+
}, identidadePai);
|
|
964
1064
|
}
|
|
965
1065
|
await acompanharSessao(carregado, sessionId, { threadId });
|
|
966
1066
|
}
|
package/dist/ship.js
CHANGED
|
@@ -51,6 +51,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
51
51
|
})();
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
53
|
exports.MODOS_QUE_AUTORIZAM_PUSH = void 0;
|
|
54
|
+
exports.verificacaoCompletaParaShip = verificacaoCompletaParaShip;
|
|
54
55
|
exports.commitQueIncorporou = commitQueIncorporou;
|
|
55
56
|
exports.autorizacaoDePush = autorizacaoDePush;
|
|
56
57
|
exports.arvoreComBranch = arvoreComBranch;
|
|
@@ -88,6 +89,10 @@ const mcp_ship_transporte_1 = require("./mcp-ship-transporte");
|
|
|
88
89
|
const branch_de_estado_1 = require("./branch-de-estado");
|
|
89
90
|
const locale_1 = require("./locale");
|
|
90
91
|
const noctum_guarda_1 = require("./noctum-guarda");
|
|
92
|
+
/** RM-081 F3: `ok` nunca basta quando a rodada nao cobriu a suite inteira. */
|
|
93
|
+
function verificacaoCompletaParaShip(verificacao) {
|
|
94
|
+
return verificacao.ok && !verificacao.parcial;
|
|
95
|
+
}
|
|
91
96
|
/**
|
|
92
97
|
* RM-037 (fatia 5, A1): o commit de primeiro pai da base que incorporou o `shaDe`: o merge que trouxe a branch, ou
|
|
93
98
|
* o proprio `shaDe` quando a base avancou por fast-forward ate ele. Com a branch ja incorporada, a ponta da base e
|
|
@@ -556,9 +561,10 @@ function ship(carregado, threadId, opcoes) {
|
|
|
556
561
|
const verificacao = (0, verify_1.verificar)(carregado, threadId, { executor: opcoes.executorVerify,
|
|
557
562
|
conducao: { filaPesada: { ...opcoes.avisoDaFilaPesada, esperarMs: opcoes.esperarFilaPesadaMs } } });
|
|
558
563
|
r.verificacao = verificacao;
|
|
559
|
-
if (!verificacao
|
|
560
|
-
const motivo = verificacao.
|
|
561
|
-
|
|
564
|
+
if (!verificacaoCompletaParaShip(verificacao)) {
|
|
565
|
+
const motivo = (verificacao.parcial ? 'verify.failed'
|
|
566
|
+
: verificacao.motivos.find((m) => m !== 'claims.unverifiable'));
|
|
567
|
+
return bloquear(motivo, (0, locale_1.textoDoCatalogo)((m) => m.ship.verificacaoReprovou(verificacao.commit, verificacao.parcial ? 'verify.parcial' : verificacao.motivos.join(', '))), (0, locale_1.textoDoCatalogo)((m) => m.ship.rodeVerify(threadId)));
|
|
562
568
|
}
|
|
563
569
|
// Referencias locais, resolvidas antes de tomar o lease.
|
|
564
570
|
const shaDe = shaDaRef(raiz, `refs/heads/${de}`);
|