@orkastery/cli 0.6.1 → 0.6.3
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/README.md +1 -1
- 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/hermes/README.md +1 -1
- package/adapters/openclaw/openclaw.plugin.json +1 -1
- package/adapters/openclaw/package.json +1 -1
- package/assets/adapters-en/claude-code/README.md +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/adapters-en/hermes/README.md +1 -1
- package/assets/docs/padroes/roadmap-de-produto.md +1 -1
- package/assets/docs-en/padroes/roadmap-de-produto.md +1 -1
- package/assets/orkmind_fixture.py +4 -1
- package/assets/references-en/testing-patterns.md +1 -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 +3 -1
- package/dist/adapters/grok-mcp-servidor.js +22 -12
- package/dist/adapters/grok.js +1 -1
- package/dist/agendador-cpu.js +10 -2
- package/dist/catalogo.js +3 -3
- package/dist/{canarios-hitl.js → cenarios-hitl.js} +7 -7
- package/dist/{canarios-i43.js → cenarios-i43.js} +16 -16
- package/dist/{canarios-pulse.js → cenarios-pulse.js} +3 -3
- package/dist/{canarios-rm057.js → cenarios-rm057.js} +3 -3
- package/dist/{canarios-sensores.js → cenarios-sensores.js} +5 -5
- package/dist/{canarios.js → cenarios.js} +22 -22
- package/dist/changelog-check.js +217 -0
- package/dist/check-agil.js +242 -5
- package/dist/check-paralelo.js +17 -4
- package/dist/ci.js +3 -2
- package/dist/claim-lint.js +29 -0
- package/dist/claims.js +5 -1
- package/dist/docs.js +8 -1
- package/dist/evalrunner.js +37 -37
- package/dist/fila-pesada.js +121 -11
- package/dist/hitl-canais.js +1 -1
- package/dist/hitl-classificacao.js +1 -0
- package/dist/hitl-presentation.js +1 -1
- package/dist/hitl-tempo-parado.js +1 -1
- package/dist/index.js +47 -29
- package/dist/init.js +1 -1
- package/dist/intelligence-graph-cli.js +27 -9
- package/dist/locale-ajuda.js +6 -6
- package/dist/locale-claims.js +16 -2
- 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 +18 -18
- 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 +16 -0
- package/dist/locale-security-scan.js +35 -1
- package/dist/locale-verify.js +15 -0
- package/dist/locale.js +24 -7
- package/dist/maestro-cli.js +12 -17
- package/dist/mcp-install.js +2 -1
- package/dist/mcp-server.js +20 -17
- 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/pedido-conducao.js +51 -0
- package/dist/preflight.js +25 -26
- package/dist/prompts.js +4 -2
- package/dist/pulse.js +4 -2
- package/dist/rede.js +24 -12
- package/dist/retry.js +12 -0
- package/dist/sandbox.js +11 -11
- package/dist/security-scan/cli.js +2 -2
- package/dist/security-scan/report.js +1 -1
- package/dist/session-watcher.js +33 -7
- package/dist/verify.js +166 -34
- package/eval/README.md +8 -8
- package/eval/fixtures/fx-codex-dry/caso.json +1 -1
- package/eval/fixtures/fx-happy/caso.json +1 -1
- package/eval/fixtures/fx-indice-reversao/caso.json +1 -1
- package/eval/fixtures/fx-listagem-abertas/caso.json +1 -1
- package/eval/fixtures/fx-omnicanal/caso.json +1 -1
- package/eval/fixtures/fx-pedido-colado/caso.json +1 -1
- package/eval/fixtures/fx-schema-drift/caso.json +1 -1
- package/package.json +1 -1
- package/references/testing-patterns.md +1 -1
- package/skills/core/orkastery-bootstrap/SKILL.md +1 -1
- package/skills/phases/check-quality/SKILL.md +1 -1
- package/skills/phases/go-implementation/SKILL.md +1 -1
package/dist/locale-verify.js
CHANGED
|
@@ -82,6 +82,14 @@ exports.VERIFY_PT_BR = {
|
|
|
82
82
|
semVeredito: (nomes) => `Sem veredito por tempo (nao e reprovacao: prazo estourado ou relogio sob steal): ${nomes}`,
|
|
83
83
|
// Classificacao e veredito
|
|
84
84
|
classificacao: (regressoes, preExistentes, semBaseline) => `Classificacao: ${regressoes} regressao(oes), ${preExistentes} pre-existente(s), ${semBaseline} falha(s) sem baseline`,
|
|
85
|
+
comparacaoPorTeste: (comando, regressoes, preExistentes, corrigidos) => `Comparacao teste a teste (${comando}): ${regressoes} regressao(oes), ${preExistentes} pre-existente(s), ` +
|
|
86
|
+
`${corrigidos} corrigido(s)`,
|
|
87
|
+
testeRegressao: (nome) => ` regressao ${nome}`,
|
|
88
|
+
testePreExistente: (nome) => ` pre-existente ${nome}`,
|
|
89
|
+
testeCorrigido: (nome) => ` corrigido ${nome}`,
|
|
90
|
+
comparacaoPorComando: (comando, classificacao, motivo) => `Comparacao somente por comando (${comando}): ${classificacao}; ${motivo === 'baseline-sem-nomes'
|
|
91
|
+
? 'a baseline nao guardou nomes de testes' : 'a rodada atual nao informou nomes de testes'}. ` +
|
|
92
|
+
'Nenhuma contagem de regressoes por teste foi calculada.',
|
|
85
93
|
regressao: (nome, comando) => ` regressao ${nome}: ${comando}`,
|
|
86
94
|
preExistente: (nome, comando) => ` pre-existente ${nome}: ${comando}`,
|
|
87
95
|
falhaSemBaseline: (nome, comando) => ` sem baseline ${nome}: ${comando}`,
|
|
@@ -171,6 +179,13 @@ exports.VERIFY_EN = {
|
|
|
171
179
|
falhou: (code) => `FAILED (exit ${code})`,
|
|
172
180
|
semVeredito: (nomes) => `No verdict for lack of time (not a failure: deadline exceeded or clock under steal): ${nomes}`,
|
|
173
181
|
classificacao: (regressoes, preExistentes, semBaseline) => `Classification: ${regressoes} regression(s), ${preExistentes} pre-existing, ${semBaseline} failure(s) without a baseline`,
|
|
182
|
+
comparacaoPorTeste: (comando, regressoes, preExistentes, corrigidos) => `Test-by-test comparison (${comando}): ${regressoes} regression(s), ${preExistentes} pre-existing, ${corrigidos} fixed`,
|
|
183
|
+
testeRegressao: (nome) => ` regression ${nome}`,
|
|
184
|
+
testePreExistente: (nome) => ` pre-existing ${nome}`,
|
|
185
|
+
testeCorrigido: (nome) => ` fixed ${nome}`,
|
|
186
|
+
comparacaoPorComando: (comando, classificacao, motivo) => `Command-only comparison (${comando}): ${classificacao === 'regressao' ? 'regression' : classificacao === 'pre-existente'
|
|
187
|
+
? 'pre-existing' : 'fixed'}; ${motivo === 'baseline-sem-nomes' ? 'the baseline did not store test names'
|
|
188
|
+
: 'the current run did not report test names'}. No per-test regression count was calculated.`,
|
|
174
189
|
regressao: (nome, comando) => ` regression ${nome}: ${comando}`,
|
|
175
190
|
preExistente: (nome, comando) => ` pre-existing ${nome}: ${comando}`,
|
|
176
191
|
falhaSemBaseline: (nome, comando) => ` no baseline ${nome}: ${comando}`,
|
package/dist/locale.js
CHANGED
|
@@ -108,22 +108,25 @@ const locale_operacao_restante_1 = require("./locale-operacao-restante");
|
|
|
108
108
|
const locale_conducao_1 = require("./locale-conducao");
|
|
109
109
|
const locale_grafo_1 = require("./locale-grafo");
|
|
110
110
|
const locale_audit_1 = require("./locale-audit");
|
|
111
|
+
const locale_preflight_1 = require("./locale-preflight");
|
|
112
|
+
const locale_maestro_1 = require("./locale-maestro");
|
|
111
113
|
exports.LOCALE_PADRAO = 'pt-BR';
|
|
112
114
|
/**
|
|
113
115
|
* Comandos cujo texto ja sai pelo catalogo, por `comando` ou por `comando subcomando`; `comando ?` e o
|
|
114
116
|
* subcomando desconhecido (o erro de uso e do proprio comando). Os demais seguem em pt-BR. Ficam de
|
|
115
|
-
* fora por decisao (D2 da F2a): `
|
|
116
|
-
* `experiencia uninstall`. A F2b (G3) acrescenta `verify` (com `--baseline`),
|
|
117
|
+
* fora por decisao (D2 da F2a): `thread new --from-finding`. A F3e acrescenta `doctor --modo`,
|
|
118
|
+
* `onboarding sync` e `experiencia uninstall`. A F2b (G3) acrescenta `verify` (com `--baseline`),
|
|
117
119
|
* `ship`, `ship registrar-pr`, `retry plan`, `retry run`, `master` (o indice), `master aceitar-omissao` e
|
|
118
120
|
* `master pedir`, `pulse` (sem `responder` nem `cadencia`) e `roadmap status`. A F3a (D5) acrescenta `docs init`, e a
|
|
119
121
|
* F3b (D1), o resto da lista do dono; a F3c completa `decisao registrar` e `network roadmap`. O conhecimento escrito
|
|
120
122
|
* (RM-026 K7, fatia 2) nasce coberto: `conhecimento listar|mostrar|colecoes|verificar` e o uso errado dele.
|
|
121
123
|
*/
|
|
122
124
|
exports.COMANDOS_COM_LOCALE = ['doctor', 'init', 'onboarding show', 'onboarding set', 'onboarding reset',
|
|
123
|
-
'onboarding ?', 'experiencia show', 'experiencia ?', 'thread new', 'thread status', 'thread ?',
|
|
125
|
+
'onboarding sync', 'onboarding ?', 'experiencia show', 'experiencia uninstall', 'experiencia ?', 'thread new', 'thread status', 'thread ?',
|
|
124
126
|
'phase list', 'phase run', 'phase ?', 'verify', 'ship', 'ship registrar-pr', 'retry plan', 'retry run',
|
|
125
127
|
'retry policy', 'retry parse', 'retry list', 'retry resume', 'retry cancel', 'retry ?',
|
|
126
|
-
'master', 'master <thread>', 'master aceitar-omissao', 'master pedir', 'master
|
|
128
|
+
'master', 'master <thread>', 'master aceitar-omissao', 'master pedir', 'master audit', 'master digest', 'master migrar',
|
|
129
|
+
'master classes', 'master ratificar', 'master batch', 'master propor',
|
|
127
130
|
'pulse', 'roadmap status', 'docs init',
|
|
128
131
|
// F3b (D1): o resto do CLI, na ordem do pedido.
|
|
129
132
|
'thread list', 'thread close', 'thread entrega', 'worktree ensure', 'worktree sync', 'worktree audit', 'worktree release', 'worktree ?',
|
|
@@ -151,7 +154,7 @@ exports.COMANDOS_COM_LOCALE = ['doctor', 'init', 'onboarding show', 'onboarding
|
|
|
151
154
|
'orquestracao status', 'orquestracao ?', 'monitor', 'licoes', 'demo',
|
|
152
155
|
'fabrica list', 'fabrica publicar', 'fabrica entrar', 'fabrica sair', 'fabrica batida', 'fabrica ?', 'eval',
|
|
153
156
|
'memory status', 'memory inventory', 'memory migrate', 'memory sync', 'memory search', 'memory index', 'memory ?',
|
|
154
|
-
'mcp install', 'conducao status', 'conducao assumir', 'conducao atualizar', 'conducao autorizar',
|
|
157
|
+
'mcp install', 'mcp serve', 'mcp ?', 'brain', 'activation', 'conducao status', 'conducao assumir', 'conducao atualizar', 'conducao autorizar',
|
|
155
158
|
'conducao autorizacao', 'conducao batida', 'conducao sentinela', 'conducao ?', 'grafo',
|
|
156
159
|
'audit packs', 'audit pack', 'audit lint', 'audit run', 'audit list', 'audit show', 'audit prompt',
|
|
157
160
|
'audit ingest', 'audit finding', 'audit achado', 'audit verify', 'audit report', 'audit relatorio',
|
|
@@ -226,8 +229,6 @@ function chaveDoMaster(bruto, opcoes) {
|
|
|
226
229
|
function cobreLocale(posicionais, opcoes) {
|
|
227
230
|
if (opcoes.json !== undefined)
|
|
228
231
|
return false;
|
|
229
|
-
if (posicionais[0] === 'doctor' && opcoes.modo !== undefined)
|
|
230
|
-
return false;
|
|
231
232
|
return exports.COMANDOS_COM_LOCALE.includes(chaveDoLocale(posicionais, opcoes));
|
|
232
233
|
}
|
|
233
234
|
/** `en_US.UTF-8`, `en-GB`, `en` viram `en`; `pt_BR.UTF-8`, `pt` viram pt-BR; o resto, undefined. */
|
|
@@ -293,7 +294,14 @@ const PT_BR = {
|
|
|
293
294
|
subcomandoDesconhecido: (comando, sub) => `subcomando desconhecido: ${comando} ${sub}`,
|
|
294
295
|
/** `exigirManifesto` fora de um projeto: o primeiro erro de quem chega (D14). */
|
|
295
296
|
manifestoNaoEncontrado: (nome, dir) => `manifesto ${nome} nao encontrado a partir de ${dir}. Rode: ork init`,
|
|
297
|
+
receiptVerifiersUso: 'uso: ork receipt-verifiers --json',
|
|
298
|
+
activationUso: 'uso: ork activation plan|status|enable|disable',
|
|
299
|
+
masterDigestUso: 'uso: ork master digest <enviar|preview|responder>',
|
|
300
|
+
masterRatificarUso: 'resposta deve ser ratificar <thread> <assinatura> <classe>',
|
|
301
|
+
masterSelecaoUso: 'seleção deve ser thread:assinatura',
|
|
296
302
|
},
|
|
303
|
+
preflight: locale_preflight_1.PREFLIGHT_PT_BR,
|
|
304
|
+
maestro: locale_maestro_1.MAESTRO_PT_BR,
|
|
297
305
|
horario: {
|
|
298
306
|
brasilia: 'horário de Brasília',
|
|
299
307
|
legendaBrasilia: 'Horários de Brasília.',
|
|
@@ -307,6 +315,7 @@ const PT_BR = {
|
|
|
307
315
|
},
|
|
308
316
|
doctor: {
|
|
309
317
|
titulo: 'ork doctor: o que vale nesta maquina agora',
|
|
318
|
+
modoUso: (modos) => `uso: ork doctor --modo ${modos}`,
|
|
310
319
|
correcao: 'correcao',
|
|
311
320
|
bloqueado: (falhas, avisos) => `Veredito: BLOQUEADO (${falhas} fail, ${avisos} warn). Corrija os itens acima antes de despachar fase.`,
|
|
312
321
|
pronto: (avisos) => `Veredito: PRONTO (${avisos} warn). Despacho de fase liberado por \`ork phase run\`.`,
|
|
@@ -731,7 +740,14 @@ const EN = {
|
|
|
731
740
|
erro: (mensagem) => `error: ${mensagem}`,
|
|
732
741
|
subcomandoDesconhecido: (comando, sub) => sub === undefined ? `missing subcommand: ${comando}` : `unknown subcommand: ${comando} ${sub}`,
|
|
733
742
|
manifestoNaoEncontrado: (nome, dir) => `\`${nome}\` not found in ${dir} or any parent directory; run \`ork init\` first.`,
|
|
743
|
+
receiptVerifiersUso: 'usage: ork receipt-verifiers --json',
|
|
744
|
+
activationUso: 'usage: ork activation plan|status|enable|disable',
|
|
745
|
+
masterDigestUso: 'usage: ork master digest <enviar|preview|responder>',
|
|
746
|
+
masterRatificarUso: 'the response must be ratificar <thread> <signature> <class>',
|
|
747
|
+
masterSelecaoUso: 'the selection must be thread:signature',
|
|
734
748
|
},
|
|
749
|
+
preflight: locale_preflight_1.PREFLIGHT_EN,
|
|
750
|
+
maestro: locale_maestro_1.MAESTRO_EN,
|
|
735
751
|
horario: {
|
|
736
752
|
brasilia: 'Brasília time',
|
|
737
753
|
legendaBrasilia: 'Times in Brasília time.',
|
|
@@ -744,6 +760,7 @@ const EN = {
|
|
|
744
760
|
},
|
|
745
761
|
doctor: {
|
|
746
762
|
titulo: 'ork doctor: what holds on this machine now',
|
|
763
|
+
modoUso: (modes) => `usage: ork doctor --modo ${modes}`,
|
|
747
764
|
correcao: 'fix',
|
|
748
765
|
bloqueado: (falhas, avisos) => `Verdict: BLOCKED (${falhas} fail, ${avisos} warn). Fix the items above before dispatching a phase.`,
|
|
749
766
|
pronto: (avisos) => `Verdict: READY (${avisos} warn). Phase dispatch allowed through \`ork phase run\`.`,
|
package/dist/maestro-cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const maestro_sources_1 = require("./maestro-sources");
|
|
|
10
10
|
const maestro_actions_1 = require("./maestro-actions");
|
|
11
11
|
const maestro_runtime_1 = require("./maestro-runtime");
|
|
12
12
|
const horario_1 = require("./horario");
|
|
13
|
+
const locale_maestro_1 = require("./locale-maestro");
|
|
13
14
|
function readMaestro(context, options) {
|
|
14
15
|
const observations = options.native && options.threadId ? (0, maestro_runtime_1.nativeForThread)(context.root, options.threadId) : [];
|
|
15
16
|
return (0, maestro_snapshot_1.maestroSnapshot)(context, { ...options, collect: ctx => {
|
|
@@ -31,31 +32,25 @@ function readMaestro(context, options) {
|
|
|
31
32
|
return sources;
|
|
32
33
|
} });
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
const ORIGEM_DO_PANORAMA = Object.freeze({
|
|
36
|
-
installation: 'fixado na instalação', cwd: 'pelo diretório atual', worktree: 'pela worktree da thread',
|
|
37
|
-
selection: 'pedido explicitamente (--projeto ou ORK_PROJETO)',
|
|
38
|
-
});
|
|
39
|
-
function maestroText(snapshot) {
|
|
35
|
+
function maestroText(snapshot, textos = locale_maestro_1.MAESTRO_PT_BR) {
|
|
40
36
|
const p = snapshot.project;
|
|
41
|
-
return [
|
|
37
|
+
return [textos.titulo(p.name),
|
|
42
38
|
// I-35: o snapshot guarda ISO; o texto ao dono diz quando consultou, no fuso dele.
|
|
43
|
-
|
|
39
|
+
textos.consulta((0, horario_1.formatarDataHoraRotulada)(snapshot.observedAt, { agora: snapshot.observedAt })),
|
|
44
40
|
// RM-052: qual cópia foi lida e o que o panorama não lê, antes de qualquer seção.
|
|
45
|
-
|
|
46
|
-
...(snapshot.notConsulted?.length ? [
|
|
41
|
+
textos.projeto(p.name, p.root ?? '', p.remote === null ? textos.semRemoto : p.remote, textos.origem[p.origin]),
|
|
42
|
+
...(snapshot.notConsulted?.length ? [textos.naoLido(snapshot.notConsulted.join(' · '))] : []),
|
|
47
43
|
...maestro_contract_1.SECTION_NAMES.map(name => {
|
|
48
44
|
const s = snapshot.sections[name];
|
|
49
|
-
return
|
|
45
|
+
return textos.secao(name, s.state, s.coverage.returned, s.coverage.total, !!s.coverage.omitted);
|
|
50
46
|
}),
|
|
51
|
-
...snapshot.sections.threads.items.slice(0, 8).map(t =>
|
|
52
|
-
|
|
53
|
-
'Use ork maestro --json para cobertura e ações; --thread ID consulta o detalhe nativo.',
|
|
47
|
+
...snapshot.sections.threads.items.slice(0, 8).map(t => textos.thread(t.title, String(t.facts.phase), t.status)),
|
|
48
|
+
textos.recomendacao(snapshot.conflicts.length, snapshot.gaps.length), textos.final,
|
|
54
49
|
].join('\n');
|
|
55
50
|
}
|
|
56
|
-
function runMaestroCli(argv, cwd = process.cwd(), trusted = {}, io = { out: (v) => console.log(v), err: (v) => console.error(v) }) {
|
|
51
|
+
function runMaestroCli(argv, cwd = process.cwd(), trusted = {}, io = { out: (v) => console.log(v), err: (v) => console.error(v) }, textos = locale_maestro_1.MAESTRO_PT_BR) {
|
|
57
52
|
if (argv.length === 1 && argv[0] === '--help') {
|
|
58
|
-
io.out(
|
|
53
|
+
io.out(textos.help);
|
|
59
54
|
return 0;
|
|
60
55
|
}
|
|
61
56
|
try {
|
|
@@ -94,7 +89,7 @@ function runMaestroCli(argv, cwd = process.cwd(), trusted = {}, io = { out: (v)
|
|
|
94
89
|
const context = (0, maestro_discovery_1.discoverMaestro)({ cwd, ...trusted });
|
|
95
90
|
const snapshot = readMaestro(context, { threadId, offsets: section ? { [section]: offset } : undefined, native: true,
|
|
96
91
|
host: { tools: ['ork_thread_status', 'ork_observe', 'ork_git_status'], child: false } });
|
|
97
|
-
io.out(json ? JSON.stringify(snapshot) : maestroText(snapshot));
|
|
92
|
+
io.out(json ? JSON.stringify(snapshot) : maestroText(snapshot, textos));
|
|
98
93
|
return 0;
|
|
99
94
|
}
|
|
100
95
|
catch (e) {
|
package/dist/mcp-install.js
CHANGED
|
@@ -55,7 +55,8 @@ const IMPRESSAO_SSH = /^SHA256:[A-Za-z0-9+/]{43}$/;
|
|
|
55
55
|
exports.TOOLS_DONO_CODEX = ['ork_thread_new', 'ork_phase_run', 'ork_request_decision'];
|
|
56
56
|
// RM-037 (rm037defeito, defeito 1): a decisao autonoma da sessao entra com as outras mutacoes do filho;
|
|
57
57
|
// sem o grant, o codex com approval_policy never recusaria a chamada.
|
|
58
|
-
exports.TOOLS_FILHO_CODEX = ['ork_artifact_write', 'ork_claim_add', 'ork_decision_record', '
|
|
58
|
+
exports.TOOLS_FILHO_CODEX = ['ork_artifact_write', 'ork_claim_add', 'ork_decision_record', 'ork_request_conduction',
|
|
59
|
+
'ork_git_commit', 'ork_verify', 'ork_verify_status', 'ork_ship'];
|
|
59
60
|
// Brain mutation tools are deliberately excluded from the existing opt-in bundle.
|
|
60
61
|
// A native integration must request exact startup grants plus scoped activation.
|
|
61
62
|
var company_brain_mcp_1 = require("./company-brain-mcp");
|
package/dist/mcp-server.js
CHANGED
|
@@ -70,9 +70,7 @@ const preflight_1 = require("./preflight");
|
|
|
70
70
|
const modos_1 = require("./modos");
|
|
71
71
|
const mcp_noctum_1 = require("./mcp-noctum");
|
|
72
72
|
const versao_1 = require("./versao");
|
|
73
|
-
const mcp_verify_1 = require("./mcp-verify");
|
|
74
73
|
const conducao_1 = require("./conducao");
|
|
75
|
-
const fila_pesada_1 = require("./fila-pesada");
|
|
76
74
|
const decisao_autonoma_1 = require("./decisao-autonoma");
|
|
77
75
|
const conducao_texto_1 = require("./conducao-texto");
|
|
78
76
|
const mcp_ship_1 = require("./mcp-ship");
|
|
@@ -87,6 +85,7 @@ const mcp_experiencia_1 = require("./mcp-experiencia");
|
|
|
87
85
|
const mcp_grafo_1 = require("./mcp-grafo");
|
|
88
86
|
const mcp_conhecimento_1 = require("./mcp-conhecimento");
|
|
89
87
|
const locale_1 = require("./locale");
|
|
88
|
+
const pedido_conducao_1 = require("./pedido-conducao");
|
|
90
89
|
const identidade = zod_1.z.string().min(1).max(80).regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/);
|
|
91
90
|
const daThread = zod_1.z.object({ threadId: identidade }).strict();
|
|
92
91
|
const daDecisao = daThread.extend({ pedidoId: identidade }).strict();
|
|
@@ -456,23 +455,20 @@ function criarServidorMcp(opcoes) {
|
|
|
456
455
|
const r = await (0, mcp_ship_1.shipMcp)(perfilShip, args, extra.signal);
|
|
457
456
|
return { ...resposta(r), ...(r.ok ? {} : { isError: true }) };
|
|
458
457
|
});
|
|
459
|
-
registrarTool('ork_verify', { description: '
|
|
458
|
+
registrarTool('ork_verify', { description: 'Inicia uma rodada assíncrona do verify canônico no processo do servidor, vinculada à thread e ao despacho. Devolve imediatamente o UUID; repetir enquanto viva reutiliza a rodada.',
|
|
460
459
|
inputSchema: daThread, annotations: { readOnlyHint: false, destructiveHint: false } }, async ({ threadId }) => {
|
|
461
460
|
thread(threadId);
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
return { ...resposta(e.recusa), isError: true };
|
|
474
|
-
throw e;
|
|
475
|
-
}
|
|
461
|
+
const { iniciarVerifyMcp } = await Promise.resolve().then(() => __importStar(require('./mcp-verify-async')));
|
|
462
|
+
const r = iniciarVerifyMcp(raiz, threadId, { host: opcoes.host, despacho: opcoes.dispatchId ?? null });
|
|
463
|
+
return { ...resposta(r), ...(r.estado === 'falhou' ? { isError: true } : {}) };
|
|
464
|
+
});
|
|
465
|
+
registrarTool('ork_verify_status', { description: 'Consulta uma rodada assíncrona do verify por UUID: na fila, rodando com a lane atual, concluída com o veredito completo do CLI ou falha tipada. Não inicia nem duplica rodada.',
|
|
466
|
+
inputSchema: daThread.extend({ rodadaId: zod_1.z.string().uuid() }).strict(), annotations: { readOnlyHint: true, destructiveHint: false } }, async ({ threadId, rodadaId }) => {
|
|
467
|
+
thread(threadId);
|
|
468
|
+
const { consultarVerifyMcp } = await Promise.resolve().then(() => __importStar(require('./mcp-verify-async')));
|
|
469
|
+
const r = consultarVerifyMcp(raiz, threadId, rodadaId);
|
|
470
|
+
const reprovou = r.estado === 'falhou' || (r.estado === 'concluido' && r.veredito?.ok === false);
|
|
471
|
+
return { ...resposta(r), ...(reprovou ? { isError: true } : {}) };
|
|
476
472
|
});
|
|
477
473
|
registrarTool('ork_git_commit', { description: 'Commita somente paths com claims e HEAD esperado na worktree da thread. Recusa hooks/filtros ativos; preserva configuracao. Commit local nao e SHIP.',
|
|
478
474
|
inputSchema: daThread.extend({ expectedHead: zod_1.z.string().regex(/^[a-f0-9]{40}$/),
|
|
@@ -649,6 +645,13 @@ function criarServidorMcp(opcoes) {
|
|
|
649
645
|
});
|
|
650
646
|
if (opcoes.threadId && opcoes.dispatchId) {
|
|
651
647
|
const despacho = opcoes.dispatchId;
|
|
648
|
+
registrarTool('ork_request_conduction', { description: 'Registra um pedido tipado desta sessao para a conducao, com comando ork exato. Nao executa o comando, nao aprova gate e nao responde pelo dono.',
|
|
649
|
+
inputSchema: daThread.extend({ motivo: zod_1.z.enum(pedido_conducao_1.MOTIVOS_DE_PEDIDO_A_CONDUCAO), detalhe: zod_1.z.string().trim().min(1).max(2000),
|
|
650
|
+
comando: zod_1.z.string().trim().min(1).max(1000) }).strict(),
|
|
651
|
+
annotations: { readOnlyHint: false, destructiveHint: false } }, async ({ threadId, motivo, detalhe, comando }) => {
|
|
652
|
+
thread(threadId);
|
|
653
|
+
return resposta((0, pedido_conducao_1.registrarPedidoAConducao)(raiz, threadId, { despacho, motivo, detalhe, comando, host: opcoes.host }));
|
|
654
|
+
});
|
|
652
655
|
registrarTool('ork_session_inbox', { description: 'Lado receptor do Mensageiro de Sessoes na sessao de fase deste despacho: confere e reserva uma vez a resposta do dono que chegou de outra sessao (conferir, com o prazo ate) e, depois de ela entrar na fila, grava o recibo (confirmar). A sessao sai do despacho deste servidor, nunca de argumento. Nao responde nem aprova pedido.',
|
|
653
656
|
inputSchema: daThread.extend({ operacao: zod_1.z.enum(['conferir', 'confirmar']), texto: zod_1.z.string().max(entrega_por_mod_1.LIMITE_DA_MENSAGEM),
|
|
654
657
|
envioId: zod_1.z.string().uuid().optional(), ate: zod_1.z.string().max(40).optional() }).strict(),
|
|
@@ -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
|
+
}
|