@orkastery/cli 0.5.1 → 0.5.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/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/ork.md +9 -0
- package/adapters/codex/skills/ork/SKILL.md +18 -3
- package/adapters/hermes/README.md +1 -0
- package/adapters/hermes/bin/ork-network-status.sh +10 -0
- package/adapters/hermes/hermes.plugin.json +1 -0
- package/adapters/hermes/hitl-ingress/__init__.py +2 -2
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
- package/adapters/openclaw/README.md +24 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +46 -11
- package/adapters/openclaw/openclaw.plugin.json +5 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +2 -2
- package/adapters/openclaw/src/index.ts +49 -11
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +39 -5
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +5 -1
- package/dist/board.js +16 -14
- package/dist/branch-de-estado.js +66 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/ci.js +8 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +48 -9
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +89 -9
- package/dist/entrega-pr.js +20 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +14 -6
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/forja.js +31 -7
- package/dist/gates.js +5 -1
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +9 -0
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/horario.js +27 -0
- package/dist/hosts.js +52 -10
- package/dist/impedimento.js +205 -0
- package/dist/index.js +391 -74
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +17 -0
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +91 -8
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +3 -0
- package/dist/licoes.js +1 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +20 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +34 -3
- package/dist/mcp-git.js +20 -3
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +50 -4
- package/dist/mcp-server.js +14 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +191 -16
- package/dist/ocupacao.js +11 -3
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +12 -10
- package/dist/parado-no-condutor.js +188 -32
- package/dist/phase.js +68 -15
- package/dist/policies.js +52 -1
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +34 -2
- package/dist/pulse.js +49 -3
- package/dist/ratelimit.js +20 -4
- package/dist/recall.js +3 -1
- package/dist/rede-adesao.js +399 -0
- package/dist/rede-forja.js +289 -0
- package/dist/rede-projetos.js +239 -0
- package/dist/rede-status.js +336 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +69 -2
- package/dist/roadmap-status.js +23 -3
- package/dist/runtime-profiles.js +22 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-watcher-claude.js +113 -23
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship.js +85 -19
- package/dist/thread.js +192 -13
- package/dist/worktree.js +5 -2
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/skills/README.md +1 -1
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
|
@@ -33,11 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.LIMITE_DE_RECENTES = exports.LIMITE_DE_PRS = exports.VALIDADE_DO_RETRATO_MIN = exports.LIMIAR_PARADO_NO_CONDUTOR_MIN = exports.CONTRATO_PRS = void 0;
|
|
36
|
+
exports.CONTRATO_FORJA_SEM_LEITURA = exports.FORJA_SEM_LEITURA = exports.LIMITE_DE_RECENTES = exports.LIMITE_DE_PRS = exports.VALIDADE_DO_RETRATO_MIN = exports.LIMIAR_PARADO_NO_CONDUTOR_MIN = exports.CONTRATO_PRS = void 0;
|
|
37
37
|
exports.nomeDeCheck = nomeDeCheck;
|
|
38
38
|
exports.repositorioDoRemoto = repositorioDoRemoto;
|
|
39
39
|
exports.lerPrsDaForja = lerPrsDaForja;
|
|
40
40
|
exports.gravarRetratoDePrs = gravarRetratoDePrs;
|
|
41
|
+
exports.avisarForjaSemLeitura = avisarForjaSemLeitura;
|
|
42
|
+
exports.esquecerForjaSemLeitura = esquecerForjaSemLeitura;
|
|
43
|
+
exports.forjaSemLeituraDoRemoto = forjaSemLeituraDoRemoto;
|
|
41
44
|
exports.lerRetratoDePrs = lerRetratoDePrs;
|
|
42
45
|
exports.perguntaAberta = perguntaAberta;
|
|
43
46
|
exports.fimDoTurno = fimDoTurno;
|
|
@@ -72,6 +75,7 @@ exports.entregasDoProjeto = entregasDoProjeto;
|
|
|
72
75
|
const fs = __importStar(require("node:fs"));
|
|
73
76
|
const path = __importStar(require("node:path"));
|
|
74
77
|
const node_child_process_1 = require("node:child_process");
|
|
78
|
+
const branch_de_estado_1 = require("./branch-de-estado");
|
|
75
79
|
const conducao_1 = require("./conducao");
|
|
76
80
|
const estado_thread_1 = require("./estado-thread");
|
|
77
81
|
const forja_1 = require("./forja");
|
|
@@ -111,6 +115,8 @@ const MINIMO_DA_CONFERENCIA_MS = 5000;
|
|
|
111
115
|
const FASES_ANTES_DA_ENTREGA = ['GOAL', 'PLAN', 'GO', 'CHECK'];
|
|
112
116
|
/** Os modos em que a #TAG ja autoriza o push (`autorizacaoDePush`, `core/src/ship.ts`). */
|
|
113
117
|
const MODOS_COM_PUSH_AUTORIZADO = ['auto', 'maestro'];
|
|
118
|
+
/** RM-037 (fatia 5, A5): o que as linhas e o resumo dizem quando a forja nao tem leitura de PR. */
|
|
119
|
+
exports.FORJA_SEM_LEITURA = 'forja sem leitura de PR';
|
|
114
120
|
/** O ambiente do `gh`: sem cor, sem prompt e sem host ou repositorio herdados (o host vai no `--repo`). */
|
|
115
121
|
function ambienteDoGh() {
|
|
116
122
|
const env = { ...process.env, GH_PROMPT_DISABLED: '1', NO_COLOR: '1', CLICOLOR: '0', CLICOLOR_FORCE: '0' };
|
|
@@ -128,6 +134,8 @@ const git = (raiz, args) => (0, util_1.exec)('git', args, raiz, 60000, { ...proc
|
|
|
128
134
|
const SHA = /^[0-9a-f]{40}$/;
|
|
129
135
|
const BRANCH = /^[A-Za-z0-9._/-]{1,200}$/;
|
|
130
136
|
const REPOSITORIO = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
137
|
+
/** O host do GitHub Enterprise guardado no retrato: rotulos alfanumericos separados por ponto, como na forja. */
|
|
138
|
+
const HOST = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/;
|
|
131
139
|
/** Texto curto vindo de fora: sem controle, num teto. */
|
|
132
140
|
function curto(v, teto = 120) {
|
|
133
141
|
if (typeof v !== 'string')
|
|
@@ -215,30 +223,87 @@ function prDaForja(bruto, base) {
|
|
|
215
223
|
return { numero: numero, branch: p.headRefName, head, estado, rascunho: p.isDraft, url,
|
|
216
224
|
criadoEm: instante(p.createdAt), mescladoEm: instante(p.mergedAt), checks: [...porChave.values()].map((x) => x.check) };
|
|
217
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* RM-037 (fatia 5, A5): o host e o `dono/nome` do remoto quando ele pode ser um GitHub (o github.com ou um host
|
|
228
|
+
* proprio), so pelo git local, sem rede nem `gh`. O GitLab fica de fora.
|
|
229
|
+
*/
|
|
230
|
+
function githubDoRemoto(raiz, remoto) {
|
|
231
|
+
// RM-047: o remoto vem do manifesto versionado; so nome de remoto chega ao git, e depois do `--`.
|
|
232
|
+
if (!(0, branch_de_estado_1.remotoValido)(remoto))
|
|
233
|
+
return null;
|
|
234
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
235
|
+
const forja = url.ok ? (0, forja_1.repositorioGithubNoHost)(url.stdout.trim()) : null;
|
|
236
|
+
// `ssh.github.com` e o SSH do github.com pela porta 443, e nao um GitHub Enterprise (sugestao da rodada 1 do CHECK).
|
|
237
|
+
return forja && REPOSITORIO.test(forja.repo) ? { host: forja.host === 'ssh.github.com' ? 'github.com' : forja.host, repositorio: forja.repo }
|
|
238
|
+
: null;
|
|
239
|
+
}
|
|
218
240
|
/** O repositorio `dono/nome` do remoto, so quando ele e do github.com (o host ancorado, nao so citado no caminho). */
|
|
219
241
|
function repositorioDoRemoto(raiz, remoto) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
242
|
+
const github = githubDoRemoto(raiz, remoto);
|
|
243
|
+
return github && github.host === 'github.com' ? github.repositorio : null;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* RM-037 (fatia 5, A5): de onde o pulse le os PRs do remoto. O github.com, como sempre; o host proprio em que o `gh`
|
|
247
|
+
* esta autenticado, que e um GitHub Enterprise (`gh auth status --hostname <host>`); ou nenhum: GitLab, caminho local,
|
|
248
|
+
* ou host em que o `gh` nao tem login. Ficar sem leitura nao e falha desta batida (o "PR nao lido"): e o estado da
|
|
249
|
+
* forja, que o pulse diz uma vez.
|
|
250
|
+
*/
|
|
251
|
+
function forjaDosPrs(raiz, remoto, executor, prazoMs) {
|
|
252
|
+
// RM-047: remoto que nao e nome de remoto nao chega ao git; para o pulse, e forja sem leitura.
|
|
253
|
+
if (!(0, branch_de_estado_1.remotoValido)(remoto)) {
|
|
254
|
+
return { leitura: false, host: null, motivo: `o remoto ${(0, branch_de_estado_1.remotoRedigido)(remoto)} não é nome de remoto do git`, semLeitura: true };
|
|
255
|
+
}
|
|
256
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
257
|
+
if (!url.ok)
|
|
258
|
+
return { leitura: false, host: null, motivo: `o remoto ${remoto} não está configurado neste checkout`, semLeitura: true };
|
|
259
|
+
const endereco = (0, forja_1.enderecoDoRemoto)(url.stdout.trim());
|
|
260
|
+
// Caminho local, ou apelido de SSH sem dominio (`git@github-trabalho:dono/repo.git`): nao ha host para ler.
|
|
261
|
+
if (!endereco) {
|
|
262
|
+
return { leitura: false, host: null, motivo: `o remoto ${remoto} não tem host de forja (caminho local ou apelido de SSH)`, semLeitura: true };
|
|
263
|
+
}
|
|
264
|
+
if ((0, forja_1.identidadeDaForja)(url.stdout.trim())?.tipo === 'gitlab') {
|
|
265
|
+
return { leitura: false, host: endereco.host, motivo: `a forja de ${remoto} (${endereco.host}) é um GitLab, e o ork só lê PR do GitHub`,
|
|
266
|
+
semLeitura: true };
|
|
267
|
+
}
|
|
268
|
+
const github = githubDoRemoto(raiz, remoto);
|
|
269
|
+
if (!github) {
|
|
270
|
+
return { leitura: false, host: endereco.host, motivo: `o remoto ${remoto} (${endereco.host}) não aponta um repositório dono/nome`,
|
|
271
|
+
semLeitura: true };
|
|
272
|
+
}
|
|
273
|
+
if (github.host === 'github.com')
|
|
274
|
+
return { leitura: true, ...github };
|
|
275
|
+
const auth = executor(['auth', 'status', '--hostname', github.host], prazoMs);
|
|
276
|
+
if (auth.status === 0)
|
|
277
|
+
return { leitura: true, ...github };
|
|
278
|
+
// So a resposta de login ausente (o `gh` 2.46 diz "You are not logged into any accounts on <host>") e o estado da
|
|
279
|
+
// forja; prazo estourado, `gh` ausente ou host fora do ar sao falha desta batida.
|
|
280
|
+
const semLogin = auth.status === 1 && /\bnot logged in/i.test(`${auth.stdout}\n${auth.stderr}`);
|
|
281
|
+
return { leitura: false, host: github.host, semLeitura: semLogin, motivo: semLogin
|
|
282
|
+
? `o gh não está autenticado em ${github.host}, a forja de ${remoto}`
|
|
283
|
+
: `gh auth status --hostname ${github.host} falhou (${auth.status === null ? 'sem código de saída' : `código ${auth.status}`}): ` +
|
|
284
|
+
(curto((0, hitl_1.redigirSegredos)(auth.stderr || auth.stdout || ''), 120) ?? 'sem detalhe') };
|
|
223
285
|
}
|
|
224
286
|
/**
|
|
225
287
|
* Le os PRs da base do repositorio do remoto em duas chamadas: os abertos (ate `LIMITE_DE_PRS`; e so a
|
|
226
288
|
* lista deles que pode dizer "sem PR") e os recentes de qualquer estado (para achar o mesclado e o fechado).
|
|
227
|
-
* O `gh` usa a autenticacao dele; nenhum token passa por aqui.
|
|
289
|
+
* O `gh` usa a autenticacao dele; nenhum token passa por aqui. RM-037 (fatia 5, A5): no GitHub Enterprise, o host
|
|
290
|
+
* vai no `--repo`; forja sem leitura de PR nao chama o `gh pr list`.
|
|
228
291
|
*/
|
|
229
292
|
function lerPrsDaForja(carregado, opcoes = {}) {
|
|
230
293
|
const lidoEm = opcoes.quando ?? new Date().toISOString();
|
|
231
294
|
const remoto = opcoes.remoto ?? carregado.manifesto.fabrica.remoto;
|
|
232
295
|
const base = carregado.manifesto.worktree.base_branch;
|
|
233
|
-
const repositorio = repositorioDoRemoto(carregado.raiz, remoto);
|
|
234
|
-
if (!repositorio)
|
|
235
|
-
return { ok: false, lidoEm, erro: `o remoto ${remoto} não é um repositório do github.com` };
|
|
236
296
|
const orcamento = opcoes.orcamentoMs ?? ORCAMENTO_DA_LEITURA_MS, fimDaLeitura = Date.now() + orcamento;
|
|
237
297
|
const resta = () => fimDaLeitura - Date.now();
|
|
298
|
+
const executor = opcoes.executor ?? ghPadrao;
|
|
299
|
+
const forja = forjaDosPrs(carregado.raiz, remoto, executor, Math.min(PRAZO_DO_GH_MS, Math.max(1, resta())));
|
|
300
|
+
if (!forja.leitura)
|
|
301
|
+
return { ok: false, lidoEm, erro: forja.motivo, ...(forja.semLeitura ? { semLeitura: { remoto, host: forja.host } } : {}) };
|
|
302
|
+
const { host, repositorio } = forja;
|
|
238
303
|
const pedir = (args) => {
|
|
239
304
|
if (resta() <= 0)
|
|
240
305
|
return `gh pr list: orçamento de ${Math.round(orcamento / 1000)} s da leitura esgotado`;
|
|
241
|
-
const r =
|
|
306
|
+
const r = executor(['pr', 'list', `--repo=${host}/${repositorio}`, `--base=${base}`, ...args], Math.min(PRAZO_DO_GH_MS, resta()));
|
|
242
307
|
if (r.status !== 0) {
|
|
243
308
|
const detalhe = curto((0, hitl_1.redigirSegredos)(r.stderr || r.stdout || ''), 160) ?? 'sem detalhe';
|
|
244
309
|
return `gh pr list falhou (${r.status === null ? 'sem código de saída' : `código ${r.status}`}): ${detalhe}`;
|
|
@@ -296,8 +361,8 @@ function lerPrsDaForja(carregado, opcoes = {}) {
|
|
|
296
361
|
semConferir.push(branch);
|
|
297
362
|
}
|
|
298
363
|
}
|
|
299
|
-
return { ok: true, retrato: { contrato: exports.CONTRATO_PRS, lidoEm, repositorio,
|
|
300
|
-
...(semConferir.length ? { semConferir } : {}), prs: [...porNumero.values()] } };
|
|
364
|
+
return { ok: true, retrato: { contrato: exports.CONTRATO_PRS, lidoEm, repositorio, ...(host !== 'github.com' ? { host } : {}), base,
|
|
365
|
+
parcial: abertos.length >= exports.LIMITE_DE_PRS, ...(semConferir.length ? { semConferir } : {}), prs: [...porNumero.values()] } };
|
|
301
366
|
}
|
|
302
367
|
catch (e) {
|
|
303
368
|
return { ok: false, lidoEm, erro: `resposta do gh pr list fora do formato: ${curto((0, hitl_1.redigirSegredos)(e.message), 120) ?? 'sem detalhe'}` };
|
|
@@ -321,6 +386,64 @@ function gravarRetratoDePrs(raiz, retrato) {
|
|
|
321
386
|
throw e;
|
|
322
387
|
}
|
|
323
388
|
}
|
|
389
|
+
const ARQUIVO_DA_FORJA_SEM_LEITURA = 'forja-sem-leitura.json';
|
|
390
|
+
exports.CONTRATO_FORJA_SEM_LEITURA = 'ork.forja-sem-leitura/v1';
|
|
391
|
+
function lerAvisoDeForjaSemLeitura(raiz) {
|
|
392
|
+
try {
|
|
393
|
+
const a = JSON.parse(fs.readFileSync(path.join(dirDoMonitor(raiz), ARQUIVO_DA_FORJA_SEM_LEITURA), 'utf8'));
|
|
394
|
+
const ditoEm = instante(a.ditoEm), motivo = curto(a.motivo, 200);
|
|
395
|
+
if (a.contrato !== exports.CONTRATO_FORJA_SEM_LEITURA || typeof a.remoto !== 'string' || !/^[A-Za-z0-9._-]{1,100}$/.test(a.remoto) ||
|
|
396
|
+
!(a.host === null || (typeof a.host === 'string' && HOST.test(a.host))) || !ditoEm || !motivo)
|
|
397
|
+
return null;
|
|
398
|
+
return { contrato: exports.CONTRATO_FORJA_SEM_LEITURA, remoto: a.remoto, host: a.host, motivo, ditoEm };
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* RM-037 (fatia 5, A5): a forja sem leitura de PR e dita uma vez por remoto e host. Com o remoto fora do github.com,
|
|
406
|
+
* o pulse dizia "PR nao lido" a cada batida, para um estado que nao muda de uma batida para a outra. A marca em
|
|
407
|
+
* `.orkastery/monitor/` guarda o que ja foi dito; devolve true quando e novidade (e grava a marca).
|
|
408
|
+
*/
|
|
409
|
+
function avisarForjaSemLeitura(raiz, semLeitura, motivo, quando) {
|
|
410
|
+
const atual = lerAvisoDeForjaSemLeitura(raiz);
|
|
411
|
+
if (atual && atual.remoto === semLeitura.remoto && atual.host === semLeitura.host)
|
|
412
|
+
return false;
|
|
413
|
+
const dir = dirDoMonitor(raiz);
|
|
414
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
415
|
+
const arquivo = path.join(dir, ARQUIVO_DA_FORJA_SEM_LEITURA), tmp = `${arquivo}.${process.pid}.${Date.now()}.tmp`;
|
|
416
|
+
const aviso = { contrato: exports.CONTRATO_FORJA_SEM_LEITURA, ...semLeitura, motivo: curto(motivo, 200) ?? exports.FORJA_SEM_LEITURA,
|
|
417
|
+
ditoEm: quando };
|
|
418
|
+
try {
|
|
419
|
+
fs.writeFileSync(tmp, JSON.stringify(aviso, null, 2) + '\n', { mode: 0o600, flag: 'wx' });
|
|
420
|
+
fs.renameSync(tmp, arquivo);
|
|
421
|
+
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
try {
|
|
424
|
+
fs.unlinkSync(tmp);
|
|
425
|
+
}
|
|
426
|
+
catch { /* ja saiu */ }
|
|
427
|
+
throw e;
|
|
428
|
+
}
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
/** A leitura voltou: a marca sai, e a forja que perder a leitura de novo volta a ser dita. */
|
|
432
|
+
function esquecerForjaSemLeitura(raiz) {
|
|
433
|
+
fs.rmSync(path.join(dirDoMonitor(raiz), ARQUIVO_DA_FORJA_SEM_LEITURA), { force: true });
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* A forja sem leitura que o pulse ja disse, so quando ela e a do remoto de agora (mesmo nome e mesmo host): o status
|
|
437
|
+
* do roadmap a le sem rede e sem `gh`.
|
|
438
|
+
*/
|
|
439
|
+
function forjaSemLeituraDoRemoto(raiz, remoto) {
|
|
440
|
+
const aviso = lerAvisoDeForjaSemLeitura(raiz);
|
|
441
|
+
if (!aviso || aviso.remoto !== remoto || !(0, branch_de_estado_1.remotoValido)(remoto))
|
|
442
|
+
return null;
|
|
443
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
444
|
+
const host = url.ok ? (0, forja_1.enderecoDoRemoto)(url.stdout.trim())?.host ?? null : null;
|
|
445
|
+
return host === aviso.host ? aviso : null;
|
|
446
|
+
}
|
|
324
447
|
/** O ultimo retrato gravado pelo pulse, conferido campo a campo e com os nomes de check limpos de novo. */
|
|
325
448
|
function lerRetratoDePrs(raiz) {
|
|
326
449
|
try {
|
|
@@ -328,6 +451,7 @@ function lerRetratoDePrs(raiz) {
|
|
|
328
451
|
const lidoEm = instante(r.lidoEm);
|
|
329
452
|
if (r.contrato !== exports.CONTRATO_PRS || !lidoEm || typeof r.repositorio !== 'string' || !REPOSITORIO.test(r.repositorio) ||
|
|
330
453
|
typeof r.base !== 'string' || typeof r.parcial !== 'boolean' || !Array.isArray(r.prs) ||
|
|
454
|
+
(r.host !== undefined && !(typeof r.host === 'string' && HOST.test(r.host))) ||
|
|
331
455
|
(r.semConferir !== undefined && !(Array.isArray(r.semConferir) && r.semConferir.every((b) => typeof b === 'string' && BRANCH.test(b)))))
|
|
332
456
|
return null;
|
|
333
457
|
const opcional = (v) => (v === null || v === undefined ? null : instante(v) ?? undefined);
|
|
@@ -351,8 +475,8 @@ function lerRetratoDePrs(raiz) {
|
|
|
351
475
|
prs.push({ numero: p.numero, branch: p.branch, head: p.head, estado, rascunho: p.rascunho,
|
|
352
476
|
url: typeof p.url === 'string' && /^https:\/\/[^\s]+$/.test(p.url) ? curto(p.url, 300) : null, criadoEm, mescladoEm, checks });
|
|
353
477
|
}
|
|
354
|
-
return { contrato: exports.CONTRATO_PRS, lidoEm, repositorio: r.repositorio,
|
|
355
|
-
...(Array.isArray(r.semConferir) && r.semConferir.length ? { semConferir: r.semConferir } : {}), prs };
|
|
478
|
+
return { contrato: exports.CONTRATO_PRS, lidoEm, repositorio: r.repositorio, ...(typeof r.host === 'string' ? { host: r.host } : {}),
|
|
479
|
+
base: r.base, parcial: r.parcial, ...(Array.isArray(r.semConferir) && r.semConferir.length ? { semConferir: r.semConferir } : {}), prs };
|
|
356
480
|
}
|
|
357
481
|
catch {
|
|
358
482
|
return null;
|
|
@@ -411,13 +535,25 @@ const doRadar = (e) => e.tipo === 'sessao_bloqueada' && e.fonte === 'ork session
|
|
|
411
535
|
* intervalo do despacho. A prova do ork no SHIP e so o `ship_done` (`provaDoOrk`): o que falta e mergear o PR
|
|
412
536
|
* ou registrar a entrega, e isso e do condutor, como o fim de turno em `blocked`. Dos 4 `human.pending` do SHIP
|
|
413
537
|
* nos ledgers de 30/09, 2 tem este formato (ork-rm037noite e ork-pacotedeexpe). O CHECK em `done` sem o veredito
|
|
414
|
-
* e outra coisa
|
|
538
|
+
* e outra coisa: `checkSemVeredito`.
|
|
415
539
|
*/
|
|
416
540
|
function shipSemRegistro(e) {
|
|
417
541
|
const { ok: provou } = (e.provaOrk ?? {});
|
|
418
542
|
return e.motivo === 'human.pending' && e.origem === 'sessions.watch' && e.fase === 'SHIP' && e.estadoNativo === 'done' &&
|
|
419
543
|
!!e.stop && provou === false;
|
|
420
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* RM-037 (fatia 5, A3): o CHECK que o observador viu terminar em `done`, com o Stop, sem exatamente um veredito
|
|
547
|
+
* legivel no `docs/check.md` (`provaDoOrk`). No #Auto, com o bloco sem pausa ao fim, ninguem perguntou nada ao dono:
|
|
548
|
+
* o passo e do condutor, que redespacha o CHECK. Nos dois casos reais (ork-i35horariodo em 20/09 e ork-pacotedeexpe
|
|
549
|
+
* em 30/09, as duas #Auto) o condutor seguiu sozinho minutos depois, sem pergunta ao dono. Fora do #Auto, segue com
|
|
550
|
+
* o dono, como antes.
|
|
551
|
+
*/
|
|
552
|
+
function checkSemVeredito(e) {
|
|
553
|
+
const { ok: provou } = (e.provaOrk ?? {});
|
|
554
|
+
return e.motivo === 'human.pending' && e.origem === 'sessions.watch' && e.fase === 'CHECK' && e.estadoNativo === 'done' &&
|
|
555
|
+
!!e.stop && provou === false;
|
|
556
|
+
}
|
|
421
557
|
/**
|
|
422
558
|
* O bloqueio que pede o dono: o prompt de permissao do hook e o que o radar leu com pergunta na tela. O
|
|
423
559
|
* carimbo do radar no fim de turno (`blocked` lido sem menu nem pergunta) nao e prompt nenhum.
|
|
@@ -473,7 +609,8 @@ function atividadeDaSessao(e) {
|
|
|
473
609
|
return !(e.sensor === 'notification' && e.notificationType === 'idle_prompt');
|
|
474
610
|
return e.tipo === 'commit' || e.tipo === 'runtime_stop' || (e.tipo === 'sessao_bloqueada' && !doRadar(e));
|
|
475
611
|
}
|
|
476
|
-
|
|
612
|
+
/** `modo`: o da thread. Sem ele, o CHECK sem o veredito fica com o dono, como fora do #Auto. */
|
|
613
|
+
function fimDoTurno(eventos, despacho, modo) {
|
|
477
614
|
const i = eventos.lastIndexOf(despacho);
|
|
478
615
|
const depois = eventos.slice(i + 1);
|
|
479
616
|
const sid = texto(despacho.sessionId);
|
|
@@ -497,12 +634,13 @@ function fimDoTurno(eventos, despacho) {
|
|
|
497
634
|
// S-a do CHECK (rodada 3): no bloco com pausa ao fim, todo `human.pending` do resultado e a fase entregue ao dono.
|
|
498
635
|
return { em: resultado.ts, tipo: 'pausa-do-bloco', sessionId: sid, fase, comProva: true };
|
|
499
636
|
}
|
|
500
|
-
else if (resultado.motivo === 'human.pending' && resultado.stop && (resultado.estadoNativo === 'blocked' || shipSemRegistro(resultado)
|
|
637
|
+
else if (resultado.motivo === 'human.pending' && resultado.stop && (resultado.estadoNativo === 'blocked' || shipSemRegistro(resultado) ||
|
|
638
|
+
(modo === 'auto' && checkSemVeredito(resultado)))) {
|
|
501
639
|
if (!retomou) {
|
|
502
640
|
const { ts: doStop } = resultado.stop;
|
|
503
641
|
const { ok: provou } = (resultado.provaOrk ?? {});
|
|
504
|
-
return { em: instante(doStop) ?? resultado.ts, tipo: 'espera-do-observador',
|
|
505
|
-
comProva: typeof provou === 'boolean' ? provou : null };
|
|
642
|
+
return { em: instante(doStop) ?? resultado.ts, tipo: checkSemVeredito(resultado) ? 'check-sem-veredito' : 'espera-do-observador',
|
|
643
|
+
sessionId: sid, fase, comProva: typeof provou === 'boolean' ? provou : null };
|
|
506
644
|
}
|
|
507
645
|
}
|
|
508
646
|
else
|
|
@@ -544,17 +682,17 @@ function pendenciaDoDono(t, eventos, quando) {
|
|
|
544
682
|
return 'prompt de permissão pendente';
|
|
545
683
|
// Aviso da rodada 6 do CHECK: o gate do observador so muda de dono com o fim de turno provado. A sessao que voltou a
|
|
546
684
|
// trabalhar depois do resultado, sem Stop novo, segue do dono, e a thread nao sai tambem como linha do condutor.
|
|
547
|
-
const fim = fimDoTurno(eventos, despacho);
|
|
685
|
+
const fim = fimDoTurno(eventos, despacho, t.modo);
|
|
548
686
|
const turnoEncerrado = !!fim && fim.tipo !== 'outro';
|
|
549
687
|
for (let k = 0; k < depois.length; k++) {
|
|
550
688
|
const e = depois[k];
|
|
551
689
|
if (e.tipo !== 'gate_blocked')
|
|
552
690
|
continue;
|
|
553
691
|
const motivo = String(e.motivo ?? '');
|
|
554
|
-
// O fim de turno que o observador viu em `blocked`,
|
|
555
|
-
// escalacao: sao justamente o que muda de dono.
|
|
692
|
+
// O fim de turno que o observador viu em `blocked`, o SHIP em `done` sem o `ship_done` (B1 da rodada 5) e, no #Auto,
|
|
693
|
+
// o CHECK em `done` sem o veredito (A3, fatia 5) nao sao escalacao: sao justamente o que muda de dono.
|
|
556
694
|
if (turnoEncerrado && motivo === 'human.pending' && e.origem === 'sessions.watch' &&
|
|
557
|
-
(e.estadoNativo === 'blocked' || shipSemRegistro(e)))
|
|
695
|
+
(e.estadoNativo === 'blocked' || shipSemRegistro(e) || (t.modo === 'auto' && checkSemVeredito(e))))
|
|
558
696
|
continue;
|
|
559
697
|
const doDono = motivo === 'human.pending' ||
|
|
560
698
|
(hitl_gates_1.MOTIVOS_DE_ESCALACAO_HUMANA.includes(motivo) && (0, hitl_classificacao_1.quemDecide)(motivo) === 'dono');
|
|
@@ -570,7 +708,7 @@ function esperaDoCondutor(t, eventos, quando) {
|
|
|
570
708
|
const despacho = ultimoDespacho(eventos);
|
|
571
709
|
if (!despacho || despacho.pausaAoFim !== false)
|
|
572
710
|
return null;
|
|
573
|
-
const fim = fimDoTurno(eventos, despacho);
|
|
711
|
+
const fim = fimDoTurno(eventos, despacho, t.modo);
|
|
574
712
|
if (!fim || fim.tipo === 'outro' || fim.tipo === 'pausa-do-bloco' || pendenciaDoDono(t, eventos, quando))
|
|
575
713
|
return null;
|
|
576
714
|
return { thread: t.id, fase: fim.fase, sessionId: fim.sessionId, fimDoTurnoEm: fim.em, tipo: fim.tipo, comProva: fim.comProva };
|
|
@@ -699,9 +837,13 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
699
837
|
// R4-4 do CHECK (rodada 4): o `ship_done` cobre a entrega do mesmo head (`shaDe`) ou do mesmo merge; a entrega
|
|
700
838
|
// nova depois dele ainda nao foi registrada. O legado sem o sha cobre tudo, como antes.
|
|
701
839
|
const cobre = (campo, sha) => ships.some((e) => typeof e[campo] !== 'string' || !SHA.test(e[campo]) || e[campo] === sha);
|
|
840
|
+
// RM-037 (fatia 5, A1): ate esta fatia, o `ork ship` com a branch ja incorporada gravava a ponta da base no
|
|
841
|
+
// `mergeSha`. Esse `ship_done` registra o merge `ship(<thread>)` que a ponta gravada contem.
|
|
842
|
+
const contemOMerge = (sha) => ships.some((e) => typeof e.mergeSha === 'string' && SHA.test(e.mergeSha) &&
|
|
843
|
+
e.mergeSha !== sha && git(raiz, ['merge-base', '--is-ancestor', sha, e.mergeSha]).code === 0);
|
|
702
844
|
return { t, eventos, branch: cabeca ? branch : null, cabeca, comProduto, publicada, temRemota: !!remota,
|
|
703
845
|
shipNoLedger: ships.length > 0, entregueNaPonta: cabeca ? cobre('shaDe', cabeca) : ships.length > 0,
|
|
704
|
-
mergeRegistrado: !!merge && cobre('mergeSha', merge.sha), merge };
|
|
846
|
+
mergeRegistrado: !!merge && (cobre('mergeSha', merge.sha) || contemOMerge(merge.sha)), merge };
|
|
705
847
|
});
|
|
706
848
|
// D2: a forja so e lida quando alguma thread tem o que mostrar la: produto numa branch que ja foi ao remoto
|
|
707
849
|
// (inteira, ou com commit novo ainda sem push, que pode ter PR aberto).
|
|
@@ -710,11 +852,15 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
710
852
|
if (opcoes.lerPrs && candidatas.length)
|
|
711
853
|
prs = opcoes.lerPrs(candidatas);
|
|
712
854
|
// O retrato so vale do repositorio e da base de agora, e lido ha menos de `VALIDADE_DO_RETRATO_MIN`.
|
|
713
|
-
|
|
855
|
+
// RM-037 (fatia 5, A5): a forja sem leitura de PR e o estado dela, dito uma vez pelo pulse; a linha nunca diz "PR nao lido".
|
|
856
|
+
const semLeituraDaForja = !!prs && !prs.ok && !!prs.semLeitura;
|
|
857
|
+
let retrato = null, semRetrato = prs && !prs.ok ? (semLeituraDaForja ? exports.FORJA_SEM_LEITURA : prs.erro) : 'sem leitura dos PRs';
|
|
714
858
|
if (prs?.ok) {
|
|
715
|
-
const r = prs.retrato;
|
|
716
|
-
|
|
859
|
+
const r = prs.retrato, atual = githubDoRemoto(raiz, remoto);
|
|
860
|
+
// O retrato vale do mesmo host: o do GitHub Enterprise (`host`) ou, sem ele, o github.com.
|
|
861
|
+
if (r.base !== baseBranch || !atual || r.repositorio !== atual.repositorio || (r.host ?? 'github.com') !== atual.host) {
|
|
717
862
|
semRetrato = 'retrato de PRs de outro repositório ou base';
|
|
863
|
+
}
|
|
718
864
|
else if (minutosDesde(r.lidoEm, quando) > exports.VALIDADE_DO_RETRATO_MIN)
|
|
719
865
|
semRetrato = 'retrato de PRs velho';
|
|
720
866
|
else if (Date.parse(r.lidoEm) - Date.parse(quando) > FOLGA_DO_RELOGIO_MIN * 60000)
|
|
@@ -727,7 +873,7 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
727
873
|
for (const f of fatos) {
|
|
728
874
|
const { t, eventos } = f;
|
|
729
875
|
const despacho = ultimoDespacho(eventos);
|
|
730
|
-
const fim = despacho ? fimDoTurno(eventos, despacho) : null;
|
|
876
|
+
const fim = despacho ? fimDoTurno(eventos, despacho, t.modo) : null;
|
|
731
877
|
const terminou = !!fim && fim.tipo !== 'outro';
|
|
732
878
|
const fimEm = terminou ? fim.em : null;
|
|
733
879
|
// A1 do CHECK (rodada 3): o fim de turno vem do ledger (Stop sem atividade depois); a tela da sessao depois
|
|
@@ -771,7 +917,15 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
771
917
|
let caso = null, desde = null, passo = '', peloGit = false;
|
|
772
918
|
const evidencia = [];
|
|
773
919
|
if (!conduzidaAgora && !doDono) {
|
|
774
|
-
if (
|
|
920
|
+
if (espera?.tipo === 'check-sem-veredito') {
|
|
921
|
+
// RM-037 (fatia 5, A3): antes de qualquer caso de entrega. Publicar ou mergear sem o veredito do CHECK pularia
|
|
922
|
+
// a revisao; e o `ork retry run` nao redespacha `human.pending` (`escalar-humano`), entao o passo e o despacho.
|
|
923
|
+
caso = 'check-sem-veredito';
|
|
924
|
+
desde = espera.fimDoTurnoEm;
|
|
925
|
+
passo = `redespachar o CHECK (ork phase run ${t.id} CHECK --prompt "<pedido da fase>")`;
|
|
926
|
+
evidencia.push('ledger: CHECK em done com o Stop, sem exatamente um veredito no docs/check.md');
|
|
927
|
+
}
|
|
928
|
+
else if (f.comProduto && publicada === false && terminou) {
|
|
775
929
|
desde = fimOuVeredito;
|
|
776
930
|
if (antesDaEntrega && !aberto) {
|
|
777
931
|
caso = 'fase-seguinte';
|
|
@@ -782,7 +936,8 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
782
936
|
// N2 da seguranca (rodada 2): branch que ja foi ao remoto pode ter PR; sem a leitura, nunca "abrir o PR". A4 da
|
|
783
937
|
// rodada 5: publicar e abrir o PR pedem a mesma autorizacao de push que o merge.
|
|
784
938
|
passo = (aberto ? `publicar os commits novos da branch ${f.branch} no PR #${aberto.numero}`
|
|
785
|
-
:
|
|
939
|
+
// RM-037 (fatia 5, A5): a forja sem leitura de PR ja foi dita uma vez; a linha so diz o passo.
|
|
940
|
+
: f.temRemota && !prSabido ? `publicar os commits novos da branch ${f.branch}${semLeituraDaForja ? '' : ' (PR não lido)'}`
|
|
786
941
|
: `publicar a branch ${f.branch} e abrir o PR`) + autorizacao;
|
|
787
942
|
}
|
|
788
943
|
evidencia.push(`refs/heads/${f.branch} tem commit fora de refs/remotes/${remoto}/${f.branch}`);
|
|
@@ -850,7 +1005,8 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
850
1005
|
caso = 'sessao-sem-pergunta';
|
|
851
1006
|
passo = f.shipNoLedger && !f.comProduto ? `fechar o MASTER da thread (ork master ${t.id})`
|
|
852
1007
|
: aberto ? `acompanhar os checks do PR #${aberto.numero}, que seguem em andamento`
|
|
853
|
-
: precisaDePr && !usouPr ? `conferir o PR da branch ${f.branch}
|
|
1008
|
+
: precisaDePr && !usouPr ? (semLeituraDaForja ? `conferir na forja o PR da branch ${f.branch} e seguir`
|
|
1009
|
+
: `conferir o PR da branch ${f.branch} (PR não lido) e seguir`)
|
|
854
1010
|
: `ler o fim da sessão ${id} (ork sessions logs ${id}) e seguir a thread`;
|
|
855
1011
|
}
|
|
856
1012
|
}
|
|
@@ -880,7 +1036,7 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
880
1036
|
: daBranch.mesclado && !f.entregueNaPonta ? (f.merge && !f.mergeRegistrado ? `PR #${daBranch.mesclado.numero} mesclado, falta registrar a entrega (${registrar})`
|
|
881
1037
|
: `PR #${daBranch.mesclado.numero} mesclado sem o assunto ship(${t.id}), falta registrar a entrega`)
|
|
882
1038
|
: !f.comProduto && f.merge && !f.mergeRegistrado ? `merge ${f.merge.sha.slice(0, 7)} na base, falta registrar a entrega (${registrar})`
|
|
883
|
-
: precisaDePr ? (!usouPr ? 'branch publicada, PR não lido'
|
|
1039
|
+
: precisaDePr ? (!usouPr ? (semLeituraDaForja ? `branch publicada, ${exports.FORJA_SEM_LEITURA}` : 'branch publicada, PR não lido')
|
|
884
1040
|
: daBranch.fechado ? `branch publicada, PR #${daBranch.fechado.numero} fechado sem merge` : 'branch publicada sem PR')
|
|
885
1041
|
: null;
|
|
886
1042
|
estados.push({ thread: t.id, branch: f.branch, comProduto: f.comProduto, publicada, pr: prDaEntrega,
|
package/dist/phase.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.REGRAS_DE_EVIDENCIA = exports.CONTRATO_DAS_FASES = void 0;
|
|
37
37
|
exports.escolherPerfil = escolherPerfil;
|
|
38
|
+
exports.perfilPedido = perfilPedido;
|
|
38
39
|
exports.perfilParaDespacho = perfilParaDespacho;
|
|
39
40
|
exports.runtimeCruzadoParaDespacho = runtimeCruzadoParaDespacho;
|
|
40
41
|
exports.estadoParaDespacho = estadoParaDespacho;
|
|
@@ -71,12 +72,15 @@ const board_1 = require("./board");
|
|
|
71
72
|
const verify_1 = require("./verify");
|
|
72
73
|
const session_watcher_1 = require("./session-watcher");
|
|
73
74
|
const session_watcher_claude_1 = require("./session-watcher-claude");
|
|
75
|
+
const manifest_1 = require("./manifest");
|
|
76
|
+
const mcp_grafo_1 = require("./mcp-grafo");
|
|
74
77
|
const runtimes_1 = require("./runtimes");
|
|
75
78
|
const setup_1 = require("./setup");
|
|
76
79
|
const modos_1 = require("./modos");
|
|
77
80
|
const gates_1 = require("./gates");
|
|
78
81
|
const policies_1 = require("./policies");
|
|
79
82
|
const ratelimit_1 = require("./ratelimit");
|
|
83
|
+
const impedimento_1 = require("./impedimento");
|
|
80
84
|
const claude_bg_1 = require("./adapters/claude-bg");
|
|
81
85
|
const codex_1 = require("./adapters/codex");
|
|
82
86
|
const memoria_1 = require("./memoria");
|
|
@@ -89,6 +93,7 @@ const ledger_1 = require("./ledger");
|
|
|
89
93
|
const estado_thread_1 = require("./estado-thread");
|
|
90
94
|
const horario_1 = require("./horario");
|
|
91
95
|
const runtime_profiles_1 = require("./runtime-profiles");
|
|
96
|
+
const sessoes_contas_1 = require("./sessoes-contas");
|
|
92
97
|
const maquina_1 = require("./maquina");
|
|
93
98
|
const fabrica_publicar_1 = require("./fabrica-publicar");
|
|
94
99
|
const conducao_1 = require("./conducao");
|
|
@@ -102,18 +107,14 @@ function escolherPerfil(raiz, runtime, opcoes = {}) {
|
|
|
102
107
|
// I-49: o despacho enxerga o estado que as outras fabricas viram na mesma conta.
|
|
103
108
|
const store = (0, runtime_profiles_1.lerPerfisComContas)(raiz, opcoes.agoraMs);
|
|
104
109
|
const doRuntime = (0, runtime_profiles_1.perfisDoRuntime)(store, runtime);
|
|
105
|
-
if (opcoes.perfil !== undefined)
|
|
106
|
-
|
|
107
|
-
if (!pedido)
|
|
108
|
-
return { perfil: null, configurados: doRuntime.length, erro: `perfil "${opcoes.perfil}" nao existe para o runtime ${runtime}` };
|
|
109
|
-
if (!(0, runtime_profiles_1.perfilDisponivel)(pedido, opcoes.agoraMs))
|
|
110
|
-
return { perfil: null, configurados: doRuntime.length,
|
|
111
|
-
erro: `perfil "${pedido.id}" esta ${pedido.estado}${pedido.esgotadoAte ? ` ate ${pedido.esgotadoAte}` : ''}` };
|
|
112
|
-
return { perfil: (0, runtime_profiles_1.perfilDeDespacho)(pedido), configurados: doRuntime.length };
|
|
113
|
-
}
|
|
110
|
+
if (opcoes.perfil !== undefined)
|
|
111
|
+
return perfilPedido(store, runtime, opcoes.perfil, opcoes.agoraMs);
|
|
114
112
|
if (doRuntime.length === 0)
|
|
115
113
|
return { perfil: null, configurados: 0 };
|
|
116
|
-
const
|
|
114
|
+
const politica = opcoes.politica ?? runtime_profiles_1.POLITICA_PADRAO;
|
|
115
|
+
const proximo = politica.distribuir === 'carga' && opcoes.carga
|
|
116
|
+
? (0, runtime_profiles_1.proximoPerfilPorCarga)(store, runtime, politica, opcoes.carga, opcoes)
|
|
117
|
+
: (0, runtime_profiles_1.proximoPerfilDisponivel)(store, runtime, politica, opcoes);
|
|
117
118
|
if (proximo)
|
|
118
119
|
return { perfil: (0, runtime_profiles_1.perfilDeDespacho)(proximo), configurados: doRuntime.length };
|
|
119
120
|
const agoraMs = opcoes.agoraMs ?? Date.now();
|
|
@@ -125,6 +126,41 @@ function escolherPerfil(raiz, runtime, opcoes = {}) {
|
|
|
125
126
|
return { perfil: null, configurados: doRuntime.length, motivo,
|
|
126
127
|
erro: `nenhum perfil disponivel do runtime ${runtime} (${doRuntime.map(p => `${p.id}: ${p.estado}`).join(', ')})` };
|
|
127
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* RM-056 (D1): o perfil PEDIDO (`--perfil`), validado contra o store. Recusa com motivo tipado e nunca
|
|
131
|
+
* troca de perfil: inexistente ou de outro runtime e `runtime.profile-invalid`; esgotado, a cota; sem
|
|
132
|
+
* login (ou de provider pago), o motivo do estado. Funcao propria, para o despacho da RM-055 rebasar limpo.
|
|
133
|
+
*/
|
|
134
|
+
function perfilPedido(store, runtime, id, agoraMs = Date.now()) {
|
|
135
|
+
const doRuntime = (0, runtime_profiles_1.perfisDoRuntime)(store, runtime);
|
|
136
|
+
const pedido = doRuntime.find(p => p.id === id);
|
|
137
|
+
if (!pedido) {
|
|
138
|
+
const outro = store.perfis.find(p => p.id === id);
|
|
139
|
+
return { perfil: null, configurados: doRuntime.length, motivo: 'runtime.profile-invalid',
|
|
140
|
+
erro: outro ? `perfil "${id}" e do runtime ${outro.runtime}, nao do ${runtime}`
|
|
141
|
+
: `perfil "${id}" nao existe no store (${doRuntime.length ? `perfis do ${runtime}: ${doRuntime.map(p => p.id).join(', ')}` : `nenhum perfil do ${runtime}`})` };
|
|
142
|
+
}
|
|
143
|
+
if ((0, runtime_profiles_1.perfilDisponivel)(pedido, agoraMs))
|
|
144
|
+
return { perfil: (0, runtime_profiles_1.perfilDeDespacho)(pedido), configurados: doRuntime.length };
|
|
145
|
+
const motivo = pedido.estado === 'esgotado' ? 'runtime.quota-exhausted' : pedido.estado === 'sem-auth'
|
|
146
|
+
? 'runtime.auth-missing' : pedido.estado === 'provider-pago' ? 'cost.violation' : 'runtime.profile-invalid';
|
|
147
|
+
return { perfil: null, configurados: doRuntime.length, motivo,
|
|
148
|
+
erro: `perfil "${pedido.id}" esta ${pedido.estado}${pedido.esgotadoAte ? ` ate ${pedido.esgotadoAte}` : ''}` };
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* RM-056 (D3): a carga dos perfis do runtime, so quando o manifesto pede `distribuir: carga` e o
|
|
152
|
+
* dono nao pediu um perfil. Consulta falha vale carga desconhecida (zero): decide o desempate.
|
|
153
|
+
*/
|
|
154
|
+
function cargaDoDespacho(carregado, runtime, politica, pedido) {
|
|
155
|
+
if (politica.distribuir !== 'carga' || pedido !== undefined || !(0, runtime_profiles_1.runtimeComPerfil)(runtime))
|
|
156
|
+
return undefined;
|
|
157
|
+
try {
|
|
158
|
+
return (0, sessoes_contas_1.sessoesVivasPorPerfil)(carregado.raiz, runtime, carregado.manifesto.concurrency.stale_after_min);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return new Map();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
128
164
|
/**
|
|
129
165
|
* I-33 (D7, D13): preflight de auth antes do despacho. O perfil escolhido tem o login conferido
|
|
130
166
|
* pelo proprio CLI com o env dele; reprovado, vira `sem-auth` no store (ou `provider-pago`, quando
|
|
@@ -136,8 +172,9 @@ function perfilParaDespacho(carregado, thread, fase, runtime, opcoes) {
|
|
|
136
172
|
const { raiz } = carregado;
|
|
137
173
|
const excluir = [...(opcoes.excluir ?? [])];
|
|
138
174
|
const politica = (0, runtime_profiles_1.politicaDeRotacao)(carregado.manifesto);
|
|
175
|
+
const carga = cargaDoDespacho(carregado, runtime, politica, opcoes.perfil);
|
|
139
176
|
for (;;) {
|
|
140
|
-
const escolha = escolherPerfil(raiz, runtime, { perfil: opcoes.perfil, excluir, politica });
|
|
177
|
+
const escolha = escolherPerfil(raiz, runtime, { perfil: opcoes.perfil, excluir, politica, carga });
|
|
141
178
|
if (escolha.erro || !escolha.perfil || opcoes.dryRun)
|
|
142
179
|
return escolha;
|
|
143
180
|
const auth = runtime === 'claude-bg' ? (0, claude_bg_1.conferirAuth)(escolha.perfil) : runtime === 'codex' ? (0, codex_1.conferirAuth)(escolha.perfil)
|
|
@@ -164,7 +201,7 @@ function perfilParaDespacho(carregado, thread, fase, runtime, opcoes) {
|
|
|
164
201
|
razao = 'o preflight de auth reprovou o perfil antes do despacho (D7): perfil sem login nunca recebe despacho';
|
|
165
202
|
}
|
|
166
203
|
excluir.push(escolha.perfil.id);
|
|
167
|
-
const proximo = opcoes.perfil === undefined ? escolherPerfil(raiz, runtime, { excluir, politica }).perfil : null;
|
|
204
|
+
const proximo = opcoes.perfil === undefined ? escolherPerfil(raiz, runtime, { excluir, politica, carga }).perfil : null;
|
|
168
205
|
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, thread.id), thread.id, ledger_1.TIPOS_DE_EVENTO.perfilRotacionado, {
|
|
169
206
|
fase, motivo, origem: `${opcoes.origem}.preflight`,
|
|
170
207
|
de: { runtime, perfil: escolha.perfil.id }, para: proximo ? { runtime, perfil: proximo.id } : null,
|
|
@@ -314,8 +351,10 @@ function montarPrompt(thread, fase, pedido, raiz, memoriaInjetada = '') {
|
|
|
314
351
|
*/
|
|
315
352
|
function montarPromptComMemoria(carregado, thread, fase, pedido, memoria) {
|
|
316
353
|
const injecao = (0, memoria_1.injecaoDaFase)(carregado, memoria, thread, fase);
|
|
354
|
+
// Mesma raiz usada pelo MCP e runtime-context; o manifesto da WT nao habilita a dica.
|
|
355
|
+
const ligado = (0, mcp_grafo_1.grafoLigado)((0, manifest_1.exigirManifesto)((0, estado_thread_1.raizDoEstado)(carregado.raiz)).manifesto);
|
|
317
356
|
return {
|
|
318
|
-
prompt: montarPrompt(thread, fase, pedido, carregado.raiz, injecao.texto),
|
|
357
|
+
prompt: montarPrompt(thread, fase, (0, prompts_1.pedidoComDicaDoGrafo)(pedido, thread.id, ligado), carregado.raiz, injecao.texto),
|
|
319
358
|
injecao,
|
|
320
359
|
};
|
|
321
360
|
}
|
|
@@ -1039,6 +1078,15 @@ tomadaPrevia) {
|
|
|
1039
1078
|
erro,
|
|
1040
1079
|
};
|
|
1041
1080
|
}
|
|
1081
|
+
// RM-055: o que so o dono resolve no terminal vira a pausa dele, com o comando exato e o que o ork
|
|
1082
|
+
// faz depois. O prompt ja esta gravado com o sha256 acima, e e ele que o retry re-despacha.
|
|
1083
|
+
const impedimento = (0, impedimento_1.registrarImpedimentoDoDono)(dir, thread, { fase, slug, runtime, cwd, origem: 'phase.run',
|
|
1084
|
+
promptPath, promptSha256: sha, perfil, saida: `${resultado.stderr}\n${erro}` });
|
|
1085
|
+
if (impedimento) {
|
|
1086
|
+
return { thread, slug, promptPath, promptSha256: sha, comando: resultado.comando, controlador: resultado.controlador,
|
|
1087
|
+
sessionId: null, verificada: false, pausaAoFim, dryRun: false, runtime, model, effort, bloqueado: false,
|
|
1088
|
+
motivo: impedimento.motivo, violacoes, naFila: null, erro: `${impedimento.motivo}: ${impedimento.trecho}` };
|
|
1089
|
+
}
|
|
1042
1090
|
return {
|
|
1043
1091
|
thread,
|
|
1044
1092
|
slug,
|
|
@@ -1130,8 +1178,13 @@ function tabelaDoLedger(raiz, threadId) {
|
|
|
1130
1178
|
detalhe.push(`acao ${String(e.acao)}`);
|
|
1131
1179
|
if (e.playbook)
|
|
1132
1180
|
detalhe.push(`playbook ${String(e.playbook)}`);
|
|
1133
|
-
|
|
1134
|
-
|
|
1181
|
+
// Ensaio de 03/10/2026 (RM-049): na decisao autonoma o pedido e o objeto `ork.hitl/v2`, e a tabela
|
|
1182
|
+
// mostrava "pedido [object Object]"; do objeto sai o id curto.
|
|
1183
|
+
if (typeof e.pedido === 'string' && e.pedido !== '')
|
|
1184
|
+
detalhe.push(`pedido ${e.pedido}`);
|
|
1185
|
+
else if (e.pedido && typeof e.pedido === 'object' && typeof e.pedido.id === 'string') {
|
|
1186
|
+
detalhe.push(`pedido ${e.pedido.id.slice(0, 8)}`);
|
|
1187
|
+
}
|
|
1135
1188
|
if (e.rodada !== undefined)
|
|
1136
1189
|
detalhe.push(`rodada ${String(e.rodada)}`);
|
|
1137
1190
|
if (e.cobertura)
|