@orkastery/cli 0.5.0 → 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/README.md +11 -2
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/onboarding.md +3 -2
- 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 +35 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +47 -12
- 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 +50 -12
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +59 -11
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +6 -2
- 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/claim-lint.js +3 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +110 -3
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +294 -37
- package/dist/entrega-pr.js +27 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +35 -9
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/fix.js +3 -3
- 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 +33 -1
- 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 +59 -13
- package/dist/impedimento.js +205 -0
- package/dist/index.js +433 -88
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +28 -5
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +267 -30
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-contract.js +71 -12
- package/dist/intelligence-graph-extract-md.js +41 -23
- package/dist/intelligence-graph-extract-ts.js +181 -11
- package/dist/intelligence-graph-extract.js +186 -9
- package/dist/intelligence-graph-index.js +205 -24
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-repo.js +10 -0
- package/dist/leases.js +680 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +12 -0
- package/dist/licoes.js +6 -4
- package/dist/liveness.js +2 -1
- package/dist/maestro-runtime.js +7 -1
- package/dist/manifest.js +44 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +36 -3
- package/dist/mcp-git.js +80 -15
- package/dist/mcp-grafo-worker.js +93 -0
- package/dist/mcp-grafo.js +279 -0
- package/dist/mcp-install.js +2 -1
- package/dist/mcp-server.js +23 -1
- package/dist/mcp-ship.js +2 -0
- package/dist/mcp-verify.js +3 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +195 -20
- package/dist/ocupacao.js +17 -5
- package/dist/onboarding.js +9 -4
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +14 -11
- package/dist/parado-no-condutor.js +1089 -0
- package/dist/phase.js +68 -15
- package/dist/policies.js +79 -3
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +414 -0
- package/dist/pulse-delivery.js +60 -7
- package/dist/pulse.js +99 -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 +162 -7
- package/dist/runtime-context.js +5 -1
- 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 -12
- package/dist/sessoes.js +87 -3
- package/dist/ship.js +110 -20
- package/dist/thread.js +212 -14
- package/dist/util.js +71 -4
- package/dist/verify.js +2 -2
- package/dist/worktree.js +34 -8
- package/eval/casos/onboarding.json +1 -1
- 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/onboarding/SKILL.md +3 -2
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
- package/skills/phases/ship-release/SKILL.md +6 -3
package/dist/ledger-stats.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.parsePeriodo = parsePeriodo;
|
|
37
37
|
exports.coletarEstatisticas = coletarEstatisticas;
|
|
38
38
|
exports.registrarEstimativaPlano = registrarEstimativaPlano;
|
|
39
|
+
exports.linhaDoHitlDeConducao = linhaDoHitlDeConducao;
|
|
39
40
|
exports.textoDasEstatisticas = textoDasEstatisticas;
|
|
40
41
|
const fs = __importStar(require("node:fs"));
|
|
41
42
|
const path = __importStar(require("node:path"));
|
|
@@ -43,6 +44,7 @@ const thread_1 = require("./thread");
|
|
|
43
44
|
const ledger_1 = require("./ledger");
|
|
44
45
|
const util_1 = require("./util");
|
|
45
46
|
const horario_1 = require("./horario");
|
|
47
|
+
const hitl_tempo_parado_1 = require("./hitl-tempo-parado");
|
|
46
48
|
const MOTIVOS_PREVENTIVOS = new Set([
|
|
47
49
|
'policy.violation', 'cost.violation', 'verify.regression', 'claims.failed', 'claims.unverifiable',
|
|
48
50
|
]);
|
|
@@ -118,7 +120,9 @@ function coletarEstatisticas(raiz, filtros) {
|
|
|
118
120
|
const riscos = {};
|
|
119
121
|
const leads = [];
|
|
120
122
|
const fontes = new Set();
|
|
121
|
-
|
|
123
|
+
const esperasDeConducao = [];
|
|
124
|
+
for (const { thread, eventos } of selecionadas) {
|
|
125
|
+
esperasDeConducao.push(...(0, hitl_tempo_parado_1.esperasDeHitl)(thread.id, eventos));
|
|
122
126
|
corrompidos += eventos.filter(e => e.tipo === 'ledger_corrupted').length;
|
|
123
127
|
const despachos = new Map();
|
|
124
128
|
for (const e of eventos)
|
|
@@ -237,6 +241,7 @@ function coletarEstatisticas(raiz, filtros) {
|
|
|
237
241
|
custoReferencia: { natureza: tarifas.nature, moeda: tarifas.currency, valor: precificadas ? Number(custo.toFixed(6)) : null, sessoesPrecificadas: precificadas, sessoesSemTarifa: semTarifa, tarifasVerificadasEm: tarifas.verifiedAt, fontes: [...fontes].sort() },
|
|
238
242
|
leadTime: { mediaMs: leads.length ? leads.reduce((a, b) => a + b, 0) / leads.length : null, amostras: leads.length },
|
|
239
243
|
esperaHumana: { milissegundos: esperaMs, fechadas: esperasFechadas, abertas: esperasAbertas },
|
|
244
|
+
hitlDeConducao: (0, hitl_tempo_parado_1.resumirTempoParado)(esperasDeConducao, desdeMs, ateMs),
|
|
240
245
|
riscosPreventivos: { total: Object.values(riscos).reduce((a, b) => a + b, 0), porMotivo: riscos },
|
|
241
246
|
estimativasPlano: { amostras: estimativas, semIaHoras, iaSemOrkHoras },
|
|
242
247
|
qualidade: { ledgersCorrompidos: corrompidos, observacoes },
|
|
@@ -255,6 +260,14 @@ function registrarEstimativaPlano(raiz, threadId, dados) {
|
|
|
255
260
|
throw Error('ledger.estimate.head-unavailable');
|
|
256
261
|
return (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, threadId), threadId, 'plan_estimate', { fase: 'PLAN', unidade: 'hours', semIaHoras: dados.semIaHoras, iaSemOrkHoras: dados.iaSemOrkHoras, por: dados.por, metodo: dados.metodo, premissas: dados.premissas, incerteza: dados.incerteza ?? 'nao informada', head: head.stdout.trim() });
|
|
257
262
|
}
|
|
263
|
+
const minutos = (ms) => ms === null ? 'sem resposta medida' : `${(ms / 60_000).toFixed(1)} min`;
|
|
264
|
+
/** RM-057: uma linha, com a meta ao lado da mediana, para o dono ver o tempo parado sem abrir o JSON. */
|
|
265
|
+
function linhaDoHitlDeConducao(h) {
|
|
266
|
+
const meta = h.dentroDaMeta === null ? '' : h.dentroDaMeta ? ' (dentro da meta de 5 min)' : ' (acima da meta de 5 min)';
|
|
267
|
+
return ` HITL de conducao ${h.pedidos} pergunta(s); parado ${(h.paradoMs / 3_600_000).toFixed(2)} h; ` +
|
|
268
|
+
`mediana ${minutos(h.medianaRespostaMs)}${meta}; ${h.abertos} aberta(s); ` +
|
|
269
|
+
`texto fora da excecao ${h.emTexto.foraDaExcecao}`;
|
|
270
|
+
}
|
|
258
271
|
function textoDasEstatisticas(r) {
|
|
259
272
|
const dinheiro = r.custoReferencia.valor === null ? 'sem cobertura' : `USD ${r.custoReferencia.valor.toFixed(6)}`;
|
|
260
273
|
return [
|
|
@@ -265,6 +278,7 @@ function textoDasEstatisticas(r) {
|
|
|
265
278
|
` tokens ${r.tokens.total} total; input ${r.tokens.input} (cached ${r.tokens.cachedInput}); output ${r.tokens.output}`,
|
|
266
279
|
` custo referencia ${dinheiro} — estimativa por tarifa publica, nao gasto/fatura`,
|
|
267
280
|
` espera humana ${(r.esperaHumana.milissegundos / 3_600_000).toFixed(2)} h; ${r.esperaHumana.abertas} aberta(s)`,
|
|
281
|
+
linhaDoHitlDeConducao(r.hitlDeConducao),
|
|
268
282
|
` riscos evitados ${r.riscosPreventivos.total} gate(s) preventivo(s)`,
|
|
269
283
|
` estimativas PLAN ${r.estimativasPlano.amostras} amostra(s)`,
|
|
270
284
|
...r.qualidade.observacoes.map(o => ` cobertura ${o}`),
|
package/dist/ledger.js
CHANGED
|
@@ -45,6 +45,7 @@ exports.caminhoLedger = caminhoLedger;
|
|
|
45
45
|
exports.registrar = registrar;
|
|
46
46
|
exports.threadPresente = threadPresente;
|
|
47
47
|
exports.registrarSeExiste = registrarSeExiste;
|
|
48
|
+
exports.ehEnsaio = ehEnsaio;
|
|
48
49
|
exports.lerLedger = lerLedger;
|
|
49
50
|
const fs = __importStar(require("node:fs"));
|
|
50
51
|
const path = __importStar(require("node:path"));
|
|
@@ -140,6 +141,9 @@ exports.TIPOS_DE_EVENTO = {
|
|
|
140
141
|
// I-33 (D5): troca de perfil ou de runtime depois de falha da conta (quem, de qual para
|
|
141
142
|
// qual, evidencia e razao). Faz parte do catalogo, nao de literal solto.
|
|
142
143
|
perfilRotacionado: 'runtime_profile_rotated',
|
|
144
|
+
// RM-037 (fatia 5): a cota que o observador viu na transcricao com a sessao viva; o perfil saiu do rodizio
|
|
145
|
+
// ali, ate a hora dita na mensagem, e nao so no fecho da fase.
|
|
146
|
+
cotaVistaNaTranscricao: 'runtime_quota_detected',
|
|
143
147
|
fixAberto: 'go_fix_opened',
|
|
144
148
|
fixDespachado: 'go_fix_dispatched',
|
|
145
149
|
reverifyConcluido: 'check_reverify',
|
|
@@ -236,6 +240,14 @@ function registrarSeExiste(dirThread, threadId, tipo, dados = {}) {
|
|
|
236
240
|
}
|
|
237
241
|
return evento;
|
|
238
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* Fatia 2 do ensaio da 0.5.0 (P2): o evento que um `--dry-run` grava (`dryRun: true`) e ensaio, nao
|
|
245
|
+
* estado. O ledger o guarda como rastro; board, escalonador, monitor (o pulse) e maestro o descartam.
|
|
246
|
+
* O ensaio do ship gravava `gate_blocked human.pending` e a thread aparecia pausada sem ninguem pedir.
|
|
247
|
+
*/
|
|
248
|
+
function ehEnsaio(e) {
|
|
249
|
+
return e.dryRun === true;
|
|
250
|
+
}
|
|
239
251
|
/** Le o ledger inteiro. Linha corrompida vira evento `ledger_corrupted` em vez de quebrar a leitura. */
|
|
240
252
|
function lerLedger(dirThread) {
|
|
241
253
|
const caminho = caminhoLedger(dirThread);
|
package/dist/licoes.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PISO_DA_PROPOSTA = exports.JANELA_DA_PROPOSTA_DIAS = void 0;
|
|
36
|
+
exports.PISO_DA_PROPOSTA = exports.JANELA_DA_PROPOSTA_DIAS = exports.DICA_DO_MOTIVO = void 0;
|
|
37
37
|
exports.lerLicoes = lerLicoes;
|
|
38
38
|
exports.resumoDasLicoes = resumoDasLicoes;
|
|
39
39
|
exports.textoDasLicoes = textoDasLicoes;
|
|
@@ -59,15 +59,17 @@ const estado_thread_1 = require("./estado-thread");
|
|
|
59
59
|
const ledger_1 = require("./ledger");
|
|
60
60
|
const policies_1 = require("./policies");
|
|
61
61
|
/** O que evita cada bloqueio, na forma de comando. Sem dica, a licao so conta a recorrencia. */
|
|
62
|
-
|
|
62
|
+
exports.DICA_DO_MOTIVO = {
|
|
63
63
|
'claims.failed': 'rode o comando da claim antes de registra-la; claim sem prova local volta como GO-FIX',
|
|
64
64
|
'verify.regression': 'grave a baseline antes do GO (`ork verify <thread> --baseline`) e rode os testes focados antes do CHECK',
|
|
65
65
|
'verify.failed': 'grave a baseline antes do GO, para a falha ter com que ser comparada',
|
|
66
66
|
'verify.timeout': 'divida o comando lento ou suba `verify.timeout_ms` no manifesto',
|
|
67
67
|
'runtime.unavailable': 'declare a ordem de fallback do bloco (`ork setup <modo> --bloco N --fallback runtime:modelo`)',
|
|
68
68
|
'runtime.quota-exhausted': 'tenha um segundo perfil da conta (`ork accounts add`) ou fallback no bloco',
|
|
69
|
+
'runtime.profile-invalid': 'confira os perfis do runtime em `ork accounts list` antes de pedir `--perfil`',
|
|
69
70
|
'tree.blocked': 'sincronize a worktree com a base antes do SHIP (`ork worktree sync <thread>`)',
|
|
70
|
-
|
|
71
|
+
// Fatia 2 do ensaio da 0.5.0 (P6): o que o CI do projeto roda, e nao o script do Orkastery.
|
|
72
|
+
'ci.failed': 'rode antes do push o que o CI do projeto roda (`ci.command` do manifesto ou, sem ele, os comandos de `verify`)',
|
|
71
73
|
'artifact.missing': 'grave o artefato da fase exatamente no caminho que o prompt pede',
|
|
72
74
|
};
|
|
73
75
|
const DICA_DA_CLASSE = {
|
|
@@ -116,7 +118,7 @@ function recorrencias(licoes) {
|
|
|
116
118
|
const classes = new Map();
|
|
117
119
|
for (const l of licoes) {
|
|
118
120
|
for (const m of l.motivos) {
|
|
119
|
-
const r = motivos.get(m) ?? { chave: `motivo:${m}`, tipo: 'motivo', nome: m, threads: [], vezes: 0, dica: DICA_DO_MOTIVO[m] ?? null };
|
|
121
|
+
const r = motivos.get(m) ?? { chave: `motivo:${m}`, tipo: 'motivo', nome: m, threads: [], vezes: 0, dica: exports.DICA_DO_MOTIVO[m] ?? null };
|
|
120
122
|
r.threads.push(l.thread);
|
|
121
123
|
motivos.set(m, r);
|
|
122
124
|
}
|
package/dist/liveness.js
CHANGED
|
@@ -120,7 +120,8 @@ function detectarFasesOrfas(carregado, opcoes = {}) {
|
|
|
120
120
|
const t = (0, thread_1.lerThread)(carregado.raiz, id), dir = (0, thread_1.dirThread)(carregado.raiz, id);
|
|
121
121
|
if (t.status !== 'aberta')
|
|
122
122
|
continue;
|
|
123
|
-
|
|
123
|
+
// Fatia 2 do ensaio da 0.5.0 (P2; CHECK, rodada 1, A1): o gate do `ship --dry-run` nao e gate em aberto.
|
|
124
|
+
const eventos = (0, ledger_1.lerLedger)(dir).filter(e => !(0, ledger_1.ehEnsaio)(e)), di = eventos.map(e => e.tipo).lastIndexOf('phase_dispatch');
|
|
124
125
|
if (di < 0)
|
|
125
126
|
continue;
|
|
126
127
|
const d = eventos[di], inicio = Date.parse(d.ts), fase = d.fase;
|
package/dist/maestro-runtime.js
CHANGED
|
@@ -47,6 +47,7 @@ const hitl_sessions_1 = require("./hitl-sessions");
|
|
|
47
47
|
const thread_1 = require("./thread");
|
|
48
48
|
const hitl_gates_1 = require("./hitl-gates");
|
|
49
49
|
const ocupacao_1 = require("./ocupacao");
|
|
50
|
+
const ledger_1 = require("./ledger");
|
|
50
51
|
const horario_1 = require("./horario");
|
|
51
52
|
const conducao_1 = require("./conducao");
|
|
52
53
|
const conducao_texto_1 = require("./conducao-texto");
|
|
@@ -74,8 +75,11 @@ const shipView = zod_1.z.union([
|
|
|
74
75
|
zod_1.z.object({
|
|
75
76
|
tipo: zod_1.z.literal('ship_done'), ts: shipTs, pushVerificado: zod_1.z.boolean(), mergeSha: shipSha,
|
|
76
77
|
shaRemoto: shipSha.nullable().optional(),
|
|
78
|
+
// RM-037 (fatia 5, A1): o push prova a ponta da base; o `mergeSha` e o merge que entregou, que pode ser mais
|
|
79
|
+
// velho que ela. Recibo sem o campo continua valendo pela regra de antes.
|
|
80
|
+
pontaDaBase: shipSha.nullable().optional(),
|
|
77
81
|
fonteDaProva: zod_1.z.string().min(1).max(512).refine(v => !/[\u0000-\u001f\u007f]/.test(v)).nullable().optional(),
|
|
78
|
-
}).refine(s => !s.pushVerificado || (s.shaRemoto === s.mergeSha && typeof s.fonteDaProva === 'string')),
|
|
82
|
+
}).refine(s => !s.pushVerificado || (s.shaRemoto === (s.pontaDaBase ?? s.mergeSha) && typeof s.fonteDaProva === 'string')),
|
|
79
83
|
zod_1.z.object({ tipo: zod_1.z.enum(['ship_started', 'ship_blocked']), ts: shipTs }),
|
|
80
84
|
]);
|
|
81
85
|
function operationalSources(reader, threads, native = [], now = new Date().toISOString(), threadScope) {
|
|
@@ -95,6 +99,8 @@ function operationalSources(reader, threads, native = [], now = new Date().toISO
|
|
|
95
99
|
events = raw.split('\n').filter(Boolean).map(line => JSON.parse(line));
|
|
96
100
|
if (events.some(e => typeof e.tipo !== 'string' || e.thread !== t.id))
|
|
97
101
|
throw Error('invalid');
|
|
102
|
+
// Fatia 2 do ensaio da 0.5.0 (P2): o ensaio (`dryRun: true`) nao vira bloqueio nem entrega incompleta.
|
|
103
|
+
events = events.filter(e => !(0, ledger_1.ehEnsaio)(e));
|
|
98
104
|
}
|
|
99
105
|
catch {
|
|
100
106
|
for (const name of names.filter(n => !['leases', 'retries'].includes(n)))
|
package/dist/manifest.js
CHANGED
|
@@ -165,6 +165,28 @@ function booleano(v, padrao) {
|
|
|
165
165
|
function mapa(v) {
|
|
166
166
|
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* RM-031 KG5 (D2): `grafo.mcp` so liga com o booleano `true`. Ausente vale `false`; texto que parece
|
|
170
|
+
* booleano, outro tipo ou `grafo` que nao e mapa tambem valem `false`, com aviso: ligar expoe as tools
|
|
171
|
+
* do grafo, e na duvida fica desligado. Chave desconhecida em `grafo` so avisa.
|
|
172
|
+
*/
|
|
173
|
+
function lerGrafo(v, avisos) {
|
|
174
|
+
const mostrar = (x) => JSON.stringify(x).slice(0, 80);
|
|
175
|
+
if (v === undefined || v === null)
|
|
176
|
+
return { mcp: false };
|
|
177
|
+
if (typeof v !== 'object' || Array.isArray(v)) {
|
|
178
|
+
avisos.push(`grafo deve ser um mapa com mcp: true ou false; vale mcp: false (${mostrar(v)} nao reconhecido)`);
|
|
179
|
+
return { mcp: false };
|
|
180
|
+
}
|
|
181
|
+
for (const chave of Object.keys(v))
|
|
182
|
+
if (chave !== 'mcp')
|
|
183
|
+
avisos.push(`grafo.${chave} desconhecida; o bloco grafo so tem mcp`);
|
|
184
|
+
const mcp = v.mcp;
|
|
185
|
+
if (mcp === undefined || mcp === null || typeof mcp === 'boolean')
|
|
186
|
+
return { mcp: mcp === true };
|
|
187
|
+
avisos.push(`grafo.mcp deve ser true ou false; vale false (${mostrar(mcp)} nao reconhecido)`);
|
|
188
|
+
return { mcp: false };
|
|
189
|
+
}
|
|
168
190
|
/** Mesmo contrato na leitura do YAML e nos consumidores de manifesto em memoria. */
|
|
169
191
|
function validarOptInPlaybook(valor) {
|
|
170
192
|
if (valor === undefined)
|
|
@@ -334,6 +356,16 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
334
356
|
avisos.push(`runtime_profiles.${nome} deve ser true ou false; vale o padrao ${padrao} (${JSON.stringify(v)} nao reconhecido)`);
|
|
335
357
|
return padrao;
|
|
336
358
|
};
|
|
359
|
+
// RM-056 (D2): opt-in. Valor desconhecido vale o padrao `ordem`, com aviso.
|
|
360
|
+
const distribuicaoDePerfis = () => {
|
|
361
|
+
const v = perfisDeRuntime.distribuir;
|
|
362
|
+
if (v === undefined || v === null || v === 'ordem')
|
|
363
|
+
return 'ordem';
|
|
364
|
+
if (v === 'carga')
|
|
365
|
+
return 'carga';
|
|
366
|
+
avisos.push(`runtime_profiles.distribuir aceita ordem ou carga; vale o padrao ordem (${JSON.stringify(v)} nao reconhecido)`);
|
|
367
|
+
return 'ordem';
|
|
368
|
+
};
|
|
337
369
|
const liveness = mapa(dados.liveness);
|
|
338
370
|
const silencioMaxMin = numero(liveness.silencio_max_min, 10);
|
|
339
371
|
if (!Number.isFinite(silencioMaxMin) || silencioMaxMin <= 0)
|
|
@@ -434,6 +466,11 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
434
466
|
'(o `ork` nao adivinha DSN, e base alheia e pior do que base nenhuma)');
|
|
435
467
|
}
|
|
436
468
|
const embedding = lerEmbedding(memory.embedding, variavelDaDsn, erros);
|
|
469
|
+
const prazoDoUniverso = memory.universo_timeout_ms === undefined ? orkmind_1.TIMEOUT_DO_UNIVERSO_MS : memory.universo_timeout_ms;
|
|
470
|
+
if (typeof prazoDoUniverso !== 'number' || !Number.isSafeInteger(prazoDoUniverso) || prazoDoUniverso <= 0 ||
|
|
471
|
+
prazoDoUniverso > orkmind_1.LIMITE_TIMEOUT_DO_UNIVERSO_MS) {
|
|
472
|
+
erros.push('memory.universo_timeout_ms: esperado inteiro em ms entre 1 e 86400000 (24 h; valor omitido)');
|
|
473
|
+
}
|
|
437
474
|
const bytes = Buffer.byteLength(bruto, 'utf8');
|
|
438
475
|
if (bytes > exports.LIMITE_MANIFESTO_BYTES) {
|
|
439
476
|
erros.push(`manifesto com ${bytes} bytes, acima do limite duro de ${exports.LIMITE_MANIFESTO_BYTES} (prosa vai para memoria com tag, nao para o YAML)`);
|
|
@@ -469,7 +506,9 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
469
506
|
worktree: {
|
|
470
507
|
base_branch: texto(worktree.base_branch, 'main'),
|
|
471
508
|
dir: texto(worktree.dir, '.claude/worktrees'),
|
|
472
|
-
|
|
509
|
+
// P4 do ensaio da 0.5.0: o `ork thread new` cria a worktree sem flag quando a chave diz true. Ausente le
|
|
510
|
+
// false, para o projeto que nunca a declarou seguir como era.
|
|
511
|
+
por_thread: booleano(worktree.por_thread, false),
|
|
473
512
|
},
|
|
474
513
|
verify: {
|
|
475
514
|
build: verify.build === null || verify.build === undefined ? undefined : texto(verify.build, ''),
|
|
@@ -500,6 +539,7 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
500
539
|
runtime_profiles: {
|
|
501
540
|
rotate_same_runtime_on_quota: chaveDeRotacao('rotate_same_runtime_on_quota', true),
|
|
502
541
|
rotate_same_runtime_on_auth: chaveDeRotacao('rotate_same_runtime_on_auth', true),
|
|
542
|
+
distribuir: distribuicaoDePerfis(),
|
|
503
543
|
},
|
|
504
544
|
// Bloco B3: o limite de escalacao tem padrao, e o padrao e conservador. Manifesto
|
|
505
545
|
// sem bloco `retry:` continua andando com 3 tentativas e janela estimada de 60 min,
|
|
@@ -518,6 +558,7 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
518
558
|
cli: texto(memory.cli, 'orkmind'),
|
|
519
559
|
tenant: texto(memory.tenant, '') || nomeProjeto,
|
|
520
560
|
timeout_ms: numero(memory.timeout_ms, 15000),
|
|
561
|
+
universo_timeout_ms: typeof prazoDoUniverso === 'number' ? prazoDoUniverso : orkmind_1.TIMEOUT_DO_UNIVERSO_MS,
|
|
521
562
|
...(embedding ? { embedding } : {}),
|
|
522
563
|
},
|
|
523
564
|
// Bloco B5: governanca de custo dos auditores. Ausente no manifesto quer dizer
|
|
@@ -534,6 +575,8 @@ function carregarManifesto(dirInicial = diretorioDoProjeto()) {
|
|
|
534
575
|
compartilhada: booleano(fabrica.compartilhada, false),
|
|
535
576
|
remoto: texto(fabrica.remoto, 'origin'),
|
|
536
577
|
},
|
|
578
|
+
// RM-031 KG5 (D2): expor as tools do grafo no MCP e opt-in do dono.
|
|
579
|
+
grafo: lerGrafo(dados.grafo, avisos),
|
|
537
580
|
policies: Object.fromEntries(Object.entries(mapa(dados.policies)).map(([k, v]) => [k, texto(v, '')])),
|
|
538
581
|
};
|
|
539
582
|
return { caminho: achado.caminho, raiz, legado: achado.legado, bytes, manifesto, erros, avisos };
|
package/dist/master-nota.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ERRO_PROVA_DE_CANAL = exports.CONTRATO_PEDIDO_DE_NOTA = void 0;
|
|
37
|
+
exports.marcaDeHost = marcaDeHost;
|
|
37
38
|
exports.exigirNotaSemHost = exigirNotaSemHost;
|
|
38
39
|
exports.arquivoDasNotas = arquivoDasNotas;
|
|
39
40
|
exports.pedirNota = pedirNota;
|
|
@@ -84,10 +85,11 @@ exports.CONTRATO_PEDIDO_DE_NOTA = 'ork.master-nota/v1';
|
|
|
84
85
|
exports.ERRO_PROVA_DE_CANAL = 'master.prova-de-canal';
|
|
85
86
|
const sha = (s) => (0, node_crypto_1.createHash)('sha256').update(s).digest('hex');
|
|
86
87
|
/**
|
|
87
|
-
*
|
|
88
|
-
* ambiente
|
|
88
|
+
* A marca de host ou de despacho do processo, ou `undefined` no terminal do dono. Lida SO do
|
|
89
|
+
* ambiente. Serve para RECUSAR (D8) e para AVISAR (RM-008, aceite por omissao sem thread), nunca
|
|
90
|
+
* para autorizar.
|
|
89
91
|
*/
|
|
90
|
-
function
|
|
92
|
+
function marcaDeHost(ambiente = process.env) {
|
|
91
93
|
let canal;
|
|
92
94
|
try {
|
|
93
95
|
canal = (0, conducao_1.canalDoProcesso)(undefined, ambiente);
|
|
@@ -97,12 +99,19 @@ function exigirNotaSemHost(ambiente = process.env) {
|
|
|
97
99
|
}
|
|
98
100
|
// B2 do CHECK: `ORK_CANAL=cli` NAO absolve. A sessao despachada herda `ORK_CANAL=cli` quando a
|
|
99
101
|
// thread e conduzida do terminal, e o Claude Code e o Codex marcam os proprios processos. Qualquer
|
|
100
|
-
// marca de host ou de despacho
|
|
101
|
-
|
|
102
|
+
// marca de host ou de despacho conta, mesmo com o canal declarado como terminal.
|
|
103
|
+
return canal !== 'cli' ? canal
|
|
102
104
|
: ambiente.ORK_DISPATCH_ID ? 'sessão despachada (ORK_DISPATCH_ID)'
|
|
103
105
|
: ambiente.CLAUDECODE === '1' ? 'claude-code (CLAUDECODE)'
|
|
104
106
|
: ambiente.CODEX_SANDBOX || ambiente.CODEX_SANDBOX_NETWORK_DISABLED ? 'codex (CODEX_SANDBOX)'
|
|
105
107
|
: (ambiente.HERMES_HOME ?? '').trim() ? 'hermes (HERMES_HOME)' : undefined;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* D8: nota em nome de pessoa, vinda de processo de host, e recusada. O canal e lido SO do
|
|
111
|
+
* ambiente: `--canal` em argv nao conta, porque quem escreve argv e justamente quem chama.
|
|
112
|
+
*/
|
|
113
|
+
function exigirNotaSemHost(ambiente = process.env) {
|
|
114
|
+
const marca = marcaDeHost(ambiente);
|
|
106
115
|
if (marca) {
|
|
107
116
|
throw new Error(`${exports.ERRO_PROVA_DE_CANAL}: nota em nome de pessoa vinda de ${marca} exige a prova de canal do ingresso. ` +
|
|
108
117
|
'Peça a nota com ork master pedir <thread>: o dono responde pelo Telegram com o código, e a nota é gravada com o recibo.');
|
package/dist/master.js
CHANGED
|
@@ -49,7 +49,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
49
49
|
};
|
|
50
50
|
})();
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
-
exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.ORDEM_DAS_CLASSES = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
|
|
52
|
+
exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.FASE_DO_TIPO = exports.ORDEM_DAS_CLASSES = exports.CLASSE_DO_MOTIVO = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
|
|
53
|
+
exports.classesPelosGates = classesPelosGates;
|
|
54
|
+
exports.sincronizacoesComABase = sincronizacoesComABase;
|
|
53
55
|
exports.parseClasse = parseClasse;
|
|
54
56
|
exports.caminhoPostmortem = caminhoPostmortem;
|
|
55
57
|
exports.caminhoMasterLog = caminhoMasterLog;
|
|
@@ -72,6 +74,8 @@ exports.aceitosPorOmissao = aceitosPorOmissao;
|
|
|
72
74
|
exports.pendentesDeScore = pendentesDeScore;
|
|
73
75
|
exports.tabelaDeEntregas = tabelaDeEntregas;
|
|
74
76
|
exports.aceitarPendentesPorOmissao = aceitarPendentesPorOmissao;
|
|
77
|
+
exports.entregasParaOmissao = entregasParaOmissao;
|
|
78
|
+
exports.motivoForaDaOmissao = motivoForaDaOmissao;
|
|
75
79
|
exports.textoDoMaster = textoDoMaster;
|
|
76
80
|
exports.tabelaDeClasses = tabelaDeClasses;
|
|
77
81
|
const path = __importStar(require("node:path"));
|
|
@@ -105,6 +109,65 @@ exports.CLASSES_DE_FALHA = {
|
|
|
105
109
|
'scope-creep': 'a entrega cresceu alem do que o GOAL prometia',
|
|
106
110
|
outra: 'nao cabe em nenhuma classe acima (descreva na justificativa)',
|
|
107
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* RM-008 (classe pelo gate): a classe que cada motivo tipado do gate sustenta quando ninguem informa
|
|
114
|
+
* `--classe`. Antes, todo gate virava "outra", a classe que o `ork licoes` ignora: 8 POSTMORTEMs de
|
|
115
|
+
* 03/10 fecharam assim por aceite por omissao. Motivo fora da tabela (prazo, falta de veredito,
|
|
116
|
+
* runtime, conta, custo, espera humana) nao cabe numa classe fixa e segue "outra".
|
|
117
|
+
*/
|
|
118
|
+
exports.CLASSE_DO_MOTIVO = {
|
|
119
|
+
'artifact.missing': 'processo',
|
|
120
|
+
'claims.failed': 'processo',
|
|
121
|
+
'claims.unverifiable': 'processo',
|
|
122
|
+
'policy.violation': 'processo',
|
|
123
|
+
'runtime.autoconferencia': 'processo',
|
|
124
|
+
'verify.regression': 'processo',
|
|
125
|
+
'verify.failed': 'processo',
|
|
126
|
+
'ci.failed': 'processo',
|
|
127
|
+
'hitl.formato': 'processo',
|
|
128
|
+
'runtime.rate-limited': 'rate-limit',
|
|
129
|
+
'runtime.quota-exhausted': 'rate-limit',
|
|
130
|
+
'lease.busy': 'conflito',
|
|
131
|
+
'conducao.em-andamento': 'conflito',
|
|
132
|
+
'tree.blocked': 'conflito',
|
|
133
|
+
};
|
|
134
|
+
/** As classes que os motivos dos gates sustentam, na ordem canonica e sem repetir. */
|
|
135
|
+
function classesPelosGates(motivos) {
|
|
136
|
+
const achadas = new Set();
|
|
137
|
+
for (const m of motivos)
|
|
138
|
+
achadas.add(exports.CLASSE_DO_MOTIVO[m] ?? 'outra');
|
|
139
|
+
if (achadas.size === 0)
|
|
140
|
+
achadas.add('sem-falha');
|
|
141
|
+
return exports.ORDEM_DAS_CLASSES.filter((c) => achadas.has(c));
|
|
142
|
+
}
|
|
143
|
+
/** Teto de merges conferidos por entrega: a branch de 03/10 com mais sincronizacoes trouxe 16. */
|
|
144
|
+
const TETO_DE_MERGES_POR_ENTREGA = 200;
|
|
145
|
+
/**
|
|
146
|
+
* RM-008 (base-avancou): quantas vezes a thread precisou trazer a base para dentro da branch. Conta os
|
|
147
|
+
* `worktree_synced` do ledger e, em cada entrega com merge, os merges da branch (entre o primeiro e o
|
|
148
|
+
* segundo pai do merge) cujo pai trazido ja estava na base. Em 03/10/2026, 29 de 35 entregas trouxeram
|
|
149
|
+
* a `origin/main` antes do merge, e nenhuma fechou com `base-avancou`. Git sem resposta conta 0 e nunca
|
|
150
|
+
* derruba o MASTER.
|
|
151
|
+
*/
|
|
152
|
+
function sincronizacoesComABase(raiz, eventos, mergeShas) {
|
|
153
|
+
let total = eventos.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.worktreeSincronizada).length;
|
|
154
|
+
for (const sha of new Set(mergeShas)) {
|
|
155
|
+
if (!/^[0-9a-f]{40}$/.test(sha))
|
|
156
|
+
continue;
|
|
157
|
+
const r = (0, util_1.exec)('git', ['rev-list', '--merges', '--parents', `--max-count=${TETO_DE_MERGES_POR_ENTREGA}`,
|
|
158
|
+
`${sha}^1..${sha}^2`], raiz, 30000);
|
|
159
|
+
if (!r.ok)
|
|
160
|
+
continue;
|
|
161
|
+
for (const linha of r.stdout.split('\n')) {
|
|
162
|
+
const pais = linha.trim().split(/\s+/).slice(1);
|
|
163
|
+
// O pai trazido (o segundo em diante) ja estava na base: e a base entrando na branch.
|
|
164
|
+
if (pais.slice(1).some((p) => /^[0-9a-f]{40}$/.test(p) &&
|
|
165
|
+
(0, util_1.exec)('git', ['merge-base', '--is-ancestor', p, `${sha}^1`], raiz, 30000).ok))
|
|
166
|
+
total += 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return total;
|
|
170
|
+
}
|
|
108
171
|
/** Ordem canonica das classes na saida do CLI. */
|
|
109
172
|
exports.ORDEM_DAS_CLASSES = [
|
|
110
173
|
'sem-falha',
|
|
@@ -138,6 +201,19 @@ function caminhoPostmortem(raiz, id) {
|
|
|
138
201
|
function caminhoMasterLog(raiz, id) {
|
|
139
202
|
return path.join((0, thread_1.dirThread)(raiz, id), 'master-log.json');
|
|
140
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* RM-008 (fases pelo tipo): a fase dos eventos que o nucleo grava sem o campo `fase`. O `verify_run`
|
|
206
|
+
* e o `ship_done` nunca trouxeram fase, e 34 dos 35 POSTMORTEM de 03/10 sairam sem o CHECK, e 33 sem o
|
|
207
|
+
* SHIP, embora o ledger os tivesse (`ork-rm037testesi`: 6 `verify_run`, 1 `ship_done`, "GOAL GO MASTER").
|
|
208
|
+
* So vale quando o evento nao traz `fase`: o campo explicito continua vencendo.
|
|
209
|
+
*/
|
|
210
|
+
exports.FASE_DO_TIPO = {
|
|
211
|
+
[ledger_1.TIPOS_DE_EVENTO.verificacao]: 'CHECK',
|
|
212
|
+
[ledger_1.TIPOS_DE_EVENTO.reverifyConcluido]: 'CHECK',
|
|
213
|
+
[ledger_1.TIPOS_DE_EVENTO.shipIniciado]: 'SHIP',
|
|
214
|
+
[ledger_1.TIPOS_DE_EVENTO.shipConcluido]: 'SHIP',
|
|
215
|
+
[ledger_1.TIPOS_DE_EVENTO.shipBloqueado]: 'SHIP',
|
|
216
|
+
};
|
|
141
217
|
/**
|
|
142
218
|
* As fases que a thread realmente percorreu, reconstruidas do LEDGER.
|
|
143
219
|
*
|
|
@@ -148,7 +224,7 @@ function fasesPercorridas(raiz, id) {
|
|
|
148
224
|
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
|
|
149
225
|
const porFase = new Map();
|
|
150
226
|
for (const e of eventos) {
|
|
151
|
-
const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : null;
|
|
227
|
+
const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : (exports.FASE_DO_TIPO[e.tipo] ?? null);
|
|
152
228
|
if (!bruta || !types_1.FASES.includes(bruta))
|
|
153
229
|
continue;
|
|
154
230
|
const atual = porFase.get(bruta) ?? {
|
|
@@ -244,7 +320,8 @@ function prepararDocumentos(raiz, id, opcoes) {
|
|
|
244
320
|
sincronizarReversao(raiz, id);
|
|
245
321
|
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
|
|
246
322
|
const gatesBloqueados = eventos
|
|
247
|
-
|
|
323
|
+
// Ensaio de 03/10/2026 (RM-049): o gate barrado por um `ork ship --dry-run` e ensaio, nao reprovacao.
|
|
324
|
+
.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.gateBloqueado && e.dryRun !== true)
|
|
248
325
|
.map((e) => ({
|
|
249
326
|
ts: e.ts,
|
|
250
327
|
motivo: String(e.motivo ?? '(sem motivo)'),
|
|
@@ -264,11 +341,20 @@ function prepararDocumentos(raiz, id, opcoes) {
|
|
|
264
341
|
let classes = opcoes.classes ?? [];
|
|
265
342
|
if (classes.length === 0) {
|
|
266
343
|
classesInferidas = true;
|
|
267
|
-
classes = gatesBloqueados.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
344
|
+
classes = classesPelosGates(gatesBloqueados.map((g) => g.motivo));
|
|
345
|
+
const motivos = [...new Set(gatesBloqueados.map((g) => g.motivo))];
|
|
346
|
+
const sincronizacoes = sincronizacoesComABase(raiz, eventos, entregas.map((e) => e.mergeSha));
|
|
347
|
+
if (sincronizacoes > 0) {
|
|
348
|
+
classes = exports.ORDEM_DAS_CLASSES.filter((c) => c === 'base-avancou' || (c !== 'sem-falha' && classes.includes(c)));
|
|
349
|
+
}
|
|
350
|
+
const pelaBase = sincronizacoes > 0
|
|
351
|
+
? ` A branch trouxe a base ${sincronizacoes} vez(es) antes da entrega: o \`ork\` juntou "base-avancou".` : '';
|
|
352
|
+
avisos.push((gatesBloqueados.length > 0
|
|
353
|
+
? `a thread levou ${gatesBloqueados.length} reprovacao(oes) tipada(s) (${motivos.join(', ')}) e nenhuma --classe foi ` +
|
|
354
|
+
`informada: o \`ork\` inferiu "${classes.join('", "')}" pelo motivo do gate.${pelaBase} Corrija com --classe <classe> --refazer.`
|
|
355
|
+
: sincronizacoes > 0
|
|
356
|
+
? `nenhuma --classe informada e nenhum gate reprovou.${pelaBase} Corrija com --classe <classe> --refazer.`
|
|
357
|
+
: 'nenhuma --classe informada e nenhum gate reprovou: o `ork` gravou "sem-falha".'));
|
|
272
358
|
}
|
|
273
359
|
// I-43 (D3): o indice e DERIVADO do ledger no momento do registro, e acompanha o
|
|
274
360
|
// score como o que a maquina achava antes de o dono falar. Quando as duas existem,
|
|
@@ -351,7 +437,7 @@ function autoriaHumana(por) {
|
|
|
351
437
|
}
|
|
352
438
|
function exigirAutoriaHumana(por) {
|
|
353
439
|
if (!autoriaHumana(por))
|
|
354
|
-
throw new Error('ratificação exige --por humano explícito; agente ou autoria pendente não pode pontuar');
|
|
440
|
+
throw new Error('ratificação exige --por humano explícito (ex.: --por "seu-nome"); agente ou autoria pendente não pode pontuar');
|
|
355
441
|
}
|
|
356
442
|
function masterRatificado(raiz, id) {
|
|
357
443
|
const t = (0, thread_1.lerThread)(raiz, id);
|
|
@@ -692,7 +778,8 @@ function tabelaDeEntregas(raiz, todas = false) {
|
|
|
692
778
|
(0, util_1.tabela)(['ID', 'SLUG', 'MODO', 'FASE', 'STATUS', 'ENTREGOU', 'INDICE', 'DE ONDE VEIO'], linhas),
|
|
693
779
|
'',
|
|
694
780
|
'ENTREGUE E ACEITO, a menos que voce diga o contrario.',
|
|
695
|
-
' ork master --aceitar-omissao
|
|
781
|
+
' ork master <id> --aceitar-omissao aceita so esta entrega, com o indice e os insumos no ledger',
|
|
782
|
+
' ork master --aceitar-omissao aceita TODAS as entregues da lista (--dry-run mostra quais, sem gravar)',
|
|
696
783
|
' ork master <id> --score <0-5> --justificativa "<por que>" --por <humano> se quiser reclamar',
|
|
697
784
|
'',
|
|
698
785
|
`Classes fixas: ${exports.ORDEM_DAS_CLASSES.join(', ')}`,
|
|
@@ -706,10 +793,40 @@ function tabelaDeEntregas(raiz, todas = false) {
|
|
|
706
793
|
* ENTREGOU: uma thread que nunca chegou ao ship nao tem entrega para aceitar, e
|
|
707
794
|
* aceita-la seria inventar um fato.
|
|
708
795
|
*/
|
|
709
|
-
function aceitarPendentesPorOmissao(raiz) {
|
|
796
|
+
function aceitarPendentesPorOmissao(raiz, opcoes = {}) {
|
|
797
|
+
return entregasParaOmissao(raiz, opcoes.thread).map((p) => aceitarPorOmissao(raiz, p.thread.id));
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* RM-008 (03/10/2026): o que `ork master --aceitar-omissao` fecharia, sem gravar nada.
|
|
801
|
+
*
|
|
802
|
+
* Na madrugada de 03/10, tres vezes, um condutor rodou `ork master --aceitar-omissao` para fechar
|
|
803
|
+
* a PROPRIA thread, e o comando fechou tambem as entregues de outras frentes paralelas. A CLI nao
|
|
804
|
+
* deixava indicar a thread. Com `thread`, o alvo e so ela; sem, continua sendo toda entrega que
|
|
805
|
+
* espera decisao (o padrao nao mudou). Thread inexistente recusa pelo `lerThread`.
|
|
806
|
+
*/
|
|
807
|
+
function entregasParaOmissao(raiz, thread) {
|
|
808
|
+
if (thread !== undefined)
|
|
809
|
+
(0, thread_1.lerThread)(raiz, thread);
|
|
710
810
|
return pendentesDeScore(raiz)
|
|
711
811
|
.filter((p) => p.entregou)
|
|
712
|
-
.
|
|
812
|
+
.filter((p) => thread === undefined || p.thread.id === thread);
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Por que a thread indicada nao entra no aceite por omissao, ou `null` quando entra.
|
|
816
|
+
* `ja-fechada` e idempotencia (nada a fazer); `fechamento-admin` e `sem-entrega` sao recusa.
|
|
817
|
+
*/
|
|
818
|
+
function motivoForaDaOmissao(raiz, id) {
|
|
819
|
+
const thread = (0, thread_1.lerThread)(raiz, id);
|
|
820
|
+
if (thread.fechamentoAdmin) {
|
|
821
|
+
return { motivo: 'fechamento-admin', texto: `a thread ${id} foi fechada administrativamente (${thread.fechamentoAdmin.motivo}); nao ha entrega para aceitar.` };
|
|
822
|
+
}
|
|
823
|
+
if (masterRatificado(raiz, id)) {
|
|
824
|
+
return { motivo: 'ja-fechada', texto: `a thread ${id} ja tem MASTER registrado; nada a aceitar.` };
|
|
825
|
+
}
|
|
826
|
+
if (!entregou(raiz, id)) {
|
|
827
|
+
return { motivo: 'sem-entrega', texto: `a thread ${id} ainda nao entregou (sem ship_done no ledger); registre a entrega antes: ork ship registrar-pr ${id}` };
|
|
828
|
+
}
|
|
829
|
+
return null;
|
|
713
830
|
}
|
|
714
831
|
/** Texto de `ork master <thread-id> --score`. */
|
|
715
832
|
function textoDoMaster(r) {
|
package/dist/mcp-artifacts.js
CHANGED
|
@@ -150,13 +150,46 @@ function comEscrita(raiz, id, executar) {
|
|
|
150
150
|
if (st) {
|
|
151
151
|
if (!st.isDirectory() || st.isSymbolicLink() || fs.realpathSync(pastaLeases) !== pastaLeases)
|
|
152
152
|
throw Error('mcp.state.unsafe: leases');
|
|
153
|
-
for (const
|
|
154
|
-
const
|
|
153
|
+
for (const nomeBytes of fs.readdirSync(pastaLeases, { encoding: 'buffer' })) {
|
|
154
|
+
const nome = nomeBytes.toString('utf8');
|
|
155
|
+
// Antes do lstat: uma decodificacao com perda nao prova que a entrada desapareceu.
|
|
156
|
+
if (!Buffer.from(nome, 'utf8').equals(nomeBytes))
|
|
157
|
+
throw Error('mcp.state.unsafe: nome fora de UTF-8 em leases');
|
|
158
|
+
const entrada = path.join(pastaLeases, nome), s = fs.lstatSync(entrada, { throwIfNoEntry: false });
|
|
159
|
+
if (!s)
|
|
160
|
+
continue; // Uma retomada pode ter acabado durante o preflight.
|
|
161
|
+
if (s.isDirectory() && nome.endsWith('.json.retomadas')) {
|
|
162
|
+
const base = nome.slice(0, -'.json.retomadas'.length);
|
|
163
|
+
if (!base || encodeURIComponent(decodeURIComponent(base)) !== base)
|
|
164
|
+
throw Error('mcp.state.unsafe: fila de retomada');
|
|
165
|
+
let candidatos;
|
|
166
|
+
try {
|
|
167
|
+
candidatos = fs.readdirSync(entrada, { encoding: 'buffer' });
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
if (e.code === 'ENOENT')
|
|
171
|
+
continue;
|
|
172
|
+
throw e;
|
|
173
|
+
}
|
|
174
|
+
for (const candidatoBytes of candidatos) {
|
|
175
|
+
const candidato = candidatoBytes.toString('utf8');
|
|
176
|
+
if (!Buffer.from(candidato, 'utf8').equals(candidatoBytes))
|
|
177
|
+
throw Error('mcp.state.unsafe: nome fora de UTF-8 na fila');
|
|
178
|
+
const c = fs.lstatSync(path.join(entrada, candidato), { throwIfNoEntry: false });
|
|
179
|
+
if (!c)
|
|
180
|
+
continue;
|
|
181
|
+
if (!/^\d+-[a-f0-9-]+\.json(?:\.tmp)?$/.test(candidato) || !c.isFile() || c.nlink !== 1)
|
|
182
|
+
throw Error('mcp.state.unsafe: candidato de retomada');
|
|
183
|
+
}
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
155
186
|
if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1)
|
|
156
187
|
throw Error('mcp.state.unsafe: lease ou fila');
|
|
157
188
|
}
|
|
158
189
|
}
|
|
159
190
|
const nome = `path:.orkastery/threads/${id}`;
|
|
191
|
+
// RM-037 (fatia 3, defeito 4): lease e fila de thread fechada sao orfaos e saem antes da conferencia.
|
|
192
|
+
(0, leases_1.podarRegioesDeThreadsFechadas)(raiz, [nome], id);
|
|
160
193
|
if ((0, leases_1.lerLease)(raiz, nome) || (0, leases_1.leasesColidentes)(raiz, nome).length)
|
|
161
194
|
throw Error('lease.busy: estado canonico ocupado');
|
|
162
195
|
const r = (0, leases_1.adquirirRegiao)(raiz, nome, { thread: id, motivo: 'MCP documento ou claim', ttlMs: 30000, retomarVencido: false });
|
|
@@ -229,6 +262,6 @@ function adicionarClaimMcp(raiz, id, entrada) {
|
|
|
229
262
|
if ((0, thread_1.lerThread)(raiz, id).status === 'fechada')
|
|
230
263
|
throw Error('mcp.claim.closed');
|
|
231
264
|
// Strings sao dados da claim; a reexecucao MCP deve usar o executor confinado.
|
|
232
|
-
return (0, claims_1.adicionarClaim)(raiz, id, entrada);
|
|
265
|
+
return (0, claims_1.adicionarClaim)(raiz, id, { ...entrada, semProvaLocal: true });
|
|
233
266
|
}));
|
|
234
267
|
}
|