@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.
Files changed (118) hide show
  1. package/adapters/claude-code/agents/ork-check.md +1 -1
  2. package/adapters/claude-code/agents/ork-go.md +1 -1
  3. package/adapters/claude-code/agents/ork-goal.md +1 -1
  4. package/adapters/claude-code/agents/ork-master.md +1 -1
  5. package/adapters/claude-code/agents/ork-plan.md +1 -1
  6. package/adapters/claude-code/agents/ork-ship.md +1 -1
  7. package/adapters/claude-code/commands/ork.md +1 -1
  8. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +2 -0
  9. package/adapters/codex/skills/ork/SKILL.md +1 -1
  10. package/adapters/openclaw/openclaw.plugin.json +1 -1
  11. package/adapters/openclaw/package.json +1 -1
  12. package/assets/adapters-en/claude-code/agents/ork-check.md +1 -1
  13. package/assets/adapters-en/claude-code/agents/ork-go.md +1 -1
  14. package/assets/adapters-en/claude-code/agents/ork-goal.md +1 -1
  15. package/assets/adapters-en/claude-code/agents/ork-master.md +1 -1
  16. package/assets/adapters-en/claude-code/agents/ork-plan.md +1 -1
  17. package/assets/adapters-en/claude-code/agents/ork-ship.md +1 -1
  18. package/assets/adapters-en/claude-code/commands/ork.md +1 -1
  19. package/assets/adapters-en/codex/skills/ork/SKILL.md +1 -1
  20. package/assets/orkmind_fixture.py +4 -1
  21. package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +1 -1
  22. package/assets/skills-en/phases/check-quality/SKILL.md +1 -1
  23. package/assets/skills-en/phases/go-implementation/SKILL.md +1 -1
  24. package/dist/adapters/claude-bg.js +9 -7
  25. package/dist/adapters/grok-events.js +227 -0
  26. package/dist/adapters/grok-mcp-servidor.js +622 -0
  27. package/dist/adapters/grok-mcp.js +178 -0
  28. package/dist/adapters/grok.js +686 -0
  29. package/dist/agendador-cpu.js +92 -0
  30. package/dist/branch-de-estado.js +7 -2
  31. package/dist/changelog-check.js +217 -0
  32. package/dist/check-agil.js +289 -25
  33. package/dist/check-paralelo.js +73 -18
  34. package/dist/ci.js +3 -2
  35. package/dist/claim-lint.js +29 -0
  36. package/dist/claims.js +4 -0
  37. package/dist/conducao.js +5 -0
  38. package/dist/docs.js +16 -16
  39. package/dist/doctor-forja.js +1 -3
  40. package/dist/doctor.js +1 -1
  41. package/dist/entrega-pr.js +10 -10
  42. package/dist/fabrica-estado.js +20 -11
  43. package/dist/fila-pesada.js +121 -11
  44. package/dist/hitl-classificacao.js +1 -0
  45. package/dist/horario.js +4 -1
  46. package/dist/index.js +63 -35
  47. package/dist/integracoes-locais.js +2 -0
  48. package/dist/intelligence-graph-cli.js +27 -9
  49. package/dist/locale-accounts.js +11 -3
  50. package/dist/locale-ajuda.js +10 -6
  51. package/dist/locale-claims.js +16 -2
  52. package/dist/locale-forja.js +2 -4
  53. package/dist/locale-grafo.js +56 -1
  54. package/dist/locale-maestro.js +38 -0
  55. package/dist/locale-network.js +8 -6
  56. package/dist/locale-onboarding.js +14 -0
  57. package/dist/locale-operacao-restante.js +2 -2
  58. package/dist/locale-preflight.js +80 -0
  59. package/dist/locale-projetos.js +6 -0
  60. package/dist/locale-prompts.js +8 -8
  61. package/dist/locale-pulse.js +4 -0
  62. package/dist/locale-retry.js +56 -2
  63. package/dist/locale-security-scan.js +35 -1
  64. package/dist/locale-ship.js +10 -2
  65. package/dist/locale-verify.js +15 -0
  66. package/dist/locale.js +24 -7
  67. package/dist/maestro-cli.js +12 -17
  68. package/dist/manifest.js +6 -1
  69. package/dist/mcp-install.js +24 -13
  70. package/dist/mcp-server.js +62 -33
  71. package/dist/mcp-verify-async.js +353 -0
  72. package/dist/mcp-verify-worker.js +17 -0
  73. package/dist/mcp-verify.js +10 -1
  74. package/dist/merge-da-entrega.js +85 -0
  75. package/dist/network-roadmap.js +18 -14
  76. package/dist/noctum-aceite.js +154 -14
  77. package/dist/noctum-cli.js +69 -12
  78. package/dist/noctum-entrega.js +55 -7
  79. package/dist/noctum-envelope.js +1 -1
  80. package/dist/noctum-execucao.js +5 -1
  81. package/dist/noctum-fechamento.js +18 -7
  82. package/dist/noctum-fila.js +6 -1
  83. package/dist/noctum-guarda.js +81 -4
  84. package/dist/noctum-maquinas.js +5 -1
  85. package/dist/noctum-modo.js +35 -7
  86. package/dist/noctum-reconciliacao.js +4 -1
  87. package/dist/noctum-rede.js +102 -0
  88. package/dist/noctum-relatorio.js +44 -10
  89. package/dist/noctum-retomada-rede.js +71 -0
  90. package/dist/noctum-vigia.js +49 -9
  91. package/dist/parado-no-condutor.js +14 -15
  92. package/dist/pedido-conducao.js +51 -0
  93. package/dist/phase.js +43 -15
  94. package/dist/postura-local.js +7 -3
  95. package/dist/preflight.js +27 -27
  96. package/dist/prompts.js +4 -2
  97. package/dist/pulse.js +4 -2
  98. package/dist/ratelimit.js +1 -0
  99. package/dist/rede.js +24 -12
  100. package/dist/retry.js +115 -10
  101. package/dist/runtime-context.js +165 -45
  102. package/dist/runtime-escada.js +7 -1
  103. package/dist/runtime-profiles.js +27 -17
  104. package/dist/runtimes.js +42 -5
  105. package/dist/security-scan/agil.js +18 -7
  106. package/dist/security-scan/cli.js +2 -2
  107. package/dist/security-scan/executor.js +8 -0
  108. package/dist/security-scan/report.js +1 -1
  109. package/dist/session-watcher-grok.js +425 -0
  110. package/dist/session-watcher.js +52 -11
  111. package/dist/sessoes-contas.js +33 -5
  112. package/dist/setup.js +11 -11
  113. package/dist/varredura-acoes.js +8 -15
  114. package/dist/verify.js +191 -43
  115. package/package.json +2 -2
  116. package/skills/core/orkastery-bootstrap/SKILL.md +1 -1
  117. package/skills/phases/check-quality/SKILL.md +1 -1
  118. 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
+ }
@@ -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
- regressoes: r.regressoes.map(c => c.nome), preExistentes: r.preExistentes.map(c => c.nome),
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
+ }
@@ -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
- /** O texto de `ork network roadmap`: o consultado e o nao consultado no alto, e cada parte com a fonte e a hora. */
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.