@orkastery/cli 0.6.4 → 0.6.5
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 +47 -18
- package/dist/ship.js +9 -3
- package/dist/verify.js +215 -52
- package/package.json +1 -1
package/dist/check-paralelo.js
CHANGED
|
@@ -34,7 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.argvDoItem = argvDoItem;
|
|
37
|
+
exports.workersDaLane = workersDaLane;
|
|
37
38
|
exports.chaveDoPerfilIntegracao = chaveDoPerfilIntegracao;
|
|
39
|
+
exports.picoDaArvoreParaPerfil = picoDaArvoreParaPerfil;
|
|
38
40
|
exports.picoCpuPorFonte = picoCpuPorFonte;
|
|
39
41
|
exports.esperaDoGrupo = esperaDoGrupo;
|
|
40
42
|
exports.rodarEmParalelo = rodarEmParalelo;
|
|
@@ -59,7 +61,7 @@ const integracoes_locais_1 = require("./integracoes-locais");
|
|
|
59
61
|
const TIMEOUT_BIN = '/usr/bin/timeout';
|
|
60
62
|
const NICE_BIN = '/usr/bin/nice';
|
|
61
63
|
const TIME_BIN = '/usr/bin/time';
|
|
62
|
-
const CONTRATO_PERFIL_INTEGRACAO = 'ork.check.cpu-integracao/
|
|
64
|
+
const CONTRATO_PERFIL_INTEGRACAO = 'ork.check.cpu-integracao/v2';
|
|
63
65
|
const INTERVALO_CPU_MS = 100;
|
|
64
66
|
/** O argv de um item: `nice` (se pedido e existir), `timeout(1)` (se existir) e o `argv` do item ou `bash -c`. */
|
|
65
67
|
function argvDoItem(item, comGrupo = fs.existsSync(TIMEOUT_BIN), comNice = fs.existsSync(NICE_BIN)) {
|
|
@@ -84,6 +86,49 @@ function vagas(max) {
|
|
|
84
86
|
livres++; },
|
|
85
87
|
};
|
|
86
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Recursos exclusivos sem dependencia artificial. Cada pedido adquire o conjunto inteiro ou espera, o que evita
|
|
91
|
+
* deadlock entre listas cruzadas; pedidos disjuntos continuam livres para avancar.
|
|
92
|
+
*/
|
|
93
|
+
function recursosExclusivos() {
|
|
94
|
+
const ocupados = new Set();
|
|
95
|
+
const fila = [];
|
|
96
|
+
const despachar = () => {
|
|
97
|
+
for (let i = 0; i < fila.length;) {
|
|
98
|
+
const pedido = fila[i];
|
|
99
|
+
if (pedido.nomes.some((nome) => ocupados.has(nome))) {
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
fila.splice(i, 1);
|
|
104
|
+
pedido.nomes.forEach((nome) => ocupados.add(nome));
|
|
105
|
+
pedido.pronto(() => {
|
|
106
|
+
pedido.nomes.forEach((nome) => ocupados.delete(nome));
|
|
107
|
+
despachar();
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
tomar: (nomes) => new Promise((pronto) => {
|
|
113
|
+
fila.push({ nomes: [...new Set(nomes)], pronto });
|
|
114
|
+
despachar();
|
|
115
|
+
}),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** A reserva que vira ORK_WORKERS quando a lane e efetivamente lancada. */
|
|
119
|
+
function workersDaLane(item, plano, cpus, totalDeLanes) {
|
|
120
|
+
if (!item.nome.startsWith('test:'))
|
|
121
|
+
return null;
|
|
122
|
+
const capacidade = (0, agendador_cpu_1.workersDaReserva)(cpus);
|
|
123
|
+
if (!plano)
|
|
124
|
+
return Math.max(1, Math.floor(capacidade / Math.max(1, Math.min(capacidade, totalDeLanes))));
|
|
125
|
+
if (item.papelCpu === 'hermetica')
|
|
126
|
+
return (0, agendador_cpu_1.workersDaReserva)(plano.cpusHermetica);
|
|
127
|
+
if (item.papelCpu === 'integracao')
|
|
128
|
+
return (0, agendador_cpu_1.workersDaReserva)(plano.cpusIntegracao);
|
|
129
|
+
// Outros fecham a cadeia depois que as reservas da varredura e da integracao voltaram.
|
|
130
|
+
return capacidade;
|
|
131
|
+
}
|
|
87
132
|
function arquivoDoPerfilIntegracao() {
|
|
88
133
|
const base = process.env.XDG_CACHE_HOME && path.isAbsolute(process.env.XDG_CACHE_HOME)
|
|
89
134
|
? process.env.XDG_CACHE_HOME : path.join(os.homedir(), '.cache');
|
|
@@ -124,22 +169,27 @@ function lerPerfilIntegracao(chave, cpus) {
|
|
|
124
169
|
try {
|
|
125
170
|
const p = JSON.parse(fs.readFileSync(arquivoDoPerfilIntegracao(), 'utf8'));
|
|
126
171
|
return p?.contrato === CONTRATO_PERFIL_INTEGRACAO && p.chave === chave && p.cpus === cpus && p.completa
|
|
127
|
-
&& Number.isFinite(p.
|
|
172
|
+
&& Number.isFinite(p.picoCpusDaArvore) && p.picoCpusDaArvore > 0 && p.picoCpusDaArvore <= cpus ? p : null;
|
|
128
173
|
}
|
|
129
174
|
catch {
|
|
130
175
|
return null;
|
|
131
176
|
}
|
|
132
177
|
}
|
|
178
|
+
/** Somente uma arvore completa e fisicamente possivel pode ensinar a reserva; lacunas de conteiner ficam na evidencia. */
|
|
179
|
+
function picoDaArvoreParaPerfil(medicao, cpus) {
|
|
180
|
+
const pico = medicao.picoCpusDaArvore;
|
|
181
|
+
return medicao.arvoreCompleta && !medicao.anomaliaDaArvore && pico !== null && pico > 0 && pico <= cpus ? pico : null;
|
|
182
|
+
}
|
|
133
183
|
function gravarPerfilIntegracao(chave, cpus, medicao) {
|
|
134
|
-
|
|
135
|
-
|
|
184
|
+
const picoCpusDaArvore = picoDaArvoreParaPerfil(medicao, cpus);
|
|
185
|
+
if (!chave || picoCpusDaArvore === null)
|
|
136
186
|
return;
|
|
137
187
|
const arquivo = arquivoDoPerfilIntegracao();
|
|
138
188
|
try {
|
|
139
189
|
fs.mkdirSync(path.dirname(arquivo), { recursive: true });
|
|
140
190
|
const temporario = `${arquivo}.${process.pid}.tmp`;
|
|
141
191
|
const perfil = { contrato: CONTRATO_PERFIL_INTEGRACAO, chave, cpus,
|
|
142
|
-
|
|
192
|
+
picoCpusDaArvore, completa: true, medidoEm: new Date().toISOString() };
|
|
143
193
|
fs.writeFileSync(temporario, JSON.stringify(perfil) + '\n', { mode: 0o600 });
|
|
144
194
|
fs.renameSync(temporario, arquivo);
|
|
145
195
|
}
|
|
@@ -271,16 +321,18 @@ function sondarCpuDaIntegracao(pid, registro, cpus) {
|
|
|
271
321
|
const fontes = new Map();
|
|
272
322
|
const motivos = new Map();
|
|
273
323
|
const amostras = [];
|
|
324
|
+
const amostrasDaArvore = [];
|
|
274
325
|
const primeiraCpuDosContainers = new Map();
|
|
275
326
|
const ultimaCpuDosContainers = new Map();
|
|
276
327
|
const amostrar = () => {
|
|
277
328
|
const tabela = processosCpu();
|
|
278
|
-
const
|
|
329
|
+
const arvore = {};
|
|
279
330
|
for (const p of arvoreDeProcessos(pid, tabela)) {
|
|
280
331
|
const x = tabela.get(p);
|
|
281
332
|
if (x)
|
|
282
|
-
|
|
333
|
+
arvore[`processo:${p}:${x.inicio}`] = x.cpuMs;
|
|
283
334
|
}
|
|
335
|
+
const atuais = { ...arvore };
|
|
284
336
|
for (const nome of nomesDosContainers(registro)) {
|
|
285
337
|
let fonte = fontes.get(nome);
|
|
286
338
|
if (!fonte) {
|
|
@@ -304,7 +356,9 @@ function sondarCpuDaIntegracao(pid, registro, cpus) {
|
|
|
304
356
|
else if (fonte)
|
|
305
357
|
motivos.set(nome, 'contador de CPU do cgroup ilegivel');
|
|
306
358
|
}
|
|
307
|
-
|
|
359
|
+
const em = Date.now();
|
|
360
|
+
amostrasDaArvore.push({ em, fontes: arvore });
|
|
361
|
+
amostras.push({ em, fontes: atuais });
|
|
308
362
|
};
|
|
309
363
|
return {
|
|
310
364
|
amostrar,
|
|
@@ -314,10 +368,14 @@ function sondarCpuDaIntegracao(pid, registro, cpus) {
|
|
|
314
368
|
const containersMs = nomes.reduce((total, nome) => total + Math.max(0, (ultimaCpuDosContainers.get(nome) ?? 0) - (primeiraCpuDosContainers.get(nome) ?? 0)), 0);
|
|
315
369
|
const ausentes = nomes.filter((nome) => !ultimaCpuDosContainers.has(nome));
|
|
316
370
|
const pico = picoCpuPorFonte(amostras, cpus);
|
|
371
|
+
const picoDaArvore = picoCpuPorFonte(amostrasDaArvore, cpus);
|
|
372
|
+
const arvoreCompleta = arvoreMs > 0 && picoDaArvore.picoCpus !== null && !picoDaArvore.anomalia;
|
|
317
373
|
return { arvoreMs, containersMs, totalMs: arvoreMs + containersMs, paredeMs,
|
|
318
|
-
picoCpus: pico.picoCpus,
|
|
374
|
+
picoCpus: pico.picoCpus, picoCpusDaArvore: picoDaArvore.picoCpus,
|
|
375
|
+
completa: arvoreCompleta && ausentes.length === 0 && !pico.anomalia, arvoreCompleta,
|
|
319
376
|
containers: nomes, ausentes, motivosDosAusentes: ausentes.map((container) => ({ container,
|
|
320
|
-
motivo: motivos.get(container) ?? 'conteiner terminou antes de uma amostra completa' })),
|
|
377
|
+
motivo: motivos.get(container) ?? 'conteiner terminou antes de uma amostra completa' })),
|
|
378
|
+
anomalia: pico.anomalia, anomaliaDaArvore: picoDaArvore.anomalia };
|
|
321
379
|
},
|
|
322
380
|
};
|
|
323
381
|
}
|
|
@@ -333,13 +391,16 @@ async function rodarEspecificacao(esp) {
|
|
|
333
391
|
const perfil = esp.medicaoCpu?.cpusIntegracao === undefined ? lerPerfilIntegracao(chaveDoPerfil, cpus) : null;
|
|
334
392
|
const medicao = esp.medicaoCpu ?? await (0, agendador_cpu_1.medirCpuDoGrupo)();
|
|
335
393
|
if (perfil)
|
|
336
|
-
Object.assign(medicao, { cpusIntegracao: perfil.
|
|
394
|
+
Object.assign(medicao, { cpusIntegracao: perfil.picoCpusDaArvore, fonteCpusIntegracao: 'medida' });
|
|
337
395
|
else if (medicao.cpusIntegracao === undefined)
|
|
338
396
|
Object.assign(medicao, { cpusIntegracao: null, fonteCpusIntegracao: 'conservadora' });
|
|
339
397
|
const plano = usaAgendador ? (0, agendador_cpu_1.planejarCpuDoGrupo)(cpus, medicao) : undefined;
|
|
340
398
|
const sinalDaReserva = plano && !plano.saturado ? path.join(esp.dir, 'reserva-devolvida.json') : undefined;
|
|
341
399
|
const itens = plano ? aplicarPlano(esp.itens, plano, sinalDaReserva) : esp.itens;
|
|
342
|
-
const
|
|
400
|
+
const tetoInformado = esp.maxParalelo && esp.maxParalelo > 0 ? esp.maxParalelo : itens.length;
|
|
401
|
+
const limite = vagas(Math.max(1, Math.min(tetoInformado, (0, agendador_cpu_1.workersDaReserva)(cpus))));
|
|
402
|
+
const exclusivos = recursosExclusivos();
|
|
403
|
+
const totalDeLanes = itens.filter((item) => item.nome.startsWith('test:')).length;
|
|
343
404
|
const porNome = new Map();
|
|
344
405
|
const indice = new Map(itens.map((item, i) => [item.nome, i]));
|
|
345
406
|
const vezDoItem = (item, i) => {
|
|
@@ -354,12 +415,14 @@ async function rodarEspecificacao(esp) {
|
|
|
354
415
|
if (j !== undefined)
|
|
355
416
|
await vezDoItem(itens[j], j);
|
|
356
417
|
}
|
|
418
|
+
const soltarRecursos = await exclusivos.tomar(item.recursos ?? []);
|
|
357
419
|
await limite.tomar();
|
|
358
420
|
try {
|
|
359
421
|
return await lancar(item, i);
|
|
360
422
|
}
|
|
361
423
|
finally {
|
|
362
424
|
limite.soltar();
|
|
425
|
+
soltarRecursos();
|
|
363
426
|
}
|
|
364
427
|
});
|
|
365
428
|
porNome.set(item.nome, vez);
|
|
@@ -434,15 +497,14 @@ async function rodarEspecificacao(esp) {
|
|
|
434
497
|
catch { /* medida incompleta abaixo */ }
|
|
435
498
|
}
|
|
436
499
|
const medicaoCpu = medirIntegracao && sonda ? sonda.fechar(arvoreMs, t.duracaoMs) : undefined;
|
|
437
|
-
if (medicaoCpu && !(arvoreMs > 0))
|
|
438
|
-
medicaoCpu.completa = false;
|
|
439
500
|
fim = { ...t, ...(medicaoCpu ? { medicaoCpu } : {}) };
|
|
440
501
|
fs.closeSync(saida);
|
|
441
502
|
fs.closeSync(erro);
|
|
442
503
|
resolve(fim);
|
|
443
504
|
};
|
|
444
505
|
// Sem o `timeout(1)`, o proprio auxiliar mata pelo prazo, como o `spawnSync` do `exec` faria.
|
|
445
|
-
const
|
|
506
|
+
const workers = workersDaLane(item, plano, cpus, totalDeLanes);
|
|
507
|
+
const ambiente = { ...process.env, ...item.ambiente, ...(workers === null ? {} : { [agendador_cpu_1.ENV_WORKERS]: String(workers) }),
|
|
446
508
|
...(medirIntegracao ? { [agendador_cpu_1.ENV_CONTAINERS_DA_LANE]: registro } : {}) };
|
|
447
509
|
const filho = (0, node_child_process_1.spawn)(bin, args, { cwd: item.cwd, env: ambiente, stdio: ['ignore', saida, erro],
|
|
448
510
|
...(comGrupo ? {} : { timeout: item.prazoMs, killSignal: 'SIGTERM' }) });
|
|
@@ -0,0 +1,149 @@
|
|
|
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_DA_SELECAO = void 0;
|
|
37
|
+
exports.comandoDaSelecao = comandoDaSelecao;
|
|
38
|
+
exports.planejarSelecaoNativa = planejarSelecaoNativa;
|
|
39
|
+
/** RM-081 F5: decisão conservadora da seleção nativa por mudanças no Agile. */
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
const leases_1 = require("./leases");
|
|
42
|
+
const manifest_1 = require("./manifest");
|
|
43
|
+
const util_1 = require("./util");
|
|
44
|
+
exports.CONTRATO_DA_SELECAO = 'ork.check.selecao/v1';
|
|
45
|
+
const LOCKFILES = new Set(['package-lock.json', 'npm-shrinkwrap.json', 'pnpm-lock.yaml', 'yarn.lock', 'poetry.lock',
|
|
46
|
+
'Pipfile.lock', 'go.mod', 'go.sum', 'Package.resolved']);
|
|
47
|
+
function objeto(v) {
|
|
48
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : null;
|
|
49
|
+
}
|
|
50
|
+
function sha(v) {
|
|
51
|
+
return typeof v === 'string' && /^[0-9a-f]{40,64}$/i.test(v);
|
|
52
|
+
}
|
|
53
|
+
/** Um argumento shell fechado, como o filtro nominal da F3. */
|
|
54
|
+
function argumento(valor) {
|
|
55
|
+
return `'${valor.replace(/'/g, `'"'"'`)}'`;
|
|
56
|
+
}
|
|
57
|
+
function comandoDaSelecao(declaracao, base, arquivos) {
|
|
58
|
+
return declaracao.comando.includes('{base}')
|
|
59
|
+
? declaracao.comando.replace('{base}', argumento(base))
|
|
60
|
+
: declaracao.comando.replace('{arquivos}', arquivos.map(argumento).join(' '));
|
|
61
|
+
}
|
|
62
|
+
function baseAtual(cwd, manifesto, commit) {
|
|
63
|
+
const r = (0, util_1.exec)('git', ['merge-base', commit, manifesto.worktree.base_branch], cwd);
|
|
64
|
+
const base = r.stdout.trim();
|
|
65
|
+
return r.ok && sha(base) ? base : null;
|
|
66
|
+
}
|
|
67
|
+
function arvoreLimpa(cwd) {
|
|
68
|
+
const r = (0, util_1.exec)('git', ['status', '--porcelain=v1', '-z', '--untracked-files=all', '--', '.', ':(exclude).orkastery'], cwd);
|
|
69
|
+
return r.ok && r.stdout === '';
|
|
70
|
+
}
|
|
71
|
+
function arquivosMudados(cwd, anterior, atual) {
|
|
72
|
+
const r = (0, util_1.exec)('git', ['diff', '--name-only', '--no-renames', '-z', anterior, atual, '--', '.', ':(exclude).orkastery'], cwd);
|
|
73
|
+
if (!r.ok)
|
|
74
|
+
return null;
|
|
75
|
+
return [...new Set(r.stdout.split('\0').filter(Boolean).map((arquivo) => arquivo.split(path.sep).join('/')))].sort();
|
|
76
|
+
}
|
|
77
|
+
function lockfile(arquivo) {
|
|
78
|
+
const nome = path.posix.basename(arquivo);
|
|
79
|
+
return LOCKFILES.has(nome) || /^requirements(?:\.[^.]+)?\.txt$/.test(nome)
|
|
80
|
+
|| /(?:^|[.-])lock(?:b|\.(?:json|ya?ml|toml))?$/i.test(nome);
|
|
81
|
+
}
|
|
82
|
+
function inteira(motivo, arquivos) {
|
|
83
|
+
return { modo: 'inteira', motivo, ...(arquivos?.length ? { arquivos } : {}) };
|
|
84
|
+
}
|
|
85
|
+
function todasInteiras(declaracoes, motivo, arquivos) {
|
|
86
|
+
return Object.fromEntries(Object.keys(declaracoes).map((lane) => [lane, inteira(motivo, arquivos)]));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decide uma vez, antes dos comandos. O último `verify_run` é o cache: qualquer forma desconhecida,
|
|
90
|
+
* veredito vermelho, base diferente ou árvore suja devolve a suíte inteira.
|
|
91
|
+
*/
|
|
92
|
+
function planejarSelecaoNativa(cwd, manifesto, eventos, commit, modo) {
|
|
93
|
+
const declaracoes = manifesto.check?.agile?.selecao ?? {};
|
|
94
|
+
if (modo !== 'agile' || Object.keys(declaracoes).length === 0)
|
|
95
|
+
return { lanes: {}, cache: null };
|
|
96
|
+
const base = baseAtual(cwd, manifesto, commit);
|
|
97
|
+
const limpa = arvoreLimpa(cwd);
|
|
98
|
+
const cache = base && limpa ? { contrato: exports.CONTRATO_DA_SELECAO, base, head: commit } : null;
|
|
99
|
+
const ultima = [...eventos].reverse().find((evento) => evento.tipo === 'verify_run');
|
|
100
|
+
if (!ultima)
|
|
101
|
+
return { lanes: todasInteiras(declaracoes, 'rodada-fria'), cache };
|
|
102
|
+
const anterior = objeto(ultima.selecao);
|
|
103
|
+
if (!anterior)
|
|
104
|
+
return { lanes: todasInteiras(declaracoes, 'cache-ausente'), cache };
|
|
105
|
+
if (!base || !limpa || ultima.veredito !== 'verdade sustentada' || anterior.contrato !== exports.CONTRATO_DA_SELECAO
|
|
106
|
+
|| !sha(anterior.base) || !sha(anterior.head) || anterior.head !== ultima.commit) {
|
|
107
|
+
return { lanes: todasInteiras(declaracoes, 'cache-invalido'), cache };
|
|
108
|
+
}
|
|
109
|
+
if (anterior.base !== base)
|
|
110
|
+
return { lanes: todasInteiras(declaracoes, 'base-mudou'), cache };
|
|
111
|
+
if (!(0, util_1.exec)('git', ['merge-base', '--is-ancestor', anterior.head, commit], cwd).ok) {
|
|
112
|
+
return { lanes: todasInteiras(declaracoes, 'cache-invalido'), cache };
|
|
113
|
+
}
|
|
114
|
+
const mudados = arquivosMudados(cwd, anterior.head, commit);
|
|
115
|
+
if (!mudados)
|
|
116
|
+
return { lanes: todasInteiras(declaracoes, 'cache-invalido'), cache };
|
|
117
|
+
const manifestos = new Set([manifest_1.NOME_MANIFESTO, manifest_1.NOME_MANIFESTO_LEGADO]);
|
|
118
|
+
const mudancaNoManifesto = mudados.filter((arquivo) => manifestos.has(path.posix.basename(arquivo)));
|
|
119
|
+
if (mudancaNoManifesto.length)
|
|
120
|
+
return { lanes: todasInteiras(declaracoes, 'manifesto-mudou', mudancaNoManifesto), cache };
|
|
121
|
+
const lockfiles = mudados.filter(lockfile);
|
|
122
|
+
if (lockfiles.length)
|
|
123
|
+
return { lanes: todasInteiras(declaracoes, 'lockfile-mudou', lockfiles), cache };
|
|
124
|
+
const lanes = {};
|
|
125
|
+
for (const [lane, declaracao] of Object.entries(declaracoes)) {
|
|
126
|
+
if (!declaracao.mapeia.length) {
|
|
127
|
+
lanes[lane] = inteira('runner-sem-garantia');
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const configuracao = mudados.filter((arquivo) => (declaracao.configuracao ?? [])
|
|
131
|
+
.some((glob) => (0, leases_1.caminhoBateComGlob)(arquivo, glob)));
|
|
132
|
+
if (configuracao.length) {
|
|
133
|
+
lanes[lane] = inteira('configuracao-mudou', configuracao);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const fora = mudados.filter((arquivo) => !declaracao.mapeia.some((glob) => (0, leases_1.caminhoBateComGlob)(arquivo, glob)));
|
|
137
|
+
if (fora.length) {
|
|
138
|
+
lanes[lane] = inteira('fora-do-mapeamento', fora);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!mudados.length) {
|
|
142
|
+
lanes[lane] = inteira('sem-mudancas');
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
lanes[lane] = { modo: 'selecionada', motivo: 'selecionada', arquivos: mudados,
|
|
146
|
+
base: anterior.head, comando: comandoDaSelecao(declaracao, anterior.head, mudados) };
|
|
147
|
+
}
|
|
148
|
+
return { lanes, cache };
|
|
149
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
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.taskCompleteFixadoDaFonte = taskCompleteFixadoDaFonte;
|
|
37
|
+
exports.taskCompleteFixadoDaSessao = taskCompleteFixadoDaSessao;
|
|
38
|
+
/** RM-075: prova somente leitura de `task_complete` no rollout já fixado pelo controller. */
|
|
39
|
+
const fs = __importStar(require("node:fs"));
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
const node_crypto_1 = require("node:crypto");
|
|
42
|
+
const codex_controller_sensor_1 = require("./adapters/codex-controller-sensor");
|
|
43
|
+
const codex_events_1 = require("./adapters/codex-events");
|
|
44
|
+
const thread_1 = require("./thread");
|
|
45
|
+
const BLOCO = 256 * 1024;
|
|
46
|
+
const chaveDaFonte = (sessionId, despachoEm) => (0, node_crypto_1.createHash)('sha256').update(sessionId + '|' + despachoEm).digest('hex');
|
|
47
|
+
/** O parser percorre o descritor autenticado inteiro; linha parcial ou corrupção não prova terminal. */
|
|
48
|
+
function taskCompleteFixadoDaFonte(fonte, agoraMs = Date.now()) {
|
|
49
|
+
return (0, codex_controller_sensor_1.consumirRolloutControllerFixado)(fonte, (fd, tamanho) => {
|
|
50
|
+
const parser = new codex_events_1.ParserCodex();
|
|
51
|
+
let terminal = null;
|
|
52
|
+
for (let offset = 0; offset < tamanho;) {
|
|
53
|
+
const buffer = Buffer.alloc(Math.min(BLOCO, tamanho - offset));
|
|
54
|
+
const lidos = fs.readSync(fd, buffer, 0, buffer.length, offset);
|
|
55
|
+
if (lidos <= 0)
|
|
56
|
+
break;
|
|
57
|
+
for (const atual of parser.push(buffer.subarray(0, lidos), agoraMs))
|
|
58
|
+
terminal = atual;
|
|
59
|
+
offset += lidos;
|
|
60
|
+
}
|
|
61
|
+
if (parser.estado.invalido || parser.bytesPendentes > 0 || parser.estado.turnoAberto ||
|
|
62
|
+
terminal?.fonte !== 'rollout.task_complete' ||
|
|
63
|
+
(terminal.numeroTurno ?? 0) < parser.estado.turnos)
|
|
64
|
+
return null;
|
|
65
|
+
return { terminal, fonte };
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Resolve somente a fixação correspondente ao despacho. Sem pin autenticado, controller ou cwd,
|
|
70
|
+
* devolve `null`: nunca descobre outro rollout para fabricar a prova.
|
|
71
|
+
*/
|
|
72
|
+
function taskCompleteFixadoDaSessao(raiz, thread, sessao, eventos, agoraMs = Date.now()) {
|
|
73
|
+
if (sessao.runtime !== 'codex')
|
|
74
|
+
return null;
|
|
75
|
+
const registro = eventos.filter(e => e.tipo === 'session_sensor_registered' &&
|
|
76
|
+
e.sessionId === sessao.sessionId && e.despachoEm === sessao.despachadaEm).at(-1);
|
|
77
|
+
if (typeof registro?.controlador !== 'string')
|
|
78
|
+
return null;
|
|
79
|
+
const despacho = eventos.filter(e => e.tipo === 'phase_dispatch' && e.sessionId === sessao.sessionId).at(-1);
|
|
80
|
+
if (despacho?.controlador !== undefined && despacho.controlador !== registro.controlador)
|
|
81
|
+
throw new Error('controlador registrado divergente do despacho');
|
|
82
|
+
const cwd = (despacho?.cwd ?? registro.cwd);
|
|
83
|
+
if (!cwd)
|
|
84
|
+
return null;
|
|
85
|
+
const dir = (0, thread_1.dirThread)(raiz, thread.id);
|
|
86
|
+
const chave = chaveDaFonte(sessao.sessionId, sessao.despachadaEm);
|
|
87
|
+
const esperado = {
|
|
88
|
+
dirSessoes: path.join(dir, 'sessoes'), sessionId: sessao.sessionId, cwd,
|
|
89
|
+
despachoEm: sessao.despachadaEm, agoraMs,
|
|
90
|
+
fixacao: path.join(dir, 'sessoes', `watcher-source-${chave}.json`),
|
|
91
|
+
vinculo: { thread: thread.id, fase: sessao.fase, promptSha256: sessao.promptSha256 },
|
|
92
|
+
};
|
|
93
|
+
const fonte = (0, codex_controller_sensor_1.lerFonteControllerFixada)(esperado.fixacao, esperado);
|
|
94
|
+
return fonte ? taskCompleteFixadoDaFonte(fonte, agoraMs) : null;
|
|
95
|
+
}
|