@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
|
@@ -0,0 +1,353 @@
|
|
|
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_VERIFY_MCP = void 0;
|
|
37
|
+
exports.iniciarVerifyMcp = iniciarVerifyMcp;
|
|
38
|
+
exports.consultarVerifyMcp = consultarVerifyMcp;
|
|
39
|
+
exports.executarVerifyMcpWorker = executarVerifyMcpWorker;
|
|
40
|
+
/**
|
|
41
|
+
* Verify assíncrono do MCP: o transporte inicia uma rodada curta e um worker do próprio servidor
|
|
42
|
+
* executa o mesmo `verificar` do CLI. O estado fica no domínio canônico da thread; o modelo nunca
|
|
43
|
+
* escolhe raiz, comando, PID ou lease.
|
|
44
|
+
*/
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const node_crypto_1 = require("node:crypto");
|
|
48
|
+
const node_child_process_1 = require("node:child_process");
|
|
49
|
+
const hitl_gates_1 = require("./hitl-gates");
|
|
50
|
+
const manifest_1 = require("./manifest");
|
|
51
|
+
const mcp_artifacts_1 = require("./mcp-artifacts");
|
|
52
|
+
const leases_1 = require("./leases");
|
|
53
|
+
const thread_1 = require("./thread");
|
|
54
|
+
const verify_1 = require("./verify");
|
|
55
|
+
const conducao_1 = require("./conducao");
|
|
56
|
+
const fila_pesada_1 = require("./fila-pesada");
|
|
57
|
+
const mcp_verify_1 = require("./mcp-verify");
|
|
58
|
+
const verify_2 = require("./verify");
|
|
59
|
+
const claims_1 = require("./claims");
|
|
60
|
+
const locale_1 = require("./locale");
|
|
61
|
+
exports.CONTRATO_VERIFY_MCP = 'ork.verify-mcp/v1';
|
|
62
|
+
const ESTADOS_VIVOS = new Set(['na-fila', 'rodando']);
|
|
63
|
+
const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
64
|
+
const LIMITE_ESTADO = 16 * 1024 * 1024;
|
|
65
|
+
function agora(dep) { return (dep?.agora?.() ?? new Date()).toISOString(); }
|
|
66
|
+
function falhaDaExecucao(e) {
|
|
67
|
+
if (e instanceof fila_pesada_1.ErroDaFilaPesada)
|
|
68
|
+
return { motivo: e.recusa.motivo, detalhe: e.message, recusa: e.recusa };
|
|
69
|
+
if (e instanceof conducao_1.ErroDeConducao)
|
|
70
|
+
return { motivo: e.recusa.motivo, detalhe: e.message, recusa: e.recusa };
|
|
71
|
+
return { motivo: 'verify.worker-failed', detalhe: e.message };
|
|
72
|
+
}
|
|
73
|
+
function inicioDoProcesso(pid) {
|
|
74
|
+
try {
|
|
75
|
+
const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
|
|
76
|
+
return stat.slice(stat.lastIndexOf(')') + 2).split(' ')[19] ?? null;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function processoVivo(processo) {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(processo.pid, 0);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return processo.inicio === null || inicioDoProcesso(processo.pid) === processo.inicio;
|
|
90
|
+
}
|
|
91
|
+
function mesmoLease(a, b) {
|
|
92
|
+
return !!a && a.nome === b.nome && a.thread === b.thread && a.pid === b.pid &&
|
|
93
|
+
a.adquiridoEm === b.adquiridoEm && a.expiraEm === b.expiraEm && a.motivo === b.motivo;
|
|
94
|
+
}
|
|
95
|
+
function diretorioDasRodadas(raiz, threadId, criar) {
|
|
96
|
+
(0, mcp_artifacts_1.validarArquivosEstadoMcp)(raiz, threadId);
|
|
97
|
+
const threadDir = fs.realpathSync((0, thread_1.dirThread)(raiz, threadId));
|
|
98
|
+
const estadoReal = fs.realpathSync(path.join(raiz, '.orkastery'));
|
|
99
|
+
if (!threadDir.startsWith(estadoReal + path.sep))
|
|
100
|
+
throw Error('mcp.verify.async.scope');
|
|
101
|
+
const dir = path.join(threadDir, 'verify-mcp');
|
|
102
|
+
const st = fs.lstatSync(dir, { throwIfNoEntry: false });
|
|
103
|
+
if (!st) {
|
|
104
|
+
if (!criar)
|
|
105
|
+
throw Error('mcp.verify.round.not-found');
|
|
106
|
+
fs.mkdirSync(dir, { mode: 0o700 });
|
|
107
|
+
}
|
|
108
|
+
const atual = fs.lstatSync(dir);
|
|
109
|
+
if (!atual.isDirectory() || atual.isSymbolicLink() || fs.realpathSync(dir) !== dir ||
|
|
110
|
+
(process.getuid && atual.uid !== process.getuid()))
|
|
111
|
+
throw Error('mcp.verify.async.scope');
|
|
112
|
+
return dir;
|
|
113
|
+
}
|
|
114
|
+
function lerArquivoSeguro(file, ausente) {
|
|
115
|
+
let fd;
|
|
116
|
+
try {
|
|
117
|
+
fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
if (ausente && e.code === 'ENOENT')
|
|
121
|
+
return null;
|
|
122
|
+
throw e;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const st = fs.fstatSync(fd);
|
|
126
|
+
if (!st.isFile() || st.nlink !== 1 || st.size > LIMITE_ESTADO || (process.getuid && st.uid !== process.getuid()))
|
|
127
|
+
throw Error('mcp.verify.async.unsafe');
|
|
128
|
+
const bytes = fs.readFileSync(fd);
|
|
129
|
+
if (bytes.length > LIMITE_ESTADO)
|
|
130
|
+
throw Error('mcp.verify.async.too-large');
|
|
131
|
+
return bytes;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
fs.closeSync(fd);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function validarEstado(v, threadId, rodadaId) {
|
|
138
|
+
const e = v;
|
|
139
|
+
if (!e || e.contrato !== exports.CONTRATO_VERIFY_MCP || e.threadId !== threadId || e.rodadaId !== rodadaId ||
|
|
140
|
+
!UUID.test(rodadaId) || !['na-fila', 'rodando', 'concluido', 'falhou'].includes(String(e.estado)) ||
|
|
141
|
+
typeof e.criadaEm !== 'string' || typeof e.atualizadaEm !== 'string' ||
|
|
142
|
+
!e.lease || e.lease.thread !== threadId || typeof e.host !== 'string')
|
|
143
|
+
throw Error('mcp.verify.async.invalid');
|
|
144
|
+
return e;
|
|
145
|
+
}
|
|
146
|
+
function lerEstado(dir, threadId, rodadaId) {
|
|
147
|
+
if (!UUID.test(rodadaId))
|
|
148
|
+
throw Error('mcp.verify.round.invalid');
|
|
149
|
+
const bytes = lerArquivoSeguro(path.join(dir, `${rodadaId}.json`), false);
|
|
150
|
+
try {
|
|
151
|
+
return validarEstado(JSON.parse(bytes.toString('utf8')), threadId, rodadaId);
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
if (e.message.startsWith('mcp.'))
|
|
155
|
+
throw e;
|
|
156
|
+
throw Error('mcp.verify.async.invalid');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function gravarAtomico(dir, nome, valor) {
|
|
160
|
+
const destino = path.join(dir, nome);
|
|
161
|
+
const temp = path.join(dir, `.${nome}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`);
|
|
162
|
+
const bytes = JSON.stringify(valor) + '\n';
|
|
163
|
+
if (Buffer.byteLength(bytes) > LIMITE_ESTADO)
|
|
164
|
+
throw Error('mcp.verify.async.too-large');
|
|
165
|
+
try {
|
|
166
|
+
fs.writeFileSync(temp, bytes, { flag: 'wx', mode: 0o600 });
|
|
167
|
+
fs.renameSync(temp, destino);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
fs.rmSync(temp, { force: true });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function gravarEstado(dir, estado) {
|
|
174
|
+
gravarAtomico(dir, `${estado.rodadaId}.json`, estado);
|
|
175
|
+
}
|
|
176
|
+
function lerAtiva(dir, threadId) {
|
|
177
|
+
const bytes = lerArquivoSeguro(path.join(dir, 'active.json'), true);
|
|
178
|
+
if (!bytes)
|
|
179
|
+
return null;
|
|
180
|
+
let id;
|
|
181
|
+
try {
|
|
182
|
+
id = JSON.parse(bytes.toString('utf8')).rodadaId;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
throw Error('mcp.verify.async.invalid');
|
|
186
|
+
}
|
|
187
|
+
if (typeof id !== 'string' || !UUID.test(id))
|
|
188
|
+
throw Error('mcp.verify.async.invalid');
|
|
189
|
+
return lerEstado(dir, threadId, id);
|
|
190
|
+
}
|
|
191
|
+
function publico(estado, reutilizada) {
|
|
192
|
+
const { host: _host, processo: _processo, lease: _lease, ...visivel } = estado;
|
|
193
|
+
return { ...visivel, ...(reutilizada === undefined ? {} : { reutilizada }) };
|
|
194
|
+
}
|
|
195
|
+
function vivo(estado, dep) {
|
|
196
|
+
return !!estado.processo && (dep?.processoVivo ?? processoVivo)(estado.processo);
|
|
197
|
+
}
|
|
198
|
+
function liberarLeaseExata(raiz, estado) {
|
|
199
|
+
if (mesmoLease((0, leases_1.lerLease)(raiz, estado.lease.nome), estado.lease))
|
|
200
|
+
(0, leases_1.liberar)(raiz, estado.lease.nome, estado.threadId);
|
|
201
|
+
}
|
|
202
|
+
function falhaDeProcesso(estado, instante) {
|
|
203
|
+
return { ...estado, estado: 'falhou', lane: null, atualizadaEm: instante,
|
|
204
|
+
falha: { motivo: 'verify.processo-morto', detalhe: 'o worker terminou sem gravar um veredito completo' } };
|
|
205
|
+
}
|
|
206
|
+
function prazoDaLease(raiz, threadId) {
|
|
207
|
+
const carregado = (0, manifest_1.exigirManifesto)(raiz);
|
|
208
|
+
const claims = (0, claims_1.lerClaims)(raiz, threadId).filter((c) => c.estado !== 'retirada');
|
|
209
|
+
const quantidade = claims.reduce((n, c) => n + c.verificar.length, 0) + (0, verify_2.comandosDoManifesto)(carregado.manifesto).length + 2;
|
|
210
|
+
const prazos = [carregado.manifesto.verify.timeout_ms ?? 600_000,
|
|
211
|
+
...Object.values(carregado.manifesto.verify.timeout_ms_por_comando ?? {}).filter((n) => typeof n === 'number')];
|
|
212
|
+
return mcp_verify_1.ESPERA_DA_FILA_PESADA_MCP_MS + Math.max(conducao_1.PRAZO_DE_SESSAO_PADRAO_MS, (0, conducao_1.prazoDaVerificacao)(Math.max(...prazos), quantidade));
|
|
213
|
+
}
|
|
214
|
+
function lancarWorker(pedido) {
|
|
215
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [pedido.worker, pedido.raiz, pedido.threadId, pedido.rodadaId], {
|
|
216
|
+
cwd: pedido.raiz, detached: true, stdio: 'ignore', env: process.env,
|
|
217
|
+
});
|
|
218
|
+
if (!child.pid)
|
|
219
|
+
throw Error('mcp.verify.worker.spawn');
|
|
220
|
+
child.unref();
|
|
221
|
+
let inicio = null;
|
|
222
|
+
for (let i = 0; i < 20 && inicio === null; i++) {
|
|
223
|
+
inicio = inicioDoProcesso(child.pid);
|
|
224
|
+
if (inicio === null)
|
|
225
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5);
|
|
226
|
+
}
|
|
227
|
+
return { pid: child.pid, inicio };
|
|
228
|
+
}
|
|
229
|
+
function iniciarVerifyMcp(raiz, threadId, vinculo, dep = {}) {
|
|
230
|
+
const carregado = (0, manifest_1.exigirManifesto)(raiz);
|
|
231
|
+
if (fs.realpathSync(carregado.raiz) !== fs.realpathSync(raiz))
|
|
232
|
+
throw Error('mcp.verify.project');
|
|
233
|
+
(0, mcp_artifacts_1.validarArquivosEstadoMcp)(raiz, threadId);
|
|
234
|
+
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
235
|
+
if (thread.status === 'fechada' || !thread.worktree)
|
|
236
|
+
throw Error('mcp.verify.thread');
|
|
237
|
+
return (0, hitl_gates_1.comLockHitl)(raiz, threadId, () => {
|
|
238
|
+
const dir = diretorioDasRodadas(raiz, threadId, true);
|
|
239
|
+
const ativa = lerAtiva(dir, threadId);
|
|
240
|
+
if (ativa && ESTADOS_VIVOS.has(ativa.estado) && vivo(ativa, dep))
|
|
241
|
+
return publico(ativa, true);
|
|
242
|
+
if (ativa) {
|
|
243
|
+
const reconciliada = ESTADOS_VIVOS.has(ativa.estado) ? falhaDeProcesso(ativa, agora(dep)) : ativa;
|
|
244
|
+
if (reconciliada !== ativa)
|
|
245
|
+
gravarEstado(dir, reconciliada);
|
|
246
|
+
liberarLeaseExata(raiz, reconciliada);
|
|
247
|
+
}
|
|
248
|
+
const nomeLease = `worktree-write:${threadId}`;
|
|
249
|
+
(0, leases_1.podarRegioesDeThreadsFechadas)(raiz, [nomeLease, 'main-tree'], threadId);
|
|
250
|
+
if ((0, leases_1.lerLease)(raiz, nomeLease) || (0, leases_1.leasesColidentes)(raiz, nomeLease).length || (0, leases_1.leasesColidentes)(raiz, 'main-tree').length)
|
|
251
|
+
throw Error('lease.busy: verify assíncrono exige a worktree livre');
|
|
252
|
+
const rodadaId = (0, node_crypto_1.randomUUID)();
|
|
253
|
+
const instante = agora(dep);
|
|
254
|
+
const regiao = (0, leases_1.adquirirRegiao)(raiz, nomeLease, { thread: threadId, motivo: `MCP VERIFY ASYNC ${rodadaId}`,
|
|
255
|
+
ttlMs: prazoDaLease(raiz, threadId), retomarVencido: false });
|
|
256
|
+
if (!regiao.ok || !regiao.lease)
|
|
257
|
+
throw Error('lease.busy: verify assíncrono não adquiriu a worktree');
|
|
258
|
+
let estado = { contrato: exports.CONTRATO_VERIFY_MCP, rodadaId, threadId, despacho: vinculo.despacho,
|
|
259
|
+
host: vinculo.host, estado: 'na-fila', lane: null, criadaEm: instante, atualizadaEm: instante,
|
|
260
|
+
processo: null, lease: regiao.lease };
|
|
261
|
+
gravarEstado(dir, estado);
|
|
262
|
+
gravarAtomico(dir, 'active.json', { contrato: exports.CONTRATO_VERIFY_MCP, rodadaId });
|
|
263
|
+
try {
|
|
264
|
+
const worker = path.resolve(__dirname, 'mcp-verify-worker.js');
|
|
265
|
+
const processo = (dep.lancar ?? lancarWorker)({ worker, raiz: fs.realpathSync(raiz), threadId, rodadaId });
|
|
266
|
+
estado = { ...estado, processo, atualizadaEm: agora(dep) };
|
|
267
|
+
gravarEstado(dir, estado);
|
|
268
|
+
return publico(estado, false);
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
estado = { ...estado, estado: 'falhou', atualizadaEm: agora(dep),
|
|
272
|
+
falha: { motivo: 'verify.worker-failed', detalhe: e.message } };
|
|
273
|
+
gravarEstado(dir, estado);
|
|
274
|
+
liberarLeaseExata(raiz, estado);
|
|
275
|
+
return publico(estado, false);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function consultarVerifyMcp(raiz, threadId, rodadaId, dep = {}) {
|
|
280
|
+
(0, thread_1.lerThread)(raiz, threadId);
|
|
281
|
+
(0, mcp_artifacts_1.validarArquivosEstadoMcp)(raiz, threadId);
|
|
282
|
+
const estado = lerEstado(diretorioDasRodadas(raiz, threadId, false), threadId, rodadaId);
|
|
283
|
+
return publico(ESTADOS_VIVOS.has(estado.estado) && !vivo(estado, dep) ? falhaDeProcesso(estado, agora(dep)) : estado);
|
|
284
|
+
}
|
|
285
|
+
function atualizarRodada(raiz, threadId, rodadaId, mudar) {
|
|
286
|
+
return (0, hitl_gates_1.comLockHitl)(raiz, threadId, () => {
|
|
287
|
+
const dir = diretorioDasRodadas(raiz, threadId, false);
|
|
288
|
+
const atual = lerEstado(dir, threadId, rodadaId);
|
|
289
|
+
const proximo = mudar(atual);
|
|
290
|
+
gravarEstado(dir, proximo);
|
|
291
|
+
return proximo;
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
/** Entrada do processo destacado; exportada para o teste hermético executar a mesma rodada sem transporte. */
|
|
295
|
+
function executarVerifyMcpWorker(raiz, threadId, rodadaId) {
|
|
296
|
+
const dir = diretorioDasRodadas(raiz, threadId, false);
|
|
297
|
+
let inicial = lerEstado(dir, threadId, rodadaId);
|
|
298
|
+
const inicioAtual = inicioDoProcesso(process.pid);
|
|
299
|
+
if (!inicial.processo || inicial.processo.pid !== process.pid ||
|
|
300
|
+
(inicial.processo.inicio !== null && inicial.processo.inicio !== inicioAtual))
|
|
301
|
+
throw Error('mcp.verify.worker.identity');
|
|
302
|
+
if (!mesmoLease((0, leases_1.lerLease)(raiz, inicial.lease.nome), inicial.lease))
|
|
303
|
+
throw Error('mcp.verify.worker.lease');
|
|
304
|
+
const atualizar = (mudanca) => {
|
|
305
|
+
inicial = atualizarRodada(raiz, threadId, rodadaId, (atual) => {
|
|
306
|
+
if (!mesmoLease((0, leases_1.lerLease)(raiz, atual.lease.nome), atual.lease))
|
|
307
|
+
return { ...atual, estado: 'falhou', lane: null, atualizadaEm: new Date().toISOString(),
|
|
308
|
+
falha: { motivo: 'verify.lease-perdida', detalhe: 'a lease da worktree mudou durante a rodada' } };
|
|
309
|
+
return { ...atual, ...mudanca, atualizadaEm: new Date().toISOString() };
|
|
310
|
+
});
|
|
311
|
+
if (inicial.estado === 'falhou')
|
|
312
|
+
throw Error(inicial.falha?.motivo ?? 'verify.worker-failed');
|
|
313
|
+
};
|
|
314
|
+
// RM-064: o estado terminal só é gravado depois de a lease voltar. Quem lê `concluido` ou `falhou`
|
|
315
|
+
// pode contar com a worktree livre; a ordem inversa deixava a recusa visível com a lease ainda presa.
|
|
316
|
+
let terminal = null;
|
|
317
|
+
try {
|
|
318
|
+
atualizar({ estado: 'na-fila', lane: 'fila-pesada' });
|
|
319
|
+
const carregado = (0, manifest_1.exigirManifesto)(raiz);
|
|
320
|
+
const resultado = (0, locale_1.comLocale)('pt-BR', () => (0, verify_1.verificar)(carregado, threadId, {
|
|
321
|
+
operacao: 'mcp.verify',
|
|
322
|
+
conducao: { canal: inicial.host, identidade: inicial.despacho,
|
|
323
|
+
filaPesada: { esperarMs: mcp_verify_1.ESPERA_DA_FILA_PESADA_MCP_MS, aoEsperar: (ocupantes) => atualizar({ estado: 'na-fila',
|
|
324
|
+
lane: 'fila-pesada', ocupantes: ocupantes.map((o) => ({ operacao: o.operacao, thread: o.thread })) }) } },
|
|
325
|
+
progresso: (lane) => atualizar({ estado: 'rodando', lane, ocupantes: undefined }),
|
|
326
|
+
}));
|
|
327
|
+
const locale = (0, locale_1.resolverLocale)(carregado.manifesto.owner?.language).locale;
|
|
328
|
+
const veredito = { ok: resultado.ok, commit: resultado.commit, motivos: resultado.motivos,
|
|
329
|
+
check: resultado.check, texto: (0, locale_1.comLocale)(locale, () => (0, verify_1.textoDoVerify)(resultado)), resultado };
|
|
330
|
+
terminal = { estado: 'concluido', lane: null, veredito, falha: undefined, ocupantes: undefined };
|
|
331
|
+
}
|
|
332
|
+
catch (e) {
|
|
333
|
+
terminal = { estado: 'falhou', lane: null, falha: falhaDaExecucao(e), ocupantes: undefined };
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
const atual = lerEstado(dir, threadId, rodadaId);
|
|
337
|
+
const leaseNossa = mesmoLease((0, leases_1.lerLease)(raiz, atual.lease.nome), atual.lease);
|
|
338
|
+
liberarLeaseExata(raiz, atual);
|
|
339
|
+
if (atual.estado === 'falhou')
|
|
340
|
+
terminal = null; // a falha já gravada (lease perdida, por exemplo) prevalece
|
|
341
|
+
else if (!leaseNossa)
|
|
342
|
+
terminal = { estado: 'falhou', lane: null, ocupantes: undefined,
|
|
343
|
+
falha: { motivo: 'verify.lease-perdida', detalhe: 'a lease da worktree mudou durante a rodada' } };
|
|
344
|
+
if (terminal) {
|
|
345
|
+
const fim = terminal;
|
|
346
|
+
try {
|
|
347
|
+
inicial = atualizarRodada(raiz, threadId, rodadaId, (a) => ({ ...a, ...fim, atualizadaEm: new Date().toISOString() }));
|
|
348
|
+
}
|
|
349
|
+
catch { /* a leitura abaixo projeta morte/falha; nunca inventa verde */ }
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return consultarVerifyMcp(raiz, threadId, rodadaId);
|
|
353
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/** Processo destacado do verify MCP. Toda autoridade vem do estado criado pelo servidor. */
|
|
4
|
+
const mcp_verify_async_1 = require("./mcp-verify-async");
|
|
5
|
+
if (require.main === module) {
|
|
6
|
+
const [raiz, threadId, rodadaId, ...resto] = process.argv.slice(2);
|
|
7
|
+
if (!raiz || !threadId || !rodadaId || resto.length)
|
|
8
|
+
process.exitCode = 2;
|
|
9
|
+
else {
|
|
10
|
+
try {
|
|
11
|
+
(0, mcp_verify_async_1.executarVerifyMcpWorker)(raiz, threadId, rodadaId);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/dist/mcp-verify.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ESPERA_DA_FILA_PESADA_MCP_MS = void 0;
|
|
37
|
+
exports.diagnosticoDoVerifyMcp = diagnosticoDoVerifyMcp;
|
|
37
38
|
exports.verificarMcp = verificarMcp;
|
|
38
39
|
/** Operação estruturada: argumentos só identificam a thread; execução sempre confinada. */
|
|
39
40
|
const fs = __importStar(require("node:fs"));
|
|
@@ -68,6 +69,14 @@ function mesmoLease(a, b) {
|
|
|
68
69
|
return !!a && a.nome === b.nome && a.thread === b.thread && a.pid === b.pid &&
|
|
69
70
|
a.adquiridoEm === b.adquiridoEm && a.expiraEm === b.expiraEm && a.motivo === b.motivo;
|
|
70
71
|
}
|
|
72
|
+
/** Parte pura do retorno MCP: permite provar o contrato mesmo quando o sandbox nao abre outro sandbox. */
|
|
73
|
+
function diagnosticoDoVerifyMcp(r) {
|
|
74
|
+
return {
|
|
75
|
+
regressoes: r.regressoes.map(c => c.nome),
|
|
76
|
+
preExistentes: r.preExistentes.map(c => c.nome),
|
|
77
|
+
comparacoes: r.comparacoes,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
71
80
|
/** Síncrono: prazo total/per-command, não cancelamento reativo do event loop. */
|
|
72
81
|
function verificarMcp(raizEntrada, threadId, conducao = {}) {
|
|
73
82
|
const deadline = Date.now() + PRAZO_TOTAL_MS;
|
|
@@ -167,7 +176,7 @@ function verificarMcp(raizEntrada, threadId, conducao = {}) {
|
|
|
167
176
|
execucoes: execucoes.slice(0, LIMITE_RETORNO).map(c => ({ nome: c.nome, ok: c.ok, code: c.code,
|
|
168
177
|
executado: c.executado === true, resumo: c.resumo })),
|
|
169
178
|
totalExecucoes: execucoes.length, omitidas: Math.max(0, execucoes.length - LIMITE_RETORNO),
|
|
170
|
-
|
|
179
|
+
...diagnosticoDoVerifyMcp(r),
|
|
171
180
|
executor: 'codex-sandbox', prazoTotalMs: PRAZO_TOTAL_MS, limitePorComandoMs: COMANDO_MAX_MS,
|
|
172
181
|
};
|
|
173
182
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.branchRegistradaDaEntrega = branchRegistradaDaEntrega;
|
|
4
|
+
exports.mergesDasEntregasNaBase = mergesDasEntregasNaBase;
|
|
5
|
+
/**
|
|
6
|
+
* Reconhecimento unico do merge que entrega uma thread na linha de primeiro pai da base.
|
|
7
|
+
*
|
|
8
|
+
* A forja pode preservar o titulo `ship(<thread>)` no assunto ou usar sua mensagem padrao.
|
|
9
|
+
* Nos formatos padrao, a branch e o vinculo: ela precisa ser exatamente a branch registrada
|
|
10
|
+
* para a thread. O fallback pela convencao existe para o `docs verificar` no CI, que nao tem
|
|
11
|
+
* `.orkastery/`, e fecha o id antes de aceitar o sufixo da fase (`ork-abc` nao casa `ork-abcd`).
|
|
12
|
+
*/
|
|
13
|
+
const branch_de_estado_1 = require("./branch-de-estado");
|
|
14
|
+
const ledger_1 = require("./ledger");
|
|
15
|
+
const thread_1 = require("./thread");
|
|
16
|
+
const util_1 = require("./util");
|
|
17
|
+
/** A branch da thread como foi registrada, preferindo o evento especifico da worktree. */
|
|
18
|
+
function branchRegistradaDaEntrega(raiz, thread) {
|
|
19
|
+
try {
|
|
20
|
+
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, thread));
|
|
21
|
+
const worktree = [...eventos].reverse().find((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.worktreeCriada && (0, branch_de_estado_1.branchValida)(e.branch));
|
|
22
|
+
if (worktree)
|
|
23
|
+
return String(worktree.branch);
|
|
24
|
+
const criada = [...eventos].reverse().find((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.threadCriada);
|
|
25
|
+
const base = criada?.base;
|
|
26
|
+
if (base && typeof base === 'object' && !Array.isArray(base)) {
|
|
27
|
+
const branch = base.branch;
|
|
28
|
+
if ((0, branch_de_estado_1.branchValida)(branch))
|
|
29
|
+
return branch;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch { /* checkout de CI ou thread sem estado local */ }
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const branchConvencionalDaThread = (branch, thread) => {
|
|
36
|
+
const prefixo = `ork/${thread}`;
|
|
37
|
+
return branch === prefixo || branch.startsWith(`${prefixo}-`);
|
|
38
|
+
};
|
|
39
|
+
function threadDoAssunto(assunto, entregas, base) {
|
|
40
|
+
const ship = /^ship\(([^)]+)\)/.exec(assunto);
|
|
41
|
+
if (ship?.[1])
|
|
42
|
+
return ship[1];
|
|
43
|
+
const github = /^Merge pull request #[1-9][0-9]* from [^/\s]+\/(\S+)$/.exec(assunto);
|
|
44
|
+
const gitlab = /^Merge branch '(.+)' into '(.+)'$/.exec(assunto);
|
|
45
|
+
const branch = github?.[1] ?? (gitlab?.[2] === base ? gitlab[1] : null);
|
|
46
|
+
if (!branch)
|
|
47
|
+
return null;
|
|
48
|
+
return entregas.find((entrega) => entrega.branch === null
|
|
49
|
+
? branchConvencionalDaThread(branch, entrega.thread)
|
|
50
|
+
: branch === entrega.branch)?.thread ?? null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Merges das entregas na base, em ordem do git log (mais novo primeiro por omissao).
|
|
54
|
+
*
|
|
55
|
+
* O assunto e lido por `%s`, portanto uma citacao somente no corpo nao entra. `--first-parent`
|
|
56
|
+
* tira commits da branch lateral. O segundo pai continua opcional no retorno para preservar a
|
|
57
|
+
* recusa tipada `entrega.sem-vinculo` de squash/rebase quando a CI e obrigatoria.
|
|
58
|
+
*/
|
|
59
|
+
function mergesDasEntregasNaBase(raiz, refBase, base, entregas, reverse = false) {
|
|
60
|
+
const saida = new Map(entregas.map((e) => [e.thread, []]));
|
|
61
|
+
if (!(0, branch_de_estado_1.branchValida)(refBase) || !(0, branch_de_estado_1.branchValida)(base))
|
|
62
|
+
return saida;
|
|
63
|
+
const args = ['log', refBase, '--first-parent', '--format=%H%x09%P%x09%cI%x09%s', ...(reverse ? ['--reverse'] : []), '--'];
|
|
64
|
+
const r = (0, util_1.exec)('git', args, raiz, 60000);
|
|
65
|
+
if (!r.ok)
|
|
66
|
+
return saida;
|
|
67
|
+
for (const linha of r.stdout.split('\n')) {
|
|
68
|
+
const [sha, pais, em, assunto] = linha.split('\t');
|
|
69
|
+
if (!(0, branch_de_estado_1.shaValido)(sha) || typeof assunto !== 'string')
|
|
70
|
+
continue;
|
|
71
|
+
const thread = threadDoAssunto(assunto, entregas, base);
|
|
72
|
+
if (!thread)
|
|
73
|
+
continue;
|
|
74
|
+
const segundo = (pais ?? '').split(' ')[1] ?? null;
|
|
75
|
+
const ms = Date.parse(em ?? '');
|
|
76
|
+
const merges = saida.get(thread) ?? [];
|
|
77
|
+
merges.push({
|
|
78
|
+
mergeSha: sha,
|
|
79
|
+
headSha: segundo && (0, branch_de_estado_1.shaValido)(segundo) ? segundo : null,
|
|
80
|
+
em: Number.isFinite(ms) ? new Date(ms).toISOString() : null,
|
|
81
|
+
});
|
|
82
|
+
saida.set(thread, merges);
|
|
83
|
+
}
|
|
84
|
+
return saida;
|
|
85
|
+
}
|
package/dist/network-roadmap.js
CHANGED
|
@@ -454,7 +454,7 @@ function maquinasDoPanorama(retratos, local, ctx, lacunas) {
|
|
|
454
454
|
const idadeMs = Math.max(0, agora - Date.parse(m.publicadoEm));
|
|
455
455
|
const semBatida = idadeMs > fabrica_estado_1.LIMIAR_SEM_BATIDA_MS;
|
|
456
456
|
if (semBatida) {
|
|
457
|
-
lacunas.push(lacuna('maquina.sem-batida', 'fabrica', m.maquina, `${m.maquina} sem retrato novo há ${(0, horario_1.duracaoCurta)(Math.floor(idadeMs / 60000))} (último em ${(0, horario_1.formatarDataHora)(m.publicadoEm, { fuso: ctx.fuso })}): ` +
|
|
457
|
+
lacunas.push(lacuna('maquina.sem-batida', 'fabrica', m.maquina, `${m.maquina} sem retrato novo há ${(0, horario_1.duracaoCurta)(Math.floor(idadeMs / 60000))} (último em ${(0, horario_1.formatarDataHora)(m.publicadoEm, { fuso: ctx.fuso, agora: ctx.quando })}): ` +
|
|
458
458
|
'as threads dela podem ter andado', `confira a ${m.maquina}: ela publica ao criar thread, despachar fase, entregar e a cada batida do pulse`));
|
|
459
459
|
}
|
|
460
460
|
saida.push({ maquina: m.maquina, por: m.por, publicadoEm: m.publicadoEm, idadeMin: Math.floor(idadeMs / 60000), semBatida,
|
|
@@ -632,7 +632,7 @@ function lerProjetoDoClone(p, geral) {
|
|
|
632
632
|
fontes.push({ parte, origem: 'clone', onde, ref: nome, commit: r.ponta, dataDoCommit, lidoEm: ctx.quando, atualizado: r.atualizado, existe: true });
|
|
633
633
|
if (!r.atualizado) {
|
|
634
634
|
lacunas.push(lacuna(`${parte}.sem-leitura`, parte, onde, `sem leitura nova de ${onde}${porque(r.tentou)}; ` +
|
|
635
|
-
`vale a última cópia desta máquina, commit ${r.ponta.slice(0, 7)} de ${(0, horario_1.formatarDataHora)(dataDoCommit, { fuso: ctx.fuso })}`, correcao()));
|
|
635
|
+
`vale a última cópia desta máquina, commit ${r.ponta.slice(0, 7)} de ${(0, horario_1.formatarDataHora)(dataDoCommit, { fuso: ctx.fuso, agora: ctx.quando })}`, correcao()));
|
|
636
636
|
}
|
|
637
637
|
return r.ponta;
|
|
638
638
|
}
|
|
@@ -1033,15 +1033,15 @@ function descreverProjeto(x) {
|
|
|
1033
1033
|
function linhaDaFonte(f, quando, fuso) {
|
|
1034
1034
|
const m = (0, locale_1.msg)().network.roadmap;
|
|
1035
1035
|
const parte = m.fonteParte(f.parte);
|
|
1036
|
-
const lido = f.lidoEm === quando ? m.lidoAgora : m.lidoEm((0, horario_1.formatarDataHora)(f.lidoEm, { fuso }));
|
|
1036
|
+
const lido = f.lidoEm === quando ? m.lidoAgora : m.lidoEm((0, horario_1.formatarDataHora)(f.lidoEm, { fuso, agora: quando }));
|
|
1037
1037
|
if (f.origem === 'estado-local')
|
|
1038
1038
|
return m.fonteLocal(parte, f.onde, lido);
|
|
1039
1039
|
if (!f.existe)
|
|
1040
1040
|
return m.fonteInexistente(parte, f.onde, lido);
|
|
1041
1041
|
const alvo = f.parte === 'roadmap' ? m.alvoDoRoadmap(f.onde) : f.onde;
|
|
1042
|
-
return m.fonteCommit(parte, alvo, (f.commit ?? '').slice(0, 7), (0, horario_1.formatarDataHora)(f.dataDoCommit, { fuso }), f.atualizado ? lido : m.ultimaCopia);
|
|
1042
|
+
return m.fonteCommit(parte, alvo, (f.commit ?? '').slice(0, 7), (0, horario_1.formatarDataHora)(f.dataDoCommit, { fuso, agora: quando }), f.atualizado ? lido : m.ultimaCopia);
|
|
1043
1043
|
}
|
|
1044
|
-
function linhasDasMaquinas(x, fuso) {
|
|
1044
|
+
function linhasDasMaquinas(x, quando, fuso) {
|
|
1045
1045
|
const m = (0, locale_1.msg)().network.roadmap;
|
|
1046
1046
|
if (x.maquinas === null)
|
|
1047
1047
|
return [m.maquinasNaoLidas];
|
|
@@ -1051,11 +1051,11 @@ function linhasDasMaquinas(x, fuso) {
|
|
|
1051
1051
|
const quem = `${m.maquina}${m.estaMaquina ? (0, locale_1.msg)().network.roadmap.estaMaquina : ''}`;
|
|
1052
1052
|
// Fatia 3: a maquina so da rede por pessoa; as threads dela neste projeto nao foram lidas.
|
|
1053
1053
|
if (m.origem === 'rede') {
|
|
1054
|
-
return [(0, locale_1.msg)().network.roadmap.maquinaSoNaRede(quem, (0, horario_1.formatarDataHora)(m.publicadoEm, { fuso }), (0, horario_1.duracaoCurta)(m.idadeMin), m.semBatida, fabrica_estado_1.BRANCH_DA_FABRICA)];
|
|
1054
|
+
return [(0, locale_1.msg)().network.roadmap.maquinaSoNaRede(quem, (0, horario_1.formatarDataHora)(m.publicadoEm, { fuso, agora: quando }), (0, horario_1.duracaoCurta)(m.idadeMin), m.semBatida, fabrica_estado_1.BRANCH_DA_FABRICA)];
|
|
1055
1055
|
}
|
|
1056
1056
|
const rm = (0, locale_1.msg)().network.roadmap;
|
|
1057
1057
|
const batida = m.origem === 'estado-local' ? rm.estadoLocalAgora
|
|
1058
|
-
: rm.retrato((0, horario_1.formatarDataHora)(m.publicadoEm, { fuso }), (0, horario_1.duracaoCurta)(m.idadeMin), m.semBatida);
|
|
1058
|
+
: rm.retrato((0, horario_1.formatarDataHora)(m.publicadoEm, { fuso, agora: quando }), (0, horario_1.duracaoCurta)(m.idadeMin), m.semBatida);
|
|
1059
1059
|
const cabeca = rm.resumoMaquina(quem, m.ativas.length, m.entreguesSemMaster, batida);
|
|
1060
1060
|
// RM-037 (rm037noite, defeito 4): o runtime e o modelo de cada thread, quando o retrato os traz.
|
|
1061
1061
|
return [cabeca, ...m.ativas.map((t) => ` ${t.id} · ${t.modo} · ${t.fase} · ${t.roadmap ?? rm.semItem}` +
|
|
@@ -1063,30 +1063,34 @@ function linhasDasMaquinas(x, fuso) {
|
|
|
1063
1063
|
(t.esperaVoce ? rm.esperaVoce(t.pergunta ?? rm.veredito) : ''))];
|
|
1064
1064
|
});
|
|
1065
1065
|
}
|
|
1066
|
-
function linhasDasReservas(x, fuso) {
|
|
1066
|
+
function linhasDasReservas(x, quando, fuso) {
|
|
1067
1067
|
const m = (0, locale_1.msg)().network.roadmap;
|
|
1068
1068
|
if (x.reservas === null)
|
|
1069
1069
|
return [m.reservasNaoLidas];
|
|
1070
1070
|
if (x.reservas.length === 0)
|
|
1071
1071
|
return [m.nenhumaReserva];
|
|
1072
|
-
return x.reservas.map((r) => m.reserva(r.item, r.maquina, r.thread ?? m.semThread, (0, horario_1.formatarDataHora)(r.desdeEm, { fuso })));
|
|
1072
|
+
return x.reservas.map((r) => m.reserva(r.item, r.maquina, r.thread ?? m.semThread, (0, horario_1.formatarDataHora)(r.desdeEm, { fuso, agora: quando })));
|
|
1073
1073
|
}
|
|
1074
1074
|
/** Fatia 3: a casa da rede por pessoa e as maquinas dela, com a batida e os projetos que declaram. */
|
|
1075
1075
|
function linhasDaRede(r, quando, fuso) {
|
|
1076
1076
|
const x = (0, locale_1.msg)().network.roadmap;
|
|
1077
|
-
const lido = r.lidoEm === quando ? x.redeLidaAgora : x.redeLidaEm((0, horario_1.formatarDataHora)(r.lidoEm, { fuso }));
|
|
1077
|
+
const lido = r.lidoEm === quando ? x.redeLidaAgora : x.redeLidaEm((0, horario_1.formatarDataHora)(r.lidoEm, { fuso, agora: quando }));
|
|
1078
1078
|
const casa = !r.casa ? x.casaAusente
|
|
1079
1079
|
: r.atualizado === null ? x.casaNaoLida(r.casa)
|
|
1080
1080
|
: x.casaLida(r.casa, r.ponta ? r.ponta.slice(0, 7) : x.semCommit, r.atualizado ? lido : x.casaUltimaCopia);
|
|
1081
1081
|
if (r.membros.length === 0)
|
|
1082
1082
|
return [casa, x.nenhumRetrato];
|
|
1083
|
-
return [casa, ...r.membros.map((m) => x.membro(m.maquina, m.estaMaquina ? x.estaMaquina : '', (0, horario_1.formatarDataHora)(m.publicadoEm, { fuso }), m.idadeMin === null ? x.batidaIlegivel : x.idade((0, horario_1.duracaoCurta)(m.idadeMin)), m.semBatida, m.versaoOrk ? x.versao(m.versaoOrk) : '', m.projetos.length ? x.projetos(m.projetos.join(', ')) : x.nenhumProjeto))];
|
|
1083
|
+
return [casa, ...r.membros.map((m) => x.membro(m.maquina, m.estaMaquina ? x.estaMaquina : '', (0, horario_1.formatarDataHora)(m.publicadoEm, { fuso, agora: quando }), m.idadeMin === null ? x.batidaIlegivel : x.idade((0, horario_1.duracaoCurta)(m.idadeMin)), m.semBatida, m.versaoOrk ? x.versao(m.versaoOrk) : '', m.projetos.length ? x.projetos(m.projetos.join(', ')) : x.nenhumProjeto))];
|
|
1084
1084
|
}
|
|
1085
1085
|
const linhaDaLacuna = (l) => {
|
|
1086
1086
|
const m = (0, locale_1.msg)().network.roadmap;
|
|
1087
1087
|
return m.lacuna(l.tipo, l.alvo ? ` (${l.alvo})` : '', m.lacunaDetalhe(l.tipo, l.parte, l.alvo, l.detalhe), m.lacunaCorrecao(l.tipo, l.correcao));
|
|
1088
1088
|
};
|
|
1089
|
-
/**
|
|
1089
|
+
/**
|
|
1090
|
+
* O texto de `ork network roadmap`: o consultado e o nao consultado no alto, e cada parte com a fonte e a hora. RM-074 (F4):
|
|
1091
|
+
* as datas omitem o ano pelo ano da leitura (`consultadoEm`), nao pelo relogio de quem le o texto: o mesmo panorama da o
|
|
1092
|
+
* mesmo texto em qualquer dia, e o retrato pt-BR F3c nao fica vermelho na virada do ano.
|
|
1093
|
+
*/
|
|
1090
1094
|
function textoDoPanoramaDaRede(p) {
|
|
1091
1095
|
const m = (0, locale_1.msg)().network.roadmap;
|
|
1092
1096
|
if (p.contrato !== exports.CONTRATO_PANORAMA_DA_REDE)
|
|
@@ -1108,8 +1112,8 @@ function textoDoPanoramaDaRede(p) {
|
|
|
1108
1112
|
// Fatia 2 do ensaio (P7): o fuso ja sai no fim do panorama (e no bloco, quando difere): sem a legenda do status.
|
|
1109
1113
|
linhas.push(x.roadmap ? (0, roadmap_status_1.textoDoStatusDoRoadmap)(x.roadmap, fuso, { legenda: false })
|
|
1110
1114
|
: m.roadmapNaoLido(x.projeto.nome, x.lacunas.map((l) => l.tipo).filter((t) => t !== 'projeto.sem-clone').join(', ') || m.semFonte));
|
|
1111
|
-
linhas.push('', m.threadsPorMaquina, ...linhasDasMaquinas(x, fuso));
|
|
1112
|
-
linhas.push('', m.reservas, ...linhasDasReservas(x, fuso));
|
|
1115
|
+
linhas.push('', m.threadsPorMaquina, ...linhasDasMaquinas(x, p.consultadoEm, fuso));
|
|
1116
|
+
linhas.push('', m.reservas, ...linhasDasReservas(x, p.consultadoEm, fuso));
|
|
1113
1117
|
linhas.push('', m.fontes, ...(x.fontes.length ? x.fontes.map((f) => linhaDaFonte(f, p.consultadoEm, fuso)) : [m.nenhumaFonte]));
|
|
1114
1118
|
linhas.push('', m.lacunas, ...(x.lacunas.length ? x.lacunas.map(linhaDaLacuna) : [m.nenhumaLacuna]));
|
|
1115
1119
|
// A legenda e a da hora da leitura, como os horarios do panorama: com a de agora, o horario de verao mudava o texto.
|